Open2

C-WebGL: CPU/GPU並列処理に対応した構造を考える会

okuokuokuoku

並列処理の必要性

WebGLでは、テクスチャなどのオブジェクトをどのタイミングでも自由に変更できる。つまり、描画に使っている最中のテクスチャを更新した場合、動画が終ってから実際の更新を行うのはWebGL側の責任になる。

これを実装できる構造を考える必要がある。。

VulkanのGPUには重要な特徴がいくつかある。(便宜上、GPU側のメモリの事を単にVRAMと呼ぶ)

https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap12.html#resources-association

  • 生成された瞬間にはVRAMアドレスは決定されていない

Resources are initially created as virtual allocations with no backing memory.

  • 一度VRAMアドレスを決定すると、オブジェクトを破棄するまで変更できない(immutable)

Once bound, the memory binding is immutable for the lifetime of the resource.

https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap12.html#vkDestroyBuffer

  • Bufferを捨てるには、操作が完了していなければならない

All submitted commands that refer to buffer, either directly or via a VkBufferView, must have completed execution

... というわけで、GPU側が処理中であっても自由にGPUオブジェクトを変更できる( ように見せている )WebGLのセマンティクスを実現するためには、何らかの方法で操作を 遅延 させる方法論が必要になる。

最初は、全ての操作をGPUへのサブミット直前まで遅延させる方向で考えることにする。つまり、あるオブジェクトがGPUに使われることが明かになったタイミングで、初めてVRAMの確保や転送を実施する。WebGLではGPUのコマンドバッファ自体は1つしかないため、 サブミットの直前はGPUの処理が完了していることが簡単に保証できる

okuokuokuoku

何がGPU flushを起こすのか問題

WebGL自体には、GPU flushの概念が存在しない。OpenGL実装が自分で考えてどのタイミングでGPUを駆動するかを選択する必要がある。WebGLのGPUコマンドには大きく分けて:

  • drawElements のような 描画命令
  • readPixels による read back
  • bufferData とか texImage2D のような 転送命令
  • (また、JavaScript側の requestAnimationFrame コールバックが完了した時点で、最新の描画データが必要になるため、事実上 フレーム終端 もGPUコマンドとなる)

の3(+1)種類ある。並列処理を考慮しないなら、これらの全てでGPU flushしてGPUを待ち合わせて進む(ロックステップ)こともできるが、並列処理する気があるならばある程度まとめて処理できるように配慮する必要がある。

... 一旦ロックステップで作るか。。この辺のデバッグ大変だし。。