为什么无法从另一个线程调用OpenGL ES函数

Cra*_*ker 10 android opengl-es

我正在尝试使用OpenGL ES为Android编写一个小型游戏引擎.我创建了一个Game Thread来更新游戏对象和GLThread来绘制场景.我读过你需要在GLSurfaceView的onSurfaceCreated方法中加载纹理.我正在关注这个但是出于某些调试目的,我试图从我的游戏线程而不是GLThread加载纹理.我没有错误,纹理没有出现在屏幕上.我花了一整天的时间试图弄清楚问题,最后我在这里阅读了下面的内容

"只需确保在主线程中只使用OpenGL." 很重要.你不能在你的游戏引擎(可能在另一个线程中)中调用一个与gl-thread不同步的纹理加载函数.设置一个标志来指示你的gl线程加载一个新的纹理(例如,你可以在OnDrawFrame(GL gl)中放置一个函数,它检查是否必须加载一个新的纹理.

我将修改我的代码,以便从GL线程加载纹理.我只是不明白为什么会这样?为什么OpenGL函数不能从另一个线程起作用?

我知道如何创建线程,但我不知道同步意味着什么.上面的摘录提到,"你不能在游戏引擎中调用(可能在另一个线程中)一个纹理加载函数,它与gl-thread不同步." 所以我想我的游戏线程可能不会与GL线程同步.是否可以创建另一个与GL Thread同步的线程,以便可以从中调用GL函数?我应该在线程中学到什么才能理解这些概念?

Tom*_*mmy 8

我认为quixoto的评论最接近.OpenGL上下文在几乎每个平台上都是特定于线程的传统原因是OpenGL严重依赖于状态,并且没有用于使一系列更改成为原子的语义.因此,例如,一个线程上的绘制操作可能是:

glVertexPointer(... supply vertex positions ...)
glTexCoordPointer(... provide texture positions ...)
/* and supply a few other pointers, maybe bind a texture */

glDrawArrays(... draw some geometry ...)
Run Code Online (Sandbox Code Playgroud)

因此,最终调用仅在前面的调用的上下文中提供可预测的结果.如果你允许那段代码被暂停,比如说,glVertexPointer另一个线程跳进来并做了很多相同的序列来绘制它的几何图形,然后这个代码继续进行,它将使用相当错误的几何图形绘制,甚至可能导致 -如果某些替换的数组小于原始数据,则为内存访问.

Android提供EGL,它支持OpenGL共享组的常见概念(虽然隐式;您提供一个现有的上下文,您希望新的上下文通过第三个参数位于公共组中eglCreateContext).如果共享组中有两个上下文,则它们中的每一个都具有独立状态,并且可以安全地仅从一个线程调用,但是每个线程都可以使用诸如纹理或顶点缓冲区对象之类的命名对象.因此,使用共享组可以同时在多个线程上执行OpenGL操作,以便能够在单个线程上组合结果.

因此,将上下文绑定到单个线程并不是一个问题.规划OpenGL本身的问题也是不可能的,因为OpenGL上下文以特定于操作系统的方式创建,管理和处理的部分原因是某些操作系统需要以完全不同的方式处理这些内容.或者能够通过展示自己独特的解决方案来提供更好的解决方案.