CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/GPU/Common/GPUDebugInterface.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "Common/Log.h"18#include "Common/Math/expression_parser.h"19#include "Common/StringUtils.h"20#include "Core/Debugger/SymbolMap.h"21#include "GPU/Common/GPUDebugInterface.h"22#include "GPU/Debugger/Debugger.h"23#include "GPU/Debugger/GECommandTable.h"24#include "GPU/GPUState.h"2526enum class GEReferenceIndex : uint32_t {27VADDR = 0x100,28IADDR,29OFFSET,30PC,31STALL,32BFLAG,33OP,34DATA,35CLUTADDR,36TRANSFERSRC,37TRANSFERDST,38PRIMCOUNT,39LASTPRIMCOUNT,4041TEXADDR0,42TEXADDR1,43TEXADDR2,44TEXADDR3,45TEXADDR4,46TEXADDR5,47TEXADDR6,48TEXADDR7,4950BONE_MATRIX = 0x200,51WORLD_MATRIX = 0x260,52VIEW_MATRIX = 0x26C,53PROJ_MATRIX = 0x278,54TGEN_MATRIX = 0x288,55MATRIX_END = 0x294,5657FIELD_START = 0x1000,58FIELD_END = 0xFF000,59};60ENUM_CLASS_BITOPS(GEReferenceIndex);6162struct ReferenceName {63GEReferenceIndex index;64const char *name;65};6667static constexpr ReferenceName referenceNames[] = {68{ GEReferenceIndex::VADDR, "vaddr" },69{ GEReferenceIndex::IADDR, "iaddr" },70{ GEReferenceIndex::OFFSET, "offset" },71{ GEReferenceIndex::PC, "pc" },72{ GEReferenceIndex::STALL, "stall" },73{ GEReferenceIndex::BFLAG, "bflag" },74{ GEReferenceIndex::BFLAG, "boundflag" },75{ GEReferenceIndex::OP, "op" },76{ GEReferenceIndex::DATA, "data" },77{ GEReferenceIndex::CLUTADDR, "clutaddr" },78{ GEReferenceIndex::TRANSFERSRC, "transfersrc" },79{ GEReferenceIndex::TRANSFERDST, "transferdst" },80{ GEReferenceIndex::PRIMCOUNT, "primcount" },81{ GEReferenceIndex::LASTPRIMCOUNT, "lastprimcount" },82{ GEReferenceIndex::TEXADDR0, "texaddr0" },83{ GEReferenceIndex::TEXADDR1, "texaddr1" },84{ GEReferenceIndex::TEXADDR2, "texaddr2" },85{ GEReferenceIndex::TEXADDR3, "texaddr3" },86{ GEReferenceIndex::TEXADDR4, "texaddr4" },87{ GEReferenceIndex::TEXADDR5, "texaddr5" },88{ GEReferenceIndex::TEXADDR6, "texaddr6" },89{ GEReferenceIndex::TEXADDR7, "texaddr7" },90};9192enum class GECmdField : uint8_t {93DATA, // Alias for the entire data.94LOW_FLAG,95LOW_U2,96LOW_U4,97LOW_U7,98LOW_U8,99LOW_U10,100LOW_U10_P1,101LOW_U11,102LOW_U16,103MID_U8,104MID_U10, // At 10, 10 bits.105MID_U10_P1, // At 10, 10 bits (add 1 to value.)106TOP_U8,107FLAG_AFTER_1, // At 1, 1 bit.108FLAG_AFTER_2, // At 2, 1 bit.109FLAG_AFTER_8, // At 8, 1 bit.110FLAG_AFTER_9, // At 9, 1 bit.111FLAG_AFTER_10, // At 10, 1 bit.112FLAG_AFTER_11, // At 11, 1 bit.113FLAG_AFTER_16, // At 16, 1 bit.114FLAG_AFTER_17, // At 17, 1 bit.115FLAG_AFTER_18, // At 18, 1 bit.116FLAG_AFTER_19, // At 19, 1 bit.117FLAG_AFTER_20, // At 20, 1 bit.118FLAG_AFTER_21, // At 21, 1 bit.119FLAG_AFTER_22, // At 22, 1 bit.120FLAG_AFTER_23, // At 23, 1 bit.121U2_AFTER_8, // At 8, 2 bits.122U3_AFTER_16, // At 16, 3 bits.123U12_AFTER_4, // At 4, 12 bits.124PRIM_TYPE, // At 16, 3 bits.125SIGNAL_TYPE, // At 16, 8 bits.126VTYPE_TC, // At 0, 2 bits.127VTYPE_COL, // At 2, 3 bits.128VTYPE_NRM, // At 5, 2 bits.129VTYPE_POS, // At 7, 2 bits.130VTYPE_WEIGHTTYPE, // At 9, 2 bits.131VTYPE_INDEX, // At 11, 2 bits.132VTYPE_WEIGHTCOUNT, // At 14, 3 bits.133VTYPE_MORPHCOUNT, // At 18, 3 bits.134PATCH_PRIM_TYPE, // At 0, 2 bits.135LIGHT_COMP, // At 0, 2 bits.136LIGHT_TYPE, // At 8, 2 bits.137LIGHT_TYPE_SPECULAR, // 1 if comp is 1 (but not 3.)138HIGH_ADDR, // At 16, 8 bits moved left to top 8 bits.139TEX_W, // At 0, 4 bits - 1 to this power.140TEX_H, // At 8, 4 bits - 1 to this power.141UVGEN_TYPE, // At 0, 2 bits.142UVGEN_PROJ, // At 8, 2 bits.143TEX_FORMAT, // At 0, 4 bits.144TEX_MINFILTER, // At 0, 3 bits.145TEX_MAGFILTER, // At 8, 1 bit.146TEX_LEVEL_MODE, // At 0, 2 bits.147LOW_U12_4_FLOAT, // At 0, 12.4 converted to float.148HIGH_S4_4_FLOAT, // At 16, s.3.4 converted to float.149TEX_FUNC, // At 0, 3 bits.150CLUT_BYTES, // At 0, 6 bits, multiplied by 8.151CLUT_FORMAT, // At 0, 2 bits.152CLUT_SHIFT, // At 2, 5 bits.153CLUT_OFFSET, // At 16, 5 bits, multiplied by 16.154COMPARE_FUNC2, // At 0, 2 bits.155COMPARE_FUNC3, // At 0, 3 bits.156STENCIL_OP_AT_0, // At 0, 3 bits.157STENCIL_OP_AT_8, // At 8, 3 bits.158STENCIL_OP_AT_16, // At 16, 3 bits.159BLEND_SRC, // At 0, 4 bits.160BLEND_DST, // At 4, 4 bits.161BLEND_EQUATION, // At 8, 3 bits.162LOGIC_OP, // At 0, 4 bits.163};164165struct FieldName {166GECmdFormat fmt;167GECmdField field;168const char *name;169};170171static constexpr FieldName fieldNames[] = {172{ GECmdFormat::PRIM, GECmdField::LOW_U16, "count" },173{ GECmdFormat::PRIM, GECmdField::PRIM_TYPE, "type" },174{ GECmdFormat::BEZIER, GECmdField::LOW_U8, "ucount" },175{ GECmdFormat::BEZIER, GECmdField::LOW_U8, "u" },176{ GECmdFormat::BEZIER, GECmdField::MID_U8, "vcount" },177{ GECmdFormat::BEZIER, GECmdField::MID_U8, "v" },178{ GECmdFormat::SPLINE, GECmdField::LOW_U8, "ucount" },179{ GECmdFormat::SPLINE, GECmdField::LOW_U8, "u" },180{ GECmdFormat::SPLINE, GECmdField::MID_U8, "vcount" },181{ GECmdFormat::SPLINE, GECmdField::MID_U8, "v" },182{ GECmdFormat::SPLINE, GECmdField::FLAG_AFTER_16, "ufirstopen" },183{ GECmdFormat::SPLINE, GECmdField::FLAG_AFTER_17, "ulastopen" },184{ GECmdFormat::SPLINE, GECmdField::FLAG_AFTER_18, "vfirstopen" },185{ GECmdFormat::SPLINE, GECmdField::FLAG_AFTER_19, "vlastopen" },186{ GECmdFormat::SIGNAL, GECmdField::LOW_U16, "data" },187{ GECmdFormat::SIGNAL, GECmdField::SIGNAL_TYPE, "type" },188{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_TC, "texcoord" },189{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_TC, "tc" },190{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_COL, "col" },191{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_COL, "color" },192{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_NRM, "normal" },193{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_POS, "pos" },194{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_POS, "position" },195{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTTYPE, "weighttype" },196{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTTYPE, "weight" },197{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_INDEX, "index" },198{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_WEIGHTCOUNT, "weightcount" },199{ GECmdFormat::VERTEX_TYPE, GECmdField::VTYPE_MORPHCOUNT, "morphcount" },200{ GECmdFormat::VERTEX_TYPE, GECmdField::FLAG_AFTER_23, "through" },201{ GECmdFormat::VERTEX_TYPE, GECmdField::FLAG_AFTER_23, "throughmode" },202{ GECmdFormat::X10_Y10, GECmdField::LOW_U10, "x" },203{ GECmdFormat::X10_Y10, GECmdField::MID_U10, "y" },204{ GECmdFormat::X10_Y10, GECmdField::LOW_U10_P1, "w" },205{ GECmdFormat::X10_Y10, GECmdField::MID_U10_P1, "h" },206{ GECmdFormat::FLAG, GECmdField::LOW_FLAG, "flag" },207{ GECmdFormat::BONE_NUM, GECmdField::LOW_U7, "num" },208{ GECmdFormat::MATRIX_NUM, GECmdField::LOW_U4, "num" },209{ GECmdFormat::FLOAT, GECmdField::DATA, "data" },210{ GECmdFormat::PATCH_DIVISION, GECmdField::LOW_U8, "u" },211{ GECmdFormat::PATCH_DIVISION, GECmdField::MID_U8, "v" },212{ GECmdFormat::PATCH_PRIM, GECmdField::PATCH_PRIM_TYPE, "type" },213{ GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "frac" },214{ GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "sub" },215{ GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U4, "subpixels" },216{ GECmdFormat::SUBPIXEL_COORD, GECmdField::U12_AFTER_4, "int" },217{ GECmdFormat::SUBPIXEL_COORD, GECmdField::U12_AFTER_4, "integer" },218{ GECmdFormat::SUBPIXEL_COORD, GECmdField::LOW_U12_4_FLOAT, "pixels" },219{ GECmdFormat::MATERIAL_UPDATE, GECmdField::LOW_FLAG, "ambient" },220{ GECmdFormat::MATERIAL_UPDATE, GECmdField::FLAG_AFTER_1, "diffuse" },221{ GECmdFormat::MATERIAL_UPDATE, GECmdField::FLAG_AFTER_2, "specular" },222{ GECmdFormat::RGB, GECmdField::LOW_U8, "r" },223{ GECmdFormat::RGB, GECmdField::LOW_U8, "red" },224{ GECmdFormat::RGB, GECmdField::MID_U8, "g" },225{ GECmdFormat::RGB, GECmdField::MID_U8, "green" },226{ GECmdFormat::RGB, GECmdField::TOP_U8, "b" },227{ GECmdFormat::RGB, GECmdField::TOP_U8, "blue" },228{ GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_COMP, "computation" },229{ GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_TYPE, "type" },230{ GECmdFormat::LIGHT_TYPE, GECmdField::LIGHT_TYPE_SPECULAR, "specular" },231{ GECmdFormat::STRIDE, GECmdField::LOW_U11, "stride" },232{ GECmdFormat::STRIDE_HIGH_ADDR, GECmdField::HIGH_ADDR, "highaddr" },233{ GECmdFormat::HIGH_ADDR, GECmdField::HIGH_ADDR, "highaddr" },234{ GECmdFormat::HIGH_ADDR_ONLY, GECmdField::HIGH_ADDR, "highaddr" },235{ GECmdFormat::TEX_SIZE, GECmdField::TEX_W, "w" },236{ GECmdFormat::TEX_SIZE, GECmdField::TEX_W, "width" },237{ GECmdFormat::TEX_SIZE, GECmdField::TEX_H, "h" },238{ GECmdFormat::TEX_SIZE, GECmdField::TEX_H, "height" },239{ GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_TYPE, "type" },240{ GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_TYPE, "uv" },241{ GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_PROJ, "proj" },242{ GECmdFormat::TEX_MAP_MODE, GECmdField::UVGEN_PROJ, "factor" },243{ GECmdFormat::TEX_LIGHT_SRC, GECmdField::LOW_U2, "u" },244{ GECmdFormat::TEX_LIGHT_SRC, GECmdField::U2_AFTER_8, "v" },245{ GECmdFormat::TEX_MODE, GECmdField::LOW_FLAG, "swizzle" },246{ GECmdFormat::TEX_MODE, GECmdField::FLAG_AFTER_8, "separateclut" },247{ GECmdFormat::TEX_MODE, GECmdField::FLAG_AFTER_8, "separate" },248{ GECmdFormat::TEX_MODE, GECmdField::U3_AFTER_16, "maxlevel" },249{ GECmdFormat::TEX_MODE, GECmdField::U3_AFTER_16, "level" },250{ GECmdFormat::TEX_FORMAT, GECmdField::TEX_FORMAT, "format" },251{ GECmdFormat::TEX_FORMAT, GECmdField::TEX_FORMAT, "fmt" },252{ GECmdFormat::TEX_FORMAT, GECmdField::FLAG_AFTER_2, "indexed" },253{ GECmdFormat::TEX_FILTER, GECmdField::TEX_MINFILTER, "min" },254{ GECmdFormat::TEX_FILTER, GECmdField::TEX_MINFILTER, "minify" },255{ GECmdFormat::TEX_FILTER, GECmdField::TEX_MAGFILTER, "mag" },256{ GECmdFormat::TEX_FILTER, GECmdField::TEX_MAGFILTER, "magnify" },257{ GECmdFormat::TEX_CLAMP, GECmdField::LOW_FLAG, "s" },258{ GECmdFormat::TEX_CLAMP, GECmdField::FLAG_AFTER_8, "t" },259{ GECmdFormat::TEX_LEVEL_MODE, GECmdField::TEX_LEVEL_MODE, "mode" },260{ GECmdFormat::TEX_LEVEL_MODE, GECmdField::HIGH_S4_4_FLOAT, "bias" },261{ GECmdFormat::TEX_FUNC, GECmdField::TEX_FUNC, "func" },262{ GECmdFormat::TEX_FUNC, GECmdField::TEX_FUNC, "function" },263{ GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_8, "alpha" },264{ GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_8, "a" },265{ GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_16, "double" },266{ GECmdFormat::TEX_FUNC, GECmdField::FLAG_AFTER_16, "doubling" },267{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_FORMAT, "format" },268{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_FORMAT, "fmt" },269{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_SHIFT, "shift" },270{ GECmdFormat::CLUT_FORMAT, GECmdField::MID_U8, "mask" },271{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_OFFSET, "offset" },272{ GECmdFormat::CLUT_FORMAT, GECmdField::CLUT_OFFSET, "base" },273{ GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "on" },274{ GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "enable" },275{ GECmdFormat::CLEAR_MODE, GECmdField::LOW_FLAG, "flag" },276{ GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_8, "color" },277{ GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_9, "alpha" },278{ GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_9, "stencil" },279{ GECmdFormat::CLEAR_MODE, GECmdField::FLAG_AFTER_10, "depth" },280{ GECmdFormat::COLOR_TEST_FUNC, GECmdField::COMPARE_FUNC2, "func" },281{ GECmdFormat::ALPHA_TEST, GECmdField::COMPARE_FUNC3, "func" },282{ GECmdFormat::ALPHA_TEST, GECmdField::MID_U8, "ref" },283{ GECmdFormat::ALPHA_TEST, GECmdField::MID_U8, "reference" },284{ GECmdFormat::ALPHA_TEST, GECmdField::TOP_U8, "mask" },285{ GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_0, "sfail" },286{ GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_8, "zfail" },287{ GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_16, "zpass" },288{ GECmdFormat::STENCIL_OP, GECmdField::STENCIL_OP_AT_16, "pass" },289{ GECmdFormat::DEPTH_TEST_FUNC, GECmdField::COMPARE_FUNC3, "func" },290{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_SRC, "src" },291{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_SRC, "srcfactor" },292{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dst" },293{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dstfactor" },294{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "dest" },295{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_DST, "destfactor" },296{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "eq" },297{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "equation" },298{ GECmdFormat::BLEND_MODE, GECmdField::BLEND_EQUATION, "mode" },299{ GECmdFormat::LOGIC_OP, GECmdField::LOGIC_OP, "op" },300{ GECmdFormat::LOGIC_OP, GECmdField::LOGIC_OP, "mode" },301{ GECmdFormat::ALPHA_PRIM, GECmdField::LOW_U8, "alpha" },302{ GECmdFormat::ALPHA_PRIM, GECmdField::PRIM_TYPE, "type" },303{ GECmdFormat::ALPHA_PRIM, GECmdField::PRIM_TYPE, "prim" },304{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_11, "antialias" },305// TODO: Clip bits?306{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_18, "shading" },307{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_18, "gouraud" },308{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_19, "cull" },309{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_20, "cullccw" },310{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_21, "tex" },311{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_22, "fog" },312{ GECmdFormat::ALPHA_PRIM, GECmdField::FLAG_AFTER_23, "dither" },313};314315struct GECmdConstant {316const char *name;317uint32_t value;318};319320// TODO: It would be nice if these were somehow typed...321static constexpr GECmdConstant constantNames[] = {322{ "GE_PRIM_POINTS", GE_PRIM_POINTS },323{ "GE_PRIM_LINES", GE_PRIM_LINES },324{ "GE_PRIM_LINE_STRIP", GE_PRIM_LINE_STRIP },325{ "GE_PRIM_TRIANGLES", GE_PRIM_TRIANGLES },326{ "GE_PRIM_TRIANGLE_STRIP", GE_PRIM_TRIANGLE_STRIP },327{ "GE_PRIM_TRIANGLE_FAN", GE_PRIM_TRIANGLE_FAN },328{ "GE_PRIM_RECTANGLES", GE_PRIM_RECTANGLES },329{ "GE_PRIM_KEEP_PREVIOUS", GE_PRIM_KEEP_PREVIOUS },330{ "POINTS", GE_PRIM_POINTS },331{ "LINES", GE_PRIM_LINES },332{ "LINE_STRIP", GE_PRIM_LINE_STRIP },333{ "TRIANGLES", GE_PRIM_TRIANGLES },334{ "TRIANGLE_STRIP", GE_PRIM_TRIANGLE_STRIP },335{ "TRIANGLE_FAN", GE_PRIM_TRIANGLE_FAN },336{ "RECTANGLES", GE_PRIM_RECTANGLES },337{ "SPRITES", GE_PRIM_RECTANGLES },338{ "KEEP_PREVIOUS", GE_PRIM_KEEP_PREVIOUS },339{ "CONTINUE", GE_PRIM_KEEP_PREVIOUS },340{ "GE_PATCHPRIM_TRIANGLES", GE_PATCHPRIM_TRIANGLES, },341{ "GE_PATCHPRIM_LINES", GE_PATCHPRIM_LINES, },342{ "GE_PATCHPRIM_POINTS", GE_PATCHPRIM_POINTS, },343{ "GE_SIGNAL_NONE", PSP_GE_SIGNAL_NONE },344{ "GE_SIGNAL_HANDLER_SUSPEND", PSP_GE_SIGNAL_HANDLER_SUSPEND },345{ "GE_SIGNAL_HANDLER_CONTINUE", PSP_GE_SIGNAL_HANDLER_CONTINUE },346{ "GE_SIGNAL_HANDLER_PAUSE", PSP_GE_SIGNAL_HANDLER_PAUSE },347{ "GE_SIGNAL_SYNC", PSP_GE_SIGNAL_SYNC },348{ "GE_SIGNAL_JUMP", PSP_GE_SIGNAL_JUMP },349{ "GE_SIGNAL_CALL", PSP_GE_SIGNAL_CALL },350{ "GE_SIGNAL_RET", PSP_GE_SIGNAL_RET },351{ "GE_SIGNAL_RJUMP", PSP_GE_SIGNAL_RJUMP },352{ "GE_SIGNAL_RCALL", PSP_GE_SIGNAL_RCALL },353{ "GE_SIGNAL_OJUMP", PSP_GE_SIGNAL_OJUMP },354{ "GE_SIGNAL_OCALL", PSP_GE_SIGNAL_OCALL },355{ "GE_VTYPE_TC_NONE", GE_VTYPE_TC_NONE >> GE_VTYPE_TC_SHIFT },356{ "GE_VTYPE_TC_8BIT", GE_VTYPE_TC_8BIT >> GE_VTYPE_TC_SHIFT },357{ "GE_VTYPE_TC_16BIT", GE_VTYPE_TC_16BIT >> GE_VTYPE_TC_SHIFT },358{ "GE_VTYPE_TC_FLOAT", GE_VTYPE_TC_FLOAT >> GE_VTYPE_TC_SHIFT },359{ "GE_VTYPE_COL_NONE", GE_VTYPE_COL_NONE >> GE_VTYPE_COL_SHIFT },360{ "GE_VTYPE_COL_565", GE_VTYPE_COL_565 >> GE_VTYPE_COL_SHIFT },361{ "GE_VTYPE_COL_5650", GE_VTYPE_COL_565 >> GE_VTYPE_COL_SHIFT },362{ "GE_VTYPE_COL_5551", GE_VTYPE_COL_5551 >> GE_VTYPE_COL_SHIFT },363{ "GE_VTYPE_COL_4444", GE_VTYPE_COL_4444 >> GE_VTYPE_COL_SHIFT },364{ "GE_VTYPE_COL_8888", GE_VTYPE_COL_8888 >> GE_VTYPE_COL_SHIFT },365{ "GE_VTYPE_NRM_NONE", GE_VTYPE_NRM_NONE >> GE_VTYPE_NRM_SHIFT },366{ "GE_VTYPE_NRM_8BIT", GE_VTYPE_NRM_8BIT >> GE_VTYPE_NRM_SHIFT },367{ "GE_VTYPE_NRM_16BIT", GE_VTYPE_NRM_16BIT >> GE_VTYPE_NRM_SHIFT },368{ "GE_VTYPE_NRM_FLOAT", GE_VTYPE_NRM_FLOAT >> GE_VTYPE_NRM_SHIFT },369{ "GE_VTYPE_POS_8BIT", GE_VTYPE_POS_8BIT >> GE_VTYPE_POS_SHIFT },370{ "GE_VTYPE_POS_16BIT", GE_VTYPE_POS_16BIT >> GE_VTYPE_POS_SHIFT },371{ "GE_VTYPE_POS_FLOAT", GE_VTYPE_POS_FLOAT >> GE_VTYPE_POS_SHIFT },372{ "GE_VTYPE_WEIGHT_NONE", GE_VTYPE_WEIGHT_NONE >> GE_VTYPE_WEIGHT_SHIFT },373{ "GE_VTYPE_WEIGHT_8BIT", GE_VTYPE_WEIGHT_8BIT >> GE_VTYPE_WEIGHT_SHIFT },374{ "GE_VTYPE_WEIGHT_16BIT", GE_VTYPE_WEIGHT_16BIT >> GE_VTYPE_WEIGHT_SHIFT },375{ "GE_VTYPE_WEIGHT_FLOAT", GE_VTYPE_WEIGHT_FLOAT >> GE_VTYPE_WEIGHT_SHIFT },376{ "GE_VTYPE_IDX_NONE", GE_VTYPE_IDX_NONE >> GE_VTYPE_IDX_SHIFT },377{ "GE_VTYPE_IDX_8BIT", GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT },378{ "GE_VTYPE_IDX_16BIT", GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT },379{ "GE_VTYPE_IDX_32BIT", GE_VTYPE_IDX_32BIT >> GE_VTYPE_IDX_SHIFT },380{ "GE_LIGHTCOMP_ONLYDIFFUSE", GE_LIGHTCOMP_ONLYDIFFUSE },381{ "GE_LIGHTCOMP_BOTH", GE_LIGHTCOMP_BOTH },382{ "GE_LIGHTCOMP_ONLYPOWDIFFUSE", GE_LIGHTCOMP_ONLYPOWDIFFUSE },383{ "GE_LIGHTTYPE_DIRECTIONAL", GE_LIGHTTYPE_DIRECTIONAL },384{ "GE_LIGHTTYPE_POINT", GE_LIGHTTYPE_POINT },385{ "GE_LIGHTTYPE_SPOT", GE_LIGHTTYPE_SPOT },386{ "GE_TEXMAP_TEXTURE_COORDS", GE_TEXMAP_TEXTURE_COORDS },387{ "GE_TEXMAP_TEXTURE_MATRIX", GE_TEXMAP_TEXTURE_MATRIX },388{ "GE_TEXMAP_ENVIRONMENT_MAP", GE_TEXMAP_ENVIRONMENT_MAP },389{ "GE_PROJMAP_POSITION", GE_PROJMAP_POSITION },390{ "GE_PROJMAP_UV", GE_PROJMAP_UV },391{ "GE_PROJMAP_NORMALIZED_NORMAL", GE_PROJMAP_NORMALIZED_NORMAL },392{ "GE_PROJMAP_NORMAL", GE_PROJMAP_NORMAL },393{ "GE_TFMT_565", GE_TFMT_5650 },394{ "GE_TFMT_5650", GE_TFMT_5650 },395{ "GE_TFMT_5551", GE_TFMT_5551 },396{ "GE_TFMT_4444", GE_TFMT_4444 },397{ "GE_TFMT_8888", GE_TFMT_8888 },398{ "GE_TFMT_CLUT4", GE_TFMT_CLUT4 },399{ "GE_TFMT_CLUT8", GE_TFMT_CLUT8 },400{ "GE_TFMT_CLUT16", GE_TFMT_CLUT16 },401{ "GE_TFMT_CLUT32", GE_TFMT_CLUT32 },402{ "GE_TFMT_DXT1", GE_TFMT_DXT1 },403{ "GE_TFMT_DXT3", GE_TFMT_DXT3 },404{ "GE_TFMT_DXT5", GE_TFMT_DXT5 },405{ "GE_CMODE_16BIT_BGR5650", GE_CMODE_16BIT_BGR5650 },406{ "GE_CMODE_16BIT_ABGR5551", GE_CMODE_16BIT_ABGR5551 },407{ "GE_CMODE_16BIT_ABGR4444", GE_CMODE_16BIT_ABGR4444 },408{ "GE_CMODE_32BIT_ABGR8888", GE_CMODE_32BIT_ABGR8888 },409{ "GE_TFILT_NEAREST", GE_TFILT_NEAREST },410{ "GE_TFILT_LINEAR", GE_TFILT_LINEAR },411{ "GE_TFILT_NEAREST_MIPMAP_NEAREST", GE_TFILT_NEAREST_MIPMAP_NEAREST },412{ "GE_TFILT_LINEAR_MIPMAP_NEAREST", GE_TFILT_LINEAR_MIPMAP_NEAREST },413{ "GE_TFILT_NEAREST_MIPMAP_LINEAR", GE_TFILT_NEAREST_MIPMAP_LINEAR },414{ "GE_TFILT_LINEAR_MIPMAP_LINEAR", GE_TFILT_LINEAR_MIPMAP_LINEAR },415{ "NEAREST", GE_TFILT_NEAREST },416{ "LINEAR", GE_TFILT_LINEAR },417{ "GE_TEXLEVEL_MODE_AUTO", GE_TEXLEVEL_MODE_AUTO },418{ "GE_TEXLEVEL_MODE_CONST", GE_TEXLEVEL_MODE_CONST },419{ "GE_TEXLEVEL_MODE_SLOPE", GE_TEXLEVEL_MODE_SLOPE },420{ "GE_TEXFUNC_MODULATE", GE_TEXFUNC_MODULATE },421{ "GE_TEXFUNC_DECAL", GE_TEXFUNC_DECAL },422{ "GE_TEXFUNC_BLEND", GE_TEXFUNC_BLEND },423{ "GE_TEXFUNC_REPLACE", GE_TEXFUNC_REPLACE },424{ "GE_TEXFUNC_ADD", GE_TEXFUNC_ADD },425{ "GE_COMP_NEVER", GE_COMP_NEVER },426{ "GE_COMP_ALWAYS", GE_COMP_ALWAYS },427{ "GE_COMP_EQUAL", GE_COMP_EQUAL },428{ "GE_COMP_NOTEQUAL", GE_COMP_NOTEQUAL },429{ "GE_COMP_LESS", GE_COMP_LESS },430{ "GE_COMP_LEQUAL", GE_COMP_LEQUAL },431{ "GE_COMP_GREATER", GE_COMP_GREATER },432{ "GE_COMP_GEQUAL", GE_COMP_GEQUAL },433{ "NEVER", GE_COMP_NEVER },434{ "ALWAYS", GE_COMP_ALWAYS },435{ "EQUAL", GE_COMP_EQUAL },436{ "NOTEQUAL", GE_COMP_NOTEQUAL },437{ "LESS", GE_COMP_LESS },438{ "LEQUAL", GE_COMP_LEQUAL },439{ "LESSEQUAL", GE_COMP_LEQUAL },440{ "GREATER", GE_COMP_GREATER },441{ "GEQUAL", GE_COMP_GEQUAL },442{ "GREATEREQUAL", GE_COMP_GEQUAL },443{ "GE_STENCILOP_KEEP", GE_STENCILOP_KEEP },444{ "GE_STENCILOP_ZERO", GE_STENCILOP_ZERO },445{ "GE_STENCILOP_REPLACE", GE_STENCILOP_REPLACE },446{ "GE_STENCILOP_INVERT", GE_STENCILOP_INVERT },447{ "GE_STENCILOP_INCR", GE_STENCILOP_INCR },448{ "GE_STENCILOP_DECR", GE_STENCILOP_DECR },449{ "GE_BLENDMODE_MUL_AND_ADD", GE_BLENDMODE_MUL_AND_ADD },450{ "GE_BLENDMODE_MUL_AND_SUBTRACT", GE_BLENDMODE_MUL_AND_SUBTRACT },451{ "GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE", GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE },452{ "GE_BLENDMODE_MIN", GE_BLENDMODE_MIN },453{ "GE_BLENDMODE_MAX", GE_BLENDMODE_MAX },454{ "GE_BLENDMODE_ABSDIFF", GE_BLENDMODE_ABSDIFF },455{ "ADD", GE_BLENDMODE_MUL_AND_ADD },456{ "SUBTRACT", GE_BLENDMODE_MUL_AND_SUBTRACT },457{ "SUBTRACT_REVERSE", GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE },458{ "MIN", GE_BLENDMODE_MIN },459{ "MAX", GE_BLENDMODE_MAX },460{ "ABSDIFF", GE_BLENDMODE_ABSDIFF },461{ "GE_SRCBLEND_DSTCOLOR", GE_SRCBLEND_DSTCOLOR },462{ "GE_SRCBLEND_INVDSTCOLOR", GE_SRCBLEND_INVDSTCOLOR },463{ "GE_SRCBLEND_SRCALPHA", GE_SRCBLEND_SRCALPHA },464{ "GE_SRCBLEND_INVSRCALPHA", GE_SRCBLEND_INVSRCALPHA },465{ "GE_SRCBLEND_DSTALPHA", GE_SRCBLEND_DSTALPHA },466{ "GE_SRCBLEND_INVDSTALPHA", GE_SRCBLEND_INVDSTALPHA },467{ "GE_SRCBLEND_DOUBLESRCALPHA", GE_SRCBLEND_DOUBLESRCALPHA },468{ "GE_SRCBLEND_DOUBLEINVSRCALPHA", GE_SRCBLEND_DOUBLEINVSRCALPHA },469{ "GE_SRCBLEND_DOUBLEDSTALPHA", GE_SRCBLEND_DOUBLEDSTALPHA },470{ "GE_SRCBLEND_DOUBLEINVDSTALPHA", GE_SRCBLEND_DOUBLEINVDSTALPHA },471{ "GE_SRCBLEND_FIXA", GE_SRCBLEND_FIXA },472{ "GE_DSTBLEND_SRCCOLOR", GE_DSTBLEND_SRCCOLOR },473{ "GE_DSTBLEND_INVSRCCOLOR", GE_DSTBLEND_INVSRCCOLOR },474{ "GE_DSTBLEND_SRCALPHA", GE_DSTBLEND_SRCALPHA },475{ "GE_DSTBLEND_INVSRCALPHA", GE_DSTBLEND_INVSRCALPHA },476{ "GE_DSTBLEND_DSTALPHA", GE_DSTBLEND_DSTALPHA },477{ "GE_DSTBLEND_INVDSTALPHA", GE_DSTBLEND_INVDSTALPHA },478{ "GE_DSTBLEND_DOUBLESRCALPHA", GE_DSTBLEND_DOUBLESRCALPHA },479{ "GE_DSTBLEND_DOUBLEINVSRCALPHA", GE_DSTBLEND_DOUBLEINVSRCALPHA },480{ "GE_DSTBLEND_DOUBLEDSTALPHA", GE_DSTBLEND_DOUBLEDSTALPHA },481{ "GE_DSTBLEND_DOUBLEINVDSTALPHA", GE_DSTBLEND_DOUBLEINVDSTALPHA },482{ "GE_DSTBLEND_FIXB", GE_DSTBLEND_FIXB },483{ "SRCALPHA", GE_SRCBLEND_SRCALPHA },484{ "INVSRCALPHA", GE_SRCBLEND_INVSRCALPHA },485{ "INVERSESRCALPHA", GE_SRCBLEND_INVSRCALPHA },486{ "DSTALPHA", GE_DSTBLEND_DSTALPHA },487{ "INVDSTALPHA", GE_DSTBLEND_INVDSTALPHA },488{ "DOUBLESRCALPHA", GE_DSTBLEND_DOUBLESRCALPHA },489{ "DOUBLEINVSRCALPHA", GE_DSTBLEND_DOUBLEINVSRCALPHA },490{ "DOUBLEDSTALPHA", GE_DSTBLEND_DOUBLEDSTALPHA },491{ "DOUBLEINVDSTALPHA", GE_DSTBLEND_DOUBLEINVDSTALPHA },492{ "FIXED", GE_DSTBLEND_FIXB },493{ "GE_LOGIC_CLEAR", GE_LOGIC_CLEAR },494{ "GE_LOGIC_AND", GE_LOGIC_AND },495{ "GE_LOGIC_AND_REVERSE", GE_LOGIC_AND_REVERSE },496{ "GE_LOGIC_COPY", GE_LOGIC_COPY },497{ "GE_LOGIC_AND_INVERTED", GE_LOGIC_AND_INVERTED },498{ "GE_LOGIC_NOOP", GE_LOGIC_NOOP },499{ "GE_LOGIC_XOR", GE_LOGIC_XOR },500{ "GE_LOGIC_OR", GE_LOGIC_OR },501{ "GE_LOGIC_NOR", GE_LOGIC_NOR },502{ "GE_LOGIC_EQUIV", GE_LOGIC_EQUIV },503{ "GE_LOGIC_INVERTED", GE_LOGIC_INVERTED },504{ "GE_LOGIC_OR_REVERSE", GE_LOGIC_OR_REVERSE },505{ "GE_LOGIC_COPY_INVERTED", GE_LOGIC_COPY_INVERTED },506{ "GE_LOGIC_OR_INVERTED", GE_LOGIC_OR_INVERTED },507{ "GE_LOGIC_NAND", GE_LOGIC_NAND },508{ "GE_LOGIC_SET", GE_LOGIC_SET },509};510511class GEExpressionFunctions : public IExpressionFunctions {512public:513GEExpressionFunctions(GPUDebugInterface *gpu) : gpu_(gpu) {}514515bool parseReference(char *str, uint32_t &referenceIndex) override;516bool parseSymbol(char *str, uint32_t &symbolValue) override;517uint32_t getReferenceValue(uint32_t referenceIndex) override;518ExpressionType getReferenceType(uint32_t referenceIndex) override;519bool getMemoryValue(uint32_t address, int size, uint32_t &dest, std::string *error) override;520521private:522bool parseFieldReference(const char *ref, const char *field, uint32_t &referenceIndex);523static uint32_t getFieldValue(GECmdFormat fmt, GECmdField field, uint32_t value);524static ExpressionType getFieldType(GECmdFormat fmt, GECmdField field);525526GPUDebugInterface *gpu_;527};528529bool GEExpressionFunctions::parseReference(char *str, uint32_t &referenceIndex) {530// TODO: Support formats and a form of fields (i.e. vtype.throughmode.)531// For now, let's just support the register bits directly.532GECmdInfo info;533if (GECmdInfoByName(str, info)) {534referenceIndex = info.reg;535return true;536}537538char *dot = strchr(str, '.');539if (dot != nullptr) {540*dot = '\0';541bool success = parseFieldReference(str, dot + 1, referenceIndex);542*dot = '.';543if (success)544return true;545}546547// Also allow non-register references.548for (const auto &entry : referenceNames) {549if (strcasecmp(str, entry.name) == 0) {550referenceIndex = (uint32_t)entry.index;551return true;552}553}554555// And matrix data. Maybe should allow column/row specification.556int subindex = -1;557int len = -1;558559if (sscanf(str, "bone%i%n", &subindex, &len) == 1) {560if (len == strlen(str) && subindex < 96) {561referenceIndex = (uint32_t)GEReferenceIndex::BONE_MATRIX + subindex;562return true;563}564}565if (sscanf(str, "world%i%n", &subindex, &len) == 1) {566if (len == strlen(str) && subindex < 12) {567referenceIndex = (uint32_t)GEReferenceIndex::WORLD_MATRIX + subindex;568return true;569}570}571if (sscanf(str, "view%i%n", &subindex, &len) == 1) {572if (len == strlen(str) && subindex < 12) {573referenceIndex = (uint32_t)GEReferenceIndex::VIEW_MATRIX + subindex;574return true;575}576}577if (sscanf(str, "proj%i%n", &subindex, &len) == 1) {578if (len == strlen(str) && subindex < 16) {579referenceIndex = (uint32_t)GEReferenceIndex::PROJ_MATRIX + subindex;580return true;581}582}583if (sscanf(str, "tgen%i%n", &subindex, &len) == 1 || sscanf(str, "texgen%i%n", &subindex, &len) == 1) {584if (len == strlen(str) && subindex < 12) {585referenceIndex = (uint32_t)GEReferenceIndex::TGEN_MATRIX + subindex;586return true;587}588}589590return false;591}592593bool GEExpressionFunctions::parseFieldReference(const char *ref, const char *field, uint32_t &referenceIndex) {594GECmdInfo info;595if (!GECmdInfoByName(ref, info)) {596return false;597}598599for (const auto &entry : fieldNames) {600if (entry.fmt == info.fmt && strcasecmp(field, entry.name) == 0) {601referenceIndex = (info.reg << 12) | (uint32_t)entry.field;602return true;603}604}605606return false;607}608609bool GEExpressionFunctions::parseSymbol(char *str, uint32_t &symbolValue) {610// Mainly useful for checking memory addresses and constants.611612for (const auto &entry : constantNames) {613if (strcasecmp(str, entry.name) == 0) {614symbolValue = entry.value;615return true;616}617}618619return g_symbolMap->GetLabelValue(str, symbolValue);620}621622uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) {623GPUgstate state = gpu_->GetGState();624if (referenceIndex < 0x100) {625GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex)).fmt;626uint32_t value = state.cmdmem[referenceIndex];627if (fmt == GECmdFormat::FLOAT)628return value << 8;629return value & 0x00FFFFFF;630}631632if (referenceIndex >= (uint32_t)GEReferenceIndex::FIELD_START && referenceIndex <= (uint32_t)GEReferenceIndex::FIELD_END) {633uint32_t value = state.cmdmem[referenceIndex >> 12] & 0x00FFFFFF;634GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex >> 12)).fmt;635return getFieldValue(fmt, GECmdField(referenceIndex & 0xFF), value);636}637638// We return the matrix value as float bits, which gets interpreted correctly in the parser.639if (referenceIndex >= (uint32_t)GEReferenceIndex::BONE_MATRIX && referenceIndex < (uint32_t)GEReferenceIndex::MATRIX_END) {640float value;641if (referenceIndex >= (uint32_t)GEReferenceIndex::TGEN_MATRIX) {642value = state.tgenMatrix[referenceIndex - (uint32_t)GEReferenceIndex::TGEN_MATRIX];643} else if (referenceIndex >= (uint32_t)GEReferenceIndex::PROJ_MATRIX) {644value = state.projMatrix[referenceIndex - (uint32_t)GEReferenceIndex::PROJ_MATRIX];645} else if (referenceIndex >= (uint32_t)GEReferenceIndex::VIEW_MATRIX) {646value = state.viewMatrix[referenceIndex - (uint32_t)GEReferenceIndex::VIEW_MATRIX];647} else if (referenceIndex >= (uint32_t)GEReferenceIndex::WORLD_MATRIX) {648value = state.worldMatrix[referenceIndex - (uint32_t)GEReferenceIndex::WORLD_MATRIX];649} else {650value = state.boneMatrix[referenceIndex - (uint32_t)GEReferenceIndex::BONE_MATRIX];651}652653uint32_t result;654memcpy(&result, &value, sizeof(result));655return result;656}657658GEReferenceIndex ref = (GEReferenceIndex)referenceIndex;659DisplayList list;660switch (ref) {661case GEReferenceIndex::VADDR:662return gpu_->GetVertexAddress();663case GEReferenceIndex::IADDR:664return gpu_->GetIndexAddress();665case GEReferenceIndex::OFFSET:666// TODO: Should use an interface method, probably.667return gstate_c.offsetAddr;668case GEReferenceIndex::PC:669if (gpu_->GetCurrentDisplayList(list)) {670return list.pc;671}672return 0;673case GEReferenceIndex::STALL:674if (gpu_->GetCurrentDisplayList(list)) {675return list.stall;676}677return 0;678case GEReferenceIndex::BFLAG:679if (gpu_->GetCurrentDisplayList(list)) {680return list.bboxResult ? 1 : 0;681}682return 0;683case GEReferenceIndex::OP:684if (gpu_->GetCurrentDisplayList(list)) {685return Memory::Read_U32(list.pc);686}687return 0;688case GEReferenceIndex::DATA:689if (gpu_->GetCurrentDisplayList(list)) {690return Memory::Read_U32(list.pc) & 0x00FFFFFF;691}692return 0;693694case GEReferenceIndex::CLUTADDR:695return state.getClutAddress();696697case GEReferenceIndex::TRANSFERSRC:698return state.getTransferSrcAddress();699700case GEReferenceIndex::TRANSFERDST:701return state.getTransferDstAddress();702703case GEReferenceIndex::PRIMCOUNT:704return GPUDebug::PrimsThisFrame();705706case GEReferenceIndex::LASTPRIMCOUNT:707return GPUDebug::PrimsLastFrame();708709case GEReferenceIndex::TEXADDR0:710case GEReferenceIndex::TEXADDR1:711case GEReferenceIndex::TEXADDR2:712case GEReferenceIndex::TEXADDR3:713case GEReferenceIndex::TEXADDR4:714case GEReferenceIndex::TEXADDR5:715case GEReferenceIndex::TEXADDR6:716case GEReferenceIndex::TEXADDR7:717return state.getTextureAddress((int)ref - (int)GEReferenceIndex::TEXADDR0);718719case GEReferenceIndex::BONE_MATRIX:720case GEReferenceIndex::WORLD_MATRIX:721case GEReferenceIndex::VIEW_MATRIX:722case GEReferenceIndex::PROJ_MATRIX:723case GEReferenceIndex::TGEN_MATRIX:724case GEReferenceIndex::MATRIX_END:725case GEReferenceIndex::FIELD_START:726case GEReferenceIndex::FIELD_END:727// Shouldn't have gotten here.728break;729}730731_assert_msg_(false, "Invalid reference index");732return 0;733}734735uint32_t GEExpressionFunctions::getFieldValue(GECmdFormat fmt, GECmdField field, uint32_t value) {736switch (field) {737case GECmdField::DATA:738return value;739case GECmdField::LOW_FLAG:740return value & 1;741case GECmdField::LOW_U2:742return value & 3;743case GECmdField::LOW_U4:744return value & 0xF;745case GECmdField::LOW_U7:746return value & 0x7F;747case GECmdField::LOW_U8:748return value & 0xFF;749case GECmdField::LOW_U10:750return value & 0x03FF;751case GECmdField::LOW_U10_P1:752return (value & 0x03FF) + 1;753case GECmdField::LOW_U11:754return value & 0x07FF;755case GECmdField::LOW_U16:756return value & 0xFFFF;757case GECmdField::MID_U8:758return (value >> 8) & 0xFF;759case GECmdField::MID_U10:760return (value >> 10) & 0x03FF;761case GECmdField::MID_U10_P1:762return ((value >> 10) & 0x03FF) + 1;763case GECmdField::TOP_U8:764return (value >> 16) & 0xFF;765case GECmdField::FLAG_AFTER_1:766return (value >> 1) & 1;767case GECmdField::FLAG_AFTER_2:768return (value >> 2) & 1;769case GECmdField::FLAG_AFTER_8:770return (value >> 8) & 1;771case GECmdField::FLAG_AFTER_9:772return (value >> 9) & 1;773case GECmdField::FLAG_AFTER_10:774return (value >> 10) & 1;775case GECmdField::FLAG_AFTER_11:776return (value >> 11) & 1;777case GECmdField::FLAG_AFTER_16:778return (value >> 16) & 1;779case GECmdField::FLAG_AFTER_17:780return (value >> 17) & 1;781case GECmdField::FLAG_AFTER_18:782return (value >> 18) & 1;783case GECmdField::FLAG_AFTER_19:784return (value >> 19) & 1;785case GECmdField::FLAG_AFTER_20:786return (value >> 20) & 1;787case GECmdField::FLAG_AFTER_21:788return (value >> 21) & 1;789case GECmdField::FLAG_AFTER_22:790return (value >> 22) & 1;791case GECmdField::FLAG_AFTER_23:792return (value >> 23) & 1;793case GECmdField::U2_AFTER_8:794return (value >> 8) & 3;795case GECmdField::U3_AFTER_16:796return (value >> 16) & 7;797case GECmdField::U12_AFTER_4:798return (value >> 4) & 0x0FFF;799800// Below here are "typed" values, maybe they'll be exposed differently than integers someday.801802case GECmdField::PRIM_TYPE:803return (value >> 16) & 7;804case GECmdField::SIGNAL_TYPE:805return (value >> 16) & 0xFF;806case GECmdField::VTYPE_TC:807return value & 3;808case GECmdField::VTYPE_COL:809return (value >> 2) & 7;810case GECmdField::VTYPE_NRM:811return (value >> 5) & 3;812case GECmdField::VTYPE_POS:813return (value >> 7) & 3;814case GECmdField::VTYPE_WEIGHTTYPE:815return (value >> 9) & 3;816case GECmdField::VTYPE_INDEX:817return (value >> 11) & 3;818case GECmdField::VTYPE_WEIGHTCOUNT:819return ((value >> 14) & 7) + 1;820case GECmdField::VTYPE_MORPHCOUNT:821return ((value >> 18) & 7) + 1;822case GECmdField::PATCH_PRIM_TYPE:823return value & 3;824case GECmdField::LIGHT_COMP:825return value & 3;826case GECmdField::LIGHT_TYPE:827return (value >> 8) & 3;828case GECmdField::LIGHT_TYPE_SPECULAR:829return (value & 3) == 1;830case GECmdField::HIGH_ADDR:831return (value << 8) & 0xFF000000;832case GECmdField::TEX_W:833return 1 << (value & 0xF);834case GECmdField::TEX_H:835return 1 << ((value >> 8) & 0xF);836case GECmdField::UVGEN_TYPE:837return value & 3;838case GECmdField::UVGEN_PROJ:839return (value >> 8) & 3;840case GECmdField::TEX_FORMAT:841return value & 0xF;842case GECmdField::TEX_MINFILTER:843return value & 7;844case GECmdField::TEX_MAGFILTER:845return (value >> 8) & 1;846case GECmdField::TEX_LEVEL_MODE:847return value & 3;848case GECmdField::LOW_U12_4_FLOAT:849{850float f = (value & 0xFFFF) / 16.0f;851uint32_t result;852memcpy(&result, &f, sizeof(result));853return result;854}855case GECmdField::HIGH_S4_4_FLOAT: // At 16, s.3.4 converted to float.856{857int value8 = (int)(s8)((value >> 16) & 0xFF);858float f = value8 / 16.0f;859uint32_t result;860memcpy(&result, &f, sizeof(result));861return result;862}863case GECmdField::TEX_FUNC:864return value & 7;865case GECmdField::CLUT_BYTES:866return (value & 0x3F) * 8;867case GECmdField::CLUT_FORMAT:868return value & 3;869case GECmdField::CLUT_SHIFT:870return (value >> 2) & 0x1F;871case GECmdField::CLUT_OFFSET:872return ((value >> 16) & 0x1F) << 4;873case GECmdField::COMPARE_FUNC2:874return value & 3;875case GECmdField::COMPARE_FUNC3:876return value & 7;877case GECmdField::STENCIL_OP_AT_0:878return value & 7;879case GECmdField::STENCIL_OP_AT_8:880return (value >> 8) & 7;881case GECmdField::STENCIL_OP_AT_16:882return (value >> 16) & 7;883case GECmdField::BLEND_SRC:884return value & 0xF;885case GECmdField::BLEND_DST:886return (value >> 4) & 0xF;887case GECmdField::BLEND_EQUATION:888return (value >> 8) & 7;889case GECmdField::LOGIC_OP:890return value & 0xF;891}892893_assert_msg_(false, "Invalid field type");894return 0;895}896897ExpressionType GEExpressionFunctions::getReferenceType(uint32_t referenceIndex) {898if (referenceIndex < 0x100) {899GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex)).fmt;900if (fmt == GECmdFormat::FLOAT)901return EXPR_TYPE_FLOAT;902return EXPR_TYPE_UINT;903}904905if (referenceIndex >= (uint32_t)GEReferenceIndex::FIELD_START && referenceIndex <= (uint32_t)GEReferenceIndex::FIELD_END) {906GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex >> 12)).fmt;907return getFieldType(fmt, GECmdField(referenceIndex & 0xFF));908}909910if (referenceIndex >= (uint32_t)GEReferenceIndex::BONE_MATRIX && referenceIndex < (uint32_t)GEReferenceIndex::MATRIX_END)911return EXPR_TYPE_FLOAT;912return EXPR_TYPE_UINT;913}914915ExpressionType GEExpressionFunctions::getFieldType(GECmdFormat fmt, GECmdField field) {916switch (field) {917case GECmdField::LOW_U12_4_FLOAT:918case GECmdField::HIGH_S4_4_FLOAT:919return EXPR_TYPE_FLOAT;920921default:922// Almost all of these are uint, so not listing each one.923break;924}925926return EXPR_TYPE_UINT;927}928929bool GEExpressionFunctions::getMemoryValue(uint32_t address, int size, uint32_t &dest, std::string *error) {930// We allow, but ignore, bad access.931// If we didn't, log/condition statements that reference registers couldn't be configured.932uint32_t valid = Memory::ValidSize(address, size);933uint8_t buf[4]{};934if (valid != 0)935memcpy(buf, Memory::GetPointerUnchecked(address), valid);936937switch (size) {938case 1:939dest = buf[0];940return true;941case 2:942dest = (buf[1] << 8) | buf[0];943return true;944case 4:945dest = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];946return true;947}948949*error = StringFromFormat("Unexpected memory access size %d", size);950return false;951}952953bool GPUDebugInitExpression(GPUDebugInterface *g, const char *str, PostfixExpression &exp) {954GEExpressionFunctions funcs(g);955return initPostfixExpression(str, &funcs, exp);956}957958bool GPUDebugExecExpression(GPUDebugInterface *g, PostfixExpression &exp, uint32_t &result) {959GEExpressionFunctions funcs(g);960return parsePostfixExpression(exp, &funcs, result);961}962963bool GPUDebugExecExpression(GPUDebugInterface *g, const char *str, uint32_t &result) {964GEExpressionFunctions funcs(g);965return parseExpression(str, &funcs, result);966}967968void GPUDebugBuffer::Allocate(u32 stride, u32 height, GEBufferFormat fmt, bool flipped, bool reversed) {969GPUDebugBufferFormat actualFmt = GPUDebugBufferFormat(fmt);970if (reversed && actualFmt < GPU_DBG_FORMAT_8888) {971actualFmt |= GPU_DBG_FORMAT_REVERSE_FLAG;972}973Allocate(stride, height, actualFmt, flipped);974}975976void GPUDebugBuffer::Allocate(u32 stride, u32 height, GPUDebugBufferFormat fmt, bool flipped) {977if (alloc_ && stride_ == stride && height_ == height && fmt_ == fmt) {978// Already allocated the right size.979flipped_ = flipped;980return;981}982983Free();984alloc_ = true;985height_ = height;986stride_ = stride;987fmt_ = fmt;988flipped_ = flipped;989990u32 pixelSize = PixelSize();991data_ = new u8[pixelSize * stride * height];992}993994void GPUDebugBuffer::Free() {995if (alloc_ && data_ != NULL) {996delete [] data_;997}998data_ = NULL;999}10001001void GPUDebugBuffer::ZeroBytes() {1002_dbg_assert_(data_);1003memset(data_, 0, PixelSize() * stride_ * height_);1004}10051006u32 GPUDebugBuffer::PixelSize() const {1007switch (fmt_) {1008case GPU_DBG_FORMAT_8888:1009case GPU_DBG_FORMAT_8888_BGRA:1010case GPU_DBG_FORMAT_FLOAT:1011case GPU_DBG_FORMAT_24BIT_8X:1012case GPU_DBG_FORMAT_24X_8BIT:1013case GPU_DBG_FORMAT_FLOAT_DIV_256:1014case GPU_DBG_FORMAT_24BIT_8X_DIV_256:1015return 4;10161017case GPU_DBG_FORMAT_888_RGB:1018return 3;10191020case GPU_DBG_FORMAT_8BIT:1021return 1;10221023default:1024return 2;1025}1026}10271028u32 GPUDebugBuffer::GetRawPixel(int x, int y) const {1029if (data_ == nullptr) {1030return 0;1031}10321033if (flipped_) {1034y = height_ - y - 1;1035}10361037u32 pixelSize = PixelSize();1038u32 byteOffset = pixelSize * (stride_ * y + x);1039const u8 *ptr = &data_[byteOffset];10401041switch (pixelSize) {1042case 4:1043return *(const u32 *)ptr;1044case 3:1045return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);1046case 2:1047return *(const u16 *)ptr;1048case 1:1049return *(const u8 *)ptr;1050default:1051return 0;1052}1053}10541055void GPUDebugBuffer::SetRawPixel(int x, int y, u32 c) {1056if (data_ == nullptr) {1057return;1058}10591060if (flipped_) {1061y = height_ - y - 1;1062}10631064u32 pixelSize = PixelSize();1065u32 byteOffset = pixelSize * (stride_ * y + x);1066u8 *ptr = &data_[byteOffset];10671068switch (pixelSize) {1069case 4:1070*(u32 *)ptr = c;1071break;1072case 3:1073ptr[0] = (c >> 0) & 0xFF;1074ptr[1] = (c >> 8) & 0xFF;1075ptr[2] = (c >> 16) & 0xFF;1076break;1077case 2:1078*(u16 *)ptr = (u16)c;1079break;1080case 1:1081*ptr = (u8)c;1082break;1083default:1084break;1085}1086}108710881089