mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 15:30:35 +00:00
c5844c4174
This way you can break when a register is changed and prim count is in a certain range, which can be convenient.
1084 lines
38 KiB
C++
1084 lines
38 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#include "Common/Log.h"
|
|
#include "Common/Math/expression_parser.h"
|
|
#include "Core/Debugger/SymbolMap.h"
|
|
#include "GPU/Common/GPUDebugInterface.h"
|
|
#include "GPU/Debugger/Debugger.h"
|
|
#include "GPU/Debugger/GECommandTable.h"
|
|
#include "GPU/GPUState.h"
|
|
|
|
enum class GEReferenceIndex : uint32_t {
|
|
VADDR = 0x100,
|
|
IADDR,
|
|
OFFSET,
|
|
PC,
|
|
STALL,
|
|
BFLAG,
|
|
OP,
|
|
DATA,
|
|
CLUTADDR,
|
|
TRANSFERSRC,
|
|
TRANSFERDST,
|
|
PRIMCOUNT,
|
|
LASTPRIMCOUNT,
|
|
|
|
TEXADDR0,
|
|
TEXADDR1,
|
|
TEXADDR2,
|
|
TEXADDR3,
|
|
TEXADDR4,
|
|
TEXADDR5,
|
|
TEXADDR6,
|
|
TEXADDR7,
|
|
|
|
BONE_MATRIX = 0x200,
|
|
WORLD_MATRIX = 0x260,
|
|
VIEW_MATRIX = 0x26C,
|
|
PROJ_MATRIX = 0x278,
|
|
TGEN_MATRIX = 0x288,
|
|
MATRIX_END = 0x294,
|
|
|
|
FIELD_START = 0x1000,
|
|
FIELD_END = 0xFF000,
|
|
};
|
|
ENUM_CLASS_BITOPS(GEReferenceIndex);
|
|
|
|
struct ReferenceName {
|
|
GEReferenceIndex index;
|
|
const char *name;
|
|
};
|
|
|
|
static constexpr ReferenceName referenceNames[] = {
|
|
{ GEReferenceIndex::VADDR, "vaddr" },
|
|
{ GEReferenceIndex::IADDR, "iaddr" },
|
|
{ GEReferenceIndex::OFFSET, "offset" },
|
|
{ GEReferenceIndex::PC, "pc" },
|
|
{ GEReferenceIndex::STALL, "stall" },
|
|
{ GEReferenceIndex::BFLAG, "bflag" },
|
|
{ GEReferenceIndex::BFLAG, "boundflag" },
|
|
{ GEReferenceIndex::OP, "op" },
|
|
{ GEReferenceIndex::DATA, "data" },
|
|
{ GEReferenceIndex::CLUTADDR, "clutaddr" },
|
|
{ GEReferenceIndex::TRANSFERSRC, "transfersrc" },
|
|
{ GEReferenceIndex::TRANSFERDST, "transferdst" },
|
|
{ GEReferenceIndex::PRIMCOUNT, "primcount" },
|
|
{ GEReferenceIndex::LASTPRIMCOUNT, "lastprimcount" },
|
|
{ GEReferenceIndex::TEXADDR0, "texaddr0" },
|
|
{ GEReferenceIndex::TEXADDR1, "texaddr1" },
|
|
{ GEReferenceIndex::TEXADDR2, "texaddr2" },
|
|
{ GEReferenceIndex::TEXADDR3, "texaddr3" },
|
|
{ GEReferenceIndex::TEXADDR4, "texaddr4" },
|
|
{ GEReferenceIndex::TEXADDR5, "texaddr5" },
|
|
{ GEReferenceIndex::TEXADDR6, "texaddr6" },
|
|
{ GEReferenceIndex::TEXADDR7, "texaddr7" },
|
|
};
|
|
|
|
enum class GECmdField : uint8_t {
|
|
DATA, // Alias for the entire data.
|
|
LOW_FLAG,
|
|
LOW_U2,
|
|
LOW_U4,
|
|
LOW_U7,
|
|
LOW_U8,
|
|
LOW_U10,
|
|
LOW_U10_P1,
|
|
LOW_U11,
|
|
LOW_U16,
|
|
MID_U8,
|
|
MID_U10, // At 10, 10 bits.
|
|
MID_U10_P1, // At 10, 10 bits (add 1 to value.)
|
|
TOP_U8,
|
|
FLAG_AFTER_1, // At 1, 1 bit.
|
|
FLAG_AFTER_2, // At 2, 1 bit.
|
|
FLAG_AFTER_8, // At 8, 1 bit.
|
|
FLAG_AFTER_9, // At 9, 1 bit.
|
|
FLAG_AFTER_10, // At 10, 1 bit.
|
|
FLAG_AFTER_11, // At 11, 1 bit.
|
|
FLAG_AFTER_16, // At 16, 1 bit.
|
|
FLAG_AFTER_17, // At 17, 1 bit.
|
|
FLAG_AFTER_18, // At 18, 1 bit.
|
|
FLAG_AFTER_19, // At 19, 1 bit.
|
|
FLAG_AFTER_20, // At 20, 1 bit.
|
|
FLAG_AFTER_21, // At 21, 1 bit.
|
|
FLAG_AFTER_22, // At 22, 1 bit.
|
|
FLAG_AFTER_23, // At 23, 1 bit.
|
|
U2_AFTER_8, // At 8, 2 bits.
|
|
U3_AFTER_16, // At 16, 3 bits.
|
|
U12_AFTER_4, // At 4, 12 bits.
|
|
PRIM_TYPE, // At 16, 3 bits.
|
|
SIGNAL_TYPE, // At 16, 8 bits.
|
|
VTYPE_TC, // At 0, 2 bits.
|
|
VTYPE_COL, // At 2, 3 bits.
|
|
VTYPE_NRM, // At 5, 2 bits.
|
|
VTYPE_POS, // At 7, 2 bits.
|
|
VTYPE_WEIGHTTYPE, // At 9, 2 bits.
|
|
VTYPE_INDEX, // At 11, 2 bits.
|
|
VTYPE_WEIGHTCOUNT, // At 14, 3 bits.
|
|
VTYPE_MORPHCOUNT, // At 18, 3 bits.
|
|
PATCH_PRIM_TYPE, // At 0, 2 bits.
|
|
LIGHT_COMP, // At 0, 2 bits.
|
|
LIGHT_TYPE, // At 8, 2 bits.
|
|
LIGHT_TYPE_SPECULAR, // 1 if comp is 1 (but not 3.)
|
|
HIGH_ADDR, // At 16, 8 bits moved left to top 8 bits.
|
|
TEX_W, // At 0, 4 bits - 1 to this power.
|
|
TEX_H, // At 8, 4 bits - 1 to this power.
|
|
UVGEN_TYPE, // At 0, 2 bits.
|
|
UVGEN_PROJ, // At 8, 2 bits.
|
|
TEX_FORMAT, // At 0, 4 bits.
|
|
TEX_MINFILTER, // At 0, 3 bits.
|
|
TEX_MAGFILTER, // At 8, 1 bit.
|
|
TEX_LEVEL_MODE, // At 0, 2 bits.
|
|
LOW_U12_4_FLOAT, // At 0, 12.4 converted to float.
|
|
HIGH_S4_4_FLOAT, // At 16, s.3.4 converted to float.
|
|
TEX_FUNC, // At 0, 3 bits.
|
|
CLUT_BYTES, // At 0, 6 bits, multiplied by 8.
|
|
CLUT_FORMAT, // At 0, 2 bits.
|
|
CLUT_SHIFT, // At 2, 5 bits.
|
|
CLUT_OFFSET, // At 16, 5 bits, multiplied by 16.
|
|
COMPARE_FUNC2, // At 0, 2 bits.
|
|
COMPARE_FUNC3, // At 0, 3 bits.
|
|
STENCIL_OP_AT_0, // At 0, 3 bits.
|
|
STENCIL_OP_AT_8, // At 8, 3 bits.
|
|
STENCIL_OP_AT_16, // At 16, 3 bits.
|
|
BLEND_SRC, // At 0, 4 bits.
|
|
BLEND_DST, // At 4, 4 bits.
|
|
BLEND_EQUATION, // At 8, 3 bits.
|
|
LOGIC_OP, // At 0, 4 bits.
|
|
};
|
|
|
|
struct FieldName {
|
|
GECmdFormat fmt;
|
|
GECmdField field;
|
|
const char *name;
|
|
};
|
|
|
|
static constexpr FieldName fieldNames[] = {
|
|
{ GECmdFormat::PRIM, GECmdField::LOW_U16, "count" },
|
|
{ GECmdFormat::PRIM, GECmdField::PRIM_TYPE, "type" },
|
|
{ GECmdFormat::BEZIER, GECmdField::LOW_U8, "ucount" },
|
|
{ GECmdFormat::BEZIER, GECmdField::LOW_U8, "u" },
|
|
{ GECmdFormat::BEZIER, GECmdField::MID_U8, "vcount" },
|
|
{ GECmdFormat::BEZIER, GECmdField::MID_U8, "v" },
|
|
{ GECmdFormat::SPLINE, GECmdField::LOW_U8, "ucount" },
|
|
{ GECmdFormat::SPLINE, GECmdField::LOW_U8, "u" },
|
|
{ GECmdFormat::SPLINE, GECmdField::MID_U8, "vcount" },
|
|
{ GECmdFormat::SPLINE, GECmdField::MID_U8, "v" },
|
|
{ GECmdFormat::SPLINE, GECmdField::FLAG_AFTER_16, "ufirstopen" },
|
|
{ GECmdFormat::SPLINE, GECmdField::FLAG_AFTER_17, "ulastopen" },
|
|
{ GECmdFormat::SPLINE, GECmdField::FLAG_AFTER_18, "vfirstopen" },
|
|
{ GECmdFormat::SPLINE, GECmdField::FLAG_AFTER_19, "vlastopen" },
|
|
{ GECmdFormat::SIGNAL, GECmdField::LOW_U16, "data" },
|
|
{ GECmdFormat::SIGNAL, GECmdField::SIGNAL_TYPE, "type" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_TC, "texcoord" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_TC, "tc" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_COL, "col" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_COL, "color" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_NRM, "normal" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_POS, "pos" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_POS, "position" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTTYPE, "weighttype" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTTYPE, "weight" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_INDEX, "index" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTCOUNT, "weightcount" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_MORPHCOUNT, "morphcount" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::FLAG_AFTER_23, "through" },
|
|
{ GECmdFormat::VERTEX_TYPE, GECmdField::FLAG_AFTER_23, "throughmode" },
|
|
{ GECmdFormat::X10_Y10, GECmdField::LOW_U10, "x" },
|
|
{ GECmdFormat::X10_Y10, GECmdField::MID_U10, "y" },
|
|
{ GECmdFormat::X10_Y10, GECmdField::LOW_U10_P1, "w" },
|
|
{ GECmdFormat::X10_Y10, GECmdField::MID_U10_P1, "h" },
|
|
{ GECmdFormat::FLAG, GECmdField::LOW_FLAG, "flag" },
|
|
{ GECmdFormat::BONE_NUM, GECmdField::LOW_U7, "num" },
|
|
{ GECmdFormat::MATRIX_NUM, GECmdField::LOW_U4, "num" },
|
|
{ GECmdFormat::FLOAT, GECmdField::DATA, "data" },
|
|
{ GECmdFormat::PATCH_DIVISION, GECmdField::LOW_U8, "u" },
|
|
{ GECmdFormat::PATCH_DIVISION, GECmdField::MID_U8, "v" },
|
|
{ GECmdFormat::PATCH_PRIM, GECmdField::PATCH_PRIM_TYPE, "type" },
|
|
{ GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "frac" },
|
|
{ GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "sub" },
|
|
{ GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "subpixels" },
|
|
{ GECmdFormat::SUBPIXEL_COORD, GECmdField::U12_AFTER_4, "int" },
|
|
{ GECmdFormat::SUBPIXEL_COORD, GECmdField::U12_AFTER_4, "integer" },
|
|
{ GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U12_4_FLOAT, "pixels" },
|
|
{ GECmdFormat::MATERIAL_UPDATE, GECmdField::LOW_FLAG, "ambient" },
|
|
{ GECmdFormat::MATERIAL_UPDATE, GECmdField::FLAG_AFTER_1, "diffuse" },
|
|
{ GECmdFormat::MATERIAL_UPDATE, GECmdField::FLAG_AFTER_2, "specular" },
|
|
{ GECmdFormat::RGB, GECmdField::LOW_U8, "r" },
|
|
{ GECmdFormat::RGB, GECmdField::LOW_U8, "red" },
|
|
{ GECmdFormat::RGB, GECmdField::MID_U8, "g" },
|
|
{ GECmdFormat::RGB, GECmdField::MID_U8, "green" },
|
|
{ GECmdFormat::RGB, GECmdField::TOP_U8, "b" },
|
|
{ GECmdFormat::RGB, GECmdField::TOP_U8, "blue" },
|
|
{ GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_COMP, "computation" },
|
|
{ GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_TYPE, "type" },
|
|
{ GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_TYPE_SPECULAR, "specular" },
|
|
{ GECmdFormat::STRIDE, GECmdField::LOW_U11, "stride" },
|
|
{ GECmdFormat::STRIDE_HIGH_ADDR, GECmdField::HIGH_ADDR, "highaddr" },
|
|
{ GECmdFormat::HIGH_ADDR, GECmdField::HIGH_ADDR, "highaddr" },
|
|
{ GECmdFormat::HIGH_ADDR_ONLY, GECmdField::HIGH_ADDR, "highaddr" },
|
|
{ GECmdFormat::TEX_SIZE, GECmdField::TEX_W, "w" },
|
|
{ GECmdFormat::TEX_SIZE, GECmdField::TEX_W, "width" },
|
|
{ GECmdFormat::TEX_SIZE, GECmdField::TEX_H, "h" },
|
|
{ GECmdFormat::TEX_SIZE, GECmdField::TEX_H, "height" },
|
|
{ GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_TYPE, "type" },
|
|
{ GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_TYPE, "uv" },
|
|
{ GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_PROJ, "proj" },
|
|
{ GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_PROJ, "factor" },
|
|
{ GECmdFormat::TEX_LIGHT_SRC, GECmdField::LOW_U2, "u" },
|
|
{ GECmdFormat::TEX_LIGHT_SRC, GECmdField::U2_AFTER_8, "v" },
|
|
{ GECmdFormat::TEX_MODE, GECmdField::LOW_FLAG, "swizzle" },
|
|
{ GECmdFormat::TEX_MODE, GECmdField::FLAG_AFTER_8, "separateclut" },
|
|
{ GECmdFormat::TEX_MODE, GECmdField::FLAG_AFTER_8, "separate" },
|
|
{ GECmdFormat::TEX_MODE, GECmdField::U3_AFTER_16, "maxlevel" },
|
|
{ GECmdFormat::TEX_MODE, GECmdField::U3_AFTER_16, "level" },
|
|
{ GECmdFormat::TEX_FORMAT, GECmdField::TEX_FORMAT, "format" },
|
|
{ GECmdFormat::TEX_FORMAT, GECmdField::TEX_FORMAT, "fmt" },
|
|
{ GECmdFormat::TEX_FORMAT, GECmdField::FLAG_AFTER_2, "indexed" },
|
|
{ GECmdFormat::TEX_FILTER, GECmdField::TEX_MINFILTER, "min" },
|
|
{ GECmdFormat::TEX_FILTER, GECmdField::TEX_MINFILTER, "minify" },
|
|
{ GECmdFormat::TEX_FILTER, GECmdField::TEX_MAGFILTER, "mag" },
|
|
{ GECmdFormat::TEX_FILTER, GECmdField::TEX_MAGFILTER, "magnify" },
|
|
{ GECmdFormat::TEX_CLAMP, GECmdField::LOW_FLAG, "s" },
|
|
{ GECmdFormat::TEX_CLAMP, GECmdField::FLAG_AFTER_8, "t" },
|
|
{ GECmdFormat::TEX_LEVEL_MODE, GECmdField::TEX_LEVEL_MODE, "mode" },
|
|
{ GECmdFormat::TEX_LEVEL_MODE, GECmdField::HIGH_S4_4_FLOAT, "bias" },
|
|
{ GECmdFormat::TEX_FUNC, GECmdField::TEX_FUNC, "func" },
|
|
{ GECmdFormat::TEX_FUNC, GECmdField::TEX_FUNC, "function" },
|
|
{ GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_8, "alpha" },
|
|
{ GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_8, "a" },
|
|
{ GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_16, "double" },
|
|
{ GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_16, "doubling" },
|
|
{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_FORMAT, "format" },
|
|
{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_FORMAT, "fmt" },
|
|
{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_SHIFT, "shift" },
|
|
{ GECmdFormat::CLUT_FORMAT, GECmdField::MID_U8, "mask" },
|
|
{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_OFFSET, "offset" },
|
|
{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_OFFSET, "base" },
|
|
{ GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "on" },
|
|
{ GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "enable" },
|
|
{ GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "flag" },
|
|
{ GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_8, "color" },
|
|
{ GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_9, "alpha" },
|
|
{ GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_9, "stencil" },
|
|
{ GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_10, "depth" },
|
|
{ GECmdFormat::COLOR_TEST_FUNC, GECmdField::COMPARE_FUNC2, "func" },
|
|
{ GECmdFormat::ALPHA_TEST, GECmdField::COMPARE_FUNC3, "func" },
|
|
{ GECmdFormat::ALPHA_TEST, GECmdField::MID_U8, "ref" },
|
|
{ GECmdFormat::ALPHA_TEST, GECmdField::MID_U8, "reference" },
|
|
{ GECmdFormat::ALPHA_TEST, GECmdField::TOP_U8, "mask" },
|
|
{ GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_0, "sfail" },
|
|
{ GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_8, "zfail" },
|
|
{ GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_16, "zpass" },
|
|
{ GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_16, "pass" },
|
|
{ GECmdFormat::DEPTH_TEST_FUNC, GECmdField::COMPARE_FUNC3, "func" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_SRC, "src" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_SRC, "srcfactor" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dst" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dstfactor" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dest" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "destfactor" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "eq" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "equation" },
|
|
{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "mode" },
|
|
{ GECmdFormat::LOGIC_OP, GECmdField::LOGIC_OP, "op" },
|
|
{ GECmdFormat::LOGIC_OP, GECmdField::LOGIC_OP, "mode" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::LOW_U8, "alpha" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::PRIM_TYPE, "type" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::PRIM_TYPE, "prim" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_11, "antialias" },
|
|
// TODO: Clip bits?
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_18, "shading" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_18, "gouraud" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_19, "cull" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_20, "cullccw" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_21, "tex" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_22, "fog" },
|
|
{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_23, "dither" },
|
|
};
|
|
|
|
struct GECmdConstant {
|
|
const char *name;
|
|
uint32_t value;
|
|
};
|
|
|
|
// TODO: It would be nice if these were somehow typed...
|
|
static constexpr GECmdConstant constantNames[] = {
|
|
{ "GE_PRIM_POINTS", GE_PRIM_POINTS },
|
|
{ "GE_PRIM_LINES", GE_PRIM_LINES },
|
|
{ "GE_PRIM_LINE_STRIP", GE_PRIM_LINE_STRIP },
|
|
{ "GE_PRIM_TRIANGLES", GE_PRIM_TRIANGLES },
|
|
{ "GE_PRIM_TRIANGLE_STRIP", GE_PRIM_TRIANGLE_STRIP },
|
|
{ "GE_PRIM_TRIANGLE_FAN", GE_PRIM_TRIANGLE_FAN },
|
|
{ "GE_PRIM_RECTANGLES", GE_PRIM_RECTANGLES },
|
|
{ "GE_PRIM_KEEP_PREVIOUS", GE_PRIM_KEEP_PREVIOUS },
|
|
{ "POINTS", GE_PRIM_POINTS },
|
|
{ "LINES", GE_PRIM_LINES },
|
|
{ "LINE_STRIP", GE_PRIM_LINE_STRIP },
|
|
{ "TRIANGLES", GE_PRIM_TRIANGLES },
|
|
{ "TRIANGLE_STRIP", GE_PRIM_TRIANGLE_STRIP },
|
|
{ "TRIANGLE_FAN", GE_PRIM_TRIANGLE_FAN },
|
|
{ "RECTANGLES", GE_PRIM_RECTANGLES },
|
|
{ "SPRITES", GE_PRIM_RECTANGLES },
|
|
{ "KEEP_PREVIOUS", GE_PRIM_KEEP_PREVIOUS },
|
|
{ "CONTINUE", GE_PRIM_KEEP_PREVIOUS },
|
|
{ "GE_PATCHPRIM_TRIANGLES", GE_PATCHPRIM_TRIANGLES, },
|
|
{ "GE_PATCHPRIM_LINES", GE_PATCHPRIM_LINES, },
|
|
{ "GE_PATCHPRIM_POINTS", GE_PATCHPRIM_POINTS, },
|
|
{ "GE_SIGNAL_NONE", PSP_GE_SIGNAL_NONE },
|
|
{ "GE_SIGNAL_HANDLER_SUSPEND", PSP_GE_SIGNAL_HANDLER_SUSPEND },
|
|
{ "GE_SIGNAL_HANDLER_CONTINUE", PSP_GE_SIGNAL_HANDLER_CONTINUE },
|
|
{ "GE_SIGNAL_HANDLER_PAUSE", PSP_GE_SIGNAL_HANDLER_PAUSE },
|
|
{ "GE_SIGNAL_SYNC", PSP_GE_SIGNAL_SYNC },
|
|
{ "GE_SIGNAL_JUMP", PSP_GE_SIGNAL_JUMP },
|
|
{ "GE_SIGNAL_CALL", PSP_GE_SIGNAL_CALL },
|
|
{ "GE_SIGNAL_RET", PSP_GE_SIGNAL_RET },
|
|
{ "GE_SIGNAL_RJUMP", PSP_GE_SIGNAL_RJUMP },
|
|
{ "GE_SIGNAL_RCALL", PSP_GE_SIGNAL_RCALL },
|
|
{ "GE_SIGNAL_OJUMP", PSP_GE_SIGNAL_OJUMP },
|
|
{ "GE_SIGNAL_OCALL", PSP_GE_SIGNAL_OCALL },
|
|
{ "GE_VTYPE_TC_NONE", GE_VTYPE_TC_NONE >> GE_VTYPE_TC_SHIFT },
|
|
{ "GE_VTYPE_TC_8BIT", GE_VTYPE_TC_8BIT >> GE_VTYPE_TC_SHIFT },
|
|
{ "GE_VTYPE_TC_16BIT", GE_VTYPE_TC_16BIT >> GE_VTYPE_TC_SHIFT },
|
|
{ "GE_VTYPE_TC_FLOAT", GE_VTYPE_TC_FLOAT >> GE_VTYPE_TC_SHIFT },
|
|
{ "GE_VTYPE_COL_NONE", GE_VTYPE_COL_NONE >> GE_VTYPE_COL_SHIFT },
|
|
{ "GE_VTYPE_COL_565", GE_VTYPE_COL_565 >> GE_VTYPE_COL_SHIFT },
|
|
{ "GE_VTYPE_COL_5650", GE_VTYPE_COL_565 >> GE_VTYPE_COL_SHIFT },
|
|
{ "GE_VTYPE_COL_5551", GE_VTYPE_COL_5551 >> GE_VTYPE_COL_SHIFT },
|
|
{ "GE_VTYPE_COL_4444", GE_VTYPE_COL_4444 >> GE_VTYPE_COL_SHIFT },
|
|
{ "GE_VTYPE_COL_8888", GE_VTYPE_COL_8888 >> GE_VTYPE_COL_SHIFT },
|
|
{ "GE_VTYPE_NRM_NONE", GE_VTYPE_NRM_NONE >> GE_VTYPE_NRM_SHIFT },
|
|
{ "GE_VTYPE_NRM_8BIT", GE_VTYPE_NRM_8BIT >> GE_VTYPE_NRM_SHIFT },
|
|
{ "GE_VTYPE_NRM_16BIT", GE_VTYPE_NRM_16BIT >> GE_VTYPE_NRM_SHIFT },
|
|
{ "GE_VTYPE_NRM_FLOAT", GE_VTYPE_NRM_FLOAT >> GE_VTYPE_NRM_SHIFT },
|
|
{ "GE_VTYPE_POS_8BIT", GE_VTYPE_POS_8BIT >> GE_VTYPE_POS_SHIFT },
|
|
{ "GE_VTYPE_POS_16BIT", GE_VTYPE_POS_16BIT >> GE_VTYPE_POS_SHIFT },
|
|
{ "GE_VTYPE_POS_FLOAT", GE_VTYPE_POS_FLOAT >> GE_VTYPE_POS_SHIFT },
|
|
{ "GE_VTYPE_WEIGHT_NONE", GE_VTYPE_WEIGHT_NONE >> GE_VTYPE_WEIGHT_SHIFT },
|
|
{ "GE_VTYPE_WEIGHT_8BIT", GE_VTYPE_WEIGHT_8BIT >> GE_VTYPE_WEIGHT_SHIFT },
|
|
{ "GE_VTYPE_WEIGHT_16BIT", GE_VTYPE_WEIGHT_16BIT >> GE_VTYPE_WEIGHT_SHIFT },
|
|
{ "GE_VTYPE_WEIGHT_FLOAT", GE_VTYPE_WEIGHT_FLOAT >> GE_VTYPE_WEIGHT_SHIFT },
|
|
{ "GE_VTYPE_IDX_NONE", GE_VTYPE_IDX_NONE >> GE_VTYPE_IDX_SHIFT },
|
|
{ "GE_VTYPE_IDX_8BIT", GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT },
|
|
{ "GE_VTYPE_IDX_16BIT", GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT },
|
|
{ "GE_VTYPE_IDX_32BIT", GE_VTYPE_IDX_32BIT >> GE_VTYPE_IDX_SHIFT },
|
|
{ "GE_LIGHTCOMP_ONLYDIFFUSE", GE_LIGHTCOMP_ONLYDIFFUSE },
|
|
{ "GE_LIGHTCOMP_BOTH", GE_LIGHTCOMP_BOTH },
|
|
{ "GE_LIGHTCOMP_ONLYPOWDIFFUSE", GE_LIGHTCOMP_ONLYPOWDIFFUSE },
|
|
{ "GE_LIGHTTYPE_DIRECTIONAL", GE_LIGHTTYPE_DIRECTIONAL },
|
|
{ "GE_LIGHTTYPE_POINT", GE_LIGHTTYPE_POINT },
|
|
{ "GE_LIGHTTYPE_SPOT", GE_LIGHTTYPE_SPOT },
|
|
{ "GE_TEXMAP_TEXTURE_COORDS", GE_TEXMAP_TEXTURE_COORDS },
|
|
{ "GE_TEXMAP_TEXTURE_MATRIX", GE_TEXMAP_TEXTURE_MATRIX },
|
|
{ "GE_TEXMAP_ENVIRONMENT_MAP", GE_TEXMAP_ENVIRONMENT_MAP },
|
|
{ "GE_PROJMAP_POSITION", GE_PROJMAP_POSITION },
|
|
{ "GE_PROJMAP_UV", GE_PROJMAP_UV },
|
|
{ "GE_PROJMAP_NORMALIZED_NORMAL", GE_PROJMAP_NORMALIZED_NORMAL },
|
|
{ "GE_PROJMAP_NORMAL", GE_PROJMAP_NORMAL },
|
|
{ "GE_TFMT_565", GE_TFMT_5650 },
|
|
{ "GE_TFMT_5650", GE_TFMT_5650 },
|
|
{ "GE_TFMT_5551", GE_TFMT_5551 },
|
|
{ "GE_TFMT_4444", GE_TFMT_4444 },
|
|
{ "GE_TFMT_8888", GE_TFMT_8888 },
|
|
{ "GE_TFMT_CLUT4", GE_TFMT_CLUT4 },
|
|
{ "GE_TFMT_CLUT8", GE_TFMT_CLUT8 },
|
|
{ "GE_TFMT_CLUT16", GE_TFMT_CLUT16 },
|
|
{ "GE_TFMT_CLUT32", GE_TFMT_CLUT32 },
|
|
{ "GE_TFMT_DXT1", GE_TFMT_DXT1 },
|
|
{ "GE_TFMT_DXT3", GE_TFMT_DXT3 },
|
|
{ "GE_TFMT_DXT5", GE_TFMT_DXT5 },
|
|
{ "GE_CMODE_16BIT_BGR5650", GE_CMODE_16BIT_BGR5650 },
|
|
{ "GE_CMODE_16BIT_ABGR5551", GE_CMODE_16BIT_ABGR5551 },
|
|
{ "GE_CMODE_16BIT_ABGR4444", GE_CMODE_16BIT_ABGR4444 },
|
|
{ "GE_CMODE_32BIT_ABGR8888", GE_CMODE_32BIT_ABGR8888 },
|
|
{ "GE_TFILT_NEAREST", GE_TFILT_NEAREST },
|
|
{ "GE_TFILT_LINEAR", GE_TFILT_LINEAR },
|
|
{ "GE_TFILT_NEAREST_MIPMAP_NEAREST", GE_TFILT_NEAREST_MIPMAP_NEAREST },
|
|
{ "GE_TFILT_LINEAR_MIPMAP_NEAREST", GE_TFILT_LINEAR_MIPMAP_NEAREST },
|
|
{ "GE_TFILT_NEAREST_MIPMAP_LINEAR", GE_TFILT_NEAREST_MIPMAP_LINEAR },
|
|
{ "GE_TFILT_LINEAR_MIPMAP_LINEAR", GE_TFILT_LINEAR_MIPMAP_LINEAR },
|
|
{ "NEAREST", GE_TFILT_NEAREST },
|
|
{ "LINEAR", GE_TFILT_LINEAR },
|
|
{ "GE_TEXLEVEL_MODE_AUTO", GE_TEXLEVEL_MODE_AUTO },
|
|
{ "GE_TEXLEVEL_MODE_CONST", GE_TEXLEVEL_MODE_CONST },
|
|
{ "GE_TEXLEVEL_MODE_SLOPE", GE_TEXLEVEL_MODE_SLOPE },
|
|
{ "GE_TEXFUNC_MODULATE", GE_TEXFUNC_MODULATE },
|
|
{ "GE_TEXFUNC_DECAL", GE_TEXFUNC_DECAL },
|
|
{ "GE_TEXFUNC_BLEND", GE_TEXFUNC_BLEND },
|
|
{ "GE_TEXFUNC_REPLACE", GE_TEXFUNC_REPLACE },
|
|
{ "GE_TEXFUNC_ADD", GE_TEXFUNC_ADD },
|
|
{ "GE_COMP_NEVER", GE_COMP_NEVER },
|
|
{ "GE_COMP_ALWAYS", GE_COMP_ALWAYS },
|
|
{ "GE_COMP_EQUAL", GE_COMP_EQUAL },
|
|
{ "GE_COMP_NOTEQUAL", GE_COMP_NOTEQUAL },
|
|
{ "GE_COMP_LESS", GE_COMP_LESS },
|
|
{ "GE_COMP_LEQUAL", GE_COMP_LEQUAL },
|
|
{ "GE_COMP_GREATER", GE_COMP_GREATER },
|
|
{ "GE_COMP_GEQUAL", GE_COMP_GEQUAL },
|
|
{ "NEVER", GE_COMP_NEVER },
|
|
{ "ALWAYS", GE_COMP_ALWAYS },
|
|
{ "EQUAL", GE_COMP_EQUAL },
|
|
{ "NOTEQUAL", GE_COMP_NOTEQUAL },
|
|
{ "LESS", GE_COMP_LESS },
|
|
{ "LEQUAL", GE_COMP_LEQUAL },
|
|
{ "LESSEQUAL", GE_COMP_LEQUAL },
|
|
{ "GREATER", GE_COMP_GREATER },
|
|
{ "GEQUAL", GE_COMP_GEQUAL },
|
|
{ "GREATEREQUAL", GE_COMP_GEQUAL },
|
|
{ "GE_STENCILOP_KEEP", GE_STENCILOP_KEEP },
|
|
{ "GE_STENCILOP_ZERO", GE_STENCILOP_ZERO },
|
|
{ "GE_STENCILOP_REPLACE", GE_STENCILOP_REPLACE },
|
|
{ "GE_STENCILOP_INVERT", GE_STENCILOP_INVERT },
|
|
{ "GE_STENCILOP_INCR", GE_STENCILOP_INCR },
|
|
{ "GE_STENCILOP_DECR", GE_STENCILOP_DECR },
|
|
{ "GE_BLENDMODE_MUL_AND_ADD", GE_BLENDMODE_MUL_AND_ADD },
|
|
{ "GE_BLENDMODE_MUL_AND_SUBTRACT", GE_BLENDMODE_MUL_AND_SUBTRACT },
|
|
{ "GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE", GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE },
|
|
{ "GE_BLENDMODE_MIN", GE_BLENDMODE_MIN },
|
|
{ "GE_BLENDMODE_MAX", GE_BLENDMODE_MAX },
|
|
{ "GE_BLENDMODE_ABSDIFF", GE_BLENDMODE_ABSDIFF },
|
|
{ "ADD", GE_BLENDMODE_MUL_AND_ADD },
|
|
{ "SUBTRACT", GE_BLENDMODE_MUL_AND_SUBTRACT },
|
|
{ "SUBTRACT_REVERSE", GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE },
|
|
{ "MIN", GE_BLENDMODE_MIN },
|
|
{ "MAX", GE_BLENDMODE_MAX },
|
|
{ "ABSDIFF", GE_BLENDMODE_ABSDIFF },
|
|
{ "GE_SRCBLEND_DSTCOLOR", GE_SRCBLEND_DSTCOLOR },
|
|
{ "GE_SRCBLEND_INVDSTCOLOR", GE_SRCBLEND_INVDSTCOLOR },
|
|
{ "GE_SRCBLEND_SRCALPHA", GE_SRCBLEND_SRCALPHA },
|
|
{ "GE_SRCBLEND_INVSRCALPHA", GE_SRCBLEND_INVSRCALPHA },
|
|
{ "GE_SRCBLEND_DSTALPHA", GE_SRCBLEND_DSTALPHA },
|
|
{ "GE_SRCBLEND_INVDSTALPHA", GE_SRCBLEND_INVDSTALPHA },
|
|
{ "GE_SRCBLEND_DOUBLESRCALPHA", GE_SRCBLEND_DOUBLESRCALPHA },
|
|
{ "GE_SRCBLEND_DOUBLEINVSRCALPHA", GE_SRCBLEND_DOUBLEINVSRCALPHA },
|
|
{ "GE_SRCBLEND_DOUBLEDSTALPHA", GE_SRCBLEND_DOUBLEDSTALPHA },
|
|
{ "GE_SRCBLEND_DOUBLEINVDSTALPHA", GE_SRCBLEND_DOUBLEINVDSTALPHA },
|
|
{ "GE_SRCBLEND_FIXA", GE_SRCBLEND_FIXA },
|
|
{ "GE_DSTBLEND_SRCCOLOR", GE_DSTBLEND_SRCCOLOR },
|
|
{ "GE_DSTBLEND_INVSRCCOLOR", GE_DSTBLEND_INVSRCCOLOR },
|
|
{ "GE_DSTBLEND_SRCALPHA", GE_DSTBLEND_SRCALPHA },
|
|
{ "GE_DSTBLEND_INVSRCALPHA", GE_DSTBLEND_INVSRCALPHA },
|
|
{ "GE_DSTBLEND_DSTALPHA", GE_DSTBLEND_DSTALPHA },
|
|
{ "GE_DSTBLEND_INVDSTALPHA", GE_DSTBLEND_INVDSTALPHA },
|
|
{ "GE_DSTBLEND_DOUBLESRCALPHA", GE_DSTBLEND_DOUBLESRCALPHA },
|
|
{ "GE_DSTBLEND_DOUBLEINVSRCALPHA", GE_DSTBLEND_DOUBLEINVSRCALPHA },
|
|
{ "GE_DSTBLEND_DOUBLEDSTALPHA", GE_DSTBLEND_DOUBLEDSTALPHA },
|
|
{ "GE_DSTBLEND_DOUBLEINVDSTALPHA", GE_DSTBLEND_DOUBLEINVDSTALPHA },
|
|
{ "GE_DSTBLEND_FIXB", GE_DSTBLEND_FIXB },
|
|
{ "SRCALPHA", GE_SRCBLEND_SRCALPHA },
|
|
{ "INVSRCALPHA", GE_SRCBLEND_INVSRCALPHA },
|
|
{ "INVERSESRCALPHA", GE_SRCBLEND_INVSRCALPHA },
|
|
{ "DSTALPHA", GE_DSTBLEND_DSTALPHA },
|
|
{ "INVDSTALPHA", GE_DSTBLEND_INVDSTALPHA },
|
|
{ "DOUBLESRCALPHA", GE_DSTBLEND_DOUBLESRCALPHA },
|
|
{ "DOUBLEINVSRCALPHA", GE_DSTBLEND_DOUBLEINVSRCALPHA },
|
|
{ "DOUBLEDSTALPHA", GE_DSTBLEND_DOUBLEDSTALPHA },
|
|
{ "DOUBLEINVDSTALPHA", GE_DSTBLEND_DOUBLEINVDSTALPHA },
|
|
{ "FIXED", GE_DSTBLEND_FIXB },
|
|
{ "GE_LOGIC_CLEAR", GE_LOGIC_CLEAR },
|
|
{ "GE_LOGIC_AND", GE_LOGIC_AND },
|
|
{ "GE_LOGIC_AND_REVERSE", GE_LOGIC_AND_REVERSE },
|
|
{ "GE_LOGIC_COPY", GE_LOGIC_COPY },
|
|
{ "GE_LOGIC_AND_INVERTED", GE_LOGIC_AND_INVERTED },
|
|
{ "GE_LOGIC_NOOP", GE_LOGIC_NOOP },
|
|
{ "GE_LOGIC_XOR", GE_LOGIC_XOR },
|
|
{ "GE_LOGIC_OR", GE_LOGIC_OR },
|
|
{ "GE_LOGIC_NOR", GE_LOGIC_NOR },
|
|
{ "GE_LOGIC_EQUIV", GE_LOGIC_EQUIV },
|
|
{ "GE_LOGIC_INVERTED", GE_LOGIC_INVERTED },
|
|
{ "GE_LOGIC_OR_REVERSE", GE_LOGIC_OR_REVERSE },
|
|
{ "GE_LOGIC_COPY_INVERTED", GE_LOGIC_COPY_INVERTED },
|
|
{ "GE_LOGIC_OR_INVERTED", GE_LOGIC_OR_INVERTED },
|
|
{ "GE_LOGIC_NAND", GE_LOGIC_NAND },
|
|
{ "GE_LOGIC_SET", GE_LOGIC_SET },
|
|
};
|
|
|
|
class GEExpressionFunctions : public IExpressionFunctions {
|
|
public:
|
|
GEExpressionFunctions(GPUDebugInterface *gpu) : gpu_(gpu) {}
|
|
|
|
bool parseReference(char *str, uint32_t &referenceIndex) override;
|
|
bool parseSymbol(char *str, uint32_t &symbolValue) override;
|
|
uint32_t getReferenceValue(uint32_t referenceIndex) override;
|
|
ExpressionType getReferenceType(uint32_t referenceIndex) override;
|
|
bool getMemoryValue(uint32_t address, int size, uint32_t &dest, char *error) override;
|
|
|
|
private:
|
|
bool parseFieldReference(const char *ref, const char *field, uint32_t &referenceIndex);
|
|
uint32_t getFieldValue(GECmdFormat fmt, GECmdField field, uint32_t value);
|
|
ExpressionType getFieldType(GECmdFormat fmt, GECmdField field);
|
|
|
|
GPUDebugInterface *gpu_;
|
|
};
|
|
|
|
bool GEExpressionFunctions::parseReference(char *str, uint32_t &referenceIndex) {
|
|
// TODO: Support formats and a form of fields (i.e. vtype.throughmode.)
|
|
// For now, let's just support the register bits directly.
|
|
GECmdInfo info;
|
|
if (GECmdInfoByName(str, info)) {
|
|
referenceIndex = info.reg;
|
|
return true;
|
|
}
|
|
|
|
char *dot = strchr(str, '.');
|
|
if (dot != nullptr) {
|
|
*dot = '\0';
|
|
bool success = parseFieldReference(str, dot + 1, referenceIndex);
|
|
*dot = '.';
|
|
if (success)
|
|
return true;
|
|
}
|
|
|
|
// Also allow non-register references.
|
|
for (const auto &entry : referenceNames) {
|
|
if (strcasecmp(str, entry.name) == 0) {
|
|
referenceIndex = (uint32_t)entry.index;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// And matrix data. Maybe should allow column/row specification.
|
|
int subindex = -1;
|
|
int len = -1;
|
|
|
|
if (sscanf(str, "bone%i%n", &subindex, &len) == 1) {
|
|
if (len == strlen(str) && subindex < 96) {
|
|
referenceIndex = (uint32_t)GEReferenceIndex::BONE_MATRIX + subindex;
|
|
return true;
|
|
}
|
|
}
|
|
if (sscanf(str, "world%i%n", &subindex, &len) == 1) {
|
|
if (len == strlen(str) && subindex < 12) {
|
|
referenceIndex = (uint32_t)GEReferenceIndex::WORLD_MATRIX + subindex;
|
|
return true;
|
|
}
|
|
}
|
|
if (sscanf(str, "view%i%n", &subindex, &len) == 1) {
|
|
if (len == strlen(str) && subindex < 12) {
|
|
referenceIndex = (uint32_t)GEReferenceIndex::VIEW_MATRIX + subindex;
|
|
return true;
|
|
}
|
|
}
|
|
if (sscanf(str, "proj%i%n", &subindex, &len) == 1) {
|
|
if (len == strlen(str) && subindex < 16) {
|
|
referenceIndex = (uint32_t)GEReferenceIndex::PROJ_MATRIX + subindex;
|
|
return true;
|
|
}
|
|
}
|
|
if (sscanf(str, "tgen%i%n", &subindex, &len) == 1 || sscanf(str, "texgen%i%n", &subindex, &len) == 1) {
|
|
if (len == strlen(str) && subindex < 12) {
|
|
referenceIndex = (uint32_t)GEReferenceIndex::TGEN_MATRIX + subindex;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GEExpressionFunctions::parseFieldReference(const char *ref, const char *field, uint32_t &referenceIndex) {
|
|
GECmdInfo info;
|
|
if (!GECmdInfoByName(ref, info)) {
|
|
return false;
|
|
}
|
|
|
|
for (const auto &entry : fieldNames) {
|
|
if (entry.fmt == info.fmt && strcasecmp(field, entry.name) == 0) {
|
|
referenceIndex = (info.reg << 12) | (uint32_t)entry.field;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GEExpressionFunctions::parseSymbol(char *str, uint32_t &symbolValue) {
|
|
// Mainly useful for checking memory addresses and constants.
|
|
|
|
for (const auto &entry : constantNames) {
|
|
if (strcasecmp(str, entry.name) == 0) {
|
|
symbolValue = entry.value;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return g_symbolMap->GetLabelValue(str, symbolValue);
|
|
}
|
|
|
|
uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) {
|
|
GPUgstate state = gpu_->GetGState();
|
|
if (referenceIndex < 0x100) {
|
|
GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex)).fmt;
|
|
uint32_t value = state.cmdmem[referenceIndex];
|
|
if (fmt == GECmdFormat::FLOAT)
|
|
return value << 8;
|
|
return value & 0x00FFFFFF;
|
|
}
|
|
|
|
if (referenceIndex >= (uint32_t)GEReferenceIndex::FIELD_START && referenceIndex <= (uint32_t)GEReferenceIndex::FIELD_END) {
|
|
uint32_t value = state.cmdmem[referenceIndex >> 12] & 0x00FFFFFF;
|
|
GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex >> 12)).fmt;
|
|
return getFieldValue(fmt, GECmdField(referenceIndex & 0xFF), value);
|
|
}
|
|
|
|
// We return the matrix value as float bits, which gets interpreted correctly in the parser.
|
|
if (referenceIndex >= (uint32_t)GEReferenceIndex::BONE_MATRIX && referenceIndex < (uint32_t)GEReferenceIndex::MATRIX_END) {
|
|
float value;
|
|
if (referenceIndex >= (uint32_t)GEReferenceIndex::TGEN_MATRIX) {
|
|
value = state.tgenMatrix[referenceIndex - (uint32_t)GEReferenceIndex::TGEN_MATRIX];
|
|
} else if (referenceIndex >= (uint32_t)GEReferenceIndex::PROJ_MATRIX) {
|
|
value = state.projMatrix[referenceIndex - (uint32_t)GEReferenceIndex::PROJ_MATRIX];
|
|
} else if (referenceIndex >= (uint32_t)GEReferenceIndex::VIEW_MATRIX) {
|
|
value = state.viewMatrix[referenceIndex - (uint32_t)GEReferenceIndex::VIEW_MATRIX];
|
|
} else if (referenceIndex >= (uint32_t)GEReferenceIndex::WORLD_MATRIX) {
|
|
value = state.worldMatrix[referenceIndex - (uint32_t)GEReferenceIndex::WORLD_MATRIX];
|
|
} else {
|
|
value = state.boneMatrix[referenceIndex - (uint32_t)GEReferenceIndex::BONE_MATRIX];
|
|
}
|
|
|
|
uint32_t result;
|
|
memcpy(&result, &value, sizeof(result));
|
|
return result;
|
|
}
|
|
|
|
GEReferenceIndex ref = (GEReferenceIndex)referenceIndex;
|
|
DisplayList list;
|
|
switch (ref) {
|
|
case GEReferenceIndex::VADDR:
|
|
return gpu_->GetVertexAddress();
|
|
case GEReferenceIndex::IADDR:
|
|
return gpu_->GetIndexAddress();
|
|
case GEReferenceIndex::OFFSET:
|
|
// TODO: Should use an interface method, probably.
|
|
return gstate_c.offsetAddr;
|
|
case GEReferenceIndex::PC:
|
|
if (gpu_->GetCurrentDisplayList(list)) {
|
|
return list.pc;
|
|
}
|
|
return 0;
|
|
case GEReferenceIndex::STALL:
|
|
if (gpu_->GetCurrentDisplayList(list)) {
|
|
return list.stall;
|
|
}
|
|
return 0;
|
|
case GEReferenceIndex::BFLAG:
|
|
if (gpu_->GetCurrentDisplayList(list)) {
|
|
return list.bboxResult ? 1 : 0;
|
|
}
|
|
return 0;
|
|
case GEReferenceIndex::OP:
|
|
if (gpu_->GetCurrentDisplayList(list)) {
|
|
return Memory::Read_U32(list.pc);
|
|
}
|
|
return 0;
|
|
case GEReferenceIndex::DATA:
|
|
if (gpu_->GetCurrentDisplayList(list)) {
|
|
return Memory::Read_U32(list.pc) & 0x00FFFFFF;
|
|
}
|
|
return 0;
|
|
|
|
case GEReferenceIndex::CLUTADDR:
|
|
return state.getClutAddress();
|
|
|
|
case GEReferenceIndex::TRANSFERSRC:
|
|
return state.getTransferSrcAddress();
|
|
|
|
case GEReferenceIndex::TRANSFERDST:
|
|
return state.getTransferDstAddress();
|
|
|
|
case GEReferenceIndex::PRIMCOUNT:
|
|
return GPUDebug::PrimsThisFrame();
|
|
|
|
case GEReferenceIndex::LASTPRIMCOUNT:
|
|
return GPUDebug::PrimsLastFrame();
|
|
|
|
case GEReferenceIndex::TEXADDR0:
|
|
case GEReferenceIndex::TEXADDR1:
|
|
case GEReferenceIndex::TEXADDR2:
|
|
case GEReferenceIndex::TEXADDR3:
|
|
case GEReferenceIndex::TEXADDR4:
|
|
case GEReferenceIndex::TEXADDR5:
|
|
case GEReferenceIndex::TEXADDR6:
|
|
case GEReferenceIndex::TEXADDR7:
|
|
return state.getTextureAddress((int)ref - (int)GEReferenceIndex::TEXADDR0);
|
|
|
|
case GEReferenceIndex::BONE_MATRIX:
|
|
case GEReferenceIndex::WORLD_MATRIX:
|
|
case GEReferenceIndex::VIEW_MATRIX:
|
|
case GEReferenceIndex::PROJ_MATRIX:
|
|
case GEReferenceIndex::TGEN_MATRIX:
|
|
case GEReferenceIndex::MATRIX_END:
|
|
case GEReferenceIndex::FIELD_START:
|
|
case GEReferenceIndex::FIELD_END:
|
|
// Shouldn't have gotten here.
|
|
break;
|
|
}
|
|
|
|
_assert_msg_(false, "Invalid reference index");
|
|
return 0;
|
|
}
|
|
|
|
uint32_t GEExpressionFunctions::getFieldValue(GECmdFormat fmt, GECmdField field, uint32_t value) {
|
|
switch (field) {
|
|
case GECmdField::DATA:
|
|
return value;
|
|
case GECmdField::LOW_FLAG:
|
|
return value & 1;
|
|
case GECmdField::LOW_U2:
|
|
return value & 3;
|
|
case GECmdField::LOW_U4:
|
|
return value & 0xF;
|
|
case GECmdField::LOW_U7:
|
|
return value & 0x7F;
|
|
case GECmdField::LOW_U8:
|
|
return value & 0xFF;
|
|
case GECmdField::LOW_U10:
|
|
return value & 0x03FF;
|
|
case GECmdField::LOW_U10_P1:
|
|
return (value & 0x03FF) + 1;
|
|
case GECmdField::LOW_U11:
|
|
return value & 0x07FF;
|
|
case GECmdField::LOW_U16:
|
|
return value & 0xFFFF;
|
|
case GECmdField::MID_U8:
|
|
return (value >> 8) & 0xFF;
|
|
case GECmdField::MID_U10:
|
|
return (value >> 10) & 0x03FF;
|
|
case GECmdField::MID_U10_P1:
|
|
return ((value >> 10) & 0x03FF) + 1;
|
|
case GECmdField::TOP_U8:
|
|
return (value >> 16) & 0xFF;
|
|
case GECmdField::FLAG_AFTER_1:
|
|
return (value >> 1) & 1;
|
|
case GECmdField::FLAG_AFTER_2:
|
|
return (value >> 2) & 1;
|
|
case GECmdField::FLAG_AFTER_8:
|
|
return (value >> 8) & 1;
|
|
case GECmdField::FLAG_AFTER_9:
|
|
return (value >> 8) & 1;
|
|
case GECmdField::FLAG_AFTER_10:
|
|
return (value >> 10) & 1;
|
|
case GECmdField::FLAG_AFTER_11:
|
|
return (value >> 11) & 1;
|
|
case GECmdField::FLAG_AFTER_16:
|
|
return (value >> 16) & 1;
|
|
case GECmdField::FLAG_AFTER_17:
|
|
return (value >> 17) & 1;
|
|
case GECmdField::FLAG_AFTER_18:
|
|
return (value >> 18) & 1;
|
|
case GECmdField::FLAG_AFTER_19:
|
|
return (value >> 19) & 1;
|
|
case GECmdField::FLAG_AFTER_20:
|
|
return (value >> 20) & 1;
|
|
case GECmdField::FLAG_AFTER_21:
|
|
return (value >> 21) & 1;
|
|
case GECmdField::FLAG_AFTER_22:
|
|
return (value >> 22) & 1;
|
|
case GECmdField::FLAG_AFTER_23:
|
|
return (value >> 23) & 1;
|
|
case GECmdField::U2_AFTER_8:
|
|
return (value >> 8) & 3;
|
|
case GECmdField::U3_AFTER_16:
|
|
return (value >> 16) & 7;
|
|
case GECmdField::U12_AFTER_4:
|
|
return (value >> 4) & 0x0FFF;
|
|
|
|
// Below here are "typed" values, maybe they'll be exposed differently than integers someday.
|
|
|
|
case GECmdField::PRIM_TYPE:
|
|
return (value >> 16) & 7;
|
|
case GECmdField::SIGNAL_TYPE:
|
|
return (value >> 16) & 0xFF;
|
|
case GECmdField::VTYPE_TC:
|
|
return value & 3;
|
|
case GECmdField::VTYPE_COL:
|
|
return (value >> 2) & 7;
|
|
case GECmdField::VTYPE_NRM:
|
|
return (value >> 5) & 3;
|
|
case GECmdField::VTYPE_POS:
|
|
return (value >> 7) & 3;
|
|
case GECmdField::VTYPE_WEIGHTTYPE:
|
|
return (value >> 9) & 3;
|
|
case GECmdField::VTYPE_INDEX:
|
|
return (value >> 11) & 3;
|
|
case GECmdField::VTYPE_WEIGHTCOUNT:
|
|
return ((value >> 14) & 7) + 1;
|
|
case GECmdField::VTYPE_MORPHCOUNT:
|
|
return ((value >> 18) & 7) + 1;
|
|
case GECmdField::PATCH_PRIM_TYPE:
|
|
return value & 3;
|
|
case GECmdField::LIGHT_COMP:
|
|
return value & 3;
|
|
case GECmdField::LIGHT_TYPE:
|
|
return (value >> 8) & 3;
|
|
case GECmdField::LIGHT_TYPE_SPECULAR:
|
|
return (value & 3) == 1;
|
|
case GECmdField::HIGH_ADDR:
|
|
return (value << 8) & 0xFF000000;
|
|
case GECmdField::TEX_W:
|
|
return 1 << (value & 0xF);
|
|
case GECmdField::TEX_H:
|
|
return 1 << ((value >> 8) & 0xF);
|
|
case GECmdField::UVGEN_TYPE:
|
|
return value & 3;
|
|
case GECmdField::UVGEN_PROJ:
|
|
return (value >> 8) & 3;
|
|
case GECmdField::TEX_FORMAT:
|
|
return value & 0xF;
|
|
case GECmdField::TEX_MINFILTER:
|
|
return value & 7;
|
|
case GECmdField::TEX_MAGFILTER:
|
|
return (value >> 8) & 1;
|
|
case GECmdField::TEX_LEVEL_MODE:
|
|
return value & 3;
|
|
case GECmdField::LOW_U12_4_FLOAT:
|
|
{
|
|
float f = (value & 0xFFFF) / 16.0f;
|
|
uint32_t result;
|
|
memcpy(&result, &f, sizeof(result));
|
|
return result;
|
|
}
|
|
case GECmdField::HIGH_S4_4_FLOAT: // At 16, s.3.4 converted to float.
|
|
{
|
|
int value8 = (int)(s8)((value >> 16) & 0xFF);
|
|
float f = value8 / 16.0f;
|
|
uint32_t result;
|
|
memcpy(&result, &f, sizeof(result));
|
|
return result;
|
|
}
|
|
case GECmdField::TEX_FUNC:
|
|
return value & 7;
|
|
case GECmdField::CLUT_BYTES:
|
|
return (value & 0x3F) * 8;
|
|
case GECmdField::CLUT_FORMAT:
|
|
return value & 3;
|
|
case GECmdField::CLUT_SHIFT:
|
|
return (value >> 2) & 0x1F;
|
|
case GECmdField::CLUT_OFFSET:
|
|
return ((value >> 16) & 0x1F) << 4;
|
|
case GECmdField::COMPARE_FUNC2:
|
|
return value & 3;
|
|
case GECmdField::COMPARE_FUNC3:
|
|
return value & 7;
|
|
case GECmdField::STENCIL_OP_AT_0:
|
|
return value & 7;
|
|
case GECmdField::STENCIL_OP_AT_8:
|
|
return (value >> 8) & 7;
|
|
case GECmdField::STENCIL_OP_AT_16:
|
|
return (value >> 16) & 7;
|
|
case GECmdField::BLEND_SRC:
|
|
return value & 0xF;
|
|
case GECmdField::BLEND_DST:
|
|
return (value >> 4) & 0xF;
|
|
case GECmdField::BLEND_EQUATION:
|
|
return (value >> 8) & 7;
|
|
case GECmdField::LOGIC_OP:
|
|
return value & 0xF;
|
|
}
|
|
|
|
_assert_msg_(false, "Invalid field type");
|
|
return 0;
|
|
}
|
|
|
|
ExpressionType GEExpressionFunctions::getReferenceType(uint32_t referenceIndex) {
|
|
if (referenceIndex < 0x100) {
|
|
GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex)).fmt;
|
|
if (fmt == GECmdFormat::FLOAT)
|
|
return EXPR_TYPE_FLOAT;
|
|
return EXPR_TYPE_UINT;
|
|
}
|
|
|
|
if (referenceIndex >= (uint32_t)GEReferenceIndex::FIELD_START && referenceIndex <= (uint32_t)GEReferenceIndex::FIELD_END) {
|
|
GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex >> 12)).fmt;
|
|
return getFieldType(fmt, GECmdField(referenceIndex & 0xFF));
|
|
}
|
|
|
|
if (referenceIndex >= (uint32_t)GEReferenceIndex::BONE_MATRIX && referenceIndex < (uint32_t)GEReferenceIndex::MATRIX_END)
|
|
return EXPR_TYPE_FLOAT;
|
|
return EXPR_TYPE_UINT;
|
|
}
|
|
|
|
ExpressionType GEExpressionFunctions::getFieldType(GECmdFormat fmt, GECmdField field) {
|
|
switch (field) {
|
|
case GECmdField::LOW_U12_4_FLOAT:
|
|
case GECmdField::HIGH_S4_4_FLOAT:
|
|
return EXPR_TYPE_FLOAT;
|
|
|
|
default:
|
|
// Almost all of these are uint, so not listing each one.
|
|
break;
|
|
}
|
|
|
|
return EXPR_TYPE_UINT;
|
|
}
|
|
|
|
bool GEExpressionFunctions::getMemoryValue(uint32_t address, int size, uint32_t &dest, char *error) {
|
|
// We allow, but ignore, bad access.
|
|
// If we didn't, log/condition statements that reference registers couldn't be configured.
|
|
bool valid = Memory::IsValidRange(address, size);
|
|
|
|
switch (size) {
|
|
case 1:
|
|
dest = valid ? Memory::Read_U8(address) : 0;
|
|
return true;
|
|
case 2:
|
|
dest = valid ? Memory::Read_U16(address) : 0;
|
|
return true;
|
|
case 4:
|
|
dest = valid ? Memory::Read_U32(address) : 0;
|
|
return true;
|
|
}
|
|
|
|
sprintf(error, "Unexpected memory access size %d", size);
|
|
return false;
|
|
}
|
|
|
|
bool GPUDebugInitExpression(GPUDebugInterface *g, const char *str, PostfixExpression &exp) {
|
|
GEExpressionFunctions funcs(g);
|
|
return initPostfixExpression(str, &funcs, exp);
|
|
}
|
|
|
|
bool GPUDebugExecExpression(GPUDebugInterface *g, PostfixExpression &exp, uint32_t &result) {
|
|
GEExpressionFunctions funcs(g);
|
|
return parsePostfixExpression(exp, &funcs, result);
|
|
}
|
|
|
|
bool GPUDebugExecExpression(GPUDebugInterface *g, const char *str, uint32_t &result) {
|
|
GEExpressionFunctions funcs(g);
|
|
return parseExpression(str, &funcs, result);
|
|
}
|
|
|
|
void GPUDebugBuffer::Allocate(u32 stride, u32 height, GEBufferFormat fmt, bool flipped, bool reversed) {
|
|
GPUDebugBufferFormat actualFmt = GPUDebugBufferFormat(fmt);
|
|
if (reversed && actualFmt < GPU_DBG_FORMAT_8888) {
|
|
actualFmt |= GPU_DBG_FORMAT_REVERSE_FLAG;
|
|
}
|
|
Allocate(stride, height, actualFmt, flipped);
|
|
}
|
|
|
|
void GPUDebugBuffer::Allocate(u32 stride, u32 height, GPUDebugBufferFormat fmt, bool flipped) {
|
|
if (alloc_ && stride_ == stride && height_ == height && fmt_ == fmt) {
|
|
// Already allocated the right size.
|
|
flipped_ = flipped;
|
|
return;
|
|
}
|
|
|
|
Free();
|
|
alloc_ = true;
|
|
height_ = height;
|
|
stride_ = stride;
|
|
fmt_ = fmt;
|
|
flipped_ = flipped;
|
|
|
|
u32 pixelSize = PixelSize();
|
|
data_ = new u8[pixelSize * stride * height];
|
|
}
|
|
|
|
void GPUDebugBuffer::Free() {
|
|
if (alloc_ && data_ != NULL) {
|
|
delete [] data_;
|
|
}
|
|
data_ = NULL;
|
|
}
|
|
|
|
void GPUDebugBuffer::ZeroBytes() {
|
|
_dbg_assert_(data_);
|
|
memset(data_, 0, PixelSize() * stride_ * height_);
|
|
}
|
|
|
|
u32 GPUDebugBuffer::PixelSize() const {
|
|
switch (fmt_) {
|
|
case GPU_DBG_FORMAT_8888:
|
|
case GPU_DBG_FORMAT_8888_BGRA:
|
|
case GPU_DBG_FORMAT_FLOAT:
|
|
case GPU_DBG_FORMAT_24BIT_8X:
|
|
case GPU_DBG_FORMAT_24X_8BIT:
|
|
case GPU_DBG_FORMAT_FLOAT_DIV_256:
|
|
case GPU_DBG_FORMAT_24BIT_8X_DIV_256:
|
|
return 4;
|
|
|
|
case GPU_DBG_FORMAT_888_RGB:
|
|
return 3;
|
|
|
|
case GPU_DBG_FORMAT_8BIT:
|
|
return 1;
|
|
|
|
default:
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
u32 GPUDebugBuffer::GetRawPixel(int x, int y) const {
|
|
if (data_ == nullptr) {
|
|
return 0;
|
|
}
|
|
|
|
if (flipped_) {
|
|
y = height_ - y - 1;
|
|
}
|
|
|
|
u32 pixelSize = PixelSize();
|
|
u32 byteOffset = pixelSize * (stride_ * y + x);
|
|
const u8 *ptr = &data_[byteOffset];
|
|
|
|
switch (pixelSize) {
|
|
case 4:
|
|
return *(const u32 *)ptr;
|
|
case 3:
|
|
return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
|
|
case 2:
|
|
return *(const u16 *)ptr;
|
|
case 1:
|
|
return *(const u8 *)ptr;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void GPUDebugBuffer::SetRawPixel(int x, int y, u32 c) {
|
|
if (data_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
if (flipped_) {
|
|
y = height_ - y - 1;
|
|
}
|
|
|
|
u32 pixelSize = PixelSize();
|
|
u32 byteOffset = pixelSize * (stride_ * y + x);
|
|
u8 *ptr = &data_[byteOffset];
|
|
|
|
switch (pixelSize) {
|
|
case 4:
|
|
*(u32 *)ptr = c;
|
|
break;
|
|
case 3:
|
|
ptr[0] = (c >> 0) & 0xFF;
|
|
ptr[1] = (c >> 8) & 0xFF;
|
|
ptr[2] = (c >> 16) & 0xFF;
|
|
break;
|
|
case 2:
|
|
*(u16 *)ptr = (u16)c;
|
|
break;
|
|
case 1:
|
|
*ptr = (u8)c;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|