mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00
427 lines
13 KiB
C++
427 lines
13 KiB
C++
#include "GsStateUtils.h"
|
|
#include "string_format.h"
|
|
#include "gs/GsDebuggerInterface.h"
|
|
|
|
// clang-format off
|
|
static const char* g_yesNoString[2] =
|
|
{
|
|
"NO",
|
|
"YES"
|
|
};
|
|
|
|
static const char* g_pixelFormats[0x40] =
|
|
{
|
|
//0x00
|
|
"PSMCT32",
|
|
"PSMCT24",
|
|
"PSMCT16",
|
|
"(INVALID)",
|
|
//0x04
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
//0x08
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"PSMCT16S",
|
|
"(INVALID)",
|
|
//0x0C
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
|
|
//0x10
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"PSMT8",
|
|
//0x14
|
|
"PSMT4",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
//0x18
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"PSMT8H",
|
|
//0x1C
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
|
|
//0x20
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
//0x24
|
|
"PSMT4HL",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
//0x28
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
//0x2C
|
|
"PSMT4HH",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
|
|
//0x30
|
|
"PSMZ32",
|
|
"PSMZ24",
|
|
"PSMZ16",
|
|
"(INVALID)",
|
|
//0x34
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
//0x38
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"PSMZ16S",
|
|
"(INVALID)",
|
|
//0x3C
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
};
|
|
|
|
static const char* g_primitiveTypeString[8] =
|
|
{
|
|
"POINT",
|
|
"LINE",
|
|
"LINESTRIP",
|
|
"TRIANGLE",
|
|
"TRIANGLESTRIP",
|
|
"TRIANGLEFAN",
|
|
"SPRITE",
|
|
"(INVALID)"
|
|
};
|
|
|
|
static const char* g_depthTestFunctionString[4] =
|
|
{
|
|
"NEVER",
|
|
"ALWAYS",
|
|
"GEQUAL",
|
|
"GREATER"
|
|
};
|
|
|
|
static const char* g_alphaTestFunctionString[8] =
|
|
{
|
|
"NEVER",
|
|
"ALWAYS",
|
|
"LESS",
|
|
"LEQUAL",
|
|
"EQUAL",
|
|
"GEQUAL",
|
|
"GREATER",
|
|
"NOTEQUAL"
|
|
};
|
|
|
|
static const char* g_alphaTestFailOpString[4] =
|
|
{
|
|
"KEEP",
|
|
"FB_ONLY",
|
|
"ZB_ONLY",
|
|
"RGB_ONLY"
|
|
};
|
|
|
|
static const char* g_alphaBlendAbdCoefString[4] =
|
|
{
|
|
"Cs",
|
|
"Cd",
|
|
"0",
|
|
"(INVALID)"
|
|
};
|
|
|
|
static const char* g_alphaBlendCCoefString[4] =
|
|
{
|
|
"As",
|
|
"Ad",
|
|
"FIX",
|
|
"(INVALID)"
|
|
};
|
|
|
|
static const char* g_textureFunctionString[4] =
|
|
{
|
|
"MODULATE",
|
|
"DECAL",
|
|
"HIGHLIGHT",
|
|
"HIGHLIGHT2"
|
|
};
|
|
|
|
static const char* g_textureClutLoadControlString[8] =
|
|
{
|
|
"DO NOT LOAD",
|
|
"LOAD",
|
|
"LOAD AND COPY CBP TO CBP0",
|
|
"LOAD AND COPY CBP TO CBP1",
|
|
"LOAD IF CBP != CBP0 AND COPY CBP TO CBP0",
|
|
"LOAD IF CBP != CBP1 AND COPY CBP TO CBP1",
|
|
"(INVALID)",
|
|
"(INVALID)",
|
|
};
|
|
|
|
static const char* g_textureMagFilterString[2] =
|
|
{
|
|
"NEAREST",
|
|
"LINEAR"
|
|
};
|
|
|
|
static const char* g_textureMinFilterString[8] =
|
|
{
|
|
"NEAREST",
|
|
"LINEAR",
|
|
"NEAREST_MIPMAP_NEAREST",
|
|
"NEAREST_MIPMAP_LINEAR",
|
|
"LINEAR_MIPMAP_NEAREST",
|
|
"LINEAR_MIPMAP_LINEAR",
|
|
"(INVALID)",
|
|
"(INVALID)"
|
|
};
|
|
|
|
static const char* g_wrapModeString[4] =
|
|
{
|
|
"REPEAT",
|
|
"CLAMP",
|
|
"REGION_CLAMP",
|
|
"REGION_REPEAT"
|
|
};
|
|
|
|
static const char* g_colorClampModeString[2] =
|
|
{
|
|
"MASK",
|
|
"CLAMP"
|
|
};
|
|
|
|
static const char* g_scanMaskModeString[4] =
|
|
{
|
|
"NONE",
|
|
"(INVALID)",
|
|
"KEEP ODD",
|
|
"KEEP EVEN"
|
|
};
|
|
// clang-format on
|
|
|
|
std::string CGsStateUtils::GetInputState(CGSHandler* gs)
|
|
{
|
|
std::string result;
|
|
|
|
bool usePrmode = (gs->GetRegisters()[GS_REG_PRMODECONT] & 1) == 0;
|
|
|
|
auto prim = make_convertible<CGSHandler::PRMODE>(0);
|
|
if(usePrmode)
|
|
{
|
|
prim <<= gs->GetRegisters()[GS_REG_PRMODE];
|
|
}
|
|
else
|
|
{
|
|
prim <<= gs->GetRegisters()[GS_REG_PRIM];
|
|
}
|
|
|
|
auto primitiveType = gs->GetRegisters()[GS_REG_PRIM] & 0x07;
|
|
auto xyOffset = make_convertible<CGSHandler::XYOFFSET>(gs->GetRegisters()[GS_REG_XYOFFSET_1 + prim.nContext]);
|
|
|
|
result += string_format("Use PRMODE: %s\r\n", g_yesNoString[usePrmode]);
|
|
|
|
result += string_format("Primitive:\r\n");
|
|
result += string_format("\tContext: %d\r\n", prim.nContext + 1);
|
|
result += string_format("\tType: %s\r\n", g_primitiveTypeString[primitiveType]);
|
|
result += string_format("\tUse Gouraud: %s\r\n", g_yesNoString[prim.nShading]);
|
|
result += string_format("\tUse Texture: %s\r\n", g_yesNoString[prim.nTexture]);
|
|
result += string_format("\tUse Fog: %s\r\n", g_yesNoString[prim.nFog]);
|
|
result += string_format("\tUse Alpha Blending: %s\r\n", g_yesNoString[prim.nAlpha]);
|
|
result += string_format("\tUse Antialiasing: %s\r\n", g_yesNoString[prim.nAntiAliasing]);
|
|
result += string_format("\tUse UV: %s\r\n", g_yesNoString[prim.nUseUV]);
|
|
result += string_format("\tUse Fixed Interpolation: %s\r\n", g_yesNoString[prim.nUseFloat]);
|
|
|
|
result += "\r\n";
|
|
|
|
CGSHandler::VERTEX vertices[3] = {};
|
|
if(auto debuggerInterface = dynamic_cast<CGsDebuggerInterface*>(gs))
|
|
{
|
|
memcpy(&vertices, debuggerInterface->GetInputVertices(), sizeof(vertices));
|
|
}
|
|
|
|
result += string_format("Positions:\r\n");
|
|
result += string_format("\t PosX PosY PosZ OfsX OfsY\r\n");
|
|
for(unsigned int i = 0; i < 3; i++)
|
|
{
|
|
auto vertex = vertices[i];
|
|
float posX = static_cast<float>((vertex.position >> 0) & 0xFFFF) / 16;
|
|
float posY = static_cast<float>((vertex.position >> 16) & 0xFFFF) / 16;
|
|
uint32 posZ = static_cast<uint32>(vertex.position >> 32);
|
|
result += string_format("\tVertex %i: %+10.4f %+10.4f 0x%08X %+10.4f %+10.4f\r\n",
|
|
i, posX, posY, posZ, posX - xyOffset.GetX(), posY - xyOffset.GetY());
|
|
}
|
|
|
|
result += "\r\n";
|
|
|
|
result += string_format("Texture Coordinates:\r\n");
|
|
result += string_format("\t S T Q U V\r\n");
|
|
for(unsigned int i = 0; i < 3; i++)
|
|
{
|
|
auto vertex = vertices[i];
|
|
auto st = make_convertible<CGSHandler::ST>(vertex.st);
|
|
auto rgbaq = make_convertible<CGSHandler::RGBAQ>(vertex.rgbaq);
|
|
auto uv = make_convertible<CGSHandler::UV>(vertex.uv);
|
|
result += string_format("\tVertex %i: %+10.4f %+10.4f %+10.4f %+10.4f %+10.4f\r\n",
|
|
i, st.nS, st.nT, rgbaq.nQ, uv.GetU(), uv.GetV());
|
|
}
|
|
|
|
result += string_format("Color:\r\n");
|
|
result += string_format("\t R G B A\r\n");
|
|
for(unsigned int i = 0; i < 3; i++)
|
|
{
|
|
auto vertex = vertices[i];
|
|
auto rgbaq = make_convertible<CGSHandler::RGBAQ>(vertex.rgbaq);
|
|
result += string_format("\tVertex %i: 0x%02X 0x%02X 0x%02X 0x%02X\r\n",
|
|
i, rgbaq.nR, rgbaq.nG, rgbaq.nB, rgbaq.nA);
|
|
}
|
|
|
|
result += string_format("Fog:\r\n");
|
|
result += string_format("\t F\r\n");
|
|
for(unsigned int i = 0; i < 3; i++)
|
|
{
|
|
auto vertex = vertices[i];
|
|
result += string_format("\tVertex %i: 0x%02X\r\n",
|
|
i, vertex.fog);
|
|
}
|
|
|
|
result += "\r\n";
|
|
|
|
auto colClamp = gs->GetRegisters()[GS_REG_COLCLAMP];
|
|
result += string_format("Color Clamping: %s\r\n", g_colorClampModeString[colClamp & 1]);
|
|
|
|
auto scanMsk = gs->GetRegisters()[GS_REG_SCANMSK];
|
|
result += string_format("Scan Mask: %s\r\n", g_scanMaskModeString[scanMsk & 3]);
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string CGsStateUtils::GetContextState(CGSHandler* gs, unsigned int contextId)
|
|
{
|
|
std::string result;
|
|
|
|
{
|
|
auto frame = make_convertible<CGSHandler::FRAME>(gs->GetRegisters()[GS_REG_FRAME_1 + contextId]);
|
|
result += string_format("Frame Buffer:\r\n");
|
|
result += string_format("\tPtr: 0x%08X\r\n", frame.GetBasePtr());
|
|
result += string_format("\tWidth: %d\r\n", frame.GetWidth());
|
|
result += string_format("\tFormat: %s\r\n", g_pixelFormats[frame.nPsm]);
|
|
result += string_format("\tWrite Mask: 0x%08X\r\n", ~frame.nMask);
|
|
}
|
|
|
|
{
|
|
auto zbuf = make_convertible<CGSHandler::ZBUF>(gs->GetRegisters()[GS_REG_ZBUF_1 + contextId]);
|
|
result += string_format("Depth Buffer:\r\n");
|
|
result += string_format("\tPtr: 0x%08X\r\n", zbuf.GetBasePtr());
|
|
result += string_format("\tFormat: %s\r\n", g_pixelFormats[zbuf.nPsm | 0x30]);
|
|
result += string_format("\tWrite Enabled: %s\r\n", g_yesNoString[(zbuf.nMask == 0)]);
|
|
}
|
|
|
|
{
|
|
auto tex0 = make_convertible<CGSHandler::TEX0>(gs->GetRegisters()[GS_REG_TEX0_1 + contextId]);
|
|
auto tex1 = make_convertible<CGSHandler::TEX1>(gs->GetRegisters()[GS_REG_TEX1_1 + contextId]);
|
|
result += string_format("Texture:\r\n");
|
|
result += string_format("\tPtr: 0x%08X\r\n", tex0.GetBufPtr());
|
|
result += string_format("\tBuffer Width: %d\r\n", tex0.GetBufWidth());
|
|
result += string_format("\tFormat: %s\r\n", g_pixelFormats[tex0.nPsm]);
|
|
result += string_format("\tWidth: %d\r\n", tex0.GetWidth());
|
|
result += string_format("\tHeight: %d\r\n", tex0.GetHeight());
|
|
result += string_format("\tHas Alpha Component: %s\r\n", g_yesNoString[tex0.nColorComp]);
|
|
result += string_format("\tFunction: %s\r\n", g_textureFunctionString[tex0.nFunction]);
|
|
result += string_format("\tCLUT Ptr: 0x%08X\r\n", tex0.GetCLUTPtr());
|
|
result += string_format("\tCLUT Format: %s\r\n", g_pixelFormats[tex0.nCPSM]);
|
|
result += string_format("\tCLUT Storage Mode: %d\r\n", tex0.nCSM + 1);
|
|
result += string_format("\tCLUT Entry Offset: %d\r\n", tex0.nCSA * 16);
|
|
result += string_format("\tCLUT Load Control: %s\r\n", g_textureClutLoadControlString[tex0.nCLD]);
|
|
result += string_format("\tLOD Use Fixed Value: %s\r\n", g_yesNoString[tex1.nLODMethod]);
|
|
result += string_format("\tMaximum Mip Level: %d\r\n", tex1.nMaxMip);
|
|
result += string_format("\tMag Filter: %s\r\n", g_textureMagFilterString[tex1.nMagFilter]);
|
|
result += string_format("\tMin Filter: %s\r\n", g_textureMinFilterString[tex1.nMinFilter]);
|
|
result += string_format("\tUse Automatic Mip Address: %s\r\n", g_yesNoString[tex1.nMipBaseAddr]);
|
|
result += string_format("\tLOD L: %d\r\n", tex1.nLODL);
|
|
result += string_format("\tLOD K: %f\r\n", tex1.GetK());
|
|
}
|
|
|
|
{
|
|
auto miptbp1 = make_convertible<CGSHandler::MIPTBP1>(gs->GetRegisters()[GS_REG_MIPTBP1_1 + contextId]);
|
|
auto miptbp2 = make_convertible<CGSHandler::MIPTBP2>(gs->GetRegisters()[GS_REG_MIPTBP2_1 + contextId]);
|
|
result += string_format("Mipmap:\r\n");
|
|
result += string_format("\tLevel 1: 0x%08X, %d\r\n", miptbp1.GetTbp1(), miptbp1.GetTbw1());
|
|
result += string_format("\tLevel 2: 0x%08X, %d\r\n", miptbp1.GetTbp2(), miptbp1.GetTbw2());
|
|
result += string_format("\tLevel 3: 0x%08X, %d\r\n", miptbp1.GetTbp3(), miptbp1.GetTbw3());
|
|
result += string_format("\tLevel 4: 0x%08X, %d\r\n", miptbp2.GetTbp4(), miptbp2.GetTbw4());
|
|
result += string_format("\tLevel 5: 0x%08X, %d\r\n", miptbp2.GetTbp5(), miptbp2.GetTbw5());
|
|
result += string_format("\tLevel 6: 0x%08X, %d\r\n", miptbp2.GetTbp6(), miptbp2.GetTbw6());
|
|
}
|
|
|
|
{
|
|
auto texA = make_convertible<CGSHandler::TEXA>(gs->GetRegisters()[GS_REG_TEXA]);
|
|
result += string_format("Texture Alpha:\r\n");
|
|
result += string_format("\tAlpha 0: 0x%02X\r\n", texA.nTA0);
|
|
result += string_format("\tAlpha 1: 0x%02X\r\n", texA.nTA1);
|
|
result += string_format("\tBlack Is Transparent: %s\r\n", g_yesNoString[texA.nAEM]);
|
|
}
|
|
|
|
{
|
|
auto clamp = make_convertible<CGSHandler::CLAMP>(gs->GetRegisters()[GS_REG_CLAMP_1 + contextId]);
|
|
result += string_format("Clamp:\r\n");
|
|
result += string_format("\tWrap Mode S: %s\r\n", g_wrapModeString[clamp.nWMS]);
|
|
result += string_format("\tWrap Mode T: %s\r\n", g_wrapModeString[clamp.nWMT]);
|
|
result += string_format("\tMin U / U Mask: %4d / 0x%03X\r\n", clamp.GetMinU(), clamp.GetMinU());
|
|
result += string_format("\tMax U / U Fix : %4d / 0x%03X\r\n", clamp.GetMaxU(), clamp.GetMaxU());
|
|
result += string_format("\tMin V / V Mask: %4d / 0x%03X\r\n", clamp.GetMinV(), clamp.GetMinV());
|
|
result += string_format("\tMax V / V Fix : %4d / 0x%03X\r\n", clamp.GetMaxV(), clamp.GetMaxV());
|
|
}
|
|
|
|
{
|
|
auto test = make_convertible<CGSHandler::TEST>(gs->GetRegisters()[GS_REG_TEST_1 + contextId]);
|
|
|
|
result += string_format("Depth Testing:\r\n");
|
|
result += string_format("\tEnabled: %s\r\n", g_yesNoString[test.nDepthEnabled]);
|
|
result += string_format("\tFunction: %s\r\n", g_depthTestFunctionString[test.nDepthMethod]);
|
|
|
|
result += string_format("Alpha Testing:\r\n");
|
|
result += string_format("\tEnabled: %s\r\n", g_yesNoString[test.nAlphaEnabled]);
|
|
result += string_format("\tFunction: %s\r\n", g_alphaTestFunctionString[test.nAlphaMethod]);
|
|
result += string_format("\tRef Value: 0x%02X\r\n", test.nAlphaRef);
|
|
result += string_format("\tFail Op: %s\r\n", g_alphaTestFailOpString[test.nAlphaFail]);
|
|
|
|
result += string_format("Destination Alpha Testing:\r\n");
|
|
result += string_format("\tEnabled: %s\r\n", g_yesNoString[test.nDestAlphaEnabled]);
|
|
result += string_format("\tPassing Value: %d\r\n", test.nDestAlphaMode);
|
|
}
|
|
|
|
{
|
|
auto alpha = make_convertible<CGSHandler::ALPHA>(gs->GetRegisters()[GS_REG_ALPHA_1 + contextId]);
|
|
result += string_format("Alpha Blending:\r\n");
|
|
result += string_format("\tA: %d, B: %d, C: %d, D: %d\r\n", alpha.nA, alpha.nB, alpha.nC, alpha.nD);
|
|
result += string_format("\tFormula: (%s - %s) * %s + %s\r\n",
|
|
g_alphaBlendAbdCoefString[alpha.nA], g_alphaBlendAbdCoefString[alpha.nB],
|
|
g_alphaBlendCCoefString[alpha.nC], g_alphaBlendAbdCoefString[alpha.nD]);
|
|
result += string_format("\tFixed Value: 0x%02X\r\n", alpha.nFix);
|
|
}
|
|
|
|
{
|
|
auto scissor = make_convertible<CGSHandler::SCISSOR>(gs->GetRegisters()[GS_REG_SCISSOR_1 + contextId]);
|
|
result += string_format("Scissor:\r\n");
|
|
result += string_format("\tTop: %d, %d\r\n", scissor.scax0, scissor.scay0);
|
|
result += string_format("\tBottom: %d, %d\r\n", scissor.scax1, scissor.scay1);
|
|
}
|
|
|
|
result += "\r\n";
|
|
|
|
return result;
|
|
}
|