マイコン向け32KiB描画エンジンの企画検討の会
とりあえず32KiB RAMで動作させるのを前提にグラフィックスエンジンの設計を考えることにした。
なぜ32KiBか?
WioTerminalのCPUはRAMが192KiBしかないため。以下のようなメモリバジェットでゲームを作ろうとしている:
サイズ | 用途 |
---|---|
64KiB | ゲームの実行ファイル(OSKやダイアログの表示時はこちらを追加RAMにする) |
64KiB | ゲームのRAM + スタック |
32KiB | 描画中データ(ダブルバッファ) |
32KiB | OSのRAM + スタック |
ゲームがアクセスできるRAMは64KiBだが、そのうち最大32KiBを描画データに使う。つまり1フレームあたり32KiBのコピーは常に発生する。まぁ2MiB/sec(32KiB x60fps)くらいのメモリ帯域は無駄にしても良いかなということで。。
WioTerminalはCPU内蔵フラッシュを持つため、OSの実行ファイルぶんのメモリをアサインする必要はない。ESP32やRaspberryPi PicoではXIP用のキャッシュリージョンを捻出する必要があるが、これらのチップではWioTerminalよりも多くのメモリがCPUに内蔵されているので特に問題は起こらない。
パラメタの分割と圧縮
32KiBの描画データを:
- オブジェクト定義
- テクスチャ定義 (含パレット)
- ビットマップ
の3パートに分割する。ビットマップは非構造データなのでどうでも良いとして、テクスチャ定義とオブジェクト定義は熱心に設計する必要がある。
オブジェクト定義
オブジェクトは、
- 点および直線(単色)
- 自由変形・回転の矩形(単色・テクスチャ)
- 自由変形の直角3角形(単色・テクスチャ)、上半分と下半分の2種
の3種のプリミティブをサポートし(点は直線の特殊例)、
- 置換
- 半透明合成 (50%のみ)
- 加算(飽和)
- 減算(飽和)
の合成モードをサポートする。
3角形の描画をサポートするが、テクスチャとして自由にUV座標を与えられるようにするべきかは悩み中。
矩形や3角形のパラメタは以下のようになる:
サイズ(bits) | 内容 |
---|---|
8 | プリミティブタイプ |
8 | アトリビュート |
16 | 原点X座標(bx) |
16 | 表示巾(bw) |
16 | 始端Y座標(sy) |
16 | 終端Y座標(ey) |
16 | 回転角度(r) |
16 | テクスチャ定義アドレス |
8 | テクスチャオフセット |
8 | 3角形のshear変形深度(後述) |
レンダリングは横方向の短冊状に行われる。が、分割済のディスプレイリストを事前構築して保持するだけのメモリは確保できないため、プリミティブリストは常に全走査されることになる。このため大半のプリミティブは描画時にリジェクトされることになり、そのリジェクトをいかに高速に行うかが問題になる。
... というわけで、始端と終端のY座標を事前計算して与え、そこから必要最低限の追加で必要なパラメタを復元する圧縮を行う。計算コストを無視した場合、自由移動・変形・回転する矩形は (x,y)-(w,h),r
の5パラメタで表現できるのは明か※なので、これが始端および終端のy座標を含むように式を変形する。
(FIXME: 図)
※: 対角としてある2点を含む矩形の数は、同様な直角三角形の数に等しく、その三角形の残りの点 c の場所は最小の内角 r が決まれば一意に決定できる(小学生向けの説明 -- 数学だともっとシンプルに書かされそう)
※: もうちょっとシンプルな説明があった。巾 w 高さ h の矩形の重心を (x,y) に配置して r 回転させた矩形は一意に定まる。
このような矩形を取り囲む鉛直な矩形の巾や高さは三角関数の定義から簡単に求められる。
一般的な3角形は (x1,y1)-(x2,y2)-(x3,y3)
の6パラメタ必要になるが、これを精度を犠牲にして5パラメタ + 256段階変形にする。任意の3角形は直角三角形の(アフィン変換で言うところの)shear変形で表現でき、この変形度合の精度を落しても目立たないのではないか...という気がする。