接續前一篇研究D3D11的,發現OpenGL有個uniform buffer object功能,可以代替uniform變數,來試驗一下。
找到的參考資料
官方說明一個範例其實前兩篇裡兩位電子妖精只是幫忙收集資料,這次才請她們測試新招式(實際修改引擎)。
使用OpenGL的某個功能得注意有哪些顯卡支援,不像Direct3D有強制力,要求顯卡廠商非實做這個功能不可,所以只要說明文件裡有寫就確定能用。
調查一下,Intel內顯要sandy bridge架構以後才有這個功能,是2011~2012年出的。
AMD所有APU都可以用。
首先要取出擴充函式,OpenGL有個特性是很多函式作業系統API裡沒有定義,要用wglGetProcAddress取出指標。
不過,我有做一套工具解決這個問題。
在一個Python程式碼裡加入glGetUniformBlockIndex、glBindBufferBase等名稱。
funcList=( ………… Func("glBufferData"), Func("glBindBufferBase"), Func("glGetUniformBlockIndex"), Func("glBufferSubData"), ………… ) |
鈷寶,動手。
鈷寶:…………(工作中)
static PFNGLBUFFERDATAPROC glBufferData; static PFNGLBINDBUFFERBASEPROC glBindBufferBase; static PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; static PFNGLBUFFERSUBDATAPROC glBufferSubData; |
自動產生C函式定義,之後的步驟也有自動化。
再來修改shader,宣告一個uniform區塊
layout(std140) uniform ShaderState{ vec4 globalColor; vec2 texSizeRcp; }; |
前篇說到要把shader嵌入程式裡,這一步也是請鈷寶幫忙。
鈷寶:(處理中)…………,包裝好了。艾莉兒:再來換我這邊準備了。C++裡宣告一個對等的struct
struct{ float globalColor[4]; float texSizeRcp[2]; }; |
C++端使用方法如下
1.用glGenBuffers和glBufferData,產生buffer物件並配置空間。
2.用glGetUniformBlockIndex取得index,再用glBindBufferBase把index和buffer物件關聯起來。
3.之後用glBufferSubData把資料傳給shader。
這方法可減少很多glGetUniformLocation和glUniformXXX的呼叫。
而且照上面網站的說法,同一個uniform buffer可以給不同的shader共用,而uniform變數各個shader是分開儲存的。
改好了,用開發中的Cyber Sprite 2試試看
艾莉兒:好,來吧。開始時沒問題,但進入標題畫面後
艾莉兒:咦,怎麼回事?………完全想不到是哪裡出問題,還是不要用Cyber Sprite 2這麼複雜的程式測,寫個比較小的程式測試。
…………
初步測試看起來是沒事。
我的電腦有兩個顯示晶片,在Intel可以用,但再用nVidia的試試看,會有compile error
查了一下shader語法說明,在shader前面加個#version看看
艾莉兒:再試試看,……還是不行。…………
再研究一下,好像可以在創建context的時候設定成compatibility profile,但想完全解決得全部改用新規格。
剛剛畫面很奇怪的原因也心裡有數了,混合uniform buffer和這些gl_變數實際上是會出問題的,只是Intel的compiler沒有把error回報。
原來沒那麼簡單,雖然已經知道OpenGL 3.0以後把一些東西列為deprecated,全部改完要做的工不少。
鈷寶:我想……,先不要用吧。查了一下目前有哪些顯卡,還有哪個版本的Android支援uniform buffer object之後,還是繼續用以前的uniform變數吧,可能等Cyber Sprite 2的下一個作品再換新方法。
關於第一篇說的OpenGL驅動程式沒寫好的問題,是個人在幾台電腦上用OpenGL做遊戲的經驗,可能是顯卡廠商對較少人用的平台就比較少維護的關係。
顯示晶片的性能不只要看晶片本身,也跟驅動程式有關係,即使晶片有某個功能,驅動程式不開放你用的話你的程式裡也不能用。
在Windows上有時一個功能在Direct3D上可以用(表示晶片有這個功能),但相同的功能OpenGL就不能用,Intel的晶片常有這種事。
事實上最近發現一個問題,在雙螢幕上開Cyber Sprite,如果視窗在第二個螢幕上遊戲就會頓,個人認為是驅動程式的問題所以不想修了,因為nVidia晶片不會這樣,用Intel晶片執行Direct3D程式也沒事。
另一個個人經驗是,如果分別在Windows和Linux跑OpenGL程式,Intel晶片在Linux上的表現往往比Windows好,因為Linux的驅動程式不是Intel開發的,是open source社群按照官方公開的規格做的。
反之AMD和nVidia的Linux版驅動程式也是官方開發的,這兩家的晶片在Windows表現比較好。