4. OpenGL綜合知識 --- 窗口系統Windows和Linux/X

說明:在本節涉及的frame buffer是以顯示爲目的的frame buffer

 

爲了將GPU繪製結果在窗口中顯示出來,必然需要將OpenGL和具體窗口系統相結合。如下圖所示,OpenGL spec定義了GL context< /span>的行爲,從具體窗口衍生出frame buffer,兩者結合,即可完成OpenGL應用程序的顯示輸出。

當然,GL context的輸出格式和Frame buffer的格式要一致才行,否則無法將GL contextframe buffer連接起來。比如,假如GL context將輸出depth值,則frame buffer中應該包括depth buffer;假如GL context輸出的顏色中的紅色分量佔8比特,則frame buffer中相應的color bufferred分量也應該是8比特;假如GL context要求輸出到back buffer中,則frame buffer就應該既包括front buffer,也包括back buffer

 

1

 

但是OpenGL spec並沒有定義如何和具體窗口系統相結合的問題,所以,需要引入新的spec來支持。具體到Windows操作系統,就是WGL;而在Linux/X下,就是GLX

 

考察一個OpenGL應用程序在Windows平臺的剛開始運行時和WGL相關的流程

1.         調用函數CreateWindowEx創建窗口hWnd

2.         調用函數GetDC得到hDC,其函數參數是hWnd

3.         調用函數ChoosePixelFormat來查詢hDC支持的所有像素格式,應用程序同時選擇出其將採用哪種像素格式

4.         調用函數SetPixelFormat設置hDC的像素格式

5.         調用函數wglCreateContext創建hGLRC,其參數是hDC

6.         調用函數wglMakeCurrent,其參數是hDChGLRC

7.         調用glAPI函數繪製

 

粗略的,我們可以這樣理解,第4步完成後將根據hDC衍生出frame buffer;第5步得到的hGLRC本質上是上圖中的GL context;而第6步則將應用程序和GL contextGL contextframe buffer連接在一起。從第7步開始,所有的glAPI都將作用於和應用程序連接的GL context;而GL context的輸出目的地則是和其連接的frame buffer

其中,第5步的hDC和第6步的hDC並不需要是同一個值,只需要這兩個hDC都設置了相同的像素格式即可,這樣就可以保證GL context的輸出格式和Frame buffer的格式的一致性。

 

 

考察一個OpenGL應用程序在Linux/X下的剛開始運行時和GLX1.4相關的流程

1.         調用函數XOpenDisplay(NULL)得到display,可以將其認爲是X server對顯卡的一個抽象

2.         查詢display,確定其連接的screen

3.         調用函數glxChooseFBConfig查詢將在其上繪製的screen所支持的fbconfigs(本質上和windows中的像素格式是相同的),應用程序同時選擇出其將採用哪種fbconfig

4.         調用函數XCreateWindow創建窗口xWin,其參數包括fbconfig的部分內容

5.         調用函數glXCreateWindow創建glxWin,參數是xWinfbconfig

6.         調用函數glXCreateNewContext創建glxCtx,參數是fbconfig

7.         調用函數glxMakeContextCurrent,其參數包括glxWinglxCtx

8.         調用glAPI函數繪製

 

粗略的,我們可以這樣理解,第5步得到的glxWin將衍生出frame buffer;第6步得到的glxCtx本質上就是上圖中的GL context;而第7步則是將應用程序和GL contextGL contextframe buffer連接在一起。從第8步開始,所有的glAPI都將作用於和應用程序連接的GL context;而GL context的輸出目的地則是和其連接的frame buffer

其中,第7步調用函數的參數glxWinglxCtx要求他們在被創建時所傳入的fbconfig參數是相同的,這樣就可以保證GL context的輸出格式和Frame buffer的格式的一致性。

 

 

至此,應該可以理解到hGLRC/glxCtxGL context的關係,它們在本質上是同一回事。hGLRC是在WGL下對GL context的封裝,glxCtx是在GLX下對GL context的封裝。hGLRCglxCtx是相對應用程序的概念,而GL context則是OpenGL內部的概念。

 

 

不管是Windows系統還是Linux/X,一個應用程序可能會多線程的在多個窗口上用OpenGL繪製。通過討論這種複雜情況,來加深對wglMakeCurrent/glxMakeContextCurrent函數(以下將簡稱爲MakeCurrent)的理解。

 

如下圖所示,某多線程程序,且已創建多個GL contexframe buffer。圖示狀態表示,線程甲已成功調用函數MakeCurrent(GL context 3, Frame buffer B),線程乙已成功調用函數MakeCurrent(GL context 1, Frame buffer A),線程丁已成功調用函數MakeCurrent(GL context 4, Frame buffer C)

接下去,在線程甲中被執行的glAPI都將作用於GL context3,其繪製結果進入Frame buffer B;在線程乙和線程丁中調用的glAPI也將分別作用於GL context 1GL context4,其繪製結果分別進入Frame buffer AFrame buffer C

 

3

 

 

假如某個線程不調用OpenGL繪製,那它可以不和任何GL context連接。每個線程同時只能最多和一個GL context連接,因爲,假如超過一個的話,該線程接下去的glAPI調用就將無法確定應該作用於哪個GL context連接了。當某個線程調用MakeCurrent函數重新設置和GL contextFrame buffer的連接關係時,原有的連接關係失效。

每個GL context最多可以和一個線程連接,因爲,假如超過一個的話,多個線程作用於同一個GL context,其繪製結果顯然不是所希望的。每個GL contxt只和一個Frame buffer連接,顯然是無法和多個Frame buffer連接的。

每個Frame buffer只和一個GL context連接,似乎spec並沒有禁止一個Frame buffer和多個GL context連接,但是,強烈不建議這樣做,很有可能驅動程序沒有針對這種情況編寫代碼的。

 

在默認情況下,不同GL context之間是相互獨立的。如果採用share context技術,可以使不同GL context之間共享部分信息,對一個GL context的改動,就會在在另一個GL context中體現出來。

 

 

在驅動程序中,爲節約顯存,frame buffer往往會被延遲到函數MakeCurrent被調用時才被真正創建。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章