From efb7f61f04eafc9e9d9b6022c27e075f629a600c Mon Sep 17 00:00:00 2001 From: png183 <97423514+png183@users.noreply.github.com> Date: Sun, 25 Aug 2024 02:06:06 -0700 Subject: [PATCH] gba: add graphics viewer support (#1626) Adds GBA support to the ares graphics viewer. Supports viewing VRAM contents as Mode 3/4/5 bitmaps, or as 4bpp/8bpp tiles. --- ares/gba/ppu/debugger.cpp | 130 ++++++++++++++++++++++++++++++++++++++ ares/gba/ppu/ppu.cpp | 2 +- ares/gba/ppu/ppu.hpp | 9 +++ 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/ares/gba/ppu/debugger.cpp b/ares/gba/ppu/debugger.cpp index 2a45d193bf..772854d05d 100644 --- a/ares/gba/ppu/debugger.cpp +++ b/ares/gba/ppu/debugger.cpp @@ -16,4 +16,134 @@ auto PPU::Debugger::load(Node::Object parent) -> void { memory.pram->setWrite([&](u32 address, u8 data) -> void { ppu.pram[address >> 1].byte(address & 1) = data; }); + + graphics.tiles4bpp = parent->append("4 BPP Tiles"); + graphics.tiles4bpp->setSize(512, 384); + graphics.tiles4bpp->setCapture([&]() -> vector { + vector output; + output.resize(512 * 384); + for(u32 tileY : range(48)) { + for(u32 tileX : range(64)) { + n32 address = tileY * 64 + tileX << 5; + for(u32 y : range(8)) { + for(u32 x : range(4)) { + n8 colors = ppu.vram[address + y * 4 + x]; + n4 leftPixel = colors & 0xf; + n4 rightPixel = colors >> 4; + output[(tileY * 8 + y) * 512 + (tileX * 8 + (x << 1))] = leftPixel * 0x111111; + output[(tileY * 8 + y) * 512 + (tileX * 8 + (x << 1)) + 1] = rightPixel * 0x111111; + } + } + } + } + return output; + }); + + graphics.tiles8bpp = parent->append("8 BPP Tiles"); + graphics.tiles8bpp->setSize(256, 384); + graphics.tiles8bpp->setCapture([&]() -> vector { + vector output; + output.resize(256 * 384); + for(u32 tileY : range(48)) { + for(u32 tileX : range(32)) { + n32 address = tileY * 32 + tileX << 6; + for(u32 y : range(8)) { + for(u32 x : range(8)) { + n9 color = ppu.vram[address + y * 8 + x]; + if(tileY >= 32) color += 0x100; //bottom 1/3 of tile viewer uses OBJ palettes + n15 pixel = ppu.pram[color]; + n8 r = pixel >> 0 & 31; r = r << 3 | r >> 2; + n8 g = pixel >> 5 & 31; g = g << 3 | g >> 2; + n8 b = pixel >> 10 & 31; b = b << 3 | b >> 2; + n8 a = 255; + output[(tileY * 8 + y) * 256 + (tileX * 8 + x)] = a << 24 | r << 16 | g << 8 | b << 0; + } + } + } + } + return output; + }); + + graphics.mode3 = parent->append("Mode 3"); + graphics.mode3->setSize(240, 160); + graphics.mode3->setCapture([&]() -> vector { + vector output; + output.resize(240 * 160); + for(u32 y : range(160)) { + for(u32 x : range(240)) { + n15 pixel = ppu.vram[y * 480 + x * 2 + 1] << 8 | ppu.vram[y * 480 + x * 2] << 0; + n8 r = pixel >> 0 & 31; r = r << 3 | r >> 2; + n8 g = pixel >> 5 & 31; g = g << 3 | g >> 2; + n8 b = pixel >> 10 & 31; b = b << 3 | b >> 2; + n8 a = 255; + output[y * 240 + x] = a << 24 | r << 16 | g << 8 | b << 0; + } + } + return output; + }); + + graphics.mode4 = parent->append("Mode 4"); + graphics.mode4->setSize(240, 320); + graphics.mode4->setCapture([&]() -> vector { + vector output; + output.resize(240 * 320); + for(u32 y : range(160)) { + for(u32 x : range(240)) { + n8 color = ppu.vram[y * 240 + x]; + n15 pixel = ppu.pram[color]; + n8 r = pixel >> 0 & 31; r = r << 3 | r >> 2; + n8 g = pixel >> 5 & 31; g = g << 3 | g >> 2; + n8 b = pixel >> 10 & 31; b = b << 3 | b >> 2; + n8 a = 255; + output[y * 240 + x] = a << 24 | r << 16 | g << 8 | b << 0; + } + } + for(u32 y : range(160)) { + for(u32 x : range(240)) { + n8 color = ppu.vram[0xa000 + y * 240 + x]; + n15 pixel = ppu.pram[color]; + n8 r = pixel >> 0 & 31; r = r << 3 | r >> 2; + n8 g = pixel >> 5 & 31; g = g << 3 | g >> 2; + n8 b = pixel >> 10 & 31; b = b << 3 | b >> 2; + n8 a = 255; + output[(y + 160) * 240 + x] = a << 24 | r << 16 | g << 8 | b << 0; + } + } + return output; + }); + + graphics.mode5 = parent->append("Mode 5"); + graphics.mode5->setSize(160, 256); + graphics.mode5->setCapture([&]() -> vector { + vector output; + output.resize(160 * 256); + for(u32 y : range(256)) { + for(u32 x : range(160)) { + n15 pixel = ppu.vram[y * 320 + x * 2 + 1] << 8 | ppu.vram[y * 320 + x * 2] << 0; + n8 r = pixel >> 0 & 31; r = r << 3 | r >> 2; + n8 g = pixel >> 5 & 31; g = g << 3 | g >> 2; + n8 b = pixel >> 10 & 31; b = b << 3 | b >> 2; + n8 a = 255; + output[y * 160 + x] = a << 24 | r << 16 | g << 8 | b << 0; + } + } + return output; + }); +} + +auto PPU::Debugger::unload(Node::Object parent) -> void { + parent->remove(memory.vram); + parent->remove(memory.pram); + parent->remove(graphics.tiles4bpp); + parent->remove(graphics.tiles8bpp); + parent->remove(graphics.mode3); + parent->remove(graphics.mode4); + parent->remove(graphics.mode5); + memory.vram.reset(); + memory.pram.reset(); + graphics.tiles4bpp.reset(); + graphics.tiles8bpp.reset(); + graphics.mode3.reset(); + graphics.mode4.reset(); + graphics.mode5.reset(); } diff --git a/ares/gba/ppu/ppu.cpp b/ares/gba/ppu/ppu.cpp index 0939d36733..1b5f7a7864 100644 --- a/ares/gba/ppu/ppu.cpp +++ b/ares/gba/ppu/ppu.cpp @@ -60,7 +60,7 @@ auto PPU::load(Node::Object parent) -> void { } auto PPU::unload() -> void { - debugger = {}; + debugger.unload(node); colorEmulation.reset(); interframeBlending.reset(); rotation.reset(); diff --git a/ares/gba/ppu/ppu.hpp b/ares/gba/ppu/ppu.hpp index cf5d613775..9739d381ea 100644 --- a/ares/gba/ppu/ppu.hpp +++ b/ares/gba/ppu/ppu.hpp @@ -10,11 +10,20 @@ struct PPU : Thread, IO { struct Debugger { //debugger.cpp auto load(Node::Object) -> void; + auto unload(Node::Object) -> void; struct Memory { Node::Debugger::Memory vram; Node::Debugger::Memory pram; } memory; + + struct Graphics { + Node::Debugger::Graphics tiles4bpp; + Node::Debugger::Graphics tiles8bpp; + Node::Debugger::Graphics mode3; + Node::Debugger::Graphics mode4; + Node::Debugger::Graphics mode5; + } graphics; } debugger; //ppu.cpp