OpenGL中的上下文 理解整理
OpenGL中的上下文(Context)
OpenGL狀態(tài)機與上下文
OpenGL是一個狀態(tài)機,它擁有非常多的狀態(tài)變量,并且每個狀態(tài)變量都有默認值。
OpenGL在渲染的時候需要一個Context來記錄了OpenGL渲染需要的所有信息和狀態(tài),可以把它理解成一個大的結(jié)構(gòu)體,它里面記錄了當(dāng)前繪制使用的顏色、是否有光照計算以及開啟的光源等非常多我們使用OpenGL函數(shù)調(diào)用設(shè)置的狀態(tài)和狀態(tài)屬性。
在程序中,我們設(shè)置的各種狀態(tài)和默認狀態(tài)會一直生效,直到我們再次修改它們。狀態(tài)機并不是一個好的設(shè)計,多個繪制算法同時跑,容易被前面的狀態(tài)所影響,OpenGL為了向前兼容,狀態(tài)機的形式就被一直延續(xù)下來了。
GPU的CS模式和上下文
如上所述,OpenGL的一組狀態(tài)機對應(yīng)著一個上下文。OpenGL采用了Client-Server模式,GPU相當(dāng)于一臺服務(wù)器,可對應(yīng)多個客戶端即上下文,一個客戶端維護著一組狀態(tài)機。大部分的OpenGL命令都是異步的,不代表真正地執(zhí)行,只是客戶端向服務(wù)器發(fā)送了一些命令(同時有一些API可實現(xiàn)同步功能)。如果兩個窗口分別對應(yīng)兩個不同的繪制上下文,則兩個窗口彼此狀態(tài)獨立,繪制狀態(tài)不會互相影響,宏觀上看繪制也是并行的。
線程私有
OpenGL的繪制命令都是作用在當(dāng)前的Context上,這個Current Context是一個線程私有(thread-local)的變量,也就是說如果我們在線程中繪制,那么需要為該線程制定一個Current Context的,當(dāng)多個線程參與繪制任務(wù)時,需要原線程解綁再重新綁定新的線程。多個線程不能同時指定同一個Context為Current Context,否則會導(dǎo)致崩潰。
OpenGL所創(chuàng)建的資源, 其實對程序員可見的僅僅是ID而已, 其內(nèi)容依賴于這個上下文, 因此在大型程序中的一般做法是申請一條線程專門用于繪制,創(chuàng)建線程時,為該繪制線程申請一個繪制上下文,一直作為Current Context,不再進行切換。所有的繪制相關(guān)的操作,都在繪制線程完成。但是如果涉及復(fù)雜的OpenGL渲染時, 這樣就未必足夠,當(dāng)有需求需多個并行的繪制任務(wù)時,則要創(chuàng)建多個Context,為并行的線程分別綁定不同的上下文。
共享上下文
一個是進程可以創(chuàng)建多個Context,它們可以分別描繪出不同的圖形界面,就像一個應(yīng)用程序可以打開多個窗口一樣。每個OpenGL Context是相互獨立的,它們都有自己的OpenGL對象集。但有時會有場景需要多個上下文使用同一份紋理資源的情況,創(chuàng)建Context,意味著系統(tǒng)資源的占用,同一份紋理重復(fù)申請會造成資源浪費,因此OpenGL上下文允許共享一部分資源。大部分OpenGL Objects是可以共享的,包括Sync Object和GLSL Objects。Container Objects和Query Objects是不能共享的。例如紋理、shader、Buffer等資源是可以共享的,但Frame Buffer Object(FBO)、Vertex Array Object(VAO)等容器對象不可共享,但可將共享的紋理和VBO綁定到各自上下文的容器對象上。上下文創(chuàng)建時可以指定共享上下文,具體可見示例。
上下文的創(chuàng)建方法
不同的操作系統(tǒng),都有各自的上下文創(chuàng)建方法和設(shè)置當(dāng)前上下文的API。
最簡單的上下文可以通過Glut或是Glfw創(chuàng)建。例如Glut的函數(shù)GlutCreateWindow除了創(chuàng)建了一個窗口,同時還創(chuàng)建了一個Context,并將創(chuàng)建的Context設(shè)置為Current Context。還可以使用glutInitContextVersion接口指定Context版本。
對于Windows平臺首先創(chuàng)建一個設(shè)備上下文(Device Context,DC),DC的創(chuàng)建可以輸入一個GPU參數(shù),從而指定DC和DC對應(yīng)的上下文將在哪個GPU上跑。以DC為輸入,可以創(chuàng)建一個繪制上下文。創(chuàng)建繪制上下文以后,調(diào)用MakeCurrent,將創(chuàng)建的上下文設(shè)置為當(dāng)前的繪制上下文。glew庫中的wglew.h封裝了windows下創(chuàng)建上下文的方法。
對于Linux平臺可以使用EGL提供的接口創(chuàng)建上下文。
創(chuàng)建了繪制上下文,并設(shè)置為當(dāng)前上下文以后,還不能使用OpenGL最新的特性,調(diào)用OpenGL 1.1以后的API仍然會崩潰。一般我們使用Glew庫,調(diào)用glewInit(),得到OpenGL隨顯卡驅(qū)動一起發(fā)布的新特性的函數(shù)入口地址。
上下文類型
在OpenGL 3.0版本之前,所有的OpenGL Context是統(tǒng)一的,都是一種兼容之前版本的模式(例如使用OpenGL 1.1編寫的代碼,在支持OpenGL 2.1的設(shè)備上可以正常的運行)。這些版本的OpenGL API也被稱之為固定管線(相比較之后引入shader的可編程管線來說), 但是從3.0開始有了變化:
- 1、 OpenGL 3.0 引入了廢棄機制,標(biāo)記了許多OpenGL的函數(shù)是廢棄的(但是3.0并沒有真正移除它們,也就是說3.0版本仍然是一個可以向后兼容的Context)
- 2、 OpenGL 3.1發(fā)布刪除了之前3.0標(biāo)記的過時函數(shù)(固定管線相關(guān)的函數(shù)),但是為了之前的OpenGL代碼可用, 引入了一個擴展ARB_compatibility,這個擴展可以讓OpenGL 3.1支持之前的OpenGL固定管線的內(nèi)容。
- 3、 正是由于這個問題,在OpenGL 3.2中正式引入了模式的概念(Profile),模式就將二者分離開來了。OpenGL 3.2 中模式包括:
- (1) Core Profile 只包含最新的Shader相關(guān)的函數(shù),程序必須使用Shader編寫
(2)compatibility Profile 可以兼容之前的OpenGL固定管線的內(nèi)容,也可以使用Core Profile中的內(nèi)容
- (1) Core Profile 只包含最新的Shader相關(guān)的函數(shù),程序必須使用Shader編寫
- 4、 3.2以后的版本直到OpenGL目前最新的版本(OpenGL 4.6)都是按照這種模式來做的。
opengl多線程繪制
實現(xiàn)效果:opengl開啟兩個線程,一個線程用于繪制,另一個線程用于加載紋理。
實現(xiàn)方法:opengl是單線程的,其他線程不能訪問另外線程的紋理資源,但是,如果兩個線程共享上下文,就可以訪問彼此的紋理資源。
繪制線程:創(chuàng)建兩個上下文
//只有主要代碼 ... context = eglCreateContext(display, config, NULL, ctxAttribs); context1 = eglCreateContext(display, config, context, ctxAttribs); ...eglMakeCurrent(display, eglSurface, eglSurface, context);加載紋理線程:綁定繪制線程中兩個上下文中的一個
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context1);參考:
https://www.khronos.org/opengl/wiki/OpenGL_Context
總結(jié)
以上是生活随笔為你收集整理的OpenGL中的上下文 理解整理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux移植遇到问题记录
- 下一篇: 使用CmakeLists应该知道的一些知