拙近作におけるVRAMアクセスのタイムシェアリングについて

2018/6/27 | 投稿者: ghost

本稿は、MSXでアセンブラまたはそれに準じる開発言語でリアルタイムアクションゲームを作る人以外には意味不明かつ無用な内容である。ただただ自身の後日の備忘のために書いている。

クリックすると元のサイズで表示します

上掲は、開発中のゲームの、主にタイマー割り込み視点で描いたロジックダイアグラムになる。暖色系(黄・橙)がタイマー割り込み、寒色(青・灰)が通常の処理の流れになる。

MSXにおいて画面に何かを表示する、というのは、VDP・TMS9918に一連のデータを渡すこと、に他ならない。その速度は、大雑把にいってRAMへの書き込みより倍遅い上、好き勝手なアドレスに気ままにアクセスできるRAMとは異なり、VRAM上で連続するデータは、排他的に一気に渡してやらないと著しく効率が悪い。

対してボクが好むシューティングゲームを含むリアルタイムアクションゲームにおいては、絶対要件でこそないが、原則としては画面表示の処理の多寡に関わらず、ゲーム実行速度は一定であることが求められる。MSXの世界では、基本的には安定したクロック源は垂直同期(VSYNC)毎に発生するタイマー割り込みしかないので、このタイマー割り込み処理、および併走する地の処理の一連の流れの中に、どのようにVDPに対するデータ渡しを配分するか、がゲーム開発全体の中で大きなウェイトを占めてくる。

で、上掲図が出て来ることになる。

サラッと読み解いておくと、横に走る点線がNTSCベースのMSXにおいて1/60秒毎にトリガされるタイマー割り込みを意味している。赤い太い横線は、これを4つ数えて4/60秒を本作における1フレームとしていることを意味する。つまり、15fps.ということ。タイマー割り込みが何もしないとする(しないとフレームもまた数えられないのでそういうことはあり得ないのだが)と、右側の青で示した主処理が赤線から開始され、次の赤線の大分と前で終了し、続く灰色で示された次フレーム待ちへと進む。

次フレーム待ちは、タイマー割り込み内で1/60秒を4回数え上げるとセットされるフラグを監視しているだけのループで、フラグが立つとこれを解除すると同時に青い主処理の先頭にジャンプする。これにより、主処理が秒間15回だけ実行される=見た目のゲームの速度が(ここまでの全処理は4/60秒いないに収まってさえいれば)一定になることが保証される。


逆に、暖色で示されたタイマー割り込み部は、1/60毎に実行すべきスプライトローテーションおよびBGM演奏を除けば、本作が1フレーム中に必要とするVRAMへのデータ転送を、前述処理も含めて1/60秒に余裕を持って終了する単位に分割したもの、ということになる。たとえば最も負荷が大きい=データ量が多い背景スクロールについては、ビットシフトによって背景データを作る処理と、それをVRAMに流し込む処理の二つに分割してある。

本作に特化した事情にも少し触れておこう。

クリックすると元のサイズで表示します

これは冒頭の図とほとんど同じだが、黄色で示した処理の実行間隔が変わっている。これは、ゲーム中の背景の星空と眼下の町並みのスクロールに対応している。本作ではプレイヤーキャラクタが夢を取得するたびにスピードメーターが上がっていくが、このスピードメーターが黄色で示した処理の実行間隔そのものであり、スクロール処理の実行間隔が狭まっていくので見た目のスクロール速度は上がっていく。至極単純な仕掛けである。

ちなみに、上掲図は最高速(7段階目)の状態を示している。パッと見、もう1つくらい実行間隔が詰めれそう=スクロール速度を上げれそうな感じがするが、本作は拙近作の定石に倣ってPALベースのMSXにも自動対応するように書かれており、これはその結果である。

クリックすると元のサイズで表示します

PAL、すなわちVSYNCが1/50秒のMSXで本作を実行すると、1フレームが3VSYNC=3/50秒=16.6fps.に調整される。この状態であっても、1フレームに少なくとも1回はスクリーンバッファVRAM転送処理を実行したいのでこういうチューニングになっている。件のPCGで描画されるボスの表示がこの処理に依存しており、これが1フレーム毎に実行されないと、ボスの移動やアニメーション(まぁコマ落ちが問題になるほどのソレはないのだが)が飛び飛びになってしまうからだ。

さて。

本作の動作する最初のデモを示した際「見た目にはわからないが、本作では従来の拙作と主処理、画像出力のタイマー割り込みに対する位置付けを、とある事情から逆転させている」と書いた。

クリックすると元のサイズで表示します

上掲は、ドラコニックスロウン佛陀斬に共通する当該ロジックを図示したものである。意図していること=負荷の多寡に関わらずゲーム速度を一定化したい、は同じだが、これらではVRMへのアクセスが地の処理系に、ゲーム本体の処理がタイマー割り込みに割り振られている。

この二つの方式(以外にもやり方はあり得るし、実際ゼビモドキはまた異なる方法を採っているのだが)は、それぞれに一長一短があってどちらが正しいというものではない……教科書的な知識としては、一般にMSX規格ではタイマー割り込み中のVRAMアクセスは禁止でこそないが推奨はされていない……し、使い分けに明確な論理があるワケでもない……と思う。特に佛陀斬は前作からの惰性で実装を決めたのだが、それはさておき。

この二つの方式……仮に“割り込み内/外VRAMアクセス”とでも呼ぶことにするか……の使い分けの観点の1つは、定型化されない=一定タイミングで繰り返す以外のVRAMアクセスを想定するか?になる。

割り込み内方式の場合、割り込みの外部でのVRAMアクセスは原則としては禁忌になる。連続しているべきデータのVDPへの渡し中に割り込みが発生し、別のVRAMアクセスが発生すると都合が悪いからだ。回避方法がないわけではないが、開発中の見通しの良さから言えば、全体の流れの任意の時点でのVRAMアクセスが想定されている場合は、割り込み外VRAMアクセスの方がよい。ドラコニックスロウンは、開発着手時点から捨て台詞等の文字演出が念頭にあったのでこの方式を採った(実はあまりその意味は結果的になかったのだが)。

逆に、主処理にせよVRAMアクセスにせよ、タイマー割り込み内に置かれる処理は、少なくともVSYNC期間より短く、可能であればそれなりに余裕を持って終了する処理である必要がある。

本作では、主処理中のある処理……まさに今手がけているところの本作の肝となる部分……が、どのくらいの処理時間を要するか見通しが立たなかったので、最悪これが1フレーム時間以内にさえ終わればゲームとしては進行できる、というところを担保したかった。そういう具合でタイマー割り込み内VRAMアクセス方式を採ることにした。

と、理屈の上ではそうなのだが。

実はドラコニックスロウンの開発で一番困ったのは、ドラゴンブレスの当たり判定(ブレス8キャラ×敵総数)がVSYNCに収まらなかった(ゆえに処理を再分割したり間引きしたりした)ことであり、開発中の新作については(今はすでに改善済みだが)ささいな考慮漏れからVRAMアクセスがNTSCベースの場合のみVSYNC中に終わらなくなって焦るという一幕があった。

何が言いたいかというと、開発中のリスクを下げるために選んだはずの実装方式が返って開発中のトラブルの原因になっている、ということであって、本稿を書いているのは、次こそは逆を引かないぞ、という決意表明を兼ねてのことなのである、多分無駄だけど。っつーか、まだやるのか。
タグ: MSX Z80



コメントを書く

名前
メールアドレス
コメント本文(1000文字まで)
URL





AutoPage最新お知らせ