Java 如何使用android OpenGL在线程之间进行通信

Java 如何使用android OpenGL在线程之间进行通信,java,android,multithreading,opengl-es,Java,Android,Multithreading,Opengl Es,假设我得到一个像素流缓冲区,我想用OpelnGL显示它们;为此,我使用了GLES20.glTexImage2D。现在我想在每次获得新缓冲区时更新图像。如何从MainActivity或其他不知道OpenGL线程的类中执行该操作 这是我的loadTexture方法 private int loadTexture () { int[] textureId = new int[1]; buffer.clear(); // buffer is a public st

假设我得到一个像素流缓冲区,我想用
OpelnGL
显示它们;为此,我使用了
GLES20.glTexImage2D
。现在我想在每次获得新缓冲区时更新图像。如何从MainActivity或其他不知道OpenGL线程的类中执行该操作

这是我的
loadTexture
方法

private int loadTexture ()
    {
        int[] textureId = new int[1];
        buffer.clear(); // buffer is a public static variable
        buffer.put(data); // data has been created for the test
        buffer.position(0);

        GLES20.glGenTextures(1, textureId, 0);
        GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureId[0] );

        GLES20.glTexImage2D ( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, 512, 512, 0,
                GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, buffer );

        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        return textureId[0];
    }
public void onDrawFrame(GL10 glUnused)
    {
        GLES20.glViewport(0, 0, mWidth, mHeight);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glUseProgram(mProgramObject);
        ...

        // Bind the base map
        GLES20.glActiveTexture ( GLES20.GL_TEXTURE0 );
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBaseMapTexId);

        // Set the base map sampler to texture unit to 0
        GLES20.glUniform1i(mBaseMapLoc, 0);

        // Bind the light map
        GLES20.glActiveTexture ( GLES20.GL_TEXTURE1 );
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mLightMapTexId);

        // Set the light map sampler to texture unit 1
        GLES20.glUniform1i(mLightMapLoc, 1);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);

        // For test purpose, I try to update the data in the buffer
        byte[] data = new byte[512*512*3];
        for ( int y = 0; y < 512; y++ )
            for ( int x = 0; x < 512; x++ )
            {
                int pixel = 200;
                data[(y * 512 + x) * 3 + 0] = (byte)((pixel >> 0) & 0xFF);
                data[(y * 512 + x) * 3 + 1] = (byte)((pixel >> 0) & 0xFF);
                data[(y * 512 + x) * 3 + 2] = (byte)((pixel >> 0) & 0xFF);
            }
        buffer.clear();
        buffer.put(data);
        buffer.position(0);          
    } 
即使我在OpenGL线程中添加了这个到
onDrawFrame
方法中

private int loadTexture ()
    {
        int[] textureId = new int[1];
        buffer.clear(); // buffer is a public static variable
        buffer.put(data); // data has been created for the test
        buffer.position(0);

        GLES20.glGenTextures(1, textureId, 0);
        GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureId[0] );

        GLES20.glTexImage2D ( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, 512, 512, 0,
                GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, buffer );

        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        return textureId[0];
    }
public void onDrawFrame(GL10 glUnused)
    {
        GLES20.glViewport(0, 0, mWidth, mHeight);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glUseProgram(mProgramObject);
        ...

        // Bind the base map
        GLES20.glActiveTexture ( GLES20.GL_TEXTURE0 );
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mBaseMapTexId);

        // Set the base map sampler to texture unit to 0
        GLES20.glUniform1i(mBaseMapLoc, 0);

        // Bind the light map
        GLES20.glActiveTexture ( GLES20.GL_TEXTURE1 );
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mLightMapTexId);

        // Set the light map sampler to texture unit 1
        GLES20.glUniform1i(mLightMapLoc, 1);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);

        // For test purpose, I try to update the data in the buffer
        byte[] data = new byte[512*512*3];
        for ( int y = 0; y < 512; y++ )
            for ( int x = 0; x < 512; x++ )
            {
                int pixel = 200;
                data[(y * 512 + x) * 3 + 0] = (byte)((pixel >> 0) & 0xFF);
                data[(y * 512 + x) * 3 + 1] = (byte)((pixel >> 0) & 0xFF);
                data[(y * 512 + x) * 3 + 2] = (byte)((pixel >> 0) & 0xFF);
            }
        buffer.clear();
        buffer.put(data);
        buffer.position(0);          
    } 
如何从MainActivity或其他不知道OpenGL线程的类中执行该操作

