我正在尝试让一款基于NDK的游戏在Android ICS上运行。它在蜂窝和姜饼上效果很好。
游戏使用一些2D渲染,一些3D渲染,在不同的执行阶段在两者之间切换。(由于第三方代码的原因,这是不可协商的。)我们使用ANativeWindow_lock()
/ANativeWindow_unlockAndPost()
进行2D渲染,使用eglCreateWindowSurface()
/gl*()
/eglSwapBuffers()
进行3D渲染。
在Honeycomb和Gingerbread上,这一切都很好。在ICS上,eglCreateWindowSurface()
失败,日志中出现以下消息:
E/SurfaceTexture( 1765): [com.fnord/com.fnord.MyActivity] connect: already connected (cur=2, req=1)
E/libEGL ( 5466): EGLNativeWindowType 0x29e9b8 already connected to another API
E/libEGL ( 5466): eglCreateWindowSurface:374 error 300b (EGL_BAD_NATIVE_WINDOW)
E/libEGL ( 5466): call to OpenGL ES API with no current context (logged once per thread)
从源代码来看,很明显eglCreateWindowSurface()
失败了,因为它打开了用于2D渲染的原生窗口,如果不首先释放曲面,它不会让我将其更改为3D。然而,ANativeWindow API似乎没有任何明显的方法来做到这一点。
其他人遇到过这种情况吗?解决方案是什么?
更新
因此,我重写了2D渲染代码,改为使用OpenGL基元(将backbuffer上传到纹理,通过一对三角形渲染纹理,swapbuffer)。这在一定程度上起作用现在发生的事情是2D渲染工作正常;然后我破坏了曲面,创建了一个新曲面,为3D渲染做准备,对eglCreateWindowSurface()
的第二次调用失败。这次,使用:
E/SurfaceTexture( 1869): [com.fnord/com.fnord.MyActivity] connect: already connected (cur=1, req=1)
并且它抛出CCD_ 9的EGL错误。
请注意,创建的新曲面具有与旧曲面完全相同的属性。我甚至试着确保在对eglCreateWindowSurface()
的两次调用之间调用eglTerminate()
/eglInitialize()
。
我可以精确地使用每个ANativeWindow一次吗?如果是这样的话,这难道不会通过Khronos的EGL一致性测试吗?那么,有没有办法让NativeActivity重新创建窗口?
更新更新
事实证明,最后一个问题是由于我未能在破坏上下文和表面之前调用eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)
。这导致破坏被延迟,直到线程解除上下文和表面的绑定,当然不是这样,所以导致对eglCreateWindowSurface()
的调用合法失败(在同一个本地窗口上不能有两个窗口表面)。
这是一个违反直觉的位,因为人们会认为调用eglTerminate()
会破坏所有EGL资源,但规范允许这样做。请注意!
这不是一个受支持的用例。它以前工作的事实对你来说只是运气,它可能会在某些设备上失败。您可以通过在不同的窗口中渲染2D或3D内容来解决此问题,或者在位图中渲染2D内容,然后将其用作GL纹理等。
您可以从OpenGL切换到CPU渲染(ANativeWindow_lock
),反之亦然,但您需要使用Surface.release()
释放已使用的Surface
,并从您的SurfaceTexture
为另一个API创建一个新的。
示例应用