为什么OpenGL ES函数不能从另一个线程调用

发布于 2024-12-11 09:14:05 字数 731 浏览 1 评论 0原文

我正在尝试使用 OpenGL ES 为 Android 编写一个小型游戏引擎。我创建了一个游戏线程来更新游戏对象,并且 GLThread 用来绘制场景。我读过您需要在 GLSurfaceView 的 onSurfaceCreated 方法中加载纹理。我正在关注这一点,但出于某些调试目的,我尝试从我的游戏线程而不是 GLThread 加载纹理。我没有收到任何错误,并且纹理没有显示在屏幕上。我花了一整天的时间试图找出问题所在,最后我读了下面的内容 此处

“请确保仅在主线程中使用 OpenGL。”非常重要。您无法在游戏引擎(可能位于另一个线程中)中调用与 gl 线程不同步的纹理加载函数。设置一个标志来指示您的 gl 线程加载新纹理(例如,您可以在 OnDrawFrame(GL gl) 中放置一个函数,该函数检查是否必须加载新纹理。

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

我知道如何创建线程,但我不知道上面的摘录提到的是什么。 “你不能调用你的游戏引擎(可能在另一个线程中)一个与 gl 线程不同步的纹理加载函数。”所以我猜我的游戏线程可能不与 GL 线程同步。是否可以创建另一个与 gl 线程同步的线程GL 线程以便可以从中调用 GL 函数?我应该在线程中学习什么来理解这些概念?

I am experimenting with writing a small game engine for Android using OpenGL ES. I have created a Game Thread which updates the game objects and the GLThread with draws the scene. I had read that you need to load the textures in onSurfaceCreated method of GLSurfaceView. I am following that but for some debugging purpose I was trying to load textures from my Game Thread instead of the GLThread. I got no errors and the texture were not showing up on the screen. I spent my entire day trying to figure out the problem and finally I read the below here

"Just be sure to only use OpenGL in the main thread." Very important. You cannot call in your Game Engine (which may be in another thread) a texture-loading function which is not synchronized with the gl-thread. Set there a flag to signal your gl-thread to load a new texture (for example, you can place a function in OnDrawFrame(GL gl) which checks if there must be a new texture loaded.

I will modify my code so that the textures will be loaded from the GL Thread. I just could not understand why is it so? Why do the OpenGL functions do not work from another thread?

I know how to create threads but I do not know what synchronization means. The above extract mentions, "You cannot call in your Game Engine (which may be in another thread) a texture-loading function which is not synchronized with the gl-thread." So I guess my Game Thread might not be synchronized with the GL Thread. Is it possible to create another thread which is synchronized to the GL Thread so that GL functions can be called from it? What should I learn in threading to understand these concepts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

贪了杯 2024-12-18 09:14:05

我认为 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 ...)

因此,最终调用仅在前面调用的上下文中提供可预测的结果。如果您允许在 glVertexPointer 之后暂停该代码,另一个线程会跳入并执行大致相同的序列来绘制其几何图形,然后继续执行此代码,它将以相当的速度绘制错误的几何结构,如果某些替换的数组小于原始数组,甚至可能导致内存访问越界。

Android 提供 EGL,它支持 OpenGL 共享组的通用概念(尽管是隐式的;您通过 eglCreateContext)。如果两个上下文位于一个共享组中,那么它们中的每一个都具有独立的状态,并且只能从一个线程安全地调用,但它们中的每一个都可以使用命名对象,例如纹理或顶点缓冲区对象。因此,使用共享组,您可以同时在多个线程上执行 OpenGL 操作,以便能够在单个线程上组合结果。

因此,将上下文绑定到单个线程并不是什么大问题。在 OpenGL 本身中规划这个问题也是不可能的,因为以特定于操作系统的方式创建、管理和处置 OpenGL 上下文的部分原因是某些操作系统需要以与其他操作系统完全不同的方式处理这些东西或者能够通过暴露自己独特的解决方案来提供更好的解决方案。

quixoto's comment is closest, I think. The traditional reason that OpenGL contexts are thread specific on pretty much every platform is that OpenGL is heavily dependent on states and has no semantics for making a series of changes atomic. So, for example, the draw operation on one thread might be:

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

glDrawArrays(... draw some geometry ...)

So the final call provides predictable results only in the context of the preceding calls. If you allow for that bit of code being paused after, say, glVertexPointer, another thread hopping in and doing much the same sequence to draw its geometry and then this code proceeding, it'll draw with quite the wrong geometry, possibly even causing out-of-bounds memory accesses if some of the replaced arrays are smaller than the originals.

Android supplies EGL, which supports the common concept of an OpenGL share group (although implicitly; you supply an existing context that you want a new context to be in a common group with via the third argument to eglCreateContext). If two contexts are in a share group then each of them has an independent state and is safe to call from only one thread but named objects such as textures or vertex buffer objects are available to each of them. So using share groups you can perform OpenGL actions on multiple threads simultaneously so as to be able to combine the results on a single thread.

Tying a context to a single thread therefore isn't so much of an issue. Planning for the issue in OpenGL itself would also be a non-starter because part of the reason that OpenGL contexts are created, managed and disposed of in an OS-specific fashion is that some OSs need to handle this stuff in radically different ways to others or are able to offer better solutions by exposing their own unique solutions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文