From 32a3d9db8075ba29eeb4e5910e258753e0894275 Mon Sep 17 00:00:00 2001 From: goyuken Date: Mon, 5 Nov 2012 04:09:04 +0000 Subject: [PATCH] gbhawk gpu viewer: work correctly with palettes and CGB extended BG data --- .../Consoles/Nintendo/Gameboy/Gambatte.cs | 21 ++- .../Consoles/Nintendo/Gameboy/LibGambatte.cs | 5 +- BizHawk.MultiClient/GBtools/GBGPUView.cs | 151 ++++++++++++++---- BizHawk.MultiClient/MainForm.cs | 1 + .../output/dll/libgambatte.dll | Bin 177664 -> 177664 bytes libgambatte/src/memory.cpp | 8 + libgambatte/src/video.h | 3 + 7 files changed, 150 insertions(+), 39 deletions(-) diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs index 41f6bfac7c..b0e1c719e5 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -149,10 +149,15 @@ namespace BizHawk.Emulation.Consoles.GB if (scanlinecallback != null) { IntPtr vram = IntPtr.Zero; - int vramlength = 0; - if (!LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.vram, ref vram, ref vramlength)) + IntPtr bgpal = IntPtr.Zero; + IntPtr sppal = IntPtr.Zero; + int unused = 0; + if (!LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.vram, ref vram, ref unused) + || !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.bgpal, ref bgpal, ref unused) + || !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.sppal, ref sppal, ref unused)) throw new Exception(); - scanlinecallback(vram, vramlength, LibGambatte.gambatte_cpuread(GambatteState, 0xff40)); + + scanlinecallback(vram, IsCGBMode(), LibGambatte.gambatte_cpuread(GambatteState, 0xff40), bgpal, sppal); } LibGambatte.gambatte_runfor(GambatteState, VideoBuffer, 160, soundbuff, ref nsamp); @@ -587,12 +592,14 @@ namespace BizHawk.Emulation.Consoles.GB #region ppudebug /// - /// a callback to be registered at a particular scanline + /// /// /// - /// length of vram in bytes - /// current LCDC status - public delegate void ScanlineCallback(IntPtr vram, int vramlength, int lcdc); + /// + /// + /// + /// + public delegate void ScanlineCallback(IntPtr vram, bool cgb, int lcdc, IntPtr bgpal, IntPtr sppal); ScanlineCallback scanlinecallback; diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs index 0edce548ee..6fee608d6f 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs @@ -315,7 +315,10 @@ namespace BizHawk.Emulation.Consoles.GB wram = 2, cartram = 3, oam = 4, - hram = 5 + hram = 5, + // these last two aren't returning native memory area data + bgpal = 6, + sppal = 7 } /// diff --git a/BizHawk.MultiClient/GBtools/GBGPUView.cs b/BizHawk.MultiClient/GBtools/GBGPUView.cs index 9d72d3e6f2..b71250a429 100644 --- a/BizHawk.MultiClient/GBtools/GBGPUView.cs +++ b/BizHawk.MultiClient/GBtools/GBGPUView.cs @@ -45,7 +45,7 @@ namespace BizHawk.MultiClient.GBtools gb.SetScanlineCallback(null, 0); } - static unsafe void DrawTile(byte* tile, int* dest, int pitch) + static unsafe void DrawTileDMG(byte* tile, int* dest, int pitch, int *pal) { for (int y = 0; y < 8; y++) { @@ -55,10 +55,8 @@ namespace BizHawk.MultiClient.GBtools dest += 7; for (int x = 0; x < 8; x++) // right to left { - int palcolor = loplane & 1 | hiplane & 2; - // todo: palette transformation - int color = palcolor * 0x555555 | unchecked((int)0xff000000); - *dest-- = color; + int color = loplane & 1 | hiplane & 2; + *dest-- = pal[color]; loplane >>= 1; hiplane >>= 1; } @@ -67,28 +65,65 @@ namespace BizHawk.MultiClient.GBtools } } - static unsafe void DrawBG(Bitmap b, IntPtr _map, IntPtr _tiles, bool wrap) + static unsafe void DrawTileCGB(byte* tile, int* dest, int pitch, int* pal, bool hflip, bool vflip) + { + if (vflip) + dest += pitch * 7; + for (int y = 0; y < 8; y++) + { + int loplane = *tile++; + int hiplane = *tile++; + hiplane <<= 1; // msb + if (!hflip) + dest += 7; + for (int x = 0; x < 8; x++) // right to left + { + int color = loplane & 1 | hiplane & 2; + *dest = pal[color]; + if (!hflip) + dest--; + else + dest++; + loplane >>= 1; + hiplane >>= 1; + } + if (!hflip) + dest++; + else + dest -= 8; + if (!vflip) + dest += pitch; + else + dest -= pitch; + } + } + + static unsafe void DrawBGCGB(Bitmap b, IntPtr _map, IntPtr _tiles, bool wrap, IntPtr _pal) { if (b.Width != 256 || b.Height != 256) throw new Exception("GPUView screwed up."); var lockdata = b.LockBits(new Rectangle(0, 0, 256, 256), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - byte* map = (byte*)_map; - int* dest = (int*)lockdata.Scan0; - int pitch = lockdata.Stride / sizeof(int); // in int*s, not bytes - + int* pal = (int*)_pal; + for (int ty = 0; ty < 32; ty++) - { + { for (int tx = 0; tx < 32; tx++) { int tileindex = map[0]; + int tileext = map[8192]; if (wrap && tileindex >= 128) tileindex -= 256; byte* tile = (byte*)(_tiles + tileindex * 16); - DrawTile(tile, dest, pitch); + if (tileext.Bit(3)) // second bank + tile += 8192; + + int* thispal = pal + 4 * (tileext & 7); + + DrawTileCGB(tile, dest, pitch, thispal, tileext.Bit(5), tileext.Bit(6)); map++; dest += 8; } @@ -98,29 +133,83 @@ namespace BizHawk.MultiClient.GBtools b.UnlockBits(lockdata); } - /// - /// core calls this on scanlines - /// - /// - /// - /// - void ScanlineCallback(IntPtr vram, int vramlength, int lcdc) + static unsafe void DrawBGDMG(Bitmap b, IntPtr _map, IntPtr _tiles, bool wrap, IntPtr _pal) { + if (b.Width != 256 || b.Height != 256) + throw new Exception("GPUView screwed up."); - DrawBG( - bmpViewBG.bmp, - vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800), - vram + (lcdc.Bit(4) ? 0x0000 : 0x1000), - !lcdc.Bit(4)); + var lockdata = b.LockBits(new Rectangle(0, 0, 256, 256), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + byte* map = (byte*)_map; + int* dest = (int*)lockdata.Scan0; + int pitch = lockdata.Stride / sizeof(int); // in int*s, not bytes + int* pal = (int*)_pal; + + for (int ty = 0; ty < 32; ty++) + { + for (int tx = 0; tx < 32; tx++) + { + int tileindex = map[0]; + if (wrap && tileindex >= 128) + tileindex -= 256; + byte* tile = (byte*)(_tiles + tileindex * 16); + DrawTileDMG(tile, dest, pitch, pal); + map++; + dest += 8; + } + dest -= 256; + dest += pitch * 8; + } + b.UnlockBits(lockdata); + } + + void ScanlineCallback(IntPtr vram, bool cgb, int lcdc, IntPtr bgpal, IntPtr sppal) + { + // set alpha on all pixels + unsafe + { + int* p; + p = (int*)bgpal; + for (int i = 0; i < 32; i++) + p[i] |= unchecked((int)0xff000000); + p = (int*)sppal; + for (int i = 0; i < 32; i++) + p[i] |= unchecked((int)0xff000000); + } + + if (!cgb) + { + DrawBGDMG( + bmpViewBG.bmp, + vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800), + vram + (lcdc.Bit(4) ? 0x0000 : 0x1000), + !lcdc.Bit(4), + bgpal); + + DrawBGDMG( + bmpViewWin.bmp, + vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800), + vram + 0x1000, // force win to second tile bank??? + true, + bgpal); + } + else + { + DrawBGCGB( + bmpViewBG.bmp, + vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800), + vram + (lcdc.Bit(4) ? 0x0000 : 0x1000), + !lcdc.Bit(4), + bgpal); + + DrawBGCGB( + bmpViewWin.bmp, + vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800), + vram + 0x1000, // force win to second tile bank??? + true, + bgpal); + } bmpViewBG.Refresh(); - - DrawBG( - bmpViewWin.bmp, - vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800), - vram + 0x1000, // force win to second tile bank??? - true); bmpViewWin.Refresh(); - } private void GBGPUView_FormClosed(object sender, FormClosedEventArgs e) diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index 8c9bb06b91..b17de0f216 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -1742,6 +1742,7 @@ namespace BizHawk.MultiClient NESPPU1.Restart(); NESNameTableViewer1.Restart(); NESDebug1.Restart(); + GBGPUView1.Restart(); PCEBGViewer1.Restart(); TI83KeyPad1.Restart(); TAStudio1.Restart(); diff --git a/BizHawk.MultiClient/output/dll/libgambatte.dll b/BizHawk.MultiClient/output/dll/libgambatte.dll index 94c1c8beae95b4ca26485373e17d8f639549fc1a..3ba2573d6560ab1b679ae52569cb84ddbcbe0497 100644 GIT binary patch delta 15419 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 delta 15364 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 diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index 72e99c495b..2405711180 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -1019,6 +1019,14 @@ bool Memory::getMemoryArea(int which, unsigned char **data, int *length) { *data = &ioamhram[384]; *length = 127; return true; + case 6: // bgpal + *data = (unsigned char *)display.bgPalette(); + *length = 32; + return true; + case 7: // sppal + *data = (unsigned char *)display.spPalette(); + *length = 32; + return true; default: // pass to cartridge return cart.getMemoryArea(which, data, length); } diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h index b7790f9208..e58c910f28 100644 --- a/libgambatte/src/video.h +++ b/libgambatte/src/video.h @@ -250,6 +250,9 @@ public: bool isCgb() const { return ppu.cgb(); } bool isDoubleSpeed() const { return ppu.lyCounter().isDoubleSpeed(); } + + unsigned long *bgPalette() { return ppu.bgPalette(); } + unsigned long *spPalette() { return ppu.spPalette(); } }; }