mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
357 lines
12 KiB
C++
357 lines
12 KiB
C++
#include "pch.h"
|
|
#include "PCE/Debugger/PceVdcTools.h"
|
|
#include "PCE/PceConsole.h"
|
|
#include "PCE/PceConstants.h"
|
|
#include "PCE/PceTypes.h"
|
|
#include "Debugger/DebugTypes.h"
|
|
#include "Debugger/MemoryDumper.h"
|
|
#include "Shared/EmuSettings.h"
|
|
#include "Shared/SettingTypes.h"
|
|
|
|
PceVdcTools::PceVdcTools(Debugger* debugger, Emulator *emu, PceConsole* console) : PpuTools(debugger, emu)
|
|
{
|
|
_console = console;
|
|
}
|
|
|
|
void PceVdcTools::SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle)
|
|
{
|
|
//Round hclock value down to previous multiple of 3
|
|
PpuTools::SetViewerUpdateTiming(viewerId, scanline, cycle / 3 * 3);
|
|
}
|
|
|
|
FrameInfo PceVdcTools::GetTilemapSize(GetTilemapOptions options, BaseState& baseState)
|
|
{
|
|
PceVideoState& state = (PceVideoState&)baseState;
|
|
if(options.Layer == 0) {
|
|
return { (uint32_t)state.Vdc.HvLatch.ColumnCount * 8, (uint32_t)state.Vdc.HvLatch.RowCount * 8 };
|
|
} else {
|
|
return { (uint32_t)state.Vdc2.HvLatch.ColumnCount * 8, (uint32_t)state.Vdc2.HvLatch.RowCount * 8 };
|
|
}
|
|
}
|
|
|
|
DebugTilemapTileInfo PceVdcTools::GetTilemapTileInfo(uint32_t x, uint32_t y, uint8_t* vram, GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState)
|
|
{
|
|
DebugTilemapTileInfo result = {};
|
|
|
|
FrameInfo size = GetTilemapSize(options, baseState);
|
|
if(x >= size.Width || y >= size.Height) {
|
|
return result;
|
|
}
|
|
|
|
PceVdcState& state = options.Layer == 0 ? ((PceVideoState&)baseState).Vdc : ((PceVideoState&)baseState).Vdc2;
|
|
|
|
uint32_t row = y / 8;
|
|
uint32_t column = x / 8;
|
|
|
|
uint16_t entryAddr = (row * state.HvLatch.ColumnCount + column) * 2;
|
|
uint16_t batEntry = vram[entryAddr] | (vram[entryAddr + 1] << 8);
|
|
|
|
result.Height = 8;
|
|
result.Width = 8;
|
|
result.PaletteIndex = batEntry >> 12;
|
|
result.TileIndex = (batEntry & 0xFFF);
|
|
result.TileMapAddress = entryAddr;
|
|
|
|
result.TileAddress = result.TileIndex * 32;
|
|
result.PaletteAddress = result.PaletteIndex * 16;
|
|
|
|
result.Row = row;
|
|
result.Column = column;
|
|
|
|
return result;
|
|
}
|
|
|
|
DebugTilemapInfo PceVdcTools::GetTilemap(GetTilemapOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
|
|
{
|
|
PceVdcState& state = options.Layer == 0 ? ((PceVideoState&)baseState).Vdc : ((PceVideoState&)baseState).Vdc2;
|
|
|
|
if(state.HvLatch.VramAccessMode == 3) {
|
|
//2BPP modes
|
|
if(state.HvLatch.CgMode) {
|
|
return InternalGetTilemap<TileFormat::PceBackgroundBpp2Cg1>(options, state, vram, palette, outBuffer);
|
|
} else {
|
|
return InternalGetTilemap<TileFormat::PceBackgroundBpp2Cg0>(options, state, vram, palette, outBuffer);
|
|
}
|
|
} else {
|
|
return InternalGetTilemap<TileFormat::Bpp4>(options, state, vram, palette, outBuffer);
|
|
}
|
|
}
|
|
|
|
template<TileFormat format>
|
|
DebugTilemapInfo PceVdcTools::InternalGetTilemap(GetTilemapOptions options, PceVdcState& state, uint8_t* vram, uint32_t* palette, uint32_t* outBuffer)
|
|
{
|
|
DebugTilemapInfo result = {};
|
|
result.Bpp = 4; //Report 2bpp modes as 4bpp to display the right palette in UI
|
|
result.Format = format;
|
|
result.TileWidth = 8;
|
|
result.TileHeight = 8;
|
|
result.ColumnCount = state.HvLatch.ColumnCount;
|
|
result.RowCount = state.HvLatch.RowCount;
|
|
result.TilemapAddress = 0;
|
|
result.TilesetAddress = 0;
|
|
result.ScrollX = state.HvReg.BgScrollX;
|
|
result.ScrollY = state.HvReg.BgScrollY;
|
|
result.ScrollWidth = (state.HvLatch.HorizDisplayWidth + 1) * 8;
|
|
result.ScrollHeight = std::min<uint32_t>(242, state.HvLatch.VertDisplayWidth);
|
|
|
|
uint8_t colorMask = 0xFF;
|
|
if(options.DisplayMode == TilemapDisplayMode::Grayscale) {
|
|
if constexpr(format == TileFormat::Bpp4 || format == TileFormat::PceSpriteBpp4) {
|
|
palette = (uint32_t*)_grayscaleColorsBpp4;
|
|
colorMask = 0x0F;
|
|
} else {
|
|
palette = (uint32_t*)_grayscaleColorsBpp2;
|
|
colorMask = 0x03;
|
|
}
|
|
}
|
|
|
|
for(uint8_t row = 0; row < state.HvLatch.RowCount; row++) {
|
|
for(uint8_t column = 0; column < state.HvLatch.ColumnCount; column++) {
|
|
uint16_t entryAddr = (row * state.HvLatch.ColumnCount + column) * 2;
|
|
uint16_t batEntry = vram[entryAddr] | (vram[entryAddr + 1] << 8);
|
|
uint8_t palIndex = batEntry >> 12;
|
|
uint16_t tileIndex = (batEntry & 0xFFF);
|
|
|
|
for(int y = 0; y < 8; y++) {
|
|
uint16_t tileAddr = tileIndex * 32 + y * 2;
|
|
for(int x = 0; x < 8; x++) {
|
|
uint8_t color = GetTilePixelColor<format>(vram, 0xFFFF, tileAddr, x);
|
|
uint16_t palAddr = color == 0 ? 0 : (palIndex * 16 + color);
|
|
uint32_t outPos = (row * 8 + y) * state.HvLatch.ColumnCount * 8 + column * 8 + x;
|
|
outBuffer[outPos] = palette[palAddr & colorMask];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void PceVdcTools::GetSpritePreview(GetSpritePreviewOptions options, BaseState& baseState, DebugSpriteInfo* sprites, uint32_t* spritePreviews, uint32_t* palette, uint32_t* outBuffer)
|
|
{
|
|
PceVdcState& state = ((PceVideoState&)baseState).Vdc;
|
|
|
|
uint32_t bgColor = GetSpriteBackgroundColor(options.Background, palette, false);
|
|
uint32_t screenWidth = std::min<uint32_t>(PceConstants::MaxScreenWidth, (state.HvLatch.HorizDisplayWidth + 1) * 8);
|
|
std::fill(outBuffer, outBuffer + 1024*1024, GetSpriteBackgroundColor(options.Background, palette, true));
|
|
for(int i = 64; i < state.HvLatch.VertDisplayWidth + 64; i++) {
|
|
std::fill(outBuffer + i * 1024 + 32, outBuffer + i * 1024 + 32 + screenWidth, bgColor);
|
|
}
|
|
|
|
int spriteCount = _console->IsSuperGrafx() ? 128 : 64;
|
|
|
|
for(int i = spriteCount - 1; i >= 0; i--) {
|
|
DebugSpriteInfo& sprite = sprites[i];
|
|
uint32_t* spritePreview = spritePreviews + i * _spritePreviewSize;
|
|
|
|
for(int y = 0; y < sprite.Height; y++) {
|
|
for(int x = 0; x < sprite.Width; x++) {
|
|
uint32_t color = spritePreview[y * sprite.Width + x];
|
|
if(color != 0) {
|
|
if(sprite.Y + y >= 1024 || sprite.X + x >= 1024) {
|
|
continue;
|
|
}
|
|
outBuffer[((sprite.Y + y) * 1024) + sprite.X + x] = color;
|
|
} else {
|
|
spritePreview[y * sprite.Width + x] = bgColor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PceVdcTools::GetSpriteInfo(PceVdcState& state, DebugSpriteInfo& sprite, uint32_t* spritePreview, uint16_t spriteIndex, GetSpritePreviewOptions& options, uint8_t* vram, uint8_t* oamRam, uint32_t* palette)
|
|
{
|
|
if(state.HvLatch.SpriteAccessMode == 1) {
|
|
uint16_t loadSp23 = oamRam[spriteIndex * 8 + 4] & 0x01;
|
|
if(loadSp23) {
|
|
InternalGetSpriteInfo<TileFormat::PceSpriteBpp2Sp23>(sprite, spritePreview, spriteIndex, options, vram, oamRam, palette);
|
|
} else {
|
|
InternalGetSpriteInfo<TileFormat::PceSpriteBpp2Sp01>(sprite, spritePreview, spriteIndex, options, vram, oamRam, palette);
|
|
}
|
|
} else {
|
|
InternalGetSpriteInfo<TileFormat::PceSpriteBpp4>(sprite, spritePreview, spriteIndex, options, vram, oamRam, palette);
|
|
}
|
|
}
|
|
|
|
template<TileFormat format>
|
|
void PceVdcTools::InternalGetSpriteInfo(DebugSpriteInfo& sprite, uint32_t* spritePreview, uint16_t spriteIndex, GetSpritePreviewOptions& options, uint8_t* vram, uint8_t* oamRam, uint32_t* palette)
|
|
{
|
|
uint16_t addr = (spriteIndex * 8);
|
|
|
|
uint16_t spriteY = (oamRam[addr] | (oamRam[addr+1] << 8)) & 0x3FF;
|
|
uint16_t spriteX = (oamRam[addr + 2] | (oamRam[addr + 3] << 8)) & 0x3FF;
|
|
uint16_t patternCode = (oamRam[addr + 4] | (oamRam[addr + 5] << 8)) & 0x7FF;
|
|
uint16_t tileIndex = patternCode >> 1;
|
|
uint16_t flags = (oamRam[addr + 6] | (oamRam[addr + 7] << 8));
|
|
|
|
uint8_t width = (flags & 0x100) ? 32 : 16;
|
|
uint8_t height;
|
|
switch((flags >> 12) & 0x03) {
|
|
default:
|
|
case 0: height = 16; break;
|
|
case 1: height = 32; break;
|
|
|
|
case 2:
|
|
case 3:
|
|
height = 64;
|
|
break;
|
|
}
|
|
|
|
bool visible = (
|
|
((spriteX + width) > 32 && (spriteX < 256 + 32)) ||
|
|
((spriteY + height) > 64 && (spriteY < 242 + 64))
|
|
);
|
|
|
|
sprite.Bpp = 4; //Report 2bpp modes as 4bpp to display the right palette in UI
|
|
sprite.Format = format;
|
|
sprite.SpriteIndex = spriteIndex;
|
|
sprite.UseExtendedVram = spriteIndex >= 64;
|
|
sprite.X = spriteX;
|
|
sprite.Y = spriteY;
|
|
sprite.RawX = spriteX;
|
|
sprite.RawY = spriteY;
|
|
sprite.Height = height;
|
|
sprite.Width = width;
|
|
sprite.TileIndex = tileIndex;
|
|
sprite.Palette = (flags & 0x0F);
|
|
sprite.PaletteAddress = (sprite.Palette + 16) * 16;
|
|
sprite.Priority = (flags & 0x80) ? DebugSpritePriority::Foreground : DebugSpritePriority::Background;
|
|
bool horizontalMirror = (flags & 0x800) != 0;
|
|
bool verticalMirror = (flags & 0x8000) != 0;
|
|
sprite.HorizontalMirror = horizontalMirror ? NullableBoolean::True : NullableBoolean::False;
|
|
sprite.VerticalMirror = verticalMirror ? NullableBoolean::True : NullableBoolean::False;
|
|
sprite.Visibility = visible ? SpriteVisibility::Visible : SpriteVisibility::Offscreen;
|
|
sprite.UseSecondTable = NullableBoolean::Undefined;
|
|
|
|
if(sprite.UseExtendedVram) {
|
|
//Sprite for VDC2, use VRAM from VDC2
|
|
vram += 0x10000;
|
|
}
|
|
|
|
if(width == 32) {
|
|
tileIndex &= ~0x01;
|
|
}
|
|
if(height == 32) {
|
|
tileIndex &= ~0x02;
|
|
} else if(height == 64) {
|
|
tileIndex &= ~0x06;
|
|
}
|
|
|
|
sprite.TileAddress = tileIndex * 64 * 2;
|
|
sprite.TileCount = 0;
|
|
for(int i = 0, rowCount = height / 16; i < rowCount; i++) {
|
|
for(int j = 0, columnCount = width / 16; j < columnCount; j++) {
|
|
sprite.TileAddresses[sprite.TileCount] = sprite.TileAddress + (i * columnCount + j) * 128;
|
|
sprite.TileCount++;
|
|
}
|
|
}
|
|
|
|
uint8_t yOffset;
|
|
int rowOffset;
|
|
|
|
for(int y = 0; y < sprite.Height; y++) {
|
|
if(verticalMirror) {
|
|
yOffset = (sprite.Height - y - 1) & 0x0F;
|
|
rowOffset = (sprite.Height - y - 1) >> 4;
|
|
} else {
|
|
yOffset = y & 0x0F;
|
|
rowOffset = y >> 4;
|
|
}
|
|
|
|
uint16_t spriteTileY = tileIndex | (rowOffset << 1);
|
|
|
|
for(int x = 0; x < sprite.Width; x++) {
|
|
uint32_t outOffset = y * sprite.Width + x;
|
|
|
|
uint8_t xOffset;
|
|
int columnOffset;
|
|
if(horizontalMirror) {
|
|
xOffset = (sprite.Width - x - 1) & 0x0F;
|
|
columnOffset = (sprite.Width - x - 1) >> 4;
|
|
} else {
|
|
xOffset = x & 0x0F;
|
|
columnOffset = x >> 4;
|
|
}
|
|
|
|
uint16_t spriteTile = spriteTileY | columnOffset;
|
|
uint16_t tileStart = spriteTile * 64;
|
|
|
|
uint16_t pixelStart = tileStart + yOffset;
|
|
|
|
uint8_t color;
|
|
if(pixelStart >= 0x8000) {
|
|
//Display specific pattern when open bus, to make problem obvious in sprite viewer
|
|
color = xOffset;
|
|
} else {
|
|
color = GetTilePixelColor<format>(vram, 0xFFFF, pixelStart * 2, xOffset);
|
|
}
|
|
|
|
if(color != 0) {
|
|
spritePreview[outOffset] = palette[color + sprite.Palette * 16 + 16*16];
|
|
} else {
|
|
spritePreview[outOffset] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PceVdcTools::GetSpriteList(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState, uint8_t* vram, uint8_t* oamRam, uint32_t* palette, DebugSpriteInfo outBuffer[], uint32_t* spritePreviews, uint32_t* screenPreview)
|
|
{
|
|
PceVdcState& state = ((PceVideoState&)baseState).Vdc;
|
|
for(int i = 0, len = _console->IsSuperGrafx() ? 128 : 64; i < len; i++) {
|
|
outBuffer[i].Init();
|
|
GetSpriteInfo(state, outBuffer[i], spritePreviews + (i * _spritePreviewSize), i, options, vram, oamRam, palette);
|
|
}
|
|
|
|
GetSpritePreview(options, baseState, outBuffer, spritePreviews, palette, screenPreview);
|
|
}
|
|
|
|
DebugSpritePreviewInfo PceVdcTools::GetSpritePreviewInfo(GetSpritePreviewOptions options, BaseState& baseState, BaseState& ppuToolsState)
|
|
{
|
|
PceVdcState& state = ((PceVideoState&)baseState).Vdc;
|
|
|
|
DebugSpritePreviewInfo info = {};
|
|
info.Height = 1024;
|
|
info.Width = 1024;
|
|
info.SpriteCount = _console->IsSuperGrafx() ? 128 : 64;
|
|
info.CoordOffsetX = 0;
|
|
info.CoordOffsetY = 0;
|
|
|
|
info.VisibleX = 32;
|
|
info.VisibleY = 64;
|
|
info.VisibleWidth = (state.HvLatch.HorizDisplayWidth + 1) * 8;
|
|
info.VisibleHeight = state.HvLatch.VertDisplayWidth;
|
|
|
|
return info;
|
|
}
|
|
|
|
DebugPaletteInfo PceVdcTools::GetPaletteInfo(GetPaletteInfoOptions options)
|
|
{
|
|
DebugPaletteInfo info = {};
|
|
info.PaletteMemType = MemoryType::PcePaletteRam;
|
|
info.HasMemType = true;
|
|
|
|
info.RawFormat = RawPaletteFormat::Rgb333;
|
|
info.ColorsPerPalette = 16;
|
|
info.BgColorCount = 16 * 16;
|
|
info.SpritePaletteOffset = info.BgColorCount;
|
|
info.SpriteColorCount = 16 * 16;
|
|
info.ColorCount = info.BgColorCount + info.SpriteColorCount;
|
|
|
|
uint32_t* palette = _emu->GetSettings()->GetPcEngineConfig().Palette;
|
|
|
|
uint8_t* pal = _debugger->GetMemoryDumper()->GetMemoryBuffer(MemoryType::PcePaletteRam);
|
|
for(int i = 0; i < 512; i++) {
|
|
info.RawPalette[i] = pal[i * 2] | (pal[i * 2 + 1] << 8);
|
|
info.RgbPalette[i] = palette[info.RawPalette[i]];
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
void PceVdcTools::SetPaletteColor(int32_t colorIndex, uint32_t color)
|
|
{
|
|
_debugger->GetMemoryDumper()->SetMemoryValue(MemoryType::PcePaletteRam, colorIndex * 2, color & 0xFF);
|
|
_debugger->GetMemoryDumper()->SetMemoryValue(MemoryType::PcePaletteRam, colorIndex * 2 + 1, (color >> 8) & 0x01);
|
|
}
|