OpenGL 4.4 和 Android

jopen 10年前發布 | 16K 次閱讀 OpenGL Android開發 移動開發

手機硬件的更新是如此迅速以至于我們開始進入一個手機與高端PC功能無異的時代。它們的區別將只是芯片的功耗不同而已。

我不想讓自己聽起來像是在推廣我們自己的芯片,但我相信Tegra K1是未來即將發生的事物的前瞻。不僅僅發生在我們身上,我希望其他行業也能加入進來,從而使開發者可以為從PC到手機安全地假設一個相對統一的功能集。K1只是首個示例,因為它的GPU核心是Kepler 。而且它不是什么營銷手段,它實際上是與運轉像GTX780這種神奇事物相同的微架構。幾年的血汗與淚水使其成為了可能。并且限于尺寸,功率和熱限制,它只有192個核心(而不是2304個),但它仍具有較強的性能競爭力。更重要的是在功能上它處于一個完全不同的陣營中,因為它支持完整的桌面級OpenGL4.4,包括幾何著色器,鑲嵌,計算等,還有像bindless這樣的支持其他事物的擴展。

但是Android只支持OpenGL ES,對嗎?實際上不是這樣的。雖然現在在Android平臺上,首選的官方支持的圖形API是OpenGL ES,你仍然可以使用EGL在平臺上創建一個"大"OpenGL 上下文,前提是你的設備支持它。這使得在不同的操作系統上傳輸數據很實用,Windows/Linux/Mac/streamOS 都有OpenGL的后臺程序,可以快速啟動并模擬裁剪平面(clip planes),alpha測試,或者spec中的少數差異。它同樣可以作為一個不錯的引用渲染后端程序,在ES渲染路徑啟動和運行之前驗證你的端口。

不要擔心,你可以在你的app中同時使用GLES和BigGL。實際上,這很簡單。最重要的事情在EGL中,它是Android為創建OpenGL上下文而公開的API。Java或C/C++同樣可以這樣做,但是要注意需要EGL_SPEC.1.4以上版本。

首先,在創建上下文(或者調用任何一個EGL函數)之前,要知道哪個版本的GL最支持當前設備。可以通過簡單地調用eglBindAPI(EGL_OPENGL_API)來完成。該API會將EGL切換到桌面OpenGL模式,如果當前設備不支持,則返回EGL_TRUE或者留下未改變的狀態并返回EGL_FALSE。鑒于該函數可以切換全局狀態,所以最安全的做法是讓EGL首先調用它,之后不再調用。

創建完上下文之后,如果eglBindAPI()函數沒有切換BigGL模式,你就要和你之前那樣創建你的ES上下文。如果切換成功,你可選擇性地創建BigGL上下文。幸運的是,EGL讓它簡單化。因為我們已經調用了eglBindAPI(EGL_OPENGL_API),EGL已經設置為BigGL模式,所以我們只需要在配置文件和上下文中調整一些屬性即可。

首先,在傳遞給eglChooseConfig()的配置屬性中,我們需要確保 EGL_RENDERABLE_TYPE 設置為 EGL_OPENGL_BIT ,而不是EGL_OPENGL_ES2_BIT.

其次, 傳遞給函數  eglCreateContext() 的屬性也需要稍微調整。對于 ES上下文,通常把 EGL_CONTEXT_CLIENT_VERSION 設為 1, 2 或3, 這取決于你想搭建哪個版本的OpenGL ES.對于BigGL上下文,我們不使用這個屬性,所以不要設置。事實上,你可以直接把BigGL的屬性列表置空。

粗略地講,這比較像下面的樣本 (為簡潔起見,忽視錯誤檢查):

if(eglBindAPI(EGL_OPENGL_API))
{
  // Create a BigGL context...
  EGLDisplay display = eglGetDisplay(...);
  eglInitialize(display, ...);
  const EGLint configAttrs[] =
  {
    EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
    // backbuffer attributes here...
    EGL_NONE
  };
  EGLConfig config;
  EGLint    numConfigs = 0;
  eglChooseConfig(display, configAttrs, &config, 1, &numConfigs);
  EGLint ctxAttrs[] =
  {
    EGL_NONE
  };
  eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttrs);
}
else
{
  // TODO: Fallback to old ES context creation...
}

最后一點問題,也是我對于使用OpenGL或者OpenGL ES的開發人員的一些建議,不論他們基于怎樣的平臺進行開發。尤其重要的一點是像上面提到的那樣在API之間進行切換。并且,不要隱式地鏈接到GL符號!就算是再多的功能,你都應當使用eglGetProcAddress(),并且當心不要在上下文中共享函數指針。如果你做了一下比較瘋狂的事情,比如在同一個應用中創建了一個BigGL上下文和一個ES上下文,或者創建了像glDrawElement()這樣的函數,在兩者的API中都存在,但是可能指向了完全不同的實現方法。這就意味著你應當僅鏈接到libEGL,所以需要通過qglGetProcAddress()函數查詢所有的符號。

編輯:應當指出的是,從技術的角度講,通過eglGetProcAddress()可獲得的“EGL_KHR_get_all_proc_addresses”應當是目前的核心功能,但是我堅信,既然目前它在Android通用EGL接口上進行了實現,也就意味著它可以單獨驅動,這可能在舊版本的Android上無法正常工作。但是如果你正在考慮支持BigGL,你可能不希望舊設備成為你道路上的絆腳石。

特別強調:我強烈建議如果可能的話,任何正在開發的應用程序應該也有GLES渲染路徑。BigGL對于開發是實用的,對于一些邊緣特性,甚至會更實用,但是有GLES后端同樣會幫助Android避免分段存儲,并且幫助你的應用更多的曝光在盡可能多的用戶面前。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!