I am having difficulty emulating the sprites that appear on and along side of the road (cars, trees, etc.) in Wacky Races. The scaling road effect works and it is updated using a combination of HBlank and General DMA. However, the sprites are updated using plain old OAM DMA. The sprite tiles appear in the correct places, but not only are they the wrong tiles, they are constantly changing. The issue might be related to intentional OAM reshuffling designed to reduce flicker caused by sprite count scanline limitations.

I also noticed that OAM DMA runs twice per frame: once during VBlank and a second time during a mid-frame HBlank. This technique potentially doubles the number of visible sprites. The sprites above the mid-frame OAM DMA look correct; it's the road-related sprites below that appear to be scrambling almost randomly.

The mid-frame HBlank-triggered OAM DMA does not finish transferring data before the end of HBlank. It actually continues into the OAM Search of the successive scanline. According to the wiki, OAM DMA can run at any scanline phase; however, during OAM DMA, the PPU does not have OAM RAM access, blocking it from any sprite rendering on such scanlines.

Since the road sprite coordinates are correct, it suggests that the OAM DMA transfer is actually working. But, the referenced sprite tiles themselves are actually changing as seen on screen.

Anyway, I'm stuck at the moment trying to understand what is special about Wacky Races. If anyone has any suggestions or hints, please respond. Thanks.

Last edited by zeroone on Mon Dec 04, 2017 10:07 am, edited 1 time in total.

I think the OAM DMA isn't the DMA you should be looking at. Try looking at HDMA. I just fixed this game in my emulator, and here's what I noticed.

The game transfers data to VRAM from line 74 to 144 via HDMA. Normally, the usual method of transferring large amounts of data for multiple scanlines is simply done by specifying how many lines the HDMA should run (Bits 0-6 of the HDMA5 register). Instead of doing that, Wacky Races manually triggers about 70 individual HDMA transfers (70 separate writes to HMDA5), each with a length of 0, meaning it runs for just one line. After an HDMA transfer, I believe the addresses in HDMA1/2 and HDMA3/4 are incremented automatically (but I have not devised a test on real HW yet), so that's how all of these HDMAs work correctly since the source/destinations are updated just fine.

My problem was that I wasn't correctly incrementing HDMA1/2 and HDMA3/4. I was updating the start/destination addresses internally based on length, however, since the length was always 0 for each HDMA transfer, none of my addresses turned out to be right. I fixed it by reading from HDMA1/2 and HDMA3/4 at the start of the DMA, incrementing a 16-bit variable that represented each address, then writing back each address to HDMA1/2 and HDMA3/4.

For what it's worth, this auto-increment behavior was responsible for a host of graphical glitches in Ken Griffey Jr.'s Slugfest in GBE+, but now those are fixed along with Wacky Races.

I think the OAM DMA isn't the DMA you should be looking at. Try looking at HDMA. I just fixed this game in my emulator, and here's what I noticed.

The game transfers data to VRAM from line 74 to 144 via HDMA. Normally, the usual method of transferring large amounts of data for multiple scanlines is simply done by specifying how many lines the HDMA should run (Bits 0-6 of the HDMA5 register). Instead of doing that, Wacky Races manually triggers about 70 individual HDMA transfers (70 separate writes to HMDA5), each with a length of 0, meaning it runs for just one line. After an HDMA transfer, I believe the addresses in HDMA1/2 and HDMA3/4 are incremented automatically (but I have not devised a test on real HW yet), so that's how all of these HDMAs work correctly since the source/destinations are updated just fine.

My problem was that I wasn't correctly incrementing HDMA1/2 and HDMA3/4. I was updating the start/destination addresses internally based on length, however, since the length was always 0 for each HDMA transfer, none of my addresses turned out to be right. I fixed it by reading from HDMA1/2 and HDMA3/4 at the start of the DMA, incrementing a 16-bit variable that represented each address, then writing back each address to HDMA1/2 and HDMA3/4.

For what it's worth, this auto-increment behavior was responsible for a host of graphical glitches in Ken Griffey Jr.'s Slugfest in GBE+, but now those are fixed along with Wacky Races.

Thanks so much. I just tested that idea and you're completely right! It apparently uses the high/low source/destination registers as moving pointers during the transfer. And, they retain the transfer length increment even after DMA is completed, enabling successive DMA to continue where the last one left off. Simply amazing. We really should be updating the wiki with these details.

Who is online

Users browsing this forum: No registered users and 1 guest

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum