M5Stackでプログラム その2

f:id:PocketGriffon:20210906232122j:plain

M5Stack Core2で動くPC-8801アルフォス、高速化してみたよ!

前回ほどのインパクトは無いけれども、自己満足の一環として見てほしいw

今回は写真少なめ、文章多めですw

 

高速化するべきところを見極める

先日の動画を見ていただいた方はおわかりかと思うけれど、ゲームデモが始まったあとのマップのスクロールが、だいーぶガタついていた。もう少しスムーズに動かんのか…と思っていたところから高速化の気持ちが高まってきた。

 

敵の動きやスクロールを見る限り、CPUの処理が遅くなっているというよりは、表示がコマ落ちしているように見える。つまりCPUエミュレーション側のCPU(ややこしい)は処理が間に合っているんだと思う。

 

他にもM5Stackでやってみたい事がいくつかあるので、表示系を気の済むまで高速化しておく事は大切だ!

 

激重状態の表示系

表示側を担当しているCPUでは、主に2つの処理が走っている。

 PC-8801のVRAMデータをM5Stackで表示できる形式へ変換

 出来上がったフレームバッファを表示

 

まずはそれぞれ1画面のデータを作るのに掛かる時間を測ってみる事にした。

f:id:PocketGriffon:20210906234607j:plain

細かい数字をみても仕方がないけど(大雑把に)変換に掛かる時間が約180ms、表示で38msほど掛かっていた!

え……合計して約220ms、…つーことは1秒間で5回も表示出来てないのか。

そりゃカクカクするわけだ(T-T)

まずは時間が掛かっている、画像データへの変換について考えてみた。

 

画像データへの変換方法

PC-8801のVRAMデータは、横8ドットが1バイトという感じで並んでいる。この情報が3プレーン分(つまり3ビット)あり、それぞれのビットが立ってる寝てるという状態で0〜7の色が決まる。

 

対してM5Stackが要求するグラフィックデータは、1ドットが2バイト、RGBが5ビット6ビット5ビットという構成になっている。

 

さらにPC-8801の横640ドットというサイズから、M5Stackの320ドットというサイズへ変換する必要もある。隣同士の色についても合成をしなければならない。

 

しかもPC-8801にはカラーパレットという機能もあり、本来の色と切り替える事が出来る。色変換にはこれも考慮しなければならない。

……結構複雑だ!(T-T)

 

この複雑な変換は、前回の公開前に片付けている。横8ドットのデータを、2ドット単位に切り分けて、テーブル引き一発で変換する仕組みを作った。640x200ドット分の変換、つまり64000回の変換が必要だが、その変換の手間は最小限に抑えられている。

ココをこれ以上の簡略化出来るとは思えない。

 

となると変換の物量(32000回)を減らすしか無い!

PC-8801側でVRAMへデータを書き込んだ際に「このラインのデータを変更した」という情報を残すようにした。こんな事をしてCPUエミュレーションが負荷掛からないの?と思われるかも知れないが、いや重たいです(^^;;

 

さすがにアドレスからラインを求める計算[(アドレス - C000h) / 80]をするので、ESP32の除算って速いのかな???と思って調べちゃったよw

f:id:PocketGriffon:20210907001751j:plain

そしたら、整数の除算は意外に速いという事が分かった。これならば処理を追加しても、そこまで深刻にはならないだろう…と判断(^-^)

 

この処理を入れてみたところ、変換に掛かる時間はほぼ0〜180msという、ものすごい変化のある処理となった(^^; ゲーム中は何かしら動いてるところがあるので、変換の時間がゼロになる事はないけれども、180msが常に掛かるという状態からも脱する事が出来た。

 

表示は速くなる??

表示に関してはまだまだざっくりとした知識しかなく、drawBitmapよりもpushImageの方が速いらしい?くらいの情報しか持ち合わせていなかった。

ご存知と思うけれど、M5Stackを使い始めたばかりの超初心者なのでゴメンね(T-T)

 

上記の「変更のあったデータのみ変換」をした後、そこの1ラインだけをpushImageしてみるコードを書いてみたが、全体で200ラインをpushImageした途端、信じられないほど遅い表示が出来上がった…。pushImageの内部構造は分かってないけれど、どうやら1回1回のリクエストがとても重たいようだ。ちなみにswapBytesはしていない。

 

この時いろんなソースを漁っている最中に、DMAという単語が目に入ってきて「あ、表示にDMA使えるんだったら良いな」くらいのイメージでしか無かった。

 

さらに調べていくと……どうやら、らびやん氏が開発した高速GFXライブラリが存在すると知った!なんと!そんな便利なものがあるのならばぜひ使ってみたい!(^-^)

名前はLovyanGFXというらしい。この世界では有名なライブラリのようだ!

 

さっそく入れて見ようと思ったが……いやはや、それまでのコードがM5.Lcdに頼りまくった作りにしていたおかげで、まずはそれを引っ剥がすところからの作業となった(^^; 最初の頃のコードは、ほぼ何も理解せずに書き散らかしていたからなぁ…汗

 

更新されたラインのみ描画するため、Spriteのサイズを横320ドット縦1ドットとして、1ラインのスプライトを並べてみる事にした。実際に200個のスプライトを用意するわけではなく、8つのスプライトを使いまわしつつ、画像データを送りまくるようにしたところ、表示が劇的に速くなった!!

 

処理の構造上、画像データを作るのと描画処理が一緒になってしまったのだが、合計で平均100msの時間で1画面が作れるようになった!最初の2.2倍だ!

スプライトのサイズが小さいおかげでバッファが内部メモリから確保されたと思うんだけど、そうしたらグラフィックデータの変換も速くなった!そうか、PSRAMって外部にあるから遅いんだな…。

 

あ…そうか、このブログを書きながら思ったが、メインメモリ64KBとかVRAM48KBを内部メモリから確保出来たら、さらに速くなるかもね…。あとで実験しておこう(^-^)

 

 

M5Stack、工夫次第でいろんなアプローチの仕方があってとても楽しいです!

少しプログラムをかじった事がある人ならば、自分なりの楽しみ方で遊べるサイコーのガジェットじゃなかろうか(^-^) 

 

ちなみにこのアルフォス(CPUとGFXで2コアぶん回し状態)をずっと立ち上げておいても、M5Stackはちっとも熱くなりません。これはこれですごい話!(^^)

 

よし、アルフォスは一旦切りつけて、次行くよー(^-^)

ではまた次回!(^^)ノ