diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 135153f..81991f6 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -82,6 +82,8 @@ PpuState Ppu::GetState() state.FrameCount = _frameCount; state.OverscanMode = _overscanMode; state.BgMode = _bgMode; + state.DirectColorMode = _directColorMode; + state.Mode7 = _mode7; state.Layers[0] = _layerConfig[0]; state.Layers[1] = _layerConfig[1]; state.Layers[2] = _layerConfig[2]; diff --git a/Core/PpuTools.cpp b/Core/PpuTools.cpp index 4bba382..8607237 100644 --- a/Core/PpuTools.cpp +++ b/Core/PpuTools.cpp @@ -141,6 +141,7 @@ void PpuTools::GetTileView(GetTileViewOptions options, uint32_t *outBuffer) for(int y = 0; y < 8; y++) { uint32_t pixelStart = addr + y * 16; + for(int x = 0; x < 8; x++) { uint8_t color = ram[(pixelStart + x * 2 + 1) & ramMask]; @@ -198,6 +199,8 @@ void PpuTools::GetTilemap(GetTilemapOptions options, uint32_t* outBuffer) PpuState state = _ppu->GetState(); options.BgMode = state.BgMode; + bool directColor = state.DirectColorMode && (options.BgMode == 3 || options.BgMode == 4 || options.BgMode == 7); + uint16_t basePaletteOffset = 0; if(options.BgMode == 0) { basePaletteOffset = options.Layer * 64; @@ -207,10 +210,8 @@ void PpuTools::GetTilemap(GetTilemapOptions options, uint32_t* outBuffer) uint8_t *cgram = _ppu->GetCgRam(); LayerConfig layer = state.Layers[options.Layer]; - uint16_t bgColor = (cgram[1] << 8) | cgram[0]; - for(int i = 0; i < 512 * 512; i++) { - outBuffer[i] = ToArgb(bgColor); - } + uint32_t bgColor = ToArgb((cgram[1] << 8) | cgram[0]); + std::fill(outBuffer, outBuffer + 1024*1024, bgColor); uint8_t bpp = layerBpp[options.BgMode][options.Layer]; if(bpp == 0) { @@ -220,37 +221,64 @@ void PpuTools::GetTilemap(GetTilemapOptions options, uint32_t* outBuffer) bool largeTileWidth = layer.LargeTiles || options.BgMode == 5 || options.BgMode == 6; bool largeTileHeight = layer.LargeTiles; - for(int row = 0; row < (layer.DoubleHeight ? 64 : 32); row++) { - uint16_t addrVerticalScrollingOffset = layer.DoubleHeight ? ((row & 0x20) << (layer.DoubleWidth ? 6 : 5)) : 0; - uint16_t baseOffset = (layer.TilemapAddress >> 1) + addrVerticalScrollingOffset + ((row & 0x1F) << 5); + if(options.BgMode == 7) { + for(int row = 0; row < 128; row++) { + for(int column = 0; column < 128; column++) { + uint32_t tileIndex = vram[row * 256 + column * 2]; + uint32_t tileAddr = tileIndex * 128; - for(int column = 0; column < (layer.DoubleWidth ? 64 : 32); column++) { - uint16_t addr = (baseOffset + (column & 0x1F) + (layer.DoubleWidth ? ((column & 0x20) << 5) : 0)) << 1; + for(int y = 0; y < 8; y++) { + uint32_t pixelStart = tileAddr + y * 16; - bool vMirror = (vram[addr + 1] & 0x80) != 0; - bool hMirror = (vram[addr + 1] & 0x40) != 0; + for(int x = 0; x < 8; x++) { + uint8_t color = vram[pixelStart + x * 2 + 1]; - uint16_t tileIndex = ((vram[addr + 1] & 0x03) << 8) | vram[addr]; - uint16_t tileStart = layer.ChrAddress + tileIndex * 8 * bpp; - - if(largeTileWidth || largeTileHeight) { - tileIndex = ( - tileIndex + - (largeTileHeight ? ((row & 0x01) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + - (largeTileWidth ? ((column & 0x01) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0) - ) & 0x3FF; + if(color != 0) { + uint32_t rgbColor; + if(directColor) { + rgbColor = ToArgb(((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xC0) << 7)); + } else { + rgbColor = GetRgbPixelColor(color, 0, 8, false, 0); + } + outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = rgbColor; + } + } + } } + } + } else { + for(int row = 0; row < (layer.DoubleHeight ? 64 : 32); row++) { + uint16_t addrVerticalScrollingOffset = layer.DoubleHeight ? ((row & 0x20) << (layer.DoubleWidth ? 6 : 5)) : 0; + uint16_t baseOffset = (layer.TilemapAddress >> 1) + addrVerticalScrollingOffset + ((row & 0x1F) << 5); - for(int y = 0; y < 8; y++) { - uint8_t yOffset = vMirror ? (7 - y) : y; - uint16_t pixelStart = tileStart + yOffset * 2; + for(int column = 0; column < (layer.DoubleWidth ? 64 : 32); column++) { + uint16_t addr = (baseOffset + (column & 0x1F) + (layer.DoubleWidth ? ((column & 0x20) << 5) : 0)) << 1; - for(int x = 0; x < 8; x++) { - uint8_t shift = hMirror ? x : (7 - x); - uint8_t color = GetTilePixelColor(vram, Ppu::VideoRamSize - 1, bpp, pixelStart, shift); - if(color != 0) { - uint8_t palette = bpp == 8 ? 0 : (vram[addr + 1] >> 2) & 0x07; - outBuffer[((row * 8) + y) * 512 + column * 8 + x] = GetRgbPixelColor(color, palette, bpp, false, basePaletteOffset); + bool vMirror = (vram[addr + 1] & 0x80) != 0; + bool hMirror = (vram[addr + 1] & 0x40) != 0; + + uint16_t tileIndex = ((vram[addr + 1] & 0x03) << 8) | vram[addr]; + uint16_t tileStart = layer.ChrAddress + tileIndex * 8 * bpp; + + if(largeTileWidth || largeTileHeight) { + tileIndex = ( + tileIndex + + (largeTileHeight ? ((row & 0x01) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + + (largeTileWidth ? ((column & 0x01) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0) + ) & 0x3FF; + } + + for(int y = 0; y < 8; y++) { + uint8_t yOffset = vMirror ? (7 - y) : y; + uint16_t pixelStart = tileStart + yOffset * 2; + + for(int x = 0; x < 8; x++) { + uint8_t shift = hMirror ? x : (7 - x); + uint8_t color = GetTilePixelColor(vram, Ppu::VideoRamSize - 1, bpp, pixelStart, shift); + if(color != 0) { + uint8_t palette = bpp == 8 ? 0 : (vram[addr + 1] >> 2) & 0x07; + outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = GetRgbPixelColor(color, palette, bpp, directColor, basePaletteOffset); + } } } } @@ -259,8 +287,8 @@ void PpuTools::GetTilemap(GetTilemapOptions options, uint32_t* outBuffer) if(options.ShowTileGrid) { constexpr uint32_t gridColor = 0xA0AAAAFF; - for(int i = 0; i < 512 * 512; i++) { - if((i & 0x07) == 0x07 || (i & 0x0E00) == 0x0E00) { + for(int i = 0; i < 1024 * 1024; i++) { + if((i & 0x07) == 0x07 || (i & 0x1C00) == 0x1C00) { BlendColors((uint8_t*)&outBuffer[i], (uint8_t*)&gridColor); } } @@ -268,18 +296,22 @@ void PpuTools::GetTilemap(GetTilemapOptions options, uint32_t* outBuffer) if(options.ShowScrollOverlay) { constexpr uint32_t overlayColor = 0x40FFFFFF; + int widthMask = options.BgMode == 7 ? 0x3FF : (layer.DoubleWidth ? 0x1FF : 0xFF); + int heightMask = options.BgMode == 7 ? 0x3FF : (layer.DoubleHeight ? 0x1FF : 0xFF); + int hScroll = options.BgMode == 7 ? state.Mode7.HScroll : layer.HScroll; + int vScroll = options.BgMode == 7 ? state.Mode7.VScroll : layer.VScroll; for(int y = 0; y < 240; y++) { for(int x = 0; x < 256; x++) { - int xPos = layer.HScroll + x; - int yPos = layer.VScroll + y; + int xPos = hScroll + x; + int yPos = vScroll + y; - xPos &= layer.DoubleWidth ? 0x1FF : 0xFF; - yPos &= layer.DoubleHeight ? 0x1FF : 0xFF; + xPos &= widthMask; + yPos &= heightMask; if(x == 0 || y == 0 || x == 255 || y == 239) { - outBuffer[(yPos << 9) | xPos] = 0xAFFFFFFF; + outBuffer[(yPos * 1024) | xPos] = 0xAFFFFFFF; } else { - BlendColors((uint8_t*)&outBuffer[(yPos << 9) | xPos], (uint8_t*)&overlayColor); + BlendColors((uint8_t*)&outBuffer[(yPos * 1024) | xPos], (uint8_t*)&overlayColor); } } } diff --git a/Core/PpuTypes.h b/Core/PpuTypes.h index 135c3d2..21171ba 100644 --- a/Core/PpuTypes.h +++ b/Core/PpuTypes.h @@ -15,17 +15,6 @@ struct LayerConfig bool LargeTiles; }; -struct PpuState -{ - uint16_t Cycle; - uint16_t Scanline; - uint32_t FrameCount; - bool OverscanMode; - - uint8_t BgMode; - LayerConfig Layers[4]; -}; - struct Mode7Config { int16_t Matrix[4]; @@ -44,6 +33,19 @@ struct Mode7Config bool ExtBgEnabled; }; +struct PpuState +{ + uint16_t Cycle; + uint16_t Scanline; + uint32_t FrameCount; + bool OverscanMode; + + uint8_t BgMode; + bool DirectColorMode; + Mode7Config Mode7; + LayerConfig Layers[4]; +}; + struct WindowConfig { bool ActiveLayers[6]; diff --git a/UI/Debugger/PpuViewer/frmTileViewer.cs b/UI/Debugger/PpuViewer/frmTileViewer.cs index 885e0f8..c7b5e96 100644 --- a/UI/Debugger/PpuViewer/frmTileViewer.cs +++ b/UI/Debugger/PpuViewer/frmTileViewer.cs @@ -43,6 +43,7 @@ namespace Mesen.GUI.Debugger cboFormat.SetEnumValue(TileFormat.Bpp4); ctrlPaletteViewer.SelectionMode = PaletteSelectionMode.SixteenColors; + _tileData = new byte[512 * 512 * 4]; _tileImage = new Bitmap(512, 512, PixelFormat.Format32bppArgb); picTilemap.Image = _tileImage; @@ -91,7 +92,9 @@ namespace Mesen.GUI.Debugger private void RefreshData() { _options.Palette = ctrlPaletteViewer.SelectedPalette; - _tileData = DebugApi.GetTileView(_options); + lock(_tileData) { + DebugApi.GetTileView(_options, _tileData); + } ctrlPaletteViewer.RefreshData(); } @@ -108,12 +111,14 @@ namespace Mesen.GUI.Debugger } using(Graphics g = Graphics.FromImage(_tileImage)) { - GCHandle handle = GCHandle.Alloc(_tileData, GCHandleType.Pinned); - Bitmap source = new Bitmap(mapWidth, mapHeight, 4 * mapWidth, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject()); - try { - g.DrawImage(source, 0, 0); - } finally { - handle.Free(); + lock(_tileData) { + GCHandle handle = GCHandle.Alloc(_tileData, GCHandleType.Pinned); + Bitmap source = new Bitmap(mapWidth, mapHeight, 4 * mapWidth, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject()); + try { + g.DrawImage(source, 0, 0); + } finally { + handle.Free(); + } } } diff --git a/UI/Debugger/PpuViewer/frmTilemapViewer.cs b/UI/Debugger/PpuViewer/frmTilemapViewer.cs index 6b203aa..dfda272 100644 --- a/UI/Debugger/PpuViewer/frmTilemapViewer.cs +++ b/UI/Debugger/PpuViewer/frmTilemapViewer.cs @@ -39,7 +39,8 @@ namespace Mesen.GUI.Debugger _notifListener = new NotificationListener(); _notifListener.OnNotification += OnNotificationReceived; - _tilemapImage = new Bitmap(512, 512, PixelFormat.Format32bppArgb); + _tilemapData = new byte[1024 * 1024 * 4]; + _tilemapImage = new Bitmap(1024, 1024, PixelFormat.Format32bppArgb); picTilemap.Image = _tilemapImage; ctrlScanlineCycleSelect.Initialize(241, 0); @@ -71,24 +72,28 @@ namespace Mesen.GUI.Debugger private void RefreshData() { _state = DebugApi.GetState(); - _tilemapData = DebugApi.GetTilemap(_options); + lock(_tilemapData) { + DebugApi.GetTilemap(_options, _tilemapData); + } } private void RefreshViewer() { - int mapWidth = _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256; - int mapHeight = _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256; + int mapWidth = _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256; + int mapHeight = _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256; if(_tilemapImage.Width != mapWidth || _tilemapImage.Height != mapHeight) { _tilemapImage = new Bitmap(mapWidth, mapHeight, PixelFormat.Format32bppArgb); picTilemap.Image = _tilemapImage; } using(Graphics g = Graphics.FromImage(_tilemapImage)) { - GCHandle handle = GCHandle.Alloc(_tilemapData, GCHandleType.Pinned); - Bitmap source = new Bitmap(512, 512, 4 * 512, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject()); - try { - g.DrawImage(source, 0, 0); - } finally { - handle.Free(); + lock(_tilemapData) { + GCHandle handle = GCHandle.Alloc(_tilemapData, GCHandleType.Pinned); + Bitmap source = new Bitmap(mapWidth, mapHeight, 4 * 1024, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject()); + try { + g.DrawImage(source, 0, 0); + } finally { + handle.Free(); + } } } @@ -98,8 +103,8 @@ namespace Mesen.GUI.Debugger private void UpdateMapSize() { - int mapWidth = _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256; - int mapHeight = _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256; + int mapWidth = _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256; + int mapHeight = _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256; picTilemap.Width = _zoomed ? mapWidth * 2 : mapWidth; picTilemap.Height = _zoomed ? mapHeight * 2 : mapHeight; } diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index 3681037..071add2 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -71,21 +71,8 @@ namespace Mesen.GUI return buffer; } - [DllImport(DllPath, EntryPoint = "GetTilemap")] private static extern void GetTilemapWrapper(GetTilemapOptions options, [In, Out] byte[] buffer); - public static byte[] GetTilemap(GetTilemapOptions options) - { - byte[] buffer = new byte[512*512*4]; - DebugApi.GetTilemapWrapper(options, buffer); - return buffer; - } - - [DllImport(DllPath, EntryPoint = "GetTileView")] private static extern void GetTileViewWrapper(GetTileViewOptions options, [In, Out] byte[] buffer); - public static byte[] GetTileView(GetTileViewOptions options) - { - byte[] buffer = new byte[512 * 512 * 4]; - DebugApi.GetTileViewWrapper(options, buffer); - return buffer; - } + [DllImport(DllPath)] public static extern void GetTilemap(GetTilemapOptions options, [In, Out] byte[] buffer); + [DllImport(DllPath)] public static extern void GetTileView(GetTileViewOptions options, [In, Out] byte[] buffer); [DllImport(DllPath)] public static extern void SetViewerUpdateTiming(Int32 viewerId, Int32 scanline, Int32 cycle); @@ -188,6 +175,9 @@ namespace Mesen.GUI [MarshalAs(UnmanagedType.I1)] public bool OverscanMode; public byte BgMode; + [MarshalAs(UnmanagedType.I1)] public bool DirectColorMode; + + public Mode7Config Mode7; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public LayerConfig[] Layers; @@ -207,6 +197,25 @@ namespace Mesen.GUI [MarshalAs(UnmanagedType.I1)] public bool LargeTiles; } + public struct Mode7Config + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public Int16[] Matrix; + + public Int16 HScroll; + public Int16 VScroll; + public Int16 CenterX; + public Int16 CenterY; + + public Byte ValueLatch; + + [MarshalAs(UnmanagedType.I1)] public bool LargeMap; + [MarshalAs(UnmanagedType.I1)] public bool FillWithTile0; + [MarshalAs(UnmanagedType.I1)] public bool HorizontalMirroring; + [MarshalAs(UnmanagedType.I1)] public bool VerticalMirroring; + [MarshalAs(UnmanagedType.I1)] public bool ExtBgEnabled; + } + public struct DebugState { public CpuState Cpu;