如何在Android上正确初始化和终止EGL

15

虽然有很多关于在Android上使用OpenGL ES的示例,但它们似乎都存在问题(即使是与Android SDK / NDK一起提供的示例),涉及EGL的初始化/终止过程。问题源自于Android应用程序模型,这使得正确使用EGL变得奇怪。

真正的问题在于,EGL是针对操作系统的进程进行初始化的,而所有的Android示例,甚至GLSurfaceView(实际上大多数示例都使用它)都涉及EGL的按组件(Activity或WallpaperService)初始化/终止。这完全是错误的,因为所有组件都在同一个进程中运行!如果应用只包含一个组件,则没有问题,但如果应用中有多个组件,并且它们都使用OpenGL ES,则这是一个问题。

考虑以下情况:两个使用OpenGL ES的应用程序组件同时运行,其中一个完成了。在完成此类组件时,将调用eglTerminate()(请查看GLSurfaceView源代码,以了解我所说的内容),这将终止整个进程的EGL!从此时开始,另一个已经运行的组件的任何EGL调用都将失败!

我检查了许多示例,它们都是以每个组件为基础初始化和终止EGL(实际上我看到的没有一个人做出了与GLSurfaceView不同的事情,大多数示例只是复制了GLSurfaceView的内部机制)。

现在,我想找到一种“正确”的方法,在Android上使用EGL。

这种“正确”的方式应该提供:

  1. 当任何第一个使用EGL的组件启动时,进行EGL初始化
  2. 当最后一个使用EGL的组件完成时,进行EGL终止
  3. 多线程。不应该限制仅能从主应用程序线程进行EGL操作。

请注意,(2)对于最小化没有使用EGL/OpenGL ES的活动实体时,是必要的来最小化系统资源的使用。

有什么想法吗?或者我在Android上忽略了一些EGL相关的内容吗?

更新

还有一个有趣的相关问题:

由于每个线程只允许一个活动渲染上下文,因此同一时间只能有一个组件使用主线程上的OpenGL ES。主线程同时运行多个使用OpenGL ES的组件会导致问题,因为最后一个调用eglMakeCurrent()的组件将隐含地“替换”所有其他组件的上下文,从而完全破坏组件逻辑。

更新2(最终)

Romain Guy透露,Android实际上有一种内部解决EGL初始化/终止问题的方法,即在eglInitialize()eglTerminate()中采用显式的“引用计数”方式(这违反了EGL规范,也没有在Android文档中提到)。


我的方法是将所有的OGL活动放在一个组件中,即使其他组件也为其生成事件。这样可以避免问题。 - Mesocyclone
1个回答

14

eglTerminate()和eglInitialize()都是有引用计数的,因此每个“组件”调用它们是可以的。特别是在Android 3.0上,在同一个应用程序中有多个OpenGL上下文是非常普遍的,使用EGL也没有任何问题。


根据EGL规范,eglInitialize() / **eglTerminate()**没有引用计数。多个OpenGL上下文本身并不是问题(规范允许),但实际问题是由于Android应用程序模型可能导致的副作用。请注意,我所概述的与上下文相关的问题无法通过任何方式“自动”解决EGL实现。 - Alexey Kryshen
似乎Android在eglInitialize() / **eglTerminate()**中真的有内部引用计数,但文档中没有任何关于此的说明。此外,虽然它解决了初始化问题(并使Android EGL不符合规范(!)),但与上下文相关的问题却无法解决。 - Alexey Kryshen
这并不是 EGL 规范所说的,但这就是它在 Android 上的工作方式。如果多个组件在同一线程上使用多个 OpenGL 上下文(它们不应该这样做),解决方案是检查当前的 EGL 上下文,如果不正确,则进行 make current 操作。例如,这种情况不会发生在 GLSurfaceView 上,因为每个 GLSurfaceView 都有自己的渲染线程。 - Romain Guy
那么,有一个内部解决方案,但为什么文档中没有信息呢?开发人员应该如何知道它呢? - Alexey Kryshen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接