【问题标题】:Creating an OpenGL 4.3 Context Crashes GLX创建 OpenGL 4.3 上下文崩溃 GLX
【发布时间】:2012-10-28 03:32:23
【问题描述】:

我正在使用 SDL2 和 C++11 构建游戏引擎(仅作为个人项目,用于娱乐和练习),我想做的一件事是尝试让图形驱动程序使用OpenGL 的最新支持版本,并根据版本改变引擎图形部分的渲染方式。通过这种方式,我可以在相关且有用的地方使用 OpenGL 的最新功能,同时也支持旧硬件。我能想到的方法有两种:

  1. 检测最新支持的 OpenGL 版本并使用它,但我想不出任何方法来做到这一点。是的,我试过谷歌。

  2. 使用反复试验,我从最新版本(4.3,但我的 GTX 460 仅支持最高 4.2,即使我更新了驱动程序),如果失败(我通过检查来检测SDL 返回 NULL 上下文),我降低版本号并重试。

我使用的方法 (#2) 在创建 4.3 上下文后立即失败。我知道我的图形驱动程序现在只支持 4.2,但我认为 GLX 旨在引发错误,提供 NULL 上下文,并让您的程序继续运行,但它无法通过上下文创建失败.我对 GLX 行为方式的假设是否错误?有没有办法在不创建上下文的情况下检测最新支持的版本?

因为我知道有些人更喜欢看到完整且最少的源代码来证明错误,所以这里是:

#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
int main() {
    if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) {
        return -1;
    }
    SDL_Window* window = SDL_CreateWindow( "SDL Window", 0, 0, 800, 600, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN );
    if( window == nullptr ) {
        return -1;
    }
    unsigned int major = 4;
    unsigned int minor = 3;
    SDL_GLContext context = nullptr;
    while( context == nullptr ) {
        SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, major );
        SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, minor );
        context = SDL_GL_CreateContext( window );
        if( context == nullptr ) {
            if( minor == 0 && major > 1 ) {
                --major;
                minor = 9;
            }
            else if( minor > 0 ) {
                --minor;
            }
            else {
                SDL_DestroyWindow( window );
                return -1;
            }
        }
    }
    SDL_Delay( 5000 );
    SDL_GL_DeleteContext( context );
    SDL_DestroyWindow( window );
    return 0;
}

另外,如果我将该代码更改为以 4.2 上下文而不是 4.3 开头,它就可以正常工作。所以错误在于专门创建 4.3 上下文。

【问题讨论】:

  • 不确定它是否会有所帮助,但这个问题指出必须在调用 SDL_Init 之前设置上下文版本:stackoverflow.com/questions/8110053/…
  • 沃恩,真的吗?这很奇怪,SDL 文档暗示它必须在调用 SDL Init 之后和创建上下文之前进行设置。此外,如果我将代码更改为从 4.2 开始,它就可以正常工作。可能应该提到...
  • 您尝试过@VaughnCato 提供的建议吗?您是否检查过来自 SDL_GL_SetAttribute 的返回值,文档建议它们应该为 0 表示成功。代码在哪里崩溃?调试器告诉你什么?
  • @X-Istence 是的,我试过了。它没有解决它。我还测试了 SDL_GL_SetAttribute 的返回值。它成功了。它只是试图创建失败的上下文。

标签: c++ opengl sdl sdl-2 glx


【解决方案1】:

这有点晚了,但我最近遇到了这个问题(尝试创建 SDL2 不支持的 opengl 上下文时仍然崩溃)

我只是创建了一个虚拟上下文,然后使用该上下文来获取 GL 版本。然后销毁该上下文(除非它正是我想要的)并制作另一个。

//Create Dummy Context
context = SDL_GL_CreateContext(window);

//Get OpenGL Version
const GLubyte* sGLVersion =  glGetString(GL_VERSION);

version = (sGLVersion[0]-'0')*10;
version += (sGLVersion[2]-'0');

//Now Check that it can support the version that you want to make and stop if you can't
//or in your case set it to that version

//If you need to make another context destroy the old one
SDL_GL_DeleteContext(context);

//and make a new one
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, minorVersion );

context = SDL_GL_CreateContext(window);

这也比暴力破解版本号要快,直到你碰巧找到一个可以工作的版本。 (通过谷歌搜索找不到您的解决方案 1 :))

