注意
本文正在建设中。
Khronos Group 发布了一个名为 EGL 的规范,它是一个 API,负责(除其他任务外)图形上下文创建、渲染表面管理以及不同 Khronos Group 图形 API(OpenGL、OpenGL ES、OpenVG)之间的互操作。有关详细信息,请参阅 Khronos EGL 网页.
目前,EGL 在操作系统/图形驱动程序供应商中并不广泛使用。最显著的采用是在 Android 架构中,EGL 是在使用 Android NDK 时为 OpenGL ES 1&2 创建渲染上下文的首要方法。此外,Mesa 在其 图形驱动程序中实现了 EGL 规范。
Emscripten 还提供 EGL v1.4 规范的实现。这允许 C/C++ 客户端代码使用(几乎)统一的代码库来在 Web、Linux(使用 Mesa)和 Android NDK 之间创建 GLES2(WebGL)渲染上下文。Emscripten 中的 EGL 规范实现并不完美,请参阅本页末尾了解状态图表。
有点令人失望的是,EGL 并不是一个能够独立完成初始化 GLES2 图形渲染(在任何平台上,不仅仅是 Emscripten)并监督各种相关任务的完整解决方案。该规范的范围有限,缺少一些功能。特别是,EGL 无法帮助完成以下任务
创建渲染窗口。EGL 规范没有指定要渲染到的目标窗口是如何创建的。必须使用特定于平台的本机窗口系统函数(X11、Win32 API、ANativeWindow)首先创建一个渲染窗口。
以任意像素增量指定渲染窗口大小。EGL 没有任何功能可以请求主渲染窗口的所需大小,或调整其大小。
指定全屏视频模式/屏幕分辨率。EGL 不能用来控制渲染是在窗口模式还是全屏模式下,或者在运行时在这些模式之间切换。
因此,对于每个平台(包括 Emscripten),都存在特定于平台的方法来执行这些任务。
在 Web 环境中,WebGL 是用于 3D 加速渲染的技术。WebGL 几乎与 GLES2 相同,并且由于 EGL 根本不适用于 WebGL,因此在本页中,WebGL 和 GLES2 术语可互换使用。因此,要创建 WebGL 上下文,可以使用 EGL,并根据其措辞,创建一个 GLES2 上下文。
执行以下步骤以使用 EGL 创建 GLES2 上下文
通过调用 eglGetDisplay
获取 EGLDisplay
对象的句柄。
通过调用 eglInitialize
初始化该显示器上的 EGL。
调用 eglGetConfigs
和/或 eglChooseConfig
一次或多次以查找表示所需主渲染目标参数的 EGLConfig
。要检查 EGLConfig
的属性,请调用 eglGetConfigAttrib
。
此时,可以使用可用的任何特定于平台的函数(X11、Win32 API、ANativeWindow)来设置要渲染到的本机窗口。对于 Emscripten,此步骤不适用,可以跳过。
通过调用 eglCreateWindowSurface
,使用有效的显示和配置参数创建一个主渲染目标表面 (EGLSurface
)。将窗口和属性列表参数设置为 null。
通过调用 eglCreateContext
创建一个 GLES2 渲染上下文 (EGLContext
),然后调用 eglMakeCurrent
激活渲染上下文。在创建上下文时,指定上下文属性 EGL_CONTEXT_CLIENT_VERSION == 2
。
完成这些步骤后,将获得一组 EGL 对象 EGLDisplay
、EGLConfig
、EGLSurface
和 EGLContext
,它们代表主 GLES2 渲染上下文。
取消初始化时清理的顺序如下
通过调用 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)
释放当前活动的渲染上下文。
通过对它调用 eglDestroyContext
取消初始化 EGLContext
对象。
通过对它们调用 eglDestroySurface
销毁所有初始化的 EGLSurface
对象。
通过调用 eglTerminate(display)
取消初始化 EGL。
删除本机渲染窗口。此步骤不适用于 Emscripten。
使用 EGL 初始化 WebGL 上下文的示例代码可以在 emscripten/test/third_party/glbook 目录中的示例应用程序中找到,更具体地说是在 esUtil.c 文件中。
本节列出了所有 EGL v1.4 函数,并描述了它们在 Emscripten 中的当前实现状态。
eglInitialize
、eglGetConfigs
、eglQueryContext
、eglQueryString
、eglQuerySurface
、eglGetCurrentContext
、glGetCurrentSurface
、eglGetCurrentDisplay
、eglReleaseThread
、eglDestroySurface
、eglDestroyContext
:已实现,应根据 EGL v1.4 规范工作。
eglSwapBuffers
:已实现,但此函数在 WebGL 下无法真正控制交换行为。在 Emscripten 下,调用此函数是可选的。在 WebGL 中,只有在代码将执行权返回到浏览器后,才会将显示屏的内容始终呈现到屏幕上,也就是说,当您从传递给 emscripten_set_main_loop()
的滴答回调处理程序返回时。但是,eglSwapBuffers
函数仍然可以用来检测何时发生 GL 上下文丢失事件。
eglGetDisplay
:已根据规范实现。Emscripten 不使用多个 EGLNativeDisplayType
对象,因此在此处传入 EGL_DEFAULT_DISPLAY
。实际上,Emscripten 目前忽略了为 Linux 模拟目的在此处传入的任何值,但您不应在将来依赖此值。
eglGetError
:已根据规范实现。
重要
根据规范,eglGetError
报告单个最新的错误,而不是所有先前错误的列表。不要像调用 glGetError
一样在循环中调用此函数。
eglChooseConfig
:已实现为存根,但此函数不执行搜索/过滤,目前与 eglGetConfigs
相同 (问题 #643).
eglGetConfigAttrib
: 已实现。查询属性 EGL_BUFFER_SIZE
, EGL_ALPHA_SIZE
, EGL_BLUE_SIZE
, EGL_GREEN_SIZE
, EGL_RED_SIZE
, EGL_DEPTH_SIZE
和 EGL_STENCIL_SIZE
当前返回硬编码的默认值 (issue #644)。 属性 EGL_MIN_SWAP_INTERVAL
和 EGL_MAX_SWAP_INTERVAL
目前没有任何功能。 相反,调用 emscripten_set_main_loop()
来指定主循环更新速率。
eglCreateWindowSurface
: 已实现,但无法多次调用此函数来创建多个渲染窗口。
eglCreateContext
: 作为存根实现。 无法多次调用此函数来创建多个上下文。
eglBindAPI
, eglQueryAPI
: 已实现,尽管这些函数在 Emscripten 中几乎没有用处,因为只支持 GLES2 客户端 API。
eglWaitClient
, eglWaitNative
: 作为无操作函数实现。 这些在 Emscripten 中没有意义。
eglSwapInterval
: 作为无操作存根实现。 目前此函数无法设置 vsync 间隔,也无法启用/禁用它。
eglMakeCurrent
: 作为无操作存根实现。
eglTerminate
: 作为无操作函数存根实现。 JavaScript 应用程序通常不会手动关闭,但在关闭浏览器或切换网页时,浏览器会自动管理所有拆卸。 因此,此函数在 Emscripten 中没有关键作用。
eglGetProcAddress
: 已实现,实验性。
以下函数目前未实现
eglCreatePbufferSurface
, eglCreatePixmapSurface
, eglCreatePbufferFromClientBuffer
, eglSurfaceAttrib
, eglBindTexImage
, eglReleaseTexImage
, eglWaitGL
, eglCopyBuffers
.
重要
不要调用 Emscripten 代码中的这些函数,否则应用程序将在尝试执行未定义函数时停止。
目前,Emscripten 在 EGL Extension Registry 中没有实现任何扩展。