Skip to content

Commit

Permalink
Merge branch 'main' into fix-enum-bitwise
Browse files Browse the repository at this point in the history
  • Loading branch information
Cons-Cat authored Nov 21, 2024
2 parents 6a4b85b + bd8ae31 commit e9af3c4
Show file tree
Hide file tree
Showing 3 changed files with 263 additions and 1 deletion.
112 changes: 111 additions & 1 deletion interface/java_binding/src/main/cpp/KtxTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_khronos_ktx_KtxTexture_getDataSize(J
return static_cast<jlong>(ktxTexture_GetDataSize(texture));
}

extern "C" JNIEXPORT jlong JNICALL Java_org_khronos_KTXTexture_getDataSizeUncompressed(JNIEnv *env, jobject thiz)
extern "C" JNIEXPORT jlong JNICALL Java_org_khronos_ktx_KtxTexture_getDataSizeUncompressed(JNIEnv *env, jobject thiz)
{
ktxTexture *texture = get_ktx_texture(env, thiz);
if (texture == NULL)
Expand All @@ -199,6 +199,116 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_khronos_KTXTexture_getDataSizeUncomp
return ktxTexture_GetDataSizeUncompressed(texture);
}


extern "C" JNIEXPORT jint JNICALL Java_org_khronos_ktx_KtxTexture_glUpload(JNIEnv *env, jobject thiz, jintArray javaTexture, jintArray javaTarget, jintArray javaGlError)
{
ktxTexture *texture = get_ktx_texture(env, thiz);
if (texture == NULL)
{
ThrowDestroyed(env);
return 0;
}

// The target array may not be NULL, and must have
// a size of at least 1
if (javaTarget == NULL)
{
ThrowByName(env, "java/lang/NullPointerException", "Parameter 'target' is null for glUpload");
return 0;
}
jsize javaTargetSize = env->GetArrayLength(javaTarget);
if (javaTargetSize == 0)
{
ThrowByName(env, "java/lang/IllegalArgumentException", "Parameter 'target' may not have length 0");
return 0;
}

// The texture array may be NULL, but if it is not NULL,
// then it must have a length of at least 1
if (javaTexture != NULL)
{
jsize javaTextureSize = env->GetArrayLength(javaTexture);
if (javaTextureSize == 0)
{
ThrowByName(env, "java/lang/IllegalArgumentException", "Parameter 'texture' may not have length 0");
return 0;
}
}

// The GL error array may be NULL, but if it is not NULL,
// then it must have a length of at least 1
if (javaGlError != NULL)
{
jsize javaGlErrorSize = env->GetArrayLength(javaGlError);
if (javaGlErrorSize == 0)
{
ThrowByName(env, "java/lang/IllegalArgumentException", "Parameter 'glError' may not have length 0");
return 0;
}
}

GLuint textureValue = 0;
if (javaTexture != NULL)
{
jint *javaTextureArrayElements = env->GetIntArrayElements(javaTexture, NULL);
if (javaTextureArrayElements == NULL)
{
// OutOfMemoryError is already pending
return 0;
}
textureValue = static_cast<GLuint>(javaTextureArrayElements[0]);
env->ReleaseIntArrayElements(javaTexture, javaTextureArrayElements, JNI_ABORT);
}

GLenum target;
GLenum glError;

KTX_error_code result = ktxTexture_GLUpload(texture, &textureValue, &target, &glError);

// Write back the texture into the array
if (javaTexture != NULL)
{
jint *javaTextureArrayElements = env->GetIntArrayElements(javaTexture, NULL);
if (javaTextureArrayElements == NULL)
{
// OutOfMemoryError is already pending
return 0;
}
javaTextureArrayElements[0] = static_cast<jint>(textureValue);
env->ReleaseIntArrayElements(javaTexture, javaTextureArrayElements, JNI_COMMIT);
}

// Write back the target into the array
if (javaTarget != NULL)
{
jint *javaTargetArrayElements = env->GetIntArrayElements(javaTarget, NULL);
if (javaTargetArrayElements == NULL)
{
// OutOfMemoryError is already pending
return 0;
}
javaTargetArrayElements[0] = static_cast<jint>(target);
env->ReleaseIntArrayElements(javaTarget, javaTargetArrayElements, JNI_COMMIT);
}

// Write back the error into the array
if (javaGlError != NULL)
{
jint *javaGlErrorArrayElements = env->GetIntArrayElements(javaGlError, NULL);
if (javaGlErrorArrayElements == NULL)
{
// OutOfMemoryError is already pending
return 0;
}
javaGlErrorArrayElements[0] = static_cast<jint>(glError);
env->ReleaseIntArrayElements(javaGlError, javaGlErrorArrayElements, JNI_COMMIT);
}
return result;
}




