【问题标题】:Android NDK OpenGL glDeleteTextures causes error: call to OpenGL ES API with no current contextAndroid NDK OpenGL glDeleteTextures 导致错误:在没有当前上下文的情况下调用 OpenGL ES API
【发布时间】:2012-01-19 20:22:43
【问题描述】:

我正在开发一个从外部摄像头渲染视频的 android 应用程序。视频帧通过 NDK 层中的 opengl 渲染到屏幕上,就像我们在 ndk 中与摄像头进行通信一样,速度更快。我没有编写代码,因为它来自第 3 方(相机的开发者),他们在 MyGLSurfaceView 中实现了 surfaceDestroyed 方法,如下所示:

   @Override
public void surfaceDestroyed(SurfaceHolder holder) {
      Log.d(TAG, "Inside GL surfaceDestroyed" );
       // TODO Auto-generated method stub
      myRenderer.surfaceDestroyed(); //call this to clean up the renderer.  
      super.surfaceDestroyed(holder);
}

myRenderer 在哪里

 myRenderer = new MyGLRenderer(mContext);

现在在渲染器中编写了以下代码:

public class MyGLRenderer implements Renderer {
    public void surfaceDestroyed()
    {
        Log.d(TAG, "Inside surfaceDestroyed" );
        /* Note: As per doc, GLSurfaceView kills the renderer and deletes any textures associated with it.
         * However, it does not clean up textures created in NDK. So, we need to do this explicitly.
         */
        mGLAdapter.destroyGlTexturesJni(myRenderer);
    }

请注意在 NDK 中创建的纹理不会被清理的注释。这是真的?我问的原因是我从这个调用中得到以下错误:

01-19 12:01:19.715: E/libEGL(27208): call to OpenGL ES API with no current context (logged once per thread)

我已经放置了一些调试语句来确定错误在 NDK 代码中的确切位置,并发现它位于某个名为 ImageRender(调用 Clean)的类的析构函数中,这是触发它的行:

void ImageRender::Clean()
{   
// destruct texture
if (m_unTexture != -1)
    glDeleteTextures( 1,&m_unTexture );
     ....

看起来他们在这里设置了 m_unTexture(这是 gl 上下文对吗?):

    int ImageRender::InitTexture( const int nWidth, const int nHeight )
    {
// Enable texture 2D first.
glEnable( GL_TEXTURE_2D );
// create texture
glGenTextures( 1,&m_unTexture );
// bind texture to target.
glBindTexture( GL_TEXTURE_2D,m_unTexture );
    ...

如果他们检查 glGetError 并且如果他们没有得到 GL_NO_ERROR 则通过代码将其设置为 -1,因此他们知道它是无效的。

好的,所以我的问题是我真的需要清理在 NDK 中创建的纹理吗?如果需要,我怎样才能没有看到的错误。我尝试使用以下方式调用:

    //from MyGLSurfaceView
    @Override
public void surfaceDestroyed(SurfaceHolder holder) {
    Log.d(TAG, "Inside GL surfaceDestroyed" );
            // TODO Auto-generated method stub

      queueEvent(new Runnable() {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            myRenderer.surfaceDestroyed(); //call this to clean up the renderer.    
        }
       });
    super.surfaceDestroyed(holder);
}

确保在 opengl 线程上调用了渲染器,但出现了同样的错误。

有什么建议吗?顺便说一句,如果我根本不调用此方法,代码似乎可以正常工作,我已经做了很长一段时间了,但是我遇到了问题,当我开始使用 opengl 框架的活动时,它将使用来自的最后一帧进行初始化以前的opengl活动。似乎重新调用此调用解决了问题,但只是在某些时候。

【问题讨论】:

    标签: android opengl-es


    【解决方案1】:

    您不能在 UI 线程上调用 myRenderer.surfaceDestroyed,因为它没有 OpenGL 上下文。 您必须使用 queueEvent,在 OpenGL 线程上运行 surfaceDestroyed。您使用 Runnable 实现的问题如下 - queueEvent 是非阻塞的。所以很可能 super.surfaceDestroyed(holder) 在 myRenderer.surfaceDestroyed() 之前被调用,并且 GL 上下文在你的任何本机代码被调用之前被销毁。

    不确定这是否可行,但尝试在 queueEvent 调用后阻塞 UI 线程并等待 Runnable 完成它的工作。像这样的:

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d(TAG, "Inside GL surfaceDestroyed" );
    
        queueEvent(new Runnable() {
            @Override
            public void run() {
                myRenderer.surfaceDestroyed();
                synchronized (myRenderer) { 
                    myRenderer.notify(); 
                }
            }
        });
    
        synchronized (myRenderer)
        {
            try { myRenderer.wait(100); }
            catch (InterruptedException e) { }
        }
    
        super.surfaceDestroyed(holder);
    }
    

    这将阻止 UI 线程最多 100 毫秒,从而允许您的本机代码清理上下文。如果需要,增加 100 到更多。

    在最坏的情况下 - 只是不要自己释放 GL 资源。让 GL 上下文为您释放它们。

    【讨论】:

    • 关于如何在另一个线程上进行调用时阻塞的有趣想法。不幸的是,尽管我仍然收到关于在没有当前上下文的情况下调用 OpenGL ES API 的错误。我不确定为什么,因为我很肯定调用 glDeleteTextures(1,&m_unTexture);发生在 super.surfaceDestroyed(holder) 调用之前(Logged all out)
    • 实际上有一个关于这个的错误 - code.google.com/p/android/issues/detail?id=19245 似乎在表面已经被销毁后调用了surfaceDestroyed。
    • GLSurfaceView.EGLContextFactory 接口有destroyContext回调。尝试使用它。如果我理解正确 - 如果您在 GLSurfaceView 上调用 setEGLContextFactory,那么您自己负责在 destryContext 回调中销毁上下文。
    • 我不确定如何或在哪里使用它?正如我所说,对 opengl 来说很新。能否详细说明
    【解决方案2】:

    回答您的其他问题:m_unTexture 是 GL 纹理名称(不是 GL 上下文)。 -1 值似乎只是纹理名称的默认初始化值,如果 glGenTextures() 无法为纹理分配新名称,则不会触及该值。

    【讨论】:

      猜你喜欢
      • 2012-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多