【问题标题】:android opengl textures loaded in background thread get overwritten在后台线程中加载的android opengl纹理被覆盖
【发布时间】:2011-07-26 10:09:55
【问题描述】:

我正在后台线程中加载纹理,然后将位图发送到 GL 线程(通过 GLSurfaceView.queueEvent(...))以将其上传到显卡。为了防止在每次图像加载后进行垃圾收集,我重用了一个具有二维功能的位图来发送纹理以打开 gl。

这就是问题所在,这个位图有时会被覆盖,因为工作线程和 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 是一个可重入锁。但这仍然不起作用,有时纹理会重复(或被下一个纹理部分覆盖)。看起来解锁是按后进先出顺序...

除了为每个加载的纹理创建一个新的位图并导致 GC 之外,还有什么想法吗? ...它可以解决几乎所有情况,有两个位图用于加载纹理并在它们之间切换,但这不是 100% 正确的。我想通过适当的线程同步来解决这个问题。

【问题讨论】:

    标签: java android multithreading concurrency locking


    【解决方案1】:

    所以过了一天后,我想通了。我使用了最初设置为 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% 正确的方法吗?

    【讨论】:

    • 这不是 100% 正确的,因为可能会发生异常并且您的信号量可能永远不会被释放。因此,您必须确保在 finally 块中调用它。
    • 你的 try { ... } 代码也是错误的。您应该重试获取信号量或完全中止。但是现在你只中断信号量的获取,而不是实际的纹理加载。
    猜你喜欢
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多