為了忘卻的紀念:析OpenGL史上第二偉大的擴展,DSA

OpenGL從1992年推出第一版以來,經歷了24年的風風雨雨,終於在4.5停止了腳步。在全面轉向Vulkan之前,我打算紀念一下OpenGL史上第二偉大的擴展,Direct State Access(DSA)。(第一偉大的擴展是framebuffer object)

狀態機的罪惡

OpenGL之前一直採用狀態機的形式,比如要給buffer填數據,就得

glBindBuffer(target, buffer);nglBufferData(target, size, data, usage);n

除了bind系列函數,其他函數都是操作當前設置在狀態機里的對象。這麼做API簡單,但缺點也非常明顯。

  1. 狀態機是全局的。你的一次bind,可能造成十萬八千里外的代碼操作錯了對象。
  2. 性能。為了不影響狀態機,很多時候你需要glGet舊的,glBind新的,操作完在glBind舊的回去。而且在驅動里,還得把它還原成非狀態機的形式。

在OpenGL 2.0的時候,曾經有傳言要廢除舊的狀態機,換用一套新的操作方法。然而最後也不了了之。一些新的API,比如fbo,用的是混合的方法。主流API還是老的狀態機模式。

EXT DSA

終於到了2007年,擴展版本的GL_EXT_direct_state_access出來了。 又是一個超級長的spec,並且在之後的七八年里不停地修改。這個擴展幾乎提供了所有OpenGL函數的一個新版本,不需要狀態機就能直接操作對象。比如前面說的buffer填數據,就可以一行搞定

glNamedBufferDataEXT(buffer, size, data, usage);n

由於沒有狀態機的設置,這裡的調用不用擔心破壞別處的代碼,性能也可以保證不降低。這樣對開發效率和運行效率都有好處。

Core/ARB DSA

到了OpenGL 4.5的時代,終於,終於,終於,DSA被升級到ARB擴展,併合併到核心。基本上就是把EXT版本的可編程流水線系列函數提升到Core/ARB。這下終於可以愉快地使用DSA了!

不過要注意的是,有一些細節還是不同的。比如原先用glGen*系列函數生成的id,內部並沒有初始化那個對象的狀態。只有到了glBind*的時候才會初始化。而Core/ARB的DSA直接提供了glCreate*系列函數,可以一步到位地建立id和初始化。很多Core/ARB的DSA函數,都需要配合glCreate*來使用,不能用於glGen*的。詳細請看Direct State Access。

平台可用性

那麼說那些平台能用DSA呢?一般來說顯卡支持什麼OpenGL版本和擴展,取決於驅動(也就是OpenGL的實現)。在Windows和Linux上,新驅動都是支持DSA的,至少也有EXT的版本。然而在Mac上,OpenGL的版本和擴展都是apple控制的。DSA完全沒有。所以,目前為止,如果你要支持Mac,就得保留一份不用DSA的代碼。可惜,可惜。

而且,這件事情有可能是永久的。Mac上也有Metal和OpenGL競爭了,apple肯定優先發展親兒子,讓曾經立下汗馬功勞的乾兒子靠邊站,不再更新。所以,現在沒有,很可能以後也不會有。


推薦閱讀:

OpenGL+FreeType 模仿黑客帝國數碼雨 V2.0
卡通渲染及其相關技術
神奇的深度圖:複雜的效果,不複雜的原理
基於物理的渲染—基於球面調和基的實時全局光照明

TAG:OpenGL | 计算机图形学 | 3D渲染 |