我做了一些快速测试。
在 Windows AMD Radeon (Ryzen 7) 上:
- 请求高达 2.1 的任何上下文版本都会导致 4.6 兼容性上下文。这正是我想要的。
- 请求任何高于 2.1 的上下文版本都会产生所请求版本的上下文。
- 我认为它在 Linux 专有驱动程序上的工作方式相同。
- 它在 Intel 和 NVidia 上可能工作相同,但我现在无法测试它。
在用于 Windows 20.3.2 的 Mesa 上
- 请求任何高达 3.1 的上下文版本都会导致 3.1 上下文。
- 请求任何高于 3.1 的上下文版本都会导致 4.5 核心上下文。这正是我想要的。
- 我认为它在 Linux 开源驱动程序上的工作方式相同
- 请求 2.0-3.2 之间的任何 OpenGL ES 版本都会导致 3.2 上下文。这正是我想要的。
在 Android 上 (Adreno 640)
- 请求 2.0-3.2 之间的任何 OpenGL ES 版本都会导致 3.2 上下文。
- 我认为它与 Android 上的其他供应商的工作方式相同。
似乎只有第一个上下文创建很慢。在这两种情况下,在我的系统上创建上下文的额外尝试会使应用程序的启动时间增加大约 4 毫秒,而使用本机驱动程序创建整个上下文 + 窗口大约需要 300 毫秒,而使用 Mesa 则需要 70 毫秒。
我没有要测试的 macOS,因此我将通过尝试向前兼容的 4.1、3.3、3.2 和 2.1 来使用保守的方法。无论如何,大多数 Mac 完全支持 4.1,所以对于他们来说,上下文将在第一次尝试时创建。
这是iOS OpenGL ES 的文档建议执行的操作:
要在您的应用程序中支持多个版本的 OpenGL ES 作为渲染选项,您应该首先尝试初始化您想要定位的最新版本的渲染上下文。如果返回的对象为 nil,则改为初始化旧版本的上下文。
所以在 GLFW 伪代码中,我的 OpenGL 策略如下所示:
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
GLFWwindow* wnd;
#ifdef __APPLE__ // macOS
const std::array<char, 2> versions[] = {{4, 1}, {3, 3}, {3, 2}, {2, 1}};
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
for(auto ver: versions)
{
if(ver[0] < 3) glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, false);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, ver[0]);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, ver[1]);
wnd = glfwCreateWindow(...);
if(wnd) break;
}
glfwMakeContextCurrent(wnd);
#else // Windows, Linux and other GLFW supported OSes
glfwWindowHint(GLFW_VISIBLE, false);
wnd = glfwCreateWindow(...);
glfwMakeContextCurrent(wnd);
std::string_view versionStr = glGetString(GL_VERSION);
if(versionStr[0] < '4' && versionStr.contains("Mesa"))
{
glfwDestroyWindow(wnd);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
wnd = glfwCreateWindow(...);
glfwMakeContextCurrent(wnd);
}
glfwShowWindow(wnd);
#endif
OpenGL ES 的代码看起来相似但更简单。移动平台将使用不同的库而不是 GLFW(GLFM/SDL 或原生 EGL)。对于 iOS,我必须先尝试 ES 3.0,然后再尝试 ES 2.0。对于 Mesa 和 Android,我只需请求 2.0 上下文并获取最新的 (3.2)。但是,对于 Android,我假设 Mali 和其他供应商的工作方式相同。
如果您可以测试我的假设以确认或否认它们,请在评论中告诉我。