captainys / TOWNSEMU

FM Towns Emulator "Tsugaru"
BSD 3-Clause "New" or "Revised" License
238 stars 17 forks source link

Sprites not rendered or flickers on some games #38

Open pinterior opened 2 years ago

pinterior commented 2 years ago

reported on:

@captainys 's analysis: https://github.com/captainys/TOWNSEMU/issues/37#issuecomment-937963455

Galaxy ForceはSpriteがbusyになるタイミングでまだスプライトの移動などが終了していないようです。そのため、スプライトのレンダリングをbusyになるタイミングにすると早すぎて、まだスプライトの位置が設定し終わっていないため、いくつかのスプライトが表示されていなかったようです。これを、readyになるタイミングでレンダリングするように切り替えてやるとすべてのスプライトが表示されるようになりました。

pinterior commented 2 years ago

idea 1:

idea 2:

captainys commented 2 years ago

とりあえず、idea 1.2に直して、Shadow of the BeastsとGalaxy Force 2その他ctestに入ってるものは正常に動作しているように見えるバージョンを昨日の晩にPUSHしたというのを掲示板に書こうとしたんですが、なんか掲示板に書けなくないですか?

スプライト1枚ずつDeviceCallBackを出してやった方が実機に近くなるのだと思いますが、スプライトが途中まで書かれているということを前提にしたプログラムはさすがに無いのではないかと思います。

意外だったけど、よく考えてみるとそうかもと思ったのは、スプライトのハードウェアがスプライトRAMを読んでいる間にもCPUが値を書き込んでしまってもなんとかなるんですね。さすがに同じバイトを同時アクセスすると何か良くないことが起こりそうに思いますが、CPUがスプライトのハードウェアよりも先に進んでいる限りは大丈夫なのかもしれません。ただ、よく考えてみると実機でタイミングを確認したとき、Sprite Readyのタイミングが次のVSYNCの直前だとあっという間に再度Sprite Busyになってしまうので、CPUはSprite Readyになった時点でスプライトの更新を始めても、次のBusyまでには間に合わないのでそれでも大丈夫なように作ってあるんでしょうね。

pinterior commented 2 years ago

スプライトが途中まで書かれているということを前提にしたプログラム

自機の上に弾を書き終わったであろうタイミングで、あとのスコア等が描かれるのと並行して当たり判定をとるようなソフトがあれば問題ですが、そのようなソフトが発見されたら、ということでよいような気もします。

同じバイトを同時アクセス

128KBデュアルポートVRAMの、CPUからはRAM側、スプライトコントローラからはシリアル側をアクセスしていると推測されるので、電気的に衝突して意図しない値を見たり意図しないアドレスに書かれることはないと思います。 (ただ、8ビット接続と推測されるのでCPUからの word, dword store が atomic にならないとは思いますが)

pinterior commented 2 years ago

ae43fdbf31fece4ab88ca236849fd7f44954e29b を拝見しましたが、state.page = 1 - state.page; は VSYNC rising edge で行わないと I/Oポート 44ch が実機動作と相違してしまいます。

BBSは書けないですね。トップページを見るとSPAMまみれという感じなのでdisk fullにでもなっているんでしょうか…

captainys commented 2 years ago

おおなるほど。Sprite BusyのFalling edgeで一気にスプライトを書くとしてRising edgeでページを切り替えるのでも大丈夫かな。というかVSYNC期間外にVRAMオフセット切り替えて断層(?)が出ないように実機はそうなってるのか。なんか大丈夫な気がしてきました。帰ったら実験してみます。

掲示板は、アメリカからの書き込みが遮断されたとかじゃないんですね。そうであればそのうち復旧するかな。

captainys commented 2 years ago

ということで、そのようにしてみました。Shadow of the Beasts, Galaxy Force 2, Afterburner 2をとりあえず試してみて問題ありませんでした。

fuzz6001 commented 2 years ago

Final Blowがスプライトダブラー的なことをしているので動作確認してみようと思ったのですが、ゲーム画面まで進めることが出来ませんでした。これについては別のissue #39 を立てておきました。 もし動かせるようでしたら確認してみて下さい。

fuzz6001 commented 2 years ago

Final Blowですが、現在のコードで表示に問題ありませんでした。

captainys commented 2 years ago

テストありがとうございました!

しかし、掲示板復活しませんね。

pinterior commented 2 years ago

レジスタ0番、1番に指定するのは表示開始インデックスなので、表示個数の確定は SPD0 が 0 から 1 になるタイミング(津軽的には state.spriteBusy を true にするタイミング)で行わないとまずい気がしてきたのですが、どうでしょうか。(また state に変数を増やす必要がありますが...)

captainys commented 2 years ago

いやあ、さすがにSprite Busyになってから書き終わるまでの間に表示個数を変更するようなコードはありますかね?多分、気持ちとしてはSprite Readyになったらスプライトの更新を初めて、できればBusyになる前にすべての更新を終わらせたいという感じではないかと思うので、多分そういう書き方をしているものは無いのではないかと思うのですが。また、仮にスプライトのアトリビュートを全部設定した後でスプライト表示個数を設定しているようなものだと、遅らせたタイミングでスプライト表示個数を確定させた方が実は意図した動きをしてしまったりするかもしれません。案外、実機ではスプライト表示個数が変わった瞬間一瞬のちらつきがあったようなものが津軽だとちらつかなくなったりしているかもしれないですね。