Open5

C-WebGL: GPUバックエンドの計画

okuokuokuoku

色々考えたけど、とりあえず:

  1. 制作したWebGL1のステートトラッカー と OpenGL ES2のGPUバックエンドを組み合わせて、今迄のアプリケーションが動作することを確認
  2. GPUバックエンドをVulkanのものに載せ替えてVulkan移植完了

の2段構えでやっていくことにした。

ステートトラッカー は、例えば glLineWidth のようなAPIが呼ばれたときに 内部のステートを更新する 。アプリケーションが供給する描画コマンドのパラメタをトラックするのでステートトラッカーと呼んでいる。

GPUバックエンド は、 glDrawElements のような実際の描画コマンドが呼出されたときに動作し、ステートトラッカーが集めたパラメータと一緒に実際の描画をGPU側に要求する。

現状では glDrawElements は実装していない (空関数のままにしている)。このように空になっている関数を列挙して、GPUバックエンドが実装しなければならないインターフェースを設計していく。

okuokuokuoku

GPUバックエンドが必須なコマンド

現状のトラッカーの実装を眺めてみると、割と頑張ればトラッカーで完結できるものがまだまだ残っているようなので、それらをトラッカーに実装していく必要がありそうだ。

というわけで、まず、GPUバックエンドが必須なコマンドを分離してしまうことにした。

(sX はGLES2規格書の章番号。6章だけ長いので分割している。)

描画系

一般的な意味での描画コマンド。ちょっと難しいのはrenderbuffer/framebufferの扱いで、ユーザが要求した形式のrenderbufferが使えるかどうかは、一旦attachしてみて checkFramebufferStatus で確認するというのが通常の使いみちになっているため、 本来、トラッカーでは完結できない 。一方、設定の度にドライバからトラッカーを呼出してステータスを更新する(= checkFramebufferStatus で返すべき結果もトラッカー側でトラッキングする)という実装も考えられるが、Framebufferについては都度ドライバ側を呼び出すことにした。

  • s2:
    • cwgl_drawArrays
    • cwgl_drawElements
  • s4:
    • cwgl_clear
    • cwgl_readPixels ★ メモリ転送を伴う
    • cwgl_renderbufferStorage ★本来はメモリ確保を伴う
    • cwgl_checkFramebufferStatus
  • s5:
    • cwgl_finish
    • cwgl_flush

転送系

GPU側のメモリとの転送を伴うAPI群。描画系との境界は非常に曖昧と言える。。

  • s2:
    • cwgl_bufferData
    • cwgl_bufferSubData
  • s3:
    • cwgl_generateMipmap
    • cwgl_texImage2D
    • cwgl_copyTexImage2D
    • cwgl_texSubImage2D
    • cwgl_copyTexSubImage2D
    • cwgl_compressedTexImage2D
    • cwgl_compressedTexSubImage2D

シェーダー系

Framebufferとは対照的に、 getProgramInfoLog はトラッカー側に結果をキャッシュさせることにした。大したサイズではないし。。このためココにはリストされない。

  • s2:
    • cwgl_compileShader
    • cwgl_linkProgram
    • cwgl_validateProgram
okuokuokuoku

シェーダー関連

これらは描画を行わないが、シェーダコンパイラとの協調が必要なのでGPUバックエンドとしての設計が必要になる:

  • s2:

    • cwgl_getActiveAttrib
    • cwgl_getAttribLocation
    • cwgl_bindAttribLocation
    • cwgl_getUniformLocation
    • cwgl_getActiveUniform
    • cwgl_uniform〜
  • s6shader:

    • cwgl_getUniform〜
okuokuokuoku

バックエンドとの協調が必要になるもの

いくつかのget系APIは、ユーザからセットした値ではなく、バックエンド側のデータを必要とするものがある。 例えばベンダ名等 (EDIT: やっぱり可能な限りステートにデータを突っ込む方針に変えた)。たぶんステートトラッカーのオブジェクトをGPUバックエンドから直接書き換える方式にするのが良いんじゃないかと思う。例えば、 getProgramInfoLog のログデータは、 linkProgram の際に常にステートトラッカーに書き出す というルールにすれば、GPUバックエンドは getProgramInfoLog をハンドルする必要はなくなる。

  • s6shader:
    • cwgl_getShaderParameter_i1
    • cwgl_getProgramParameter_i1
    • cwgl_getProgramInfoLog
    • cwgl_getShaderInfoLog
okuokuokuoku

本来ステートトラッカーで完結できるが現状未実装のもの

いくつか特に理由なく実装をサボっているものがある。

シェーダー関連

WebGL1および2では、フラグメントシェーダ + 頂点シェーダ の組合せを越えるものは存在しないので、getAttachedShaders はもうちょっとシンプルなAPIに変更できる。

  • s2:

    • cwgl_shaderSource
  • s6obj:

    • cwgl_getShaderSource
    • cwgl_getAttachedShaders

is〜 系API

WebGLにおける is〜 系APIはinvalidatedされているかどうかを判別することも要求している。WebGLの invalidated flag はcontext lostの際にセットされる。C-WebGLには今のところcontext lostの概念は存在しないので、 is〜 系APIは常にtrueを返却するしかない。

ややこしいのは、ShaderやProgramにはDelete APIや DELETE_STATUS enumが存在するものの、これらが実行されてもuseProgramされている最中はisProgramやisShaderはtrueを返却する必要がある点。

更に、本来のGLES2のisTextureは "bindされるまではtextureでないのでfalse" というルールだが、WebGLのisTextureはcreateTextureで生成された瞬間からtrueとなるので挙動が絶妙に異なる(はず)。

  • s6shader:

    • cwgl_isShader
    • cwgl_isProgram
  • s6obj:

    • cwgl_isTexture
    • cwgl_isBuffer
    • cwgl_isFramebuffer
    • cwgl_isRenderbuffer