2012-10-28 79 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可用)