Okay, I got it figured out. Great catch, FitzRoy.
I wrote:regardless of who gets it right or wrong, we should both work together to figure out why and get it working correctly in (all) emulators.
As promised:
The basic gist is that neither work RAM nor video RAM should be cleared upon a soft reset.
If you clear work RAM, it appears to work because the game thinks a hard power cycle occurred.
If you do not clear work RAM, but clear video RAM, the game knows a soft power cycle occurred, and doesn't bother to reload BG3's tiledata. This causes the graphics corruption seen in emulators.
bsnes:
I actually didn't clear VRAM on soft reset, but there was another problem:
There was a bug in my tiledata caching system. I cache the 2/4/8bpp to linear data conversion to speed up rendering ... whenever VRAM is written to, that tile is marked as invalid. Whenever the renderer tries to draw a tile, it checks the flag. When invalid, it will reload the contents from actual VRAM and mark the tile as valid again.
All well and good, but I got the clear value wrong (that, or I was still resetting VRAM to 0 on soft reset, so I was using it as a speedup.) 0 is considered valid, and 1 is considered invalid. In my reset routine, I was calling clear_tiledata_cache(), which set all the states to zero, and also flushed the caches themselves to 0x00.
So I was basically saying, "all of the caches match real VRAM, and all of real VRAM is 0x00." You don't see this bug in other games, because they re-write the VRAM data, and it gets marked as invalid again.
The solution is that I really don't need to clear the tiledata cache at all on a reset ... the data is still valid. So I moved that to only occur during a power cycle, and I also fixed the flag clear inside the routine as well. I'll also relabel the state block names to have _invalid at the end, so the value of 0 or 1 is more obvious.
Snes9X:
Snes9X is clearing only VRAM on soft reset:
cpu.cpp:S9xSoftReset():
Comment out or remove this line:
Code: Select all
memset (Memory.VRAM, 0x00, 0x10000);
Move to S9xHardReset() or whatever if it's not there already.
ZSNES:
https://zsnes.bountysource.com/svn/!sou ... rc/initc.c
GUIDoReset calls init65816. init65816 calls clearvidsound. clearvidsound:1495 contains:
Erase that, and put it inside void powercycle() instead.
The reason the tiledata still shows up even after a reset from the GUI, is because ZSNES' tiledata cache is not being flushed, even though the VRAM is.
It's essentially the mirror opposite of the problem bsnes had.
If you want proof: run Super Buster Bros V1.0 to the title screen. Take a savestate. Open it in bview (available @
http://byuu.cinnamonpirate.com/programming/), View->Goto address->20c13->Go. View->Mode->4bpp. You'll see lots of font data there. Or use whatever sprite viewer you want -- 0x20c13 is the start of VRAM data.
Now reset the game in ZSNES, go to the title screen again, take another savestate. Load that savestate in bview, do the same as above. You'll see that all of the font data is missing from VRAM, yet it still shows up on the screen. Either reload the state you just took immediately (which will flush the tiledata cache), or load the same ZST in vSNES, and you'll see the data is not there.
I wasn't able to track down how to clear the tiledata cache, though. I'm not familiar enough with ZSNES, so I'll leave that to Nach or Jonas. Just add that flush call inside clearvidmem and everything should be fine.
Also, I'm sorry if I seem like a pest in pointing this out ... I'm not trying to make a big deal out of the bug, I'm only pointing it out so that it can be fixed. The screw-up in bsnes was much worse, so I have no room to brag anyway.
Super Sleuth and SNESGT:
I can't cite exact source lines to change, but the above should be enough info to fix it.