DaveTCode / nes-emulator-rust

A NES emulator written in rust
MIT License
5 stars 1 forks source link

Gradius shows some strange sprites #62

Closed DaveTCode closed 3 years ago

DaveTCode commented 3 years ago

image

Gradius (and other games with sprite zero hit controlling the bottom of the screen) appear to show some sprites strangely as in the above screenshot.

Games with status bars at the bottom will typically rely on a sprite zero hit tight loop which will then update various bits of the PPU rendering pipeline in a subroutine. So two things are possible here:

  1. I'm picking up on sprite zero at the wrong point
  2. I'm not handling mid frame ppu updates properly

The second is very likely and the first is quite easy to test. So I'll start with #1 and move onto two when I've proved that sprite zero handling is correct (or fixed it)

DaveTCode commented 3 years ago

Worth noting that I do correctly not scroll the status bar at the bottom so I'm handling the PPUSCROLL updates to some degree at least!

DaveTCode commented 3 years ago
2020-11-15T20:06:35.725472600+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 42954783 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.752461700+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43044124 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.771716700+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43133466 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.784770700+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43222807 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.802791200+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43312149 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.815565800+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43401490 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.837730300+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43490832 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.858820800+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43580173 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.873080600+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43669515 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.889878400+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43758856 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E
2020-11-15T20:06:35.904920100+00:00 ERROR rust_nes::ppu - Sprite zero hit on cycle 43848198 scanline 207 dot 249 bg_pixel 03 sprite_pixel 1E

I'm spotting sprite zero at exactly the right point each frame so that's ruled out as an issue. I'll remove sprite zero hits for now and see if that fixes sprites (whilst breaking the status bar)

DaveTCode commented 3 years ago

No sprite zero hangs the game. Great, that's no use for testing then!

DaveTCode commented 3 years ago

image

is what happens on the sprite zero hit check. So

  1. Subroutine at 8BC3 which doesn't touch PPU
  2. Load A with PPUSTATUS (48 here)
  3. Store 0 in PPUSCROLL (v was 7766, t was 4027, x scroll was 1), afterwards, t was 0, fine x was 0 and vram addr was 0380??
  4. Store PPUCONTROL (but in this case didn't change any flags)

So the most interesting question is what PPUSCROLL updates do to the sprite fetch routine. We're on dot 290 after this which is firmly during sprite fetch. Sprite fetch doesn't touch v/t as far as I can tell, it does read from the nametable but why would it matter what we'd set on PPUSCROLL?

DaveTCode commented 3 years ago

Throughout the whole of this process the sprite table doesn't seem to get changed in other emulators. The only time the set of sprites in OAMRAM is updated is in vblank and the updated sprites are not what's being badly rendered.

On retrospect maybe the sprite zero bit is irrelevant? The sprites for line X get loaded on line X-1, all of which are way before scanline 207.

DaveTCode commented 3 years ago

Managed to get screenshots on pretty much exactly the same frame: image

image

So we have 3 sprites, they should be tile numbers: 19, 1B; 1B, 19; 17, 15 Sprite indexes: 2B, 1C, 09, 3A, 27, 18 where the second and third sprites are horizontal and vertically flipped but the first is neither. So nothing to do with sprite indexes, 1 & 2 are the same and 2 looks fine but 1 doesn't. Nothing to do with flipping (2 looks fine but 3 doesn't).

Doesn't seem to be anything to do with the sprite index either, (where they're checked in order so timing could be off?

DaveTCode commented 3 years ago

Secondary OAM RAM as dumped on dot 0 of scanline 43 shows:

[2A, 17, 22, D4, 2A, 15, 22, CC, 2A, 15, E2, EA, 2A, 1B, 22, BE, 2A, 17, E2, E2, 2A, 19, 22, B6, F4, FF, FF, FF, FF, FF, FF, FF]

for me and

[2A, 17, 22, D4, 2A, 15, 22, CC, 2A, 15, E2, EA, 2A, 1B, 22, BE, 2A, 17, E2, E2, 2A, 19, 22, B6, F4, FF, FF, FF, FF, FF, FF, FF]

which is identical. So it's very much NOT secondary OAM loading that's wrong. I.e. Sprite selection is correct, which leaves sprite fetch. Maybe this is actually about mapper nametable selection???

DaveTCode commented 3 years ago

Mapper is cnrom and only switch happens during the sprite zero catch, banking switched from 0 -> 1 for the bottom few lines. No change to mirroring on the bank and no change to mapper banks during operation

DaveTCode commented 3 years ago

Force setting vertical flip to false results in sprites looking correct so that's the issue. Most likely how I work out what address to use when the sprite is vertically flipped. Joy.