Android NDK OpenGL glDeleteTextures导致错误:调用没有当前上下文的OpenGL ES API

时间:2012-01-19 20:22:44

标签: android opengl-es

我正在开发一个Android应用程序,它可以从外部摄像头渲染视频。当我们在ndk中与相机进行通信时,视频帧通过NDK层中的opengl呈现到屏幕,并且速度更快。我没有编写来自第三方(相机开发人员)的代码,他们已经在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活动。似乎把这个电话回来解决问题只是在某些时候。

2 个答案:

答案 0 :(得分:3)

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

不确定这是否有效,但在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语境为你释放它们。

答案 1 :(得分:0)

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