EmscriptenにおけるOpenGLサポート

Emscriptenは3つのOpenGLモードを提供します

このトピックでは、これらのモードと、それらの有効化方法について説明します。

ヒント

新しいコードにはWebGLフレンドリーなOpenGL ES 2.0/3.0のサブセットを使用し、可能であれば既存のコードをこのサブセットに移植することを強くお勧めします。他の2つのモードは効率が低く、それらの機能に大きく依存するコードベースの場合にのみ検討する必要があります。

WebGLフレンドリーなOpenGL ES 2.0/3.0のサブセット

デフォルトでは、EmscriptenはOpenGL ES 2.0のWebGLフレンドリーなサブセットをターゲットにします。これは、各GLコマンドがWebGLにほぼ直接マッピングされるため、GLコマンドのセットがWebGLに直接マップされるGL ESコマンドのセットです。これには、OpenGL ES 2.0のほぼすべてが含まれていますが、クライアントサイド配列、およびWebGL 1.0仕様/第6章に記載されているその他の機能は除きます。

OpenGL ESのWebGLサブセットを対象としてプログラミングするには、GL ES 2.0ヘッダーファイルとGL ES 2.0 APIを使用し、WebGL仕様の第6章で指定された制限に従います。

このモードは、ブラウザで提供されるWebGL機能に最適に適合するため、デフォルトで使用されます。

WebGL 2をターゲットにするには、リンカフラグ-sMAX_WEBGL_VERSION=2を渡します。このフラグを指定すると、ランタイム時にWebGL 2コンテキストの作成が有効になります(コンテキスト作成時に明示的に指定されていない限り、デフォルトになります)。ただし、WebGL 1コンテキストを作成することもできるため、アプリケーションはWebGL 2を要求するか、WebGL 1へのフォールバックをサポートするかを選択できます。

コードサイズを削減するためにWebGL 2のみをターゲットにし、WebGL 1のサポートを完全に削除するには、リンカフラグ-sMIN_WEBGL_VERSION=2-sMAX_WEBGL_VERSION=2を渡します。

OpenGL ES 2.0/3.0のエミュレーション

このビルドモードは、WebGL 1コア仕様の一部ではないOpenGL ES 2.0/3.0の一部の機能をエミュレートします。

特に、このモードはWebGLフレンドリーなOpenGL ES 2.0/3.0のサブセットにないクライアントサイド配列をエミュレートします1

これにより、バインドされたバッファなしでglDrawArraysglDrawElementsなどの関数を使用できるようになり、EmscriptenのGLバインディングがバッファを自動的に設定します(WebGLでは、バッファをバインドする必要があります)。

注記

このビルドモードには、クライアントサイドインデックスバッファの最大インデックスが、そのバッファのインデックスの総数より小さくする必要があるという制限があります。issue #4214で詳細を確認してください。

OpenGL ES 2.0のエミュレーションを有効にするには、プロジェクトの最終実行ファイル(.js/.html)をリンクする際に、emccオプション-sFULL_ES2を指定します。

OpenGL ES 3.0のエミュレーションを有効にするには、プロジェクトの最終実行ファイル(.js/.html)をリンクする際に、emccオプション-sFULL_ES3を指定します。これにより、メモリブロックをクライアントサイドメモリにマッピングするためのエミュレーションが追加されます。-sFULL_ES2-sFULL_ES3のフラグは直交しているため、いずれか一方または両方を指定してさまざまな機能をエミュレートできます。

旧式のデスクトップOpenGL API機能のエミュレーション

このOpenGLモードでは、多くのレガシーデスクトップOpenGL 1.x機能とコマンド(例:「イミディエイトモード」とglNormalPointer)がサポートされます。

エミュレーションは決して完全ではありませんが、Sauerbraten 3Dゲーム(BananaBreadプロジェクト)やその他の現実世界のコードベースをEmscriptenを使用して移植するのに十分でした。

このモードを有効にするには、プロジェクトの最終実行ファイル(.js/.html)をリンクする際に、emccオプション-sLEGACY_GL_EMULATIONを指定します。

最適化設定