'the swine' 误认为默认版本是支持的最大版本(至少在我默认为 2.1 的版本中,我有 4.3 可用)

【讨论】:

    【解决方案2】:

    这可能表明 SDL 的 X11_GL_CreateContext() 中存在错误(在网上它说 SDL2 仍处于试验阶段)。您找出支持的 OpenGL 版本的策略是有效的,但是为了让 SDL 为您提供前向兼容的上下文,它首先需要创建一个临时上下文,调用 glXGetProcAddress() 来获取 glCreateContextAttribsARB (如果没有一个活动的 OpenGL 上下文),然后它会尝试初始化您请求的 OpenGL 版本。现在,如果它失败了,它会处理临时上下文并返回 NULL。

    我的猜测是它第二次无法创建临时上下文,我建议使用调试信息构建 SDL,并尝试找出 X11_GL_CreateContext() 中失败的确切位置(或至少插入几个 printf)。

    另一方面,如果您将 SDL_GL_CONTEXT_MAJOR_VERSION 和 SDL_GL_CONTEXT_MINOR_VERSION 保留为默认值,您已经获得了最大的 OpenGL 版本。你只是没有得到一个向前兼容的上下文,这意味着它会让一些在未来版本中被认为是“错误”的行为溜走。

    此外,一般而言,创建具有最大版本的前向兼容上下文并不是一个好主意。例如。在 OpenGL 3.2 中,向前兼容的配置文件强制使用顶点数组对象,这使得不使用 VAO 的旧代码被破坏。因此,如果为 OpenGL 3.1(或任何其他版本)编写的应用程序试图获得最新的向前兼容配置文件,它实际上可能在将来停止工作。这不是一个好主意。

    一种选择是决定使用一个向前兼容的配置文件,这非常有用,因为它会报告有关已弃用功能的错误。如果您真的想使用更多版本,则需要更多代码路径(= 更多版本的游戏引擎)才能这样做。要检测 OpenGL 版本,我建议创建一个虚拟 SDL 窗口,初始化一个简单的 OpenGL 配置文件,获取版本并关闭所有内容,然后使用您决定的版本再次初始化。应该可以的。

    另一种选择是仅将向前兼容的配置文件用于开发,并将简单的旧配置文件用于分发。它是最兼容的并且涉及最少的工作(无论如何,您都想忽略发布版本中的大多数 OpenGL 错误 - 错误报告甚至可能被驱动程序禁用)。

    【讨论】:

    • 这很可能是因为 SDL 中的错误。我将对其进行测试以查看是否可以追踪任何内容,但我很确定这是驱动程序错误(我还测试了 SFML,它实际上具有类似的功能来测试最大支持的 GL 版本,它也失败了)。我尝试不设置 SDL_GL_CONTEXT_*_VERSION,它给了我一个 2.1 的上下文,所以这不起作用。我确实想编写多个版本的渲染代码——毕竟这是一个需要我学习的项目。
    • 更新:我在 SDL 中放了一堆 printfs 来测试它在哪里崩溃。它专门在这一行崩溃:context = glXCreateContextAttribs(display, framebuffer_config[0], share_context, True, attribs); 所以是的,它看起来确实是驱动程序问题,因为它超出了临时上下文和所有内容。
    • @OniLink 可能是。如果我没记错的话,OpenGL 4.3 驱动程序仍然只是测试版(至少 NVidia 是)。但我仍然认为带有虚拟窗口和完全关闭的初始化可能会成功。
    • 不幸的是,如果我什至尝试创建 4.3 上下文,它会崩溃,并且在不设置版本的情况下创建虚拟窗口会创建 2.1 上下文,我不这么认为。我假设我应该将此作为错误报告给 NVidia?因为我很确定它不应该崩溃到桌面,所以只需抛出一个错误并给出一个 nullptr。
    • @OniLink 好吧,我完全误解了这一点。我以为它第二次崩溃了。所以是的,可能会去寻求错误报告或只是等待新的驱动程序,无论如何他们都可能会修复它。您还可以将驱动程序降级为稳定版本。我在 arm4 上用 windows / linux / windows CE / linux 编写了相同的代码,它适用于我,我从 9.9 版开始并递减直到它成功。
    猜你喜欢
    • 1970-01-01
    • 2013-08-10
    • 1970-01-01
    • 2021-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    相关资源
    最近更新 更多