Я использую SDL2 и C ++ 11 для создания игрового движка (как личный проект, для развлечения и для практики), и одна из вещей, которые я хочу сделать, это попробовать и заставить графический драйвер использовать последнюю поддерживаемую версию OpenGL, и изменить способ визуализации графической части движка в зависимости от версии. Таким образом, я могу использовать новейшие функции OpenGL, где они актуальны и полезны, но также поддерживают старое оборудование. Есть два метода, которые я могу придумать:
Обнаружение последней поддерживаемой версии OpenGL и ее использование, но я не могу придумать, как это сделать. Да, я пробовал Google.
Используя метод проб и ошибок, где я начинаю с самой последней версии (4.3, но мой GTX 460 поддерживает только до 4.2, даже если я обновил драйверы), и если это не удается (что я обнаруживаю, проверяя SDL, чтобы возвратить контекст NULL ), Я опускаю номер версии и пытаюсь снова.
Метод, который я использую (# 2), терпит неудачу сразу после создания контекста 4.3. Я знаю, что мои графические драйверы сейчас поддерживают только 4.2, но я думал, что GLX был спроектирован, чтобы выдавать ошибку, давать нулевой контекст и позволить вашей программе продолжать работу, но вместо этого она не может пройти через неудачное создание контекста. , Мое предположение о том, как 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 X11_GL_CreateContext () (в Интернете говорится, что SDL2 все еще экспериментальный). Ваша стратегия определения поддерживаемой версии OpenGL действительна, но для того, чтобы SDL предоставил вам совместимый с пересылкой контекст, сначала нужно создать временный контекст, вызвать glXGetProcAddress (), чтобы получить glCreateContextAttribsARB (он не может этого сделать, не имея активный контекст OpenGL), а затем он пытается инициализировать запрошенную вами версию OpenGL. Теперь, если это не удается, он удаляет временный контекст и возвращает NULL.
Я предполагаю, что во второй раз это не удается при создании временного контекста, я бы предложил создать SDL с отладочной информацией и попытаться выяснить, где именно в X11_GL_CreateContext () он терпит неудачу (или, по крайней мере, вставить пару printf).
С другой стороны, вы уже получите максимальную версию OpenGL, если оставите значения SDL_GL_CONTEXT_MAJOR_VERSION и SDL_GL_CONTEXT_MINOR_VERSION по умолчанию. Вы просто не получите контекста, совместимого с прямой связью, что означает, что некоторое поведение, которое в будущих версиях будет считаться «ошибочным», ускользнет.
Кроме того, в общем случае не рекомендуется создавать совместимый с прямым переходом контекст с максимально возможной версией. Например. в OpenGL 3.2 профиль, совместимый с прямым доступом, обеспечивает использование объектов массива вершин, что приводит к повреждению старого кода, в котором не использовались VAO. Так что, если приложение, написанное для OpenGL 3.1 (или любой другой версии), попытается получить новейший профиль, совместимый с прямой пересылкой, оно может фактически перестать работать в будущем. Это не очень хорошая идея.
Один из вариантов — принять решение об использовании одного совместимого с прямым профилем профиля, который в основном очень полезен, так как сообщает об ошибках устаревших функций. Если вы действительно хотите использовать больше версий, вам нужно больше путей кода (= больше версий игрового движка) для этого. Чтобы обнаружить версию OpenGL, я бы предложил создать фиктивное окно SDL, инициализировать простой профиль OpenGL, получить версию и закрыть все, а затем снова выполнить инициализацию с версией, для которой вы решили. Это должно работать.
Другим вариантом является использование совместимого с прямой версией профиля только для разработки и использование простого устаревшего профиля для распространения. Он наиболее совместим и требует минимальных усилий (в любом случае вы хотите игнорировать большинство ошибок OpenGL в версии выпуска — драйвер может даже отключить создание отчетов об ошибках).
Это немного поздно, но я недавно столкнулся с этой проблемой (все еще происходит сбой при попытке создать контекст 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)