このモード(-sLEGACY_GL_EMULATION)では、GLエミュレーションレイヤのパフォーマンスを調整するために使用できる追加のフラグがいくつかあります。

  • -sGL_UNSAFE_OPTSは、冗長なGL作業とクリーンアップをスキップしようとします。この最適化は安全ではないため、デフォルトでは有効になっていません。

  • -sGL_FFP_ONLYは、GLエミュレーションレイヤに、コードがプログラム可能なパイプライン/シェーダーをまったく使用しないことを伝えます。これにより、GLエミュレーションコードは、安全であることがわかっている場合に、追加の最適化を実行できます。

  • シェル** .html**ファイルにModule.GL_MAX_TEXTURE_IMAGE_UNITS整数を追加して、コードで使用されるテクスチャユニットの最大数を信号として送信します。これにより、GLエミュレーションレイヤは、実行する固定関数パイプライン(FFP)エミュレーションシェーダーを調べているときに、使用されていないテクスチャユニットを反復処理することでクロックサイクルを無駄にしません。

コードベースが現在サポートされていないデスクトップOpenGL機能に依存している場合

RegalデスクトップOpenGLエミュレーションライブラリに対してコードベースをビルドすることを検討できます。これは、OpenGL ES 2.0の上にデスクトップOpenGL機能をサポートすることを目的としています。これは、プロジェクトによってはEmscriptenのGLエミュレーションよりも優れている場合と劣っている場合があります。もう1つのオプションは、ゲームのOpenGLからGLESへの高速変換を目的としたgl4esを使用することです。これはOpenGL ES 2.0の上にOpenGL 2.1プロファイルをターゲットにしており、すでにEmscriptenでいくつかのゲームの移植に使用されています。

OpenGL ES拡張機能

コードを移植する際には、デスクトップOpenGL、OpenGL ES、およびWebGLにはそれぞれ独自の拡張機能レジストリがあることに注意してください。つまり、デスクトップOpenGLまたはOpenGL ES拡張機能は、ある程度の互換性はあるものの、自動的にWebGL拡張機能になるわけではありません。WebGL 1.0拡張機能レジストリで、登録されている拡張機能の完全なリストを確認してください。

さらに、デスクトップまたはモバイルOpenGLとは異なり、WebGLでは、拡張機能が公開する機能が有効になる前に、最初に拡張機能を有効にする必要があります。ネイティブAPIのSDL、EGL、GLUT、またはGLFWのいずれかを使用してGLコンテキストを作成する場合、ほとんどの拡張機能に対してこれは自動的に行われます。代わりにHTML5 WebGLコンテキスト作成APIを使用する場合は、WebGL拡張機能を自動的に有効にするかどうかを明示的に選択する必要があります。コンテキストの作成時に拡張機能が自動的に有効になっていない場合、HTML5 API関数emscripten_webgl_enable_extensionを使用して有効にすることができます。デバッグ関連の拡張機能、ドラフト拡張機能、およびベンダープレフィックス付きの拡張機能(MOZ_ *、WEBKIT_ *)は、コンテキスト作成時に自動的に有効になることはなく、常に手動で有効にする必要があります。

WebGL 1からWebGL 2に移行する際には、一部のWebGL 1拡張機能がコアWebGL 2に移行され、そのため、それらの機能はもはやGL拡張機能として宣伝されなくなっていることに注意してください。これは、機能が欠けているという意味ではなく、GL拡張機能の存在を最初に機能テストする必要なしに、WebGL 2でこれらの機能を使用できることを意味します。

テストコード/例

test/third_party/glbook内のファイルは、OpenGL ES 2.0/3.0のWebGL対応サブセットのみを使用するいくつかの簡単な例を提供しています。

他のモードは、test/test_browser.pyにあるいくつかのテストを含む、様々なテストで網羅されています。テストを見つける最良の方法は、ソースコードで適切なコンパイラフラグ(FULL_ES2LEGACY_GL_EMULATIONなど)を検索することです。

バグレポート

Emscriptenのバグトラッカーには、様々なGL関連の問題を追跡するためのOpenGLおよびOpenGLエミュレーションに固有のラベルがあります。

脚注

1

クライアントサイド配列は、GPU側データを使用するよりも効率が悪いことから、WebGLには含まれていません。