我正在使用SDL2和C ++ 11来构建游戏引擎(就像个人项目一样,为了娱乐和练习),我想要做的一件事就是尝试让图形驱动程序使用最新支持的OpenGL版本,并根据版本改变引擎图形部分的呈现方式。这样我可以使用OpenGL的最新功能,它们相关且有用,但也支持旧硬件。我能想到两种方法:
检测最新支持的OpenGL版本并使用它,但我想不出任何方法可以做到这一点。是的,我试过谷歌。
使用试验和错误,我从最新版本开始(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上下文。
答案 0 :(得分:2)
这有点晚了,但我最近遇到了这个问题(在尝试创建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))
'猪'错误地认为默认版本是支持的最大版本(至少在我的默认版本中它默认为2.1,我有4.3可用)
答案 1 :(得分: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错误 - 驱动程序甚至可能会禁用错误报告)。