Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GL upload function to Java interface #959

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

javagl
Copy link
Contributor

@javagl javagl commented Nov 13, 2024

(This builds upon #957, so that should be merged first)

This adds bindings for the ktxTexture_GLUpload function to the Java interface.

There certainly are a few degrees of freedom about how exactly that should be offered. And there is a trade-off between "trying to closely resemble the existing API" and "trying to create a nice API for Java". The main point here being that the function receives three pointers (to int values, essentially). And pointers don't exist in Java.

A common (although not pretty) way is to emulate these with single-element arrays. So the call currently looks like this:

int texture[] = { 0 };
int target[] = { 0 };
int glError[] = { 0 };
int result = ktxTexture.glUpload(texture, target, glError);

This will fill the given arrays with the values that are returned from the native layer, accordingly.

Proper testing may be difficult. The basic call conditions are checked in a unit test. But beyond that, really using the function will require an OpenGL context to be current, so that 1. requires an OpenGL binding for the test, and 2. can hardly happen during the standard test runs.


I tried it out in a very basic experiment. This experiment currently used https://www.lwjgl.org/ , but I'll probably also try it with https://jogamp.org/ . Given that LWJGL is the library behind https://libgdx.com/ and https://jmonkeyengine.org/ , that's likely to be a primary goal.

The result of that experiment is shown here...

Khronos KTX in Java

... and I frankly couldn't care less that it's upside down. It works 🙃

* @throws IllegalArgumentException Any array that is not
* <code>null</code> has a length of 0
*/
public native int glUpload(int texture[], int target[], int glError[]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious. Why are these parameters arrays?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's mentioned in the first post. And it is the most important "design decision" here. I'll elaborate that in a comment below.

@MarkCallow
Copy link
Collaborator

and I frankly couldn't care less that it's upside down.

The upside-down image is hugely more likely to be an application issue than an issue with glUpload.

@javagl
Copy link
Contributor Author

javagl commented Nov 14, 2024

A detail:

The upside-down image is hugely more likely to be an application issue than an issue with glUpload.

I'm aware of the abundance of issues related to "textures being upside-down" (and crutches like UNPACK_FLIP_Y_WEBGL didn't make it better, but maybe worse - another possible source of this issue). What I find interesting, though, is that

But that's all (probably) unrelated to glUpload itself.


About the inlined comment:

Just curious. Why are these parameters arrays?

In the C version, these parameters are pointers, like GLuint *pTexture. And the function can conveniently be called by passing in the address of a local variable, as in

GLuint texture = 0;
ktxTexture_GLUpload(kTexture, &texture, ...);

In Java, there are no pointers or addresses. And we have to return (up to) three int values from this function - in addition to the return value that represents the KtxErrorCode.

There are different options for this:

Using arrays (as it is done here)

This is a (somewhat quirky, but IMHO reasonable) way of emulating "pointers". It is still somewhat convenient:

int texture[] = { 0 };
int result = ktxTexture.glUpload(texture, ...);
// The GL texture ID is now in `texture[0]`

It also most closely resembles the original API.

Defining a structure to carry these values

One could create a struct-like class, like

class GlUploadParameters {
    int texture;
    int target;
    int error;
}

And then call the function like this:

GlUploadParameters p = new GlUploadParameters();
int result = ktxTexture.glUpload(texture, r);
// The GL texture ID is now in `p.texture`

But defining, documenting, and accessing such a structure always involves some overhead of which I'm not sure whether it brings reasonable benefit here.


In the JavaScript bindings, the glUpload function seems to return an "anonymous" (untyped) object with the result properties:

            val texObject = val::module_property("GL")["textures"][texname];
            ret.set("object", texObject);
            ret.set("target", target);
            ret.set("error", error);
            return ret;

This does raise some questions about the error handling - the KTX_error_code is not present there. But untyped objects don't exist in Java either.

The Python bindings do not seem to offer the glUpload function at all.

@javagl
Copy link
Contributor Author

javagl commented Nov 14, 2024

(A small note: The build failure at https://github.com/KhronosGroup/KTX-Software/actions/runs/11837211122/job/32983720702?pr=959#step:17:53 looks like it is unrelated to this PR, but in doubt, I'll re-start/investigate)

@MarkCallow
Copy link
Collaborator

I'm aware of the abundance of issues related to "textures being upside-down" (and crutches like UNPACK_FLIP_Y_WEBGL didn't make it better, but maybe worse - another possible source of this issue). What I find interesting, though, is that

* Dragging-and-dropping a PNG file into https://sandbox.babylonjs.com/ shows it properly

* Dragging-and-dropping the KTX file that was _directly_ created from that PNG into into https://sandbox.babylonjs.com/ shows it upside down

But that's all (probably) unrelated to glUpload itself.

It is indeed unrelated to glUpload. It uploads the image data in the same memory order it is found in the input file which in KTX defaults to the first byte being the top-left corner (equivalent to KTXorientation of "rd"). But OpenGL's commonly used orientation has the first byte being the bottom left corner.

Applications need to check the image orientation of the KTX file and, if differs from the coordinate system, they are using, take steps to show the image with the correct orientation. That can be by y-flipping the image (ugh!), changing the texture coordinates or using a texture transform. Your observation suggests that Babylon is not properly handling KTX files. It is obviously taking one of the steps I suggested when handling PNG files. Most likely it is y-flipping the image before uploading to WebGL. It is not doing anything for KTX files. You can test this theory by creating the file with toktx using the --lower_left_maps_to_s0t0 option which will flip the image and try loading that with Babylon.

@MarkCallow
Copy link
Collaborator

Thanks for the explanation about the arrays. Agree they seem the best way to return the values in Java.

The JS binding is done the way it is due to EMBIND. Maybe there is a better way. If so, now would be a good time to fix it as the upcoming release contains a major rewrite of the wrapper.

Is there a python wrapper for OpenGL?

@MarkCallow
Copy link
Collaborator

(A small note: The build failure at https://github.com/KhronosGroup/KTX-Software/actions/runs/11837211122/job/32983720702?pr=959#step:17:53 looks like it is unrelated to this PR, but in doubt, I'll re-start/investigate)

Why do you say that? The error is due to this warning

D:\a\KTX-Software\KTX-Software\interface\java_binding\src\main\cpp\KtxTexture.cpp(251,13): warning C4189: 'pTexture': local variable is initialized but not referenced [D:\a\KTX-Software\KTX-Software\build\interface\java_binding\ktx-jni.vcxproj]
  KtxTexture1.cpp

which is turned into an error because CI uses -Werror or whatever the MSVC equivalent is.

@javagl
Copy link
Contributor Author

javagl commented Nov 14, 2024

Your observation suggests that Babylon is not properly handling KTX files

It seems to be handling them properly when they are part of glTF and used as textures. The preview being upside down may just be a detail. (And the fact that it is even possible to simply drag-and-drop a KTX file into an online viewer and have a preview is already tremendously helpful - at least, until I get my Java application together that is the reason for all the stuff that I'm doing here...). Maybe the fact that it's shown upside down could be tracked somewhere in https://github.com/babylonjs , but it doesn't seem to be critical.


The JS binding is done the way it is due to EMBIND.

I cannot say much about the JS bindings, and would have to take a closer look at the actual .js binding files to better understand the options. (I'd mainly be curious about the error handling here...)


Is there a python wrapper for OpenGL?

There seem to be bindings at https://pyopengl.sourceforge.net/ but I'm even less familiar with Python than with JavaScript.


Why do you say that? The error is due to this warning

I see, indeed, that's before that "Update test log" failure (and likely causes it). I removed the unused variable - let's see whether the build passes now.

@MarkCallow
Copy link
Collaborator

I guess merging #957 caused the conflict.

The Travis-CI failure is because the Java wrapper test is failing on macOS for some reason.

@MarkCallow
Copy link
Collaborator

Maybe the fact that it's shown upside down could be tracked somewhere in https://github.com/babylonjs , but it doesn't seem to be critical.

I'll open an issue but first please run ktx info on the file and tell me if it has KTXorientation metadata, if so, the value, and, for completeness, the tool used to create the KTX file.

# Conflicts:
#	interface/java_binding/src/test/java/org/khronos/ktx/test/KtxTexture2Test.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants