2011-07-26 114 views
0

我在後臺線程中加載紋理,然後將位圖發送到GL線程(通過GLSurfaceView.queueEvent(...))將其上傳到圖形卡。爲了防止在每次圖像加載後垃圾收集,我重新使用一個具有二維權力的位圖來發送紋理來打開gl。在後臺線程中加載的android opengl紋理被覆蓋

這就是問題所在,這個位圖有時會被覆蓋,因爲工作線程和GL線程正在互相爭鬥。據我瞭解,它是不可能獲得一個線程(工人)的鎖,並在另一個線程(GL)解鎖它。所以我想出了這樣一個解決方案(我的線程是HandlerThread):

public boolean handleMessage(Message msg) { 
    switch(msg.what) { 
     case MESSAGE_FROM_MAIN_THREAD: 
      m_Lock.lock(); 
      loadTextureFromAssets(msg.obj.toString(), msg.arg1); 
      break; 

     case MESSAGE_FROM_GL_THREAD: 
      m_Lock.unlock(); 
      break; 
    } 

    return true; 
} 

是m_Lock是一個ReentrantLock的。但這仍然不起作用,有時紋理會重複(或被下一個紋理部分覆蓋)。它看起來像解鎖是LIFO命令...

任何想法,除了爲每個加載的紋理創建一個新的位圖,並導致GC? ...幾乎所有的情況下都可以解決這個問題,它有兩個Bitmaps用於加載紋理並在它們之間切換,但這不是100%正確的。我想通過適當的線程同步來解決這個問題。

回答

2

所以過了一天,我想出了這一點。我用一個信號量初始設定爲1,並LoadTextureFromAssets(...)之前獲取它,並在發送到GL一個Runnable的端部釋放它上傳的質地:

public boolean handleMessage(Message msg) { 
    switch(msg.what) { 
     case MESSAGE_FROM_MAIN_THREAD: 
      try { 
       m_Semaphore.acquire(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 

      loadTextureFromAssets(msg.obj.toString(), msg.arg1); 

      break; 

     case MESSAGE_FROM_GL_THREAD: 
      // not needed for now 
      break; 

    } 

    return true; 
} 

和int上傳方法:

// load the image from assests and then... 
m_GLSurface.queueEvent(new Runnable() { 
     public void run() { 
       gl.glBindTexture(GL10.GL_TEXTURE_2D, m_TexId); 

       gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); 
       gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); 
       gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
       gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); 

       if (gl instanceof GL11) { 
        // GL 1.1 has auto mip-map generation 
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_LINEAR); 
        gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE); 
       } 

       GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, m_TexBitmap, 0); 

       m_Semaphore.release(); 
      } 
    }); 

這是100%正確的方式嗎?

+1

這不是100%正確的,因爲可能會發生異常,並且可能永遠不會釋放您的信號量。因此你必須確保你在finally塊中調用它。 –

+0

此外,您的嘗試{...}代碼是錯誤的。您應該重試獲取信號量或完全中止。但是現在你只中斷了信號量的獲取,而不是實際的紋理加載。 –