Emscripten 中的 EGL 支援

注意

本文正在建構中。

Khronos Group 發布了一個名為 EGL 的規範,它是一個 API,可以處理(在其他任務中)圖形上下文建立、渲染表面管理,以及不同 Khronos Group 圖形 API(OpenGL、OpenGL ES、OpenVG)之間的互操作。如需詳細資訊,請參閱 Khronos EGL 網頁

目前,EGL 在作業系統/圖形驅動程式供應商之間並未廣泛使用。最顯著的採用是在 Android 架構中,當使用 Android NDK 時,EGL 是建立 OpenGL ES 1&2 渲染上下文的主要方法。此外,Mesa 在其 圖形驅動程式中實作了 EGL 規範。

Emscripten 也提供了 EGL v1.4 規範的實作。這允許 C/C++ 客戶端程式碼使用(幾乎)統一的程式碼庫,以在 Web、Linux(使用 Mesa)和 Android NDK 上建立 GLES2 (WebGL) 渲染上下文。Emscripten 中 EGL 規範的實作並不完美,請參閱本頁結尾的狀態圖表。

EGL 不是什麼?

有點令人失望的是,EGL 並不是一個自行足夠的完整解決方案,用於初始化 GLES2 圖形渲染(在任何平台上,而不僅僅是 Emscripten)並監督各種相關任務。規範的範圍有限,並且缺乏某些功能。特別是,EGL 無法協助執行以下任務

  • 建立渲染視窗。EGL 規範沒有指定如何建立要渲染到的目標視窗。必須使用平台特定的原生視窗系統函數(X11、Win32 API、ANativeWindow)來先建立渲染視窗。

  • 以任意像素增量指定渲染視窗大小。EGL 沒有任何功能可以請求主渲染視窗的所需大小,或調整其大小。

  • 指定全螢幕視訊模式/螢幕解析度。EGL 不能用於控制是以視窗模式還是全螢幕模式進行渲染,或在執行時期在這兩者之間切換。

因此,對於每個平台(包括 Emscripten),都存在平台特定的方法來執行這些任務。

如何使用 EGL 建立 WebGL 上下文?

在 Web 環境中,WebGL 是用於 3D 加速渲染的技術。WebGL 幾乎與 GLES2 相同,而且由於 EGL 完全不適用於 WebGL,因此在本頁的所有目的中,WebGL 和 GLES2 這兩個術語可以互換使用。因此,要建立 WebGL 上下文,可以使用 EGL,並根據其措辭,建立 GLES2 上下文。

初始化

執行以下步驟以使用 EGL 建立 GLES2 上下文

  1. 呼叫 eglGetDisplay 取得 EGLDisplay 物件的控制代碼。

  2. 呼叫 eglInitialize 在該顯示器上初始化 EGL。

  3. 呼叫 eglGetConfigs 和/或 eglChooseConfig 一次或多次,以找到代表所需主渲染目標參數的 EGLConfig。若要檢查 EGLConfig 的屬性,請呼叫 eglGetConfigAttrib

  4. 此時,可以使用任何可用的平台特定函數(X11Win32 APIANativeWindow)來設定要渲染的原生視窗。對於 Emscripten,此步驟不適用,可以跳過。

  5. 呼叫 eglCreateWindowSurface,並使用有效的顯示器和組態參數,建立主要渲染目標表面 (EGLSurface)。將視窗和屬性清單參數設定為 null。

  6. 呼叫 eglCreateContext 建立 GLES2 渲染上下文 (EGLContext),然後呼叫 eglMakeCurrent 來啟動渲染上下文。建立上下文時,請指定上下文屬性 EGL_CONTEXT_CLIENT_VERSION == 2

執行這些步驟後,您會擁有一組 EGL 物件 EGLDisplayEGLConfigEGLSurfaceEGLContext,它們代表主要的 GLES2 渲染上下文。

清理

取消初始化時的清理順序如下

  1. 呼叫 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) 以釋放目前作用中的渲染上下文。

  2. 在其上呼叫 eglDestroyContext,以取消初始化 EGLContext 物件。

  3. 在其上呼叫 eglDestroySurface,以銷毀所有已初始化的 EGLSurface 物件。

  4. 呼叫 eglTerminate(display) 以完全取消初始化 EGL。

  5. 刪除原生渲染視窗。此步驟不適用於 Emscripten。

