Android GLES20 - 无法创建 VBO - JNI 错误

Posted

技术标签:

【中文标题】Android GLES20 - 无法创建 VBO - JNI 错误【英文标题】:Android GLES20 - cannot create VBO - JNI ERROR 【发布时间】:2016-07-12 09:20:40 【问题描述】:

我正在 android 中使用 GLES20 创建 VBO,目前遇到了 JNI 错误。我仔细检查了容量和价值计数。我还检查了缓冲区(我的代码中的 STANDARD_QUAD)是否获取和 ID。 我真的不知道如何继续。我在 2 个不同的物理设备和一个模拟器上进行了测试,所以问题一定出在代码的某个地方。

代码:

    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);

输出:

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)

编辑:

把代码改成下面,错误就变了。

    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);

错误变为JNI DETECTED ERROR IN APPLICATION: jarray was null。但绝对缓冲区!= null。真的很奇怪。

【问题讨论】:

这行GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity(), buffer, GLES20.GL_STATIC_DRAW); 是否可能包含在互斥体中? @Shark 如果您的意思是它是否已同步,则否,除非 android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1561) 已同步。 再次阅读堆栈跟踪,我提到的那一行是有问题的,因为它以某种方式调用ReleasePrimitiveArrayCritical 导致called too many critical releases 错误,这可能与某些互斥锁相关,也可能不相关(参见held mutexes= "mutator lock"(shared held)部分?) @Shark 纯数组是什么意思? GLES20.glBufferData(...) 只接受 java.nio.Buffer 对象。 你是对的。我想那时我不知道:/ 看看更多的链接,比如this one 【参考方案1】:

我终于通过使用buffer.position(0) 而不是buffer.flip() 解决了这个问题。

根据文档,buffer.flip() 应该可以正常工作,因为它也将位置设置为 0。唯一的区别是 flip() 还将 limit 设置为最后一个位置(有关更多信息,请参阅the docs信息)。 因此,限制可能会导致奇怪的行为。

【讨论】:

以上是关于Android GLES20 - 无法创建 VBO - JNI 错误的主要内容,如果未能解决你的问题,请参考以下文章

GLES2学习VBO和VAO的使用

GLES2.0 上的 VBO glDrawElements 和 glVertexAttribPointer 不显示任何内容

Android:android.view.GLES20RecordingCanvas.drawBitmap 处的 java.lang.NullPointerException

OpenGL ES 2.0 VBO 问题

帧缓冲区 OES 不完整,android

VBO - 我可以在初始化时做啥?