yuniframe: UI描画の部分更新手法の調査

お絵かきソフトを作っていると電力消費が気になる。ペン入力で更新されるのは4Kの広大なフレームバッファのごく一部であり、それをblitするために消費される電力のうち、メモリトラフィックは相当な割合を占める。(アクティブ時間が長くなるのと、メモリトラフィック自体の両方の意味で)
というわけで、 Webブラウザ以外で 部分更新を実装する方法を考える。残念ながらWebブラウザは部分更新を実施する良い方法はない。
差分更新モードの必要性
全てのモダンAPIでflip先のバッファを知ることができるため、1 または 2 フレーム前の状態から差分更新するというスタイルで部分更新を実現できる。
通常のシチュエーションでは逆、つまりflipしたバッファは内容を捨て、タイルベースのGPUで描画開始時のリードバックを不要にしている。よって、画面の大半が更新されないと保証できない限り、差分更新は電力の無駄になる可能性がある。
yuniframeはWeb 〜 デスクトップ全てをサポートしたいので、差分更新モード(blitモード)と全画面更新モード(full screenモード)の両方を持つのが良さそうだ。
単純なpreserveで不充分なのは、単純なpreserveを行うとトリプルバッファのシステムでは常にフルスクリーンのコピーが1回必要になってしまうという点があるため。つまり、トリプルバッファのシステム(大抵のシステムはトリプルバッファを採用する)では描画できるようになったバッファが2 フレーム前の状態ということがあり得るが、単純なpreserveではこの状態でも全画面コピーによって1 フレーム前の状態を見せなければならない。

Vulkan / DirectX
Vulkan や DirectX上ではswap chainを直接制御できるためバックバッファに直接描く方法が使える。
DX12は DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
がpreserve back bufferの意味で使用できる。

Metal
Metalはswap chainを抽象化してしまっているが、 CAMetalDrawable
から MTLTexture
の形でバックバッファを取得できる https://github.com/flutter/flutter/issues/33939#issuecomment-698957381 。

OpenGL ES + EGL
一般にOpenGL系のAPIはバックバッファに対する直接アクセスは提供しない(GPUの持ちものであるという思想)が、EGLに EGL_EXT_buffer_age
という直球の拡張が存在する。

WebGL
WebGLというかWebブラウザは、完全なバッファリングを要求する。このため、 EGL_BUFFER_PRESERVED
に相当する挙動(または完全なdiscard)だけが存在する。