首先,让我们更正一些术语。没有“OpenGL线程”这样的东西;如果你使用这个术语,它会很快变得非常混乱

您拥有的是来自平台特定渲染层的渲染上下文(例如iOS上的EAGL、Android上的EGL)。每个渲染上下文在任何时间点都可以在一个线程中处于活动状态,但可以移动线程(例如,通过调用EGL平台层的
eglMakeCurrent
),这就是为什么在概念上考虑“OpenGL线程”是一个如此糟糕的想法的原因

将上下文绑定到线程将删除任何现有上下文的绑定,并从其他线程取消绑定新上下文。除了在线程之间移动线程外,还可以将多个不同的渲染上下文绑定到并行运行的多个不同线程,这对于这个问题很重要

通过将同一共享组中的多个渲染上下文绑定到不同的线程(例如,如果使用EGL,请参见
share_context
参数至
eglCreateContext
),可以实现所需的数据共享。您可以在一个上下文中创建纹理,上载数据,然后另一个上下文可以绑定并使用它。同步(例如,让另一个线程知道何时可以安全地使用该纹理绑定)必须通过应用程序级同步协议完成-API不提供该协议

关于多个上下文之间的状态同步的规则变得有点复杂(总之,它通常是惰性的,并且只有在上下文重新绑定资源时才同步),因此我强烈建议阅读OpenGL ES 2.0规范的附录C(或更高版本的ES中的同等内容-它没有改变)

如何从MainActivity或其他不知道OpenGL线程的类中执行该操作

首先,让我们更正一些术语。没有“OpenGL线程”这样的东西;如果你使用这个术语,它会很快变得非常混乱

您拥有的是来自平台特定渲染层的渲染上下文(例如iOS上的EAGL、Android上的EGL)。每个渲染上下文在任何时间点都可以在一个线程中处于活动状态,但可以移动线程(例如,通过调用EGL平台层的
eglMakeCurrent
),这就是为什么在概念上考虑“OpenGL线程”是一个如此糟糕的想法的原因

将上下文绑定到线程将删除任何现有上下文的绑定,并从其他线程取消绑定新上下文。除了在线程之间移动线程外,还可以将多个不同的渲染上下文绑定到并行运行的多个不同线程,这对于这个问题很重要

通过将同一共享组中的多个渲染上下文绑定到不同的线程(例如,如果使用EGL,请参见
share_context
参数至
eglCreateContext
),可以实现所需的数据共享。您可以在一个上下文中创建纹理,上载数据,然后另一个上下文可以绑定并使用它。同步(例如,让另一个线程知道何时可以安全地使用该纹理绑定)必须通过应用程序级同步协议完成-API不提供该协议


关于多个上下文之间的状态同步的规则变得有点复杂(总之,它通常是惰性的,并且只有在上下文重新绑定资源时才同步),因此我强烈建议阅读OpenGL ES 2.0规范的附录C(或更高版本的ES中的同等规范-它没有更改)。

感谢您的回复。事实上,即使在正确的背景下,我也有一个问题。在
onDrawFrame
中,我尝试更改缓冲区变量,但这不会更新纹理,怎么可能?您的“缓冲区”变量是程序的局部变量;这与渲染API使用的纹理数据无关。调用
glTexImage2D
时,图形驱动程序会获取一份副本。如果要修改纹理的内容,则需要更新“缓冲区”,然后再次调用
glTexImage2D
,以更改图形堆栈看到的内容。感谢您的回复。我试着听从你的劝告。因此,我在
onDrawFrame
的底部添加了以下代码
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mBaseMapTexId);GLES20.glTexSubImage2D(GLES20.GL_纹理_2D,0,GLES20.GL_RGB,512,0,GLES20.GL_RGB,GLES20.GL_无符号_字节,bufer)
,其中
mBaseMapTexId
是在
loadTexture()
方法中设置的纹理ID,但它不起作用(当然知道我在
onDrawFrame
方法中更新了
buffer
)。谢谢你的帮助谢谢你的回复。事实上,即使在正确的背景下,我也有一个问题。在
onDrawFrame
中,我尝试更改缓冲区变量,但这不会更新纹理,怎么可能?您的“缓冲区”变量是程序的局部变量;这与渲染API使用的纹理数据无关。调用
glTexImage2D
时,图形驱动程序会获取一份副本。如果要修改纹理的内容,需要更新“缓冲区”,然后调用
glTexImage2D
ag