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