extern "C" JNIEXPORT jint JNICALL Java_org_khronos_ktx_KtxTexture_getElementSize(JNIEnv *env, jobject thiz)
{
ktxTexture *texture = get_ktx_texture(env, thiz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,61 @@ public boolean isDestroyed() {
*/
public native long getImageOffset(int level, int layer, int faceSlice);

/**
* Create a GL texture object from a {@link KtxTexture} object.<br>
* <br>
* This may only be called when a GL context is current.<br>
* <br>
* In order to ensure that the GL uploader is not linked into an application
* unless explicitly called, this is not a virtual function. It determines
* the texture type then dispatches to the correct function.<br>
* <br>
* Sets the texture object's <code>GL_TEXTURE_MAX_LEVEL</code> parameter
* according to the number of levels in the KTX data, provided the
* context supports this feature.<br>
* <br>
* Unpacks compressed {@link KtxInternalformat#GL_ETC1_RGB8_OES} and
* <code>GL_ETC2_*</code> format textures in software when the format
* is not supported by the GL context, provided the library has been
* compiled with <code>SUPPORT_SOFTWARE_ETC_UNPACK</code> defined as 1.
*
* It will also convert textures with legacy formats to their modern
* equivalents when the format is not supported by the GL context,
* provided the library has been compiled with
* <code>SUPPORT_LEGACY_FORMAT_CONVERSION</code> defined as 1.
*
* @param texture An array that is either <code>null</code>, or
* has a length of at least 1. It contains the name of the GL texture
* object to load. If it is <code>null</code> or contains 0, the
* function will generate a texture name. The function binds either
* the generated name or the name given in <code>texture</code> to
* the texture target returned in <code>target</code>, before
* loading the texture data. If pTexture is not <code>null</code>
* and a name was generated, the generated name will be returned
* in <code>texture</code>.
* @param target An array with a length of at least 1, where
* element 0 will receive the GL target value
* @param glError An array with a length of at least 1, where
* element 0 will receive any GL error information
* @return {@link KtxErrorCode#SUCCESS} on sucess.
* Returns {@link KtxErrorCode#GL_ERROR} when GL error was raised by
* <code>glBindTexture</code>, <code>glGenTextures</code> or
* <code>gl*TexImage*</code> The GL error will be returned in
* <code>glError</code> if <code>glError</code> is not
* <code>null</code>. Returns {@link KtxErrorCode#INVALID_VALUE}
* when target is <code>null</code> or the size of a mip level
* is greater than the size of the preceding level. Returns
* {@link KtxErrorCode#NOT_FOUND} when a dynamically loaded
* OpenGL function required by the loader was not found.
* Returns {@link KtxErrorCode#UNSUPPORTED_TEXTURE_TYPE} when
* the type of texture is not supported by the current OpenGL context.
* @throws NullPointerException If the given <code>target</code>
* array is <code>null</code>
* @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[]);

/**
* Destroy the KTX texture and free memory image resources.<br>
* <br>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -599,4 +599,101 @@ public void testSupercompressionZLIB() throws IOException {

t.destroy();
}

@Test
public void testBindings() {
Path testKtxFile = Paths.get("")
.resolve("../../tests/testimages/astc_ldr_4x4_FlightHelmet_baseColor.ktx2")
.toAbsolutePath()
.normalize();

// The purpose of this test is to check the bindings for the 'native'
// functions that only return a value. When the binding for one of
// these functions is not implemented properly, then trying to call
// it will cause an 'UnsatisfiedLinkError'.
// This does not cover all 'native' functions: Some of them can only
// sensibly be called in the context of the other tests.

KtxTexture2 texture = KtxTexture2.createFromNamedFile(testKtxFile.toString(),
KtxTextureCreateFlagBits.NO_FLAGS);

// Native getter methods from the 'KtxTexture2' class
texture.getOETF();
texture.getPremultipliedAlpha();
texture.needsTranscoding();
texture.getSupercompressionScheme();
texture.getVkFormat();

// Native getter methods from the 'KtxTexture' class
texture.isArray();
texture.isCubemap();
texture.isCompressed();
texture.getGenerateMipmaps();
texture.getBaseWidth();
texture.getBaseHeight();
texture.getBaseDepth();
texture.getNumDimensions();
texture.getNumLevels();
texture.getNumFaces();
texture.getDataSize();
texture.getDataSizeUncompressed();
texture.getElementSize();
texture.getRowPitch(0);
texture.getImageSize(0);
}

@Test
public void testGlUpload() {
Path testKtxFile = Paths.get("")
.resolve("../../tests/testimages/astc_ldr_4x4_FlightHelmet_baseColor.ktx2")
.toAbsolutePath()
.normalize();

KtxTexture2 ktxTexture = KtxTexture2.createFromNamedFile(testKtxFile.toString(),
KtxTextureCreateFlagBits.NO_FLAGS);
ktxTexture.transcodeBasis(KtxTranscodeFormat.BC1_RGB, 0);

// This test checks the error conditions that are supposed
// to be handled by the JNI layer by throwing exceptions.
// The test can NOT perform an actual, "valid" call that
// causes ktxTexture_GLUpload to be called internally,
// because that would require a GL context to be current.
int texture0[] = { };
int target0[] = { };
int glError0[] = { };
int texture1[] = { 0 };
int target1[] = { 0 };
int glError1[] = { 0 };

// Expect NullPointerException when target is null
assertThrows(NullPointerException.class,
() -> {
ktxTexture.glUpload(texture1, null, glError1);
},
"Expected to throw NullPointerException");

// Expect IllegalArgumentException when texture length is 0
assertThrows(IllegalArgumentException.class,
() -> {
ktxTexture.glUpload(texture0, target1, glError1);
},
"Expected to throw NullPointerException");

// Expect IllegalArgumentException when target length is 0
assertThrows(IllegalArgumentException.class,
() -> {
ktxTexture.glUpload(texture1, target0, glError1);
},
"Expected to throw NullPointerException");

// Expect IllegalArgumentException when glError length is 0
assertThrows(IllegalArgumentException.class,
() -> {
ktxTexture.glUpload(texture1, target1, glError0);
},
"Expected to throw NullPointerException");

ktxTexture.destroy();
}

}

0 comments on commit e9af3c4

Please sign in to comment.