2012-10-28 46 views
5

我使用SDL2和C++ 11来构建游戏引擎(就像一个个人项目,为了好玩和练习),我想要做的事情之一是尝试并让图形驱动程序使用最新支持的OpenGL版本,并根据版本改变引擎图形部分的渲染方式。通过这种方式,我可以使用OpenGL的最新功能,它们相关且有用,但也支持较旧的硬件。有两种方法我能想到的:创建一个OpenGL 4.3上下文崩溃GLX

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

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

创建4.3上下文后,我使用的方法(#2)立即失败。我知道我的图形驱动程序现在只支持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上下文。

+0

不确定是否会有所帮助,但此问题指出在调用SDL_Init之前必须设置上下文版本:http://stackoverflow.com/questions/8110053/creating-an-opengl-3-2- 3-x-context-in-sdl-1-3 –

+0

Vaughn,真的吗?很奇怪,SDL文档暗示它必须在调用SDL Init之后并在创建上下文之前设置。另外,如果我将代码更改为从4.2开始,它工作得很好。大概应该提到... – OniLink

+0

你有没有试过@VaughnCato提供的建议?你是否检查过'SDL_GL_SetAttribute'的返回值,文档建议它们应该为0才能成功。 在代码中它崩溃了吗?调试器告诉你什么? –

回答

1

这可能表示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错误 - 甚至可能会由驱动程序禁用错误报告)。

+0

这很可能是因为SDL中的一个错误。我要测试它是否可以追踪任何内容,但我很确定这是一个驱动程序错误(我也测试过SFML,它实际上具有类似的功能来测试最大支持的GL版本,但它也失败了)。 我试着不设置SDL_GL_CONTEXT _ * _ VERSION,它给了我一个2.1上下文,所以这是行不通的。我确实希望编写多个版本的渲染代码 - 毕竟,这是一个供我学习的项目。 – OniLink

+0

更新:我在SDL中放了一堆printfs来测试它崩溃的位置。它特别崩溃在这条线: '上下文= glXCreateContextAttribs(显示, framebuffer_config [0], share_context,TRUE,attribs);' 所以是的,它看起来像一个驱动器的问题,因为它使人们过去临时上下文和一切。 – OniLink

+0

@OniLink可以。如果我没有弄错,OpenGL 4.3驱动程序仍然只是测试版(至少NVidia的)。但是我仍然认为带有虚拟窗口和完全关闭的init可能会做到这一点。 –

2

这是有点晚了,但我最近这个问题挣扎

我只是创造了一个虚拟的环境,然后使用该语境是(试图创建一个OpenGL上下文中SDL2那不是支持时仍然崩溃)获取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,你找不到谷歌搜索:))

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