2012-01-19 67 views
0

我上從外部攝像頭視頻呈現一個Android應用程序的工作來電的OpenGL ES API。視頻幀通過NDK層中的opengl呈現給屏幕,因爲我們在ndk中與相機進行通信,速度更快。我沒有寫代碼,因爲它從第三方(相機的開發者)來了,他們已經實施的方法surfaceDestroyed在MyGLSurfaceView如下:的Android NDK的OpenGL glDeleteTextures會導致錯誤:沒有當前上下文

@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(這就要求清潔)類,這裏是觸發它的行:

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活動。似乎把這個呼叫重新固定在問題上,但只有一些時間。

回答

3

你不能調用UI線程myRenderer.surfaceDestroyed,因爲它沒有OpenGL上下文。 您必須使用queueEvent,才能在OpenGL線程上運行surfaceDestroyed。使用Runnable實現的問題如下 - queueEvent是非阻塞的。因此,在調用任何本地代碼之前,myRenderer.surfaceDestroyed()和GL上下文被銷燬之前,最有可能調用super.surfaceDestroyed(持有者)。

不知道這是否會工作,但嘗試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); 
} 

這將阻止最多100毫秒的UI線程,允許您的本機代碼清理上下文。如果需要增加100個以上。

在最壞的情況 - 就是不自由GL自己的資源。讓GL上下文爲你解除它們。

+0

關於如何在另一個線程上進行調用時阻止有趣的想法。不幸的是,儘管我仍然遇到了在沒有當前上下文的情況下調用OpenGL ES API的錯誤。我不知道爲什麼,因爲我肯定要調用glDeleteTextures(1,&m_unTexture);發生在super.surfaceDestroyed(holder)調用之前(記錄下所有內容) –

+0

實際上有一個bug正好填充了這個 - http://code.google.com/p/android/issues/detail?id=19245看來surfaceDestroyed是所謂的表面已經被破壞。 –

+1

[GLSurfaceView.EGLContextFactory](http://developer.android.com/reference/android/opengl/GLSurfaceView.EGLContextFactory.html)接口具有destroyContext回調。嘗試使用它。如果我理解正確 - 如果您在GLSurfaceView上調用setEGLContextFactory,那麼您自己負責銷燬destryContext callaback中的上下文。 –

0

要回答您的其他問題:m_unTexture是GL紋理名稱(不是GL上下文)。如果glGenTextures()未能爲紋理分配新名稱,-1值似乎只是紋理名稱的默認初始值,如果glGenTextures()未能爲其分配新的名稱,則該值不會被觸及。

相關問題