During the transition scenes during the Legend of Zelda - Oracle of Ages intro, graphical corruption (well, technically it's tiledata from the new scene while the tilemap hasn't been updated yet) is briefly flashed on screen with my GBC emulator. Here's an example:

Other emulators also show two screens of corruption, whereas in higan it's about 30 screens or so (eg half a second.)

Other emulators tend to show an all orange screen between this transition for the bulk of it.

Has any Game Boy Color emudevs come across this issue before? Anyone have any ideas on what might be the issue? Seems like it could be any number of things, and I'm not sure how to go about debugging this >_>

Last edited by byuu on Tue Aug 01, 2017 3:33 am, edited 1 time in total.

This looks like it's DMA related. I think the overwhelming majority of GBC specific graphical issues are related to the new HDMA or GDMA in some way (not doing them at the right time or not doing them correctly, mostly the former imo). My guess here is that maybe you trigger only one GDMA where you need multiple. I haven't touched Oracle of Ages in a while, so I'm just throwing something out there.

Having said that, you really should double-check LCD enabling/disabling, at least for the fact that most GBC emulators get the glitched screen wrong. When I say that, I mean, you shouldn't even really be seeing it in something like BGB or Gambatte or whatever you're using as a reference. Generally, when VRAM corruption could potentially appear on-screen, the game shuts off the LCD briefly and displays a white screen. When you enable the LCD again, it "skips" the next frame and continues drawing the white screen instead. The 2nd frame after re-enabling the LCD is the expected frame, however. A lot of emulators ignore this behavior because it's so hard to actually see that single frame acting up. So ultimately, your goal with higan should be zero corruption displayed (unless it's verified like that on hardware, in which case the game was improperly programmed to begin with).

As far as debugging goes, I'd log all DMAs per frame and log whenever any LCDC write happens (to check for LCD enable/disable, but also any errant tile-map switching).

The game is turning LCDC off at LY=148 ($00), then turning it back on again 44 scanlines later ($e7).

To nitpick/correct you, whichever is correct, it does not happens 44 scanlines later per se. When LCDC is off, no rendering is happening and LY is not incremented and (afair) locked to a value of 00. If I'm understanding for example the SNES PPU correctly, you cannot turn off the PPU like this on SNES. You can blank it, but it will still output a video signal, as not to lose sync with the TV or display. Gameboy has no such considerations and the PPU can be turned off at any time (with the optional Nintendo guideline restriction to only turn it off during VBlank to avoid physical damage to the LCD) and can likewise be turned on at any time, which restarts drawing the frame from the top. Including being out of sync with the host system, on an emulator that aims for perfect frame sync, which I assume is the case with Higan-GB.

Will be interesting to see your approach to this issue. You might simply resync the frame output to the host frame rate, but then you will need to drop or insert 1 frame sometimes when the LCD is turned on to ensure that the long term timing doesn't drift, if you care about that. (This is the sort of thing speedrunners care about, so that emulator play times are comparable to hardware play times.)

You may need to duplicate a frame anyway because 59.73 Hz (GB, GBC, GBA frame rate) is less than 59.94, 60, 60.10, etc.

The usual strategy of Higan is to lock the emulated console's frame rate to the host frame rate, and repitch the sound to fit. I don't know if it can be made to emulate the timing realistically. But even so, there might be value in keeping the emulated speed at least internally consistent long term.

Good luck doing anything like that if you're emulating a Game Boy and a Super Game Boy 2 linked together. Both Game Boy systems are running at a nominal 59.73 Hz, thanks in part to the second oscillator in the SGB2, but the SGB2 has to upconvert that to 60.10 Hz for display.

I'd also like to add that the Nintendo guideline about turning the PPU off in vblank applies to DMG/MGB only, so CGB-only games like Oracle of Ages are free to do whatever they please.Real SGB/SGB2 devices seem to use a form of double-buffering or something like that, because adjusting the SGB/SGB2 CPU speed doesn't seem to cause tearing or other unwanted side-effects. So basically it buffers and draws full frames only on the SNES/SFC side.

It's quite within the realm of possibility now for higan to simply leave the display blanked for a while and throw off the timing.

The much harder question is ... what do we do once the display is off? I presume the screen shown on the Game Boy will slowly fade away if you leave the LCD off. It would be quite an abuse bottleneck potential to flush out a solid white screen the instant the dispay is disabled.

Imagine a bastard writing a loop that just does "LCDC.d7=0, LCDC.d7=1" ... they'd skyrocket the framerate into the thousands, which neither higan nor any monitor couldt keep up with :P (could keep an is_dirty flag after first pixel render from a white screen flush, but this is a cat and mouse game I'd rather not have.)

But you know, emulators can't protect against EVERY stupid thing a user might try, so maybe I'll just do that and say, "don't abuse my emulator, please."

One thing I'm going to have to do as well is extend libco to be able to restart threads without reallocating the thread memory. Something like co_recreate(entrypoint, cothread_t). We'll see.

Imagine a bastard writing a loop that just does "LCDC.d7=0, LCDC.d7=1" ... they'd skyrocket the framerate into the thousands, which neither higan nor any monitor couldt keep up with (could keep an is_dirty flag after first pixel render from a white screen flush, but this is a cat and mouse game I'd rather not have.)

I can confirm that this is a thing. Made about half of the emulators I tested it on hang. I stumbled upon that by accident, though, when researching whether you could draw only half the screen (on hardware) for an effective 120 FPS output but using only the top half of the LCD. Wasn't too successful though...

Okay, I've changed higan's implementation to set LY=0 on LCDC.d7 1->0 (disable) transitions, instead of on 0->1 transitions. And now the PPU stays frozen until the display is enabled again.

This does indeed make Oracle of Ages run very well with far less corruption. Thank you very much, everyone! :D

So now I'm left with two questions to finish the implementation:

1. how soon does the image on the LCD fade to blank (white)? 16ms or so?

2. when you enable the LCD again via LCDC.d7 0->1, how long does it take before the LCD starts rendering again? Can it start plotting pixels at the top left of the display again immediately? Does it take 16ms or so?

If anyone knows the answer, please state your degree of confidence in your timing numbers, so I can comment appropriately in the code, thanks :3

2. when you enable the LCD again via LCDC.d7 0->1, how long does it take before the LCD starts rendering again? Can it start plotting pixels at the top left of the display again immediately? Does it take 16ms or so?

Can't verify the 1st question, but the second question has been settled for a while, based on AntonioND's timing docs. It takes a full frame after you turn on the LCD to display anything besides the white screen. So approximately 16ms from whenever you turn it back on. A good test would be to draw something during that first blank screen ("Your emulator sucks"), then during VBlank change it (maybe draw nothing, or at least an animated icon to let people know it's not frozen) for the next frame that appears. Wait until the next VBlank and disable/re-enable the LCD, and repeat. You'd get that psuedo-transparency effect with everything drawn, but emulators that fail the test would display that message.

So to be clear, the entire time the LCD is warminig up again, LY is read back as zero, yes?

Not sure. Maybe someone else knows. If you turn it on, I'm assuming that it functionally "works" in the sense that interrupts and DMAs and anything related to the LCD starts up again, just that the LCD won't pull data from VRAM. I'm also assuming you still get the same VRAM write-protections during scanlines that you'd normally have, but it would be interesting to see if you still had unlimited VRAM access during that blank frame. Both cases are easy enough to test with some modifications to my proposed test ROM.

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