0

I'm creating a VBO with GLES20 in Android and am currently running into a JNI error. I doublechecked capacity and value counts. I also checked, if the buffer (STANDARD_QUAD in my code) gets and ID. I really don't know how to continue. I tested on 2 different physical devices and one emulator, so the fault must be in the code somewhere.

Code:

    ByteBuffer buffer = ByteBuffer.allocate(30 * 4);
    buffer.order(ByteOrder.nativeOrder());
    buffer.asFloatBuffer().put(new float[]{
            0, 0, 0,    0,0,
            0,  1, 0,   0,1,
             1, 0, 0,   1,0,
             1,  1, 0,  1,1,
            1, 0, 0,    1,0,
             0, 1, 0,   0,1
    });
    buffer.flip();

    int[] vboids = new int[1];
    GLES20.glGenBuffers(1, vboids, 0);
    STANDARD_QUAD = vboids[0];
    System.out.println("init vbo (std quad): " + STANDARD_QUAD + ", buffer.capacity: " + buffer.capacity());
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, STANDARD_QUAD);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity(), buffer, GLES20.GL_STATIC_DRAW);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

Output:

init vbo (std quad): 1, buffer.capacity: 120
JNI DETECTED ERROR IN APPLICATION: thread Thread[13,tid=19730,Runnable,Thread*=0xb4e08800,peer=0x12c07060,"GLThread 13050"] called too many critical releases
     in call to ReleasePrimitiveArrayCritical
     from void android.opengl.GLES20.glBufferData(int, int, java.nio.Buffer, int)
 "GLThread 13050" prio=5 tid=13 Runnable
   | group="main" sCount=0 dsCount=0 obj=0x12c07060 self=0xb4e08800
   | sysTid=19730 nice=-11 cgrp=apps sched=0/0 handle=0xaf854300
   | state=R schedstat=( 73594541 5530250 17 ) utm=6 stm=1 core=5 HZ=100
   | stack=0xa10fe000-0xa1100000 stackSize=1036KB
   | held mutexes= "mutator lock"(shared held)
   native: #00 pc 00004c58  /system/lib/libbacktrace_libc++.so (UnwindCurrent::Unwind(unsigned int, ucontext*)+23)
   native: #01 pc 000034c1  /system/lib/libbacktrace_libc++.so (Backtrace::Unwind(unsigned int, ucontext*)+8)
   native: #02 pc 0025c5ad  /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::mirror::ArtMethod*)+84)
   native: #03 pc 0023f8cb  /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+162)
   native: #04 pc 000b313d  /system/lib/libart.so (art::JniAbort(char const*, char const*)+620)
   native: #05 pc 000b386d  /system/lib/libart.so (art::JniAbortF(char const*, char const*, ...)+68)
   native: #06 pc 000b6b65  /system/lib/libart.so (art::ScopedCheck::ScopedCheck(_JNIEnv*, int, char const*)+1436)
   native: #07 pc 000c1de7  /system/lib/libart.so (art::CheckJNI::ReleasePrimitiveArrayCritical(_JNIEnv*, _jarray*, void*, int)+42)
   native: #08 pc 000684d1  /system/lib/libandroid_runtime.so (???)
   native: #09 pc 000736e3  /system/lib/libandroid_runtime.so (???)
   native: #10 pc 01574071  /system/framework/arm/boot.oat (Java_android_opengl_GLES20_glBufferData__IILjava_nio_Buffer_2I+128)
   at android.opengl.GLES20.glBufferData(Native method)
   at my.package.glsl.GuiProgram.initQuad(GuiProgram.java:66)
   at my.package.glsl.GuiProgram.onCreated(GuiProgram.java:111)
   at my.package.glsl.Program.create(Program.java:67)
   at my.package.glsl.Shaders.initialize(Shaders.java:26)
   at my.package.myapplication.FullscreenActivity.renderGL(FullscreenActivity.java:66)
   at my.package.myapplication.FullscreenActivity.access$000(FullscreenActivity.java:22)
   at my.package.myapplication.FullscreenActivity$1.render(FullscreenActivity.java:42)
   at my.package.opengl.OpenglRenderer.onDrawFrame(OpenglRenderer.java:38)
   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1561)
   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1278)

EDIT:

Changing the code to the following, the error changes.

    FloatBuffer buffer = ByteBuffer.allocate(30 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    buffer.put(new float[]{
            //...
    });
    buffer.flip();
    //...
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity() * 4, buffer, GLES20.GL_STATIC_DRAW);

The error changes to JNI DETECTED ERROR IN APPLICATION: jarray was null. But definitely buffer != null. It's really weird.

mad_manny
  • 1,081
  • 16
  • 28
  • Is this line `GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity(), buffer, GLES20.GL_STATIC_DRAW);` perhaps wrapped in a mutex? – Shark Jul 12 '16 at 09:27
  • @Shark if you mean wether it is synchronized then no, except `android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1561)` is synchronized. – mad_manny Jul 12 '16 at 09:32
  • Read the stacktrace again, the line I mentioned is problematic since somehow it calls `ReleasePrimitiveArrayCritical` which causes the `called too many critical releases` error, which may or may not be tied to some mutex (see this `held mutexes= "mutator lock"(shared held)` part?) – Shark Jul 12 '16 at 09:39
  • 1
    @Shark What do you mean by plain array? `GLES20.glBufferData(...)` only accepts `java.nio.Buffer` objects. – mad_manny Jul 12 '16 at 09:51
  • You're right. I guess I don't know then :/ Take a look at a few more links like [this one](http://stackoverflow.com/questions/25053786/opengl-es-2-on-android-how-to-use-vbos?rq=1) – Shark Jul 12 '16 at 10:01
  • @Shark I moved the code block directly to the `onSurfaceCreated(...)` method of the Renderer to be sure no custom synchronization is done. I still get the same error. – mad_manny Jul 12 '16 at 10:02

1 Answers1

1

I finally solved it by using buffer.position(0) instead of buffer.flip().

According to the docs buffer.flip() should work correct, as it is also setting the position to 0. The only difference is that flip() is also setting the limit to the last position (see the docs for more information). So it's possible that the limit causes the weird behaviour.

mad_manny
  • 1,081
  • 16
  • 28