範例程式碼

emscripten/test/third_party/glbook 目錄中的範例應用程式中,可以找到使用 EGL 初始化 WebGL 上下文的範例程式碼,更具體而言,是在 esUtil.c 檔案中。

實作狀態與注意事項

本節列出所有 EGL v1.4 函數,並說明它們在 Emscripten 中的目前實作狀態。

完全實作

  • eglInitializeeglGetConfigseglQueryContexteglQueryStringeglQuerySurfaceeglGetCurrentContextglGetCurrentSurfaceeglGetCurrentDisplayeglReleaseThreadeglDestroySurfaceeglDestroyContext:已實作,且應根據 EGL v1.4 規範運作。

  • eglSwapBuffers:已實作,但此函數無法真正控制 WebGL 下的交換行為。在 Emscripten 下呼叫此函數是可選的。在 WebGL 中,只有在程式碼將執行權返回給瀏覽器之後,也就是當您從傳遞給 emscripten_set_main_loop() 的勾選回呼處理程式返回時,才會將顯示器的內容呈現到螢幕上。eglSwapBuffers 函數仍然可以用於偵測何時發生 GL 上下文遺失事件。

  • eglGetDisplay:根據規範實作。Emscripten 不會使用多個 EGLNativeDisplayType 物件,因此請在此處傳入 EGL_DEFAULT_DISPLAY。Emscripten 目前實際上會忽略在此處傳入的任何值,以用於 Linux 模擬目的,但您不應在未來依賴此行為。

  • eglGetError:根據規範實作。

    重要

    根據規範,eglGetError 會報告單一最近發生的錯誤,而不是先前所有錯誤的清單。請勿以您呼叫 glGetError 的方式在迴圈中呼叫此函數。

部分實作

  • eglChooseConfig:已實作為存根,但此函式不會進行搜尋/篩選,目前與 eglGetConfigs 相同(issue #643)。

  • eglGetConfigAttrib:已實作。查詢屬性 EGL_BUFFER_SIZEEGL_ALPHA_SIZEEGL_BLUE_SIZEEGL_GREEN_SIZEEGL_RED_SIZEEGL_DEPTH_SIZEEGL_STENCIL_SIZE 目前會回傳硬編碼的預設值(issue #644)。屬性 EGL_MIN_SWAP_INTERVALEGL_MAX_SWAP_INTERVAL 目前沒有任何作用。請改為呼叫 emscripten_set_main_loop() 來指定主迴圈更新速率。

  • eglCreateWindowSurface:已實作,但無法多次呼叫此函式以建立多個渲染視窗。

  • eglCreateContext:已實作為存根。無法多次呼叫此函式以建立多個上下文。

  • eglBindAPIeglQueryAPI:已實作,儘管這些函式在 Emscripten 上幾乎沒有用處,因為僅支援 GLES2 用戶端 API。

  • eglWaitClienteglWaitNative:已實作為無操作函式。這些在 Emscripten 上沒有意義。

  • eglSwapInterval:已實作為無操作存根。目前此函式無法設定垂直同步間隔,或啟用/停用它。

  • eglMakeCurrent:已實作為無操作存根。

  • eglTerminate:已實作為無操作函式存根。JavaScript 應用程式通常不會手動關閉,但在關閉瀏覽器或切換網頁時,瀏覽器會自動管理所有終止操作。因此,此函式在 Emscripten 中並不具有關鍵的重要性。

  • eglGetProcAddress:已實作,實驗性功能。

缺少功能

目前未實作下列函式

  • eglCreatePbufferSurfaceeglCreatePixmapSurfaceeglCreatePbufferFromClientBuffereglSurfaceAttribeglBindTexImageeglReleaseTexImageeglWaitGLeglCopyBuffers

重要

請勿在 Emscripten 程式碼中呼叫這些函式,否則應用程式在嘗試執行未定義的函式時會停止。

EGL 擴充功能

目前,Emscripten 沒有實作 EGL 擴充功能註冊表 中的任何擴充功能。