在下一版的KlayGE中,D3D9外掛程式光榮退休,OpenGL外掛程式將要取代它在WinXP下 的位置。眾所周知,ATI的OpenGL驅動一直毛病眾多。因此解決OpenGL外掛程式在ATI卡上出現的錯誤成了當務之急。本文就討論一下在增強 OpenGL外掛程式的過程中遇到的陷阱及其解決方案。測試的顯卡為HD5870,所有問題在9.12-10.10的驅動中都會出現。
glBlitFramebufferEXT
在以前的版本裡,OpenGL外掛程式在ATI顯卡上的文字顯示總是亂碼。一開始懷疑是vbo或者shader造成的,最後定位在texture本身。在texture的局部拷貝過程中,OpenGL外掛程式用的是GL_EXT_framebuffer_blit擴充的glBlitFramebufferEXT。ATI驅動對GL_EXT_framebuffer_blit的支援似乎並不完善,結果是雖然什麼錯誤都沒發生,但拿目標texture來使用的時候總是一團亂麻,如所示:
如果這個時候用glGetTexImage擷取texture資料,卻又是正確的。繞開這個問題的方法就是用pbo把源texture和目標 texture都map出來,然後memcopy;或者更傳統的gluScaleImage。此問題修好之後,所有例子的文字顯示在ATI卡上恢複了正 常:
glClearBufferfi/glClearBufferfv/glClearBufferiv
在一些例子,比如Parallax中,出現了畫面空白的現象。clear color buffer能起作用,但depth/stencil buffer卻沒有被正確地清除。在支援OpenGL3及以上的情況下,OpenGL外掛程式會預設調用glClearBuffer*的函數來直接清除 buffer,而不用傳統的方法:先調用glClearColor,glClearDepth,glClearStencil設定清除的值,然後調用 glClear來完成清除的工作。在ATI卡上,似乎glClearBufferfi/glClearBufferfv/glClearBufferiv 這些用來清除depth/stencil的函數並沒有起作用。解決方案只能是退回到傳統的Clear方法。
這麼做之後,絕大部分例子都能正常渲染了:
glBeginConditionalRender
Deferred shading的例子用query conditional來判斷一個光源是否可見。原先的版本在ATI卡上一執行就發生系統死結,必須強製冷啟動才能解決,破壞性極大,而且完全沒有機會調試。(難道是因為query conditional是NV提出來的緣故?)一次湊巧看了http://www.g-truc.net/post-0318.html,確定就是因為query conditional造成了死結。
把相關語句繞開之後Deferred shading恢複正常了。
GLSL
GLSL的問題其實不能算是陷阱,但值得關注。ATI驅動的GLSL編譯器可謂中規中矩,符合GLSL標準的shader一般沒啥問題,但不符合標 準的會死得很難看。NVIDIA的GLSL編譯器則大不相同,相容很多NV自己的“擴充”,比如支援數組的varying。所以其實在ATI卡上能工作的 GLSL基本也能在NV的卡上工作。如果你希望你的GLSL可以在ATI平台上跑,我的推薦是用AMD GPU ShaderAnalyzer測試一下(GPU ShaderAnalyzer是個純軟體的分析器,在NV的平台上也能運行)。如果GLSL有問題,就會立刻顯現出來。
經過一系列的嘗試,Cg到GLSL的轉化終於可以在ATI平台上順利執行,包括Geometry shader:
以上就是我在KlayGE中遇到的ATI OpenGL驅動陷阱。希望對大家以後遇到的問題有所協助。
轉自http://www.klayge.org