描画の高速化

今まで6502コアの最適化ばっかりやってましたが、携帯JavaではPPUのエミュレーションが処理時間の内でかなりの割合を占めているようです。

ファミコンのVRAMとかのビデオ周りの仕組みはかなりややこしいことになってます。
たぶん、2キロバイトという極めて少ないVRAMでたくさんのキャラクタを画面に出すための工夫なんだと思います。

VRAMはキャラクタのピクセルパターン、つまりキャラクタの形の情報を持っていません。VRAMにはキャラクタ番号とパレットセット番号だけを持っています。
キャラクタのピクセルパターンは基本的にはロムに入っているので、予め用意された形を色を設定して画面に表示することしかファミコンでは出来ないわけです。

PPUのエミュレーションでは、1つのピクセルを描画するために、VRAMのデータを元にCHR-ROM、アトリビュートテーブル、パレットテーブルを参照して、ビット演算をゴニョゴニョやってようやく1つのピクセルが描画できるのです。
テーブル参照が何度もあるので、ソフトウェア的に処理するにはけっこーしんどい感じなんですよ。
それから、1ピクセル単位の描画はたぶん携帯Javaではどうやったって速くならないのではないかと思います。

そこで、携帯の画面へ単純にBitBltするだけで描画可能なピクセルフォーマットにCHR-ROMのデータを予め変換しておくことが高速化の方法として考えられます。
キャラクタパタンはロムに入っているので、プログラムから形を描きかえたりはできないので、こんなことも可能なはずです。

最初にエミュレータでゲームを動かして、「画面に描画した回数の多かったキャラクタパタンのランキング」を統計情報として取得します。
そして、上位256個のキャラクタパタンとかは、高速に描画できるようにピクセルフォーマット変換したデータを保持しておくようにします。
よく使うものはこっちから転送して描画するわけです。これをキャラクタキャッシュという名前で呼ぶことにします。
キャラクタキャッシュにエントリが存在するか否かは、ハッシュテーブルを1つ用意しておいて、それを参照することで調べるようにします。

こういう高速化をやってるエミュレータももしかしたらあるのかも知れませんが、とりあえず聞いたことはないです。

キャッシュの領域でメモリを食いますが、携帯Javaのヒープは数メガバイトあるみたいなので、何とかなるでしょう。

本当は、キャッシュに持つキャラクタを動的に実行時に更新していく仕組みにできたら効率が良さそうなんですけどね。プログラムが複雑にならなそうなら試してみたいです。

こういう仕組みにしてしまう以上、ラスタをいじる画面エフェクトの再現は諦めるしかないと思います。

また、カセット内にキャラクタパタン用RAMを増設しているゲームは動作不能になります。メジャーなところでは、ファイナルファンタジー3がそうらしいです。