nba-emu / NanoBoyAdvance

A cycle-accurate Nintendo Game Boy Advance emulator.
GNU General Public License v3.0
955 stars 53 forks source link

Too much sprite pixels per scanline #338

Open GValiente opened 7 months ago

GValiente commented 7 months ago

In the test ROM of this mGBA issue, if you press A button, NanoBoyAdvance 1.7.1 renders more sprite pixels than hardware.

In this case, VisualBoyAdvance seems to do the right thing:

nba_vs_vba

fleroviux commented 7 months ago

It seems like there are some subtleties around the final cycle that can fetch sprite VRAM and the final cycle that can fetch sprite OAM. I have a tentative fix, but I think I will need to write some hardware test to figure out the right behavior for all cases.

alyosha-tas commented 4 months ago

I made a test for this case here: https://github.com/alyosha-tas/gba-tests/blob/master/ppu/Sprite_Last_VRAM_Access.gba

The result should be:

vram_test

The right edges of the black rectangles should align. The ones on top of the text run out of sprite rendering time as in the original test. The timing part of this test shows that the last vram access still happens as expected.

I think the interpretation here is that vram reading for sprites happens on the even cycles, while adding data to the internal sprite buffer happens on odd cycles. Sprite rendering shuts down on the odd cycles so the vram access still happens but the data isn't added to the buffer because the shut down happens.

It turns out the same thing happens when hblank free bit it set, which is demonstrated here: https://github.com/alyosha-tas/gba-tests/blob/master/ppu/Sprite_Last_VRAM_Access_Free.gba

fleroviux commented 4 months ago

@alyosha-tas Thanks for the additional test. I came to the same conclusion that the extra pixel had to be fetched but not output last time I looked at this, so your explanation mostly makes sense to me. But I would make an educated guess that pixel output/buffering can happen both on odd and even cycles for regular (non-affine) sprites. Probably the VRAM read is latched into a register and then processed over the next two cycle. To be able to output two pixels in a single cycle would add a lot of hardware overhead I think and it would be unlike anything I've seen on the GBA so far.

alyosha-tas commented 4 months ago

I guess that would need a separate test manually disabling sprite rendering on a VRAM access. I'll see about making additional tests for this case.