Emscripten 中的 OpenGL 支持

Emscripten 提供三种 OpenGL 模式

本主题提供有关模式的信息,以及如何启用它们。

提示

我们强烈建议对新代码使用 OpenGL ES 2.0/3.0 的 WebGL 友好子集,并在可能的情况下将现有代码移植到该子集。其他两种模式效率较低,应仅在严重依赖这些功能的代码库中使用。

OpenGL ES 2.0/3.0 的 WebGL 友好子集

默认情况下,Emscripten 目标是 OpenGL ES 2.0 的 WebGL 友好子集。这是直接映射到 WebGL 的 GL ES 命令集,因此每个 GL 命令都与 WebGL 具有大致直接的映射。它包含几乎所有 OpenGL ES 2.0,但值得注意的例外是客户端数组,以及 WebGL 1.0 规范/第 6 章 中列出的其他一些功能。

要针对 OpenGL ES 的 WebGL 子集进行编程,可以使用 GL ES 2.0 头文件和 GL ES 2.0 API,同时遵守 WebGL 规范第 6 章中指定的限制。

此模式在默认情况下使用,因为它最符合浏览器提供的 WebGL 功能。

要针对 WebGL 2,请传递链接器标志 -sMAX_WEBGL_VERSION=2。指定此标志会在运行时启用(并默认使用,除非在创建上下文时另有指定)创建 WebGL 2 上下文,但仍然可以创建 WebGL 1 上下文,因此应用程序可以选择是否需要 WebGL 2 或是否支持回退到 WebGL 1。

要仅针对 WebGL 2 并完全放弃对 WebGL 1 的支持以节省代码大小,请传递链接器标志 -sMIN_WEBGL_VERSION=2-sMAX_WEBGL_VERSION=2

OpenGL ES 2.0/3.0 模拟

此构建模式模拟一些不在核心 WebGL 1 规范中的 OpenGL ES 2.0/3.0 功能。

特别是,此模式模拟客户端数组,这些数组从 OpenGL ES 2.0/3.0 的 WebGL 友好子集 中缺失 1

这允许你使用函数 glDrawArraysglDrawElements 等,而不必绑定缓冲区,Emscripten 的 GL 绑定会自动设置缓冲区(WebGL 要求绑定缓冲区)。

注意

此构建模式有一个限制,即客户端索引缓冲区中的最大索引必须小于该缓冲区中的索引总数。有关更多详细信息,请参阅 问题 #4214

要启用 *OpenGL ES 2.0 模拟*,在链接项目的最终可执行文件 (.js/.html) 时,请指定 emcc 选项 -sFULL_ES2

要启用 *OpenGL ES 3.0 模拟*,在链接项目的最终可执行文件 (.js/.html) 时,请指定 emcc 选项 -sFULL_ES3。这将添加模拟功能,以将内存块映射到客户端内存。标志 -sFULL_ES2-sFULL_ES3 是正交的,因此可以指定一个或两个来模拟不同的功能。

模拟旧的桌面 OpenGL API 功能

此 OpenGL 模式启用对许多旧的桌面 OpenGL 1.x 功能和命令的支持(例如“立即模式”和 glNormalPointer)。

虽然模拟并不完整,但它足以移植 Sauerbraten 3D 游戏(BananaBread 项目)和一些其他使用 Emscripten 的真实世界代码库。

要启用此模式,在链接项目的最终可执行文件 (.js/.html) 时,请指定 emcc 选项 -sLEGACY_GL_EMULATION

优化设置

在此模式下 (-sLEGACY_GL_EMULATION),有一些额外的标志可用于调整 GL 模拟层的性能

  • -sGL_UNSAFE_OPTS 尝试跳过冗余的 GL 工作和清理。此优化不安全,因此默认情况下未启用。

  • -sGL_FFP_ONLY 告诉 GL 模拟层你的代码根本不会使用可编程管道/着色器。这允许 GL 模拟代码在知道这样做是安全的时执行额外的优化。

  • Module.GL_MAX_TEXTURE_IMAGE_UNITS 整数添加到你的 shell **.html** 文件中,以表示代码使用的最大纹理单元数。这确保了 GL 模拟层在检查要运行哪个固定功能管道 (FFP) 模拟着色器时不会浪费时钟周期来迭代未使用的纹理单元。

如果我的代码库依赖于目前不支持的桌面 OpenGL 功能,该怎么办?

你可以考虑针对 Regal 桌面 OpenGL 模拟库构建代码库,该库旨在在 OpenGL ES 2.0 之上支持桌面 OpenGL 功能。这可能比 Emscripten 的 GL 模拟工作得更好或更差,具体取决于项目。另一个选择是使用 gl4es,它旨在快速将 OpenGL 转换为 GLES 用于游戏。它在 OpenGL ES 2.0 之上针对 OpenGL 2.1 配置文件,并已被用于使用 Emscripten 移植一些游戏。

OpenGL ES 扩展

在移植代码时,应该注意桌面 OpenGL、OpenGL ES 和 WebGL 各自拥有自己的扩展注册表。这意味着桌面 OpenGL 或 OpenGL ES 扩展不会自动也成为 WebGL 扩展,尽管存在一定程度的奇偶校验。有关已注册扩展的完整列表,请参阅 WebGL 1.0 扩展注册表

此外,在 WebGL 中,与桌面或移动 OpenGL 不同,扩展必须首先激活才能使其暴露的功能生效。如果你使用 SDL、EGL、GLUT 或 GLFW 等本机 API 之一来创建你的 GL 上下文,则对于大多数扩展来说,这将自动完成。如果你改用 HTML5 WebGL 上下文创建 API,则必须明确选择是否自动启用 WebGL 扩展。如果在创建上下文时未自动启用扩展,则可以使用 HTML5 API 函数 emscripten_webgl_enable_extension 来激活它。与调试相关的扩展、草案扩展和供应商前缀扩展 (MOZ_*, WEBKIT_*) 永远不会在创建上下文时自动启用,而必须始终手动激活。

从 WebGL 1 迁移到 WebGL 2 时,请注意一些 WebGL 1 扩展已迁移到核心 WebGL 2,因此它们的功能不再作为 GL 扩展进行宣传。这并不意味着这些功能会丢失,而是意味着可以在 WebGL 2 中使用这些功能,而无需先测试 GL 扩展的存在。

测试代码/示例

中的文件 test/third_party/glbook 提供了许多仅使用 OpenGL ES 2.0/3.0 的 WebGL 友好子集 的简单示例。

其他模式在各种测试中都有涵盖,包括 test/test_browser.py 中的几个测试。找到这些测试的最佳方法是在源代码中搜索相应的编译器标志:FULL_ES2LEGACY_GL_EMULATION 等。

错误报告

Emscripten 错误追踪器 有专门针对 OpenGL 和 OpenGL 模拟的标签,用于追踪各种与 GL 相关的 issue。

脚注

1

WebGL 中缺少客户端数组,因为它们比正确使用 GPU 侧数据效率低。