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/Windows/GEDebugger/TabState.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/CommonWindows.h"18#include <commctrl.h>19#include <array>20#include "Common/CommonFuncs.h"21#include "Common/CommonTypes.h"22#include "Common/Data/Encoding/Utf8.h"23#include "Common/Data/Text/Parsers.h"24#include "Common/Log.h"25#include "Common/StringUtils.h"26#include "Windows/resource.h"27#include "Windows/InputBox.h"28#include "Windows/GEDebugger/GEDebugger.h"29#include "Windows/GEDebugger/TabState.h"30#include "Windows/W32Util/ContextMenu.h"31#include "GPU/GPUState.h"32#include "GPU/GeDisasm.h"33#include "GPU/Common/GPUDebugInterface.h"34#include "GPU/Debugger/Breakpoints.h"35#include "GPU/Debugger/Stepping.h"3637using namespace GPUBreakpoints;3839// First column is the breakpoint icon.40static const GenericListViewColumn stateValuesCols[] = {41{ L"", 0.03f },42{ L"Name", 0.40f },43{ L"Value", 0.57f },44};4546GenericListViewDef stateValuesListDef = {47stateValuesCols,48ARRAY_SIZE(stateValuesCols),49nullptr,50false,51};5253enum StateValuesCols {54STATEVALUES_COL_BREAKPOINT,55STATEVALUES_COL_NAME,56STATEVALUES_COL_VALUE,57};5859enum CmdFormatType {60CMD_FMT_HEX = 0,61CMD_FMT_NUM,62CMD_FMT_FLOAT24,63CMD_FMT_PTRWIDTH,64CMD_FMT_XY,65CMD_FMT_XYXY,66CMD_FMT_XYZ,67CMD_FMT_XYPLUS1,68CMD_FMT_TEXSIZE,69CMD_FMT_F16_XY,70CMD_FMT_VERTEXTYPE,71CMD_FMT_TEXFMT,72CMD_FMT_CLUTFMT,73CMD_FMT_COLORTEST,74CMD_FMT_ALPHATEST,75CMD_FMT_STENCILTEST,76CMD_FMT_ZTEST,77CMD_FMT_OFFSETADDR,78CMD_FMT_VADDR,79CMD_FMT_IADDR,80CMD_FMT_MATERIALUPDATE,81CMD_FMT_STENCILOP,82CMD_FMT_BLENDMODE,83CMD_FMT_FLAG,84CMD_FMT_CLEARMODE,85CMD_FMT_TEXFUNC,86CMD_FMT_TEXMODE,87CMD_FMT_LOGICOP,88CMD_FMT_TEXWRAP,89CMD_FMT_TEXLEVEL,90CMD_FMT_TEXFILTER,91CMD_FMT_TEXMAPMODE,92CMD_FMT_TEXSHADELS,93CMD_FMT_SHADEMODEL,94CMD_FMT_LIGHTMODE,95CMD_FMT_LIGHTTYPE,96CMD_FMT_CULL,97CMD_FMT_PATCHPRIMITIVE,98};99100struct TabStateRow {101const TCHAR *title;102u8 cmd;103CmdFormatType fmt;104u8 enableCmd;105u8 otherCmd;106u8 otherCmd2;107};108109static const TabStateRow stateFlagsRows[] = {110{ L"Lighting enable", GE_CMD_LIGHTINGENABLE, CMD_FMT_FLAG },111{ L"Light 0 enable", GE_CMD_LIGHTENABLE0, CMD_FMT_FLAG },112{ L"Light 1 enable", GE_CMD_LIGHTENABLE1, CMD_FMT_FLAG },113{ L"Light 2 enable", GE_CMD_LIGHTENABLE2, CMD_FMT_FLAG },114{ L"Light 3 enable", GE_CMD_LIGHTENABLE3, CMD_FMT_FLAG },115{ L"Depth clamp enable", GE_CMD_DEPTHCLAMPENABLE, CMD_FMT_FLAG },116{ L"Cullface enable", GE_CMD_CULLFACEENABLE, CMD_FMT_FLAG },117{ L"Texture map enable", GE_CMD_TEXTUREMAPENABLE, CMD_FMT_FLAG },118{ L"Fog enable", GE_CMD_FOGENABLE, CMD_FMT_FLAG },119{ L"Dither enable", GE_CMD_DITHERENABLE, CMD_FMT_FLAG },120{ L"Alpha blend enable", GE_CMD_ALPHABLENDENABLE, CMD_FMT_FLAG },121{ L"Alpha test enable", GE_CMD_ALPHATESTENABLE, CMD_FMT_FLAG },122{ L"Depth test enable", GE_CMD_ZTESTENABLE, CMD_FMT_FLAG },123{ L"Stencil test enable", GE_CMD_STENCILTESTENABLE, CMD_FMT_FLAG },124{ L"Antialias enable", GE_CMD_ANTIALIASENABLE, CMD_FMT_FLAG },125{ L"Patch cull enable", GE_CMD_PATCHCULLENABLE, CMD_FMT_FLAG },126{ L"Color test enable", GE_CMD_COLORTESTENABLE, CMD_FMT_FLAG },127{ L"Logic op enable", GE_CMD_LOGICOPENABLE, CMD_FMT_FLAG },128{ L"Depth write disable", GE_CMD_ZWRITEDISABLE, CMD_FMT_FLAG },129};130131static const TabStateRow stateLightingRows[] = {132{ L"Ambient color", GE_CMD_AMBIENTCOLOR, CMD_FMT_HEX },133{ L"Ambient alpha", GE_CMD_AMBIENTALPHA, CMD_FMT_HEX },134{ L"Material update", GE_CMD_MATERIALUPDATE, CMD_FMT_MATERIALUPDATE },135{ L"Material emissive", GE_CMD_MATERIALEMISSIVE, CMD_FMT_HEX },136{ L"Material ambient", GE_CMD_MATERIALAMBIENT, CMD_FMT_HEX },137{ L"Material diffuse", GE_CMD_MATERIALDIFFUSE, CMD_FMT_HEX },138{ L"Material alpha", GE_CMD_MATERIALALPHA, CMD_FMT_HEX },139{ L"Material specular", GE_CMD_MATERIALSPECULAR, CMD_FMT_HEX },140{ L"Mat. specular coef", GE_CMD_MATERIALSPECULARCOEF, CMD_FMT_FLOAT24 },141{ L"Reverse normals", GE_CMD_REVERSENORMAL, CMD_FMT_FLAG },142{ L"Shade model", GE_CMD_SHADEMODE, CMD_FMT_SHADEMODEL },143{ L"Light mode", GE_CMD_LIGHTMODE, CMD_FMT_LIGHTMODE, GE_CMD_LIGHTINGENABLE },144{ L"Light type 0", GE_CMD_LIGHTTYPE0, CMD_FMT_LIGHTTYPE, GE_CMD_LIGHTENABLE0 },145{ L"Light type 1", GE_CMD_LIGHTTYPE1, CMD_FMT_LIGHTTYPE, GE_CMD_LIGHTENABLE1 },146{ L"Light type 2", GE_CMD_LIGHTTYPE2, CMD_FMT_LIGHTTYPE, GE_CMD_LIGHTENABLE2 },147{ L"Light type 3", GE_CMD_LIGHTTYPE3, CMD_FMT_LIGHTTYPE, GE_CMD_LIGHTENABLE3 },148{ L"Light pos 0", GE_CMD_LX0, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE0, GE_CMD_LY0, GE_CMD_LZ0 },149{ L"Light pos 1", GE_CMD_LX1, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE1, GE_CMD_LY1, GE_CMD_LZ1 },150{ L"Light pos 2", GE_CMD_LX2, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE2, GE_CMD_LY2, GE_CMD_LZ2 },151{ L"Light pos 3", GE_CMD_LX3, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE3, GE_CMD_LY3, GE_CMD_LZ3 },152{ L"Light dir 0", GE_CMD_LDX0, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE0, GE_CMD_LDY0, GE_CMD_LDZ0 },153{ L"Light dir 1", GE_CMD_LDX1, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE1, GE_CMD_LDY1, GE_CMD_LDZ1 },154{ L"Light dir 2", GE_CMD_LDX2, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE2, GE_CMD_LDY2, GE_CMD_LDZ2 },155{ L"Light dir 3", GE_CMD_LDX3, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE3, GE_CMD_LDY3, GE_CMD_LDZ3 },156{ L"Light att 0", GE_CMD_LKA0, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE0, GE_CMD_LKB0, GE_CMD_LKC0 },157{ L"Light att 1", GE_CMD_LKA1, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE1, GE_CMD_LKB1, GE_CMD_LKC1 },158{ L"Light att 2", GE_CMD_LKA2, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE2, GE_CMD_LKB2, GE_CMD_LKC2 },159{ L"Light att 3", GE_CMD_LKA3, CMD_FMT_XYZ, GE_CMD_LIGHTENABLE3, GE_CMD_LKB3, GE_CMD_LKC3 },160{ L"Lightspot coef 0", GE_CMD_LKS0, CMD_FMT_FLOAT24, GE_CMD_LIGHTENABLE0 },161{ L"Lightspot coef 1", GE_CMD_LKS1, CMD_FMT_FLOAT24, GE_CMD_LIGHTENABLE1 },162{ L"Lightspot coef 2", GE_CMD_LKS2, CMD_FMT_FLOAT24, GE_CMD_LIGHTENABLE2 },163{ L"Lightspot coef 3", GE_CMD_LKS3, CMD_FMT_FLOAT24, GE_CMD_LIGHTENABLE3 },164{ L"Light angle 0", GE_CMD_LKO0, CMD_FMT_FLOAT24, GE_CMD_LIGHTENABLE0 },165{ L"Light angle 1", GE_CMD_LKO1, CMD_FMT_FLOAT24, GE_CMD_LIGHTENABLE1 },166{ L"Light angle 2", GE_CMD_LKO2, CMD_FMT_FLOAT24, GE_CMD_LIGHTENABLE2 },167{ L"Light angle 3", GE_CMD_LKO3, CMD_FMT_FLOAT24, GE_CMD_LIGHTENABLE3 },168{ L"Light ambient 0", GE_CMD_LAC0, CMD_FMT_HEX, GE_CMD_LIGHTENABLE0 },169{ L"Light diffuse 0", GE_CMD_LDC0, CMD_FMT_HEX, GE_CMD_LIGHTENABLE0 },170{ L"Light specular 0", GE_CMD_LSC0, CMD_FMT_HEX, GE_CMD_LIGHTENABLE0 },171{ L"Light ambient 1", GE_CMD_LAC1, CMD_FMT_HEX, GE_CMD_LIGHTENABLE1 },172{ L"Light diffuse 1", GE_CMD_LDC1, CMD_FMT_HEX, GE_CMD_LIGHTENABLE1 },173{ L"Light specular 1", GE_CMD_LSC1, CMD_FMT_HEX, GE_CMD_LIGHTENABLE1 },174{ L"Light ambient 2", GE_CMD_LAC2, CMD_FMT_HEX, GE_CMD_LIGHTENABLE2 },175{ L"Light diffuse 2", GE_CMD_LDC2, CMD_FMT_HEX, GE_CMD_LIGHTENABLE2 },176{ L"Light specular 2", GE_CMD_LSC2, CMD_FMT_HEX, GE_CMD_LIGHTENABLE2 },177{ L"Light ambient 3", GE_CMD_LAC3, CMD_FMT_HEX, GE_CMD_LIGHTENABLE3 },178{ L"Light diffuse 3", GE_CMD_LDC3, CMD_FMT_HEX, GE_CMD_LIGHTENABLE3 },179{ L"Light specular 3", GE_CMD_LSC3, CMD_FMT_HEX, GE_CMD_LIGHTENABLE3 },180};181182static const TabStateRow stateTextureRows[] = {183{ L"Texture L0 addr", GE_CMD_TEXADDR0, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH0 },184{ L"Texture L0 size", GE_CMD_TEXSIZE0, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE },185{ L"Tex format", GE_CMD_TEXFORMAT, CMD_FMT_TEXFMT, GE_CMD_TEXTUREMAPENABLE },186{ L"Tex CLUT", GE_CMD_CLUTADDR, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_CLUTADDRUPPER },187{ L"Tex CLUT format", GE_CMD_CLUTFORMAT, CMD_FMT_CLUTFMT, GE_CMD_TEXTUREMAPENABLE },188189{ L"Tex U scale", GE_CMD_TEXSCALEU, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE },190{ L"Tex V scale", GE_CMD_TEXSCALEV, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE },191{ L"Tex U offset", GE_CMD_TEXOFFSETU, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE },192{ L"Tex V offset", GE_CMD_TEXOFFSETV, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE },193{ L"Tex mapping mode", GE_CMD_TEXMAPMODE, CMD_FMT_TEXMAPMODE, GE_CMD_TEXTUREMAPENABLE },194{ L"Tex shade srcs", GE_CMD_TEXSHADELS, CMD_FMT_TEXSHADELS, GE_CMD_TEXTUREMAPENABLE },195{ L"Tex func", GE_CMD_TEXFUNC, CMD_FMT_TEXFUNC, GE_CMD_TEXTUREMAPENABLE },196{ L"Tex env color", GE_CMD_TEXENVCOLOR, CMD_FMT_HEX, GE_CMD_TEXTUREMAPENABLE },197{ L"Tex mode", GE_CMD_TEXMODE, CMD_FMT_TEXMODE, GE_CMD_TEXTUREMAPENABLE },198{ L"Tex filtering", GE_CMD_TEXFILTER, CMD_FMT_TEXFILTER, GE_CMD_TEXTUREMAPENABLE },199{ L"Tex wrapping", GE_CMD_TEXWRAP, CMD_FMT_TEXWRAP, GE_CMD_TEXTUREMAPENABLE },200{ L"Tex level/bias", GE_CMD_TEXLEVEL, CMD_FMT_TEXLEVEL, GE_CMD_TEXTUREMAPENABLE },201{ L"Tex lod slope", GE_CMD_TEXLODSLOPE, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE },202{ L"Texture L1 addr", GE_CMD_TEXADDR1, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH1 },203{ L"Texture L2 addr", GE_CMD_TEXADDR2, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH2 },204{ L"Texture L3 addr", GE_CMD_TEXADDR3, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH3 },205{ L"Texture L4 addr", GE_CMD_TEXADDR4, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH4 },206{ L"Texture L5 addr", GE_CMD_TEXADDR5, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH5 },207{ L"Texture L6 addr", GE_CMD_TEXADDR6, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH6 },208{ L"Texture L7 addr", GE_CMD_TEXADDR7, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH7 },209{ L"Texture L1 size", GE_CMD_TEXSIZE1, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE },210{ L"Texture L2 size", GE_CMD_TEXSIZE2, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE },211{ L"Texture L3 size", GE_CMD_TEXSIZE3, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE },212{ L"Texture L4 size", GE_CMD_TEXSIZE4, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE },213{ L"Texture L5 size", GE_CMD_TEXSIZE5, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE },214{ L"Texture L6 size", GE_CMD_TEXSIZE6, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE },215{ L"Texture L7 size", GE_CMD_TEXSIZE7, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE },216};217218static const TabStateRow stateSettingsRows[] = {219{ L"Framebuffer", GE_CMD_FRAMEBUFPTR, CMD_FMT_PTRWIDTH, 0, GE_CMD_FRAMEBUFWIDTH },220{ L"Framebuffer format", GE_CMD_FRAMEBUFPIXFORMAT, CMD_FMT_TEXFMT },221{ L"Depthbuffer", GE_CMD_ZBUFPTR, CMD_FMT_PTRWIDTH, 0, GE_CMD_ZBUFWIDTH },222{ L"Viewport Scale", GE_CMD_VIEWPORTXSCALE, CMD_FMT_XYZ, 0, GE_CMD_VIEWPORTYSCALE, GE_CMD_VIEWPORTZSCALE },223{ L"Viewport Offset", GE_CMD_VIEWPORTXCENTER, CMD_FMT_XYZ, 0, GE_CMD_VIEWPORTYCENTER, GE_CMD_VIEWPORTZCENTER },224{ L"Scissor", GE_CMD_SCISSOR1, CMD_FMT_XYXY, 0, GE_CMD_SCISSOR2 },225{ L"Region", GE_CMD_REGION1, CMD_FMT_XYXY, 0, GE_CMD_REGION2 },226{ L"Color test", GE_CMD_COLORTEST, CMD_FMT_COLORTEST, GE_CMD_COLORTESTENABLE, GE_CMD_COLORREF, GE_CMD_COLORTESTMASK },227{ L"Alpha test", GE_CMD_ALPHATEST, CMD_FMT_ALPHATEST, GE_CMD_ALPHATESTENABLE },228{ L"Clear mode", GE_CMD_CLEARMODE, CMD_FMT_CLEARMODE },229{ L"Stencil test", GE_CMD_STENCILTEST, CMD_FMT_STENCILTEST, GE_CMD_STENCILTESTENABLE },230{ L"Stencil test op", GE_CMD_STENCILOP, CMD_FMT_STENCILOP, GE_CMD_STENCILTESTENABLE },231{ L"Depth test", GE_CMD_ZTEST, CMD_FMT_ZTEST, GE_CMD_ZTESTENABLE },232{ L"RGB mask", GE_CMD_MASKRGB, CMD_FMT_HEX },233{ L"Stencil/alpha mask", GE_CMD_MASKALPHA, CMD_FMT_HEX },234{ L"Transfer src", GE_CMD_TRANSFERSRC, CMD_FMT_PTRWIDTH, 0, GE_CMD_TRANSFERSRCW },235{ L"Transfer src pos", GE_CMD_TRANSFERSRCPOS, CMD_FMT_XY },236{ L"Transfer dst", GE_CMD_TRANSFERDST, CMD_FMT_PTRWIDTH, 0, GE_CMD_TRANSFERDSTW },237{ L"Transfer dst pos", GE_CMD_TRANSFERDSTPOS, CMD_FMT_XY },238{ L"Transfer size", GE_CMD_TRANSFERSIZE, CMD_FMT_XYPLUS1 },239{ L"Vertex type", GE_CMD_VERTEXTYPE, CMD_FMT_VERTEXTYPE },240{ L"Offset addr", GE_CMD_OFFSETADDR, CMD_FMT_OFFSETADDR },241{ L"Vertex addr", GE_CMD_VADDR, CMD_FMT_VADDR },242{ L"Index addr", GE_CMD_IADDR, CMD_FMT_IADDR },243{ L"Min Z", GE_CMD_MINZ, CMD_FMT_HEX },244{ L"Max Z", GE_CMD_MAXZ, CMD_FMT_HEX },245{ L"Offset", GE_CMD_OFFSETX, CMD_FMT_F16_XY, 0, GE_CMD_OFFSETY },246{ L"Cull mode", GE_CMD_CULL, CMD_FMT_CULL, GE_CMD_CULLFACEENABLE },247{ L"Alpha blend mode", GE_CMD_BLENDMODE, CMD_FMT_BLENDMODE, GE_CMD_ALPHABLENDENABLE },248{ L"Blend color A", GE_CMD_BLENDFIXEDA, CMD_FMT_HEX, GE_CMD_ALPHABLENDENABLE },249{ L"Blend color B", GE_CMD_BLENDFIXEDB, CMD_FMT_HEX, GE_CMD_ALPHABLENDENABLE },250{ L"Logic Op", GE_CMD_LOGICOP, CMD_FMT_LOGICOP, GE_CMD_LOGICOPENABLE },251{ L"Fog 1", GE_CMD_FOG1, CMD_FMT_FLOAT24, GE_CMD_FOGENABLE },252{ L"Fog 2", GE_CMD_FOG2, CMD_FMT_FLOAT24, GE_CMD_FOGENABLE },253{ L"Fog color", GE_CMD_FOGCOLOR, CMD_FMT_HEX, GE_CMD_FOGENABLE },254{ L"Morph Weight 0", GE_CMD_MORPHWEIGHT0, CMD_FMT_FLOAT24 },255{ L"Morph Weight 1", GE_CMD_MORPHWEIGHT1, CMD_FMT_FLOAT24 },256{ L"Morph Weight 2", GE_CMD_MORPHWEIGHT2, CMD_FMT_FLOAT24 },257{ L"Morph Weight 3", GE_CMD_MORPHWEIGHT3, CMD_FMT_FLOAT24 },258{ L"Morph Weight 4", GE_CMD_MORPHWEIGHT4, CMD_FMT_FLOAT24 },259{ L"Morph Weight 5", GE_CMD_MORPHWEIGHT5, CMD_FMT_FLOAT24 },260{ L"Morph Weight 6", GE_CMD_MORPHWEIGHT6, CMD_FMT_FLOAT24 },261{ L"Morph Weight 7", GE_CMD_MORPHWEIGHT7, CMD_FMT_FLOAT24 },262// TODO: Format?263{ L"Patch division", GE_CMD_PATCHDIVISION, CMD_FMT_HEX },264{ L"Patch primitive", GE_CMD_PATCHPRIMITIVE, CMD_FMT_PATCHPRIMITIVE },265// TODO: Format?266{ L"Patch facing", GE_CMD_PATCHFACING, CMD_FMT_HEX, GE_CMD_PATCHCULLENABLE },267{ L"Dither 0", GE_CMD_DITH0, CMD_FMT_HEX, GE_CMD_DITHERENABLE },268{ L"Dither 1", GE_CMD_DITH1, CMD_FMT_HEX, GE_CMD_DITHERENABLE },269{ L"Dither 2", GE_CMD_DITH2, CMD_FMT_HEX, GE_CMD_DITHERENABLE },270{ L"Dither 3", GE_CMD_DITH3, CMD_FMT_HEX, GE_CMD_DITHERENABLE },271{ L"Imm vertex XY", GE_CMD_VSCX, CMD_FMT_F16_XY, 0, GE_CMD_VSCY },272{ L"Imm vertex Z", GE_CMD_VSCZ, CMD_FMT_HEX },273{ L"Imm vertex tex STQ", GE_CMD_VTCS, CMD_FMT_XYZ, 0, GE_CMD_VTCT, GE_CMD_VTCQ },274{ L"Imm vertex color0", GE_CMD_VCV, CMD_FMT_HEX },275{ L"Imm vertex color1", GE_CMD_VSCV, CMD_FMT_HEX },276{ L"Imm vertex fog", GE_CMD_VFC, CMD_FMT_HEX },277// TODO: Format?278{ L"Imm vertex prim", GE_CMD_VAP, CMD_FMT_HEX },279};280281// TODO: Commands not present in the above lists (some because they don't have meaningful values...):282// GE_CMD_PRIM, GE_CMD_BEZIER, GE_CMD_SPLINE, GE_CMD_BOUNDINGBOX,283// GE_CMD_JUMP, GE_CMD_BJUMP, GE_CMD_CALL, GE_CMD_RET, GE_CMD_END, GE_CMD_SIGNAL, GE_CMD_FINISH,284// GE_CMD_BONEMATRIXNUMBER, GE_CMD_BONEMATRIXDATA, GE_CMD_WORLDMATRIXNUMBER, GE_CMD_WORLDMATRIXDATA,285// GE_CMD_VIEWMATRIXNUMBER, GE_CMD_VIEWMATRIXDATA, GE_CMD_PROJMATRIXNUMBER, GE_CMD_PROJMATRIXDATA,286// GE_CMD_TGENMATRIXNUMBER, GE_CMD_TGENMATRIXDATA,287// GE_CMD_LOADCLUT, GE_CMD_TEXFLUSH, GE_CMD_TEXSYNC,288// GE_CMD_TRANSFERSTART,289// GE_CMD_UNKNOWN_*290291static std::vector<TabStateRow> watchList;292293static void ToggleWatchList(const TabStateRow &info) {294for (size_t i = 0; i < watchList.size(); ++i) {295if (watchList[i].cmd == info.cmd) {296watchList.erase(watchList.begin() + i);297return;298}299}300301watchList.push_back(info);302}303304static bool ToggleBreakpoint(const TabStateRow &info) {305if (IsCmdBreakpoint(info.cmd)) {306RemoveCmdBreakpoint(info.cmd);307if (info.otherCmd)308RemoveCmdBreakpoint(info.otherCmd);309if (info.otherCmd2)310RemoveCmdBreakpoint(info.otherCmd2);311return false;312}313314AddCmdBreakpoint(info.cmd);315if (info.otherCmd)316AddCmdBreakpoint(info.otherCmd);317if (info.otherCmd2)318AddCmdBreakpoint(info.otherCmd2);319return true;320}321322bool PromptStateValue(const TabStateRow &info, HWND hparent, const wchar_t *title, u32 &value) {323if (info.fmt == CMD_FMT_FLOAT24 || info.fmt == CMD_FMT_XYZ) {324union {325u32 u;326float f;327} temp = { value << 8 };328329std::string strvalue = StringFromFormat("%f", temp.f);330bool res = InputBox_GetString(GetModuleHandle(NULL), hparent, title, strvalue, strvalue);331if (!res)332return false;333334// Okay, the result could be a simple float, hex (0x...), or invalid.335if (sscanf(strvalue.c_str(), "0x%08x", &value) == 1)336return true;337if (sscanf(strvalue.c_str(), "%f", &temp.f) == 1) {338value = temp.u >> 8;339return true;340}341return false;342}343return InputBox_GetHex(GetModuleHandle(NULL), hparent, title, value, value);344}345346CtrlStateValues::CtrlStateValues(const TabStateRow *rows, int rowCount, HWND hwnd)347: GenericListControl(hwnd, stateValuesListDef),348rows_(rows), rowCount_(rowCount) {349SetIconList(12, 12, { (HICON)LoadIcon(GetModuleHandle(nullptr), (LPCWSTR)IDI_BREAKPOINT_SMALL) });350Update();351}352353void FormatStateRow(wchar_t *dest, const TabStateRow &info, u32 value, bool enabled, u32 otherValue, u32 otherValue2) {354switch (info.fmt) {355case CMD_FMT_HEX:356swprintf(dest, 255, L"%06x", value);357break;358359case CMD_FMT_NUM:360swprintf(dest, 255, L"%d", value);361break;362363case CMD_FMT_FLOAT24:364swprintf(dest, 255, L"%f", getFloat24(value));365break;366367case CMD_FMT_PTRWIDTH:368value |= (otherValue & 0x00FF0000) << 8;369otherValue &= 0xFFFF;370swprintf(dest, 255, L"%08x, w=%d", value, otherValue);371break;372373case CMD_FMT_XY:374{375int x = value & 0x3FF;376int y = value >> 10;377swprintf(dest, 255, L"%d,%d", x, y);378}379break;380381case CMD_FMT_XYPLUS1:382{383int x = value & 0x3FF;384int y = value >> 10;385swprintf(dest, 255, L"%d,%d", x + 1, y + 1);386}387break;388389case CMD_FMT_XYXY:390{391int x1 = value & 0x3FF;392int y1 = value >> 10;393int x2 = otherValue & 0x3FF;394int y2 = otherValue >> 10;395swprintf(dest, 255, L"%d,%d - %d,%d", x1, y1, x2, y2);396}397break;398399case CMD_FMT_XYZ:400{401float x = getFloat24(value);402float y = getFloat24(otherValue);403float z = getFloat24(otherValue2);404swprintf(dest, 255, L"%f, %f, %f", x, y, z);405}406break;407408case CMD_FMT_TEXSIZE:409{410int w = 1 << (value & 0x1f);411int h = 1 << ((value >> 8) & 0x1f);412swprintf(dest, 255, L"%dx%d", w, h);413}414break;415416case CMD_FMT_F16_XY:417{418float x = (float)value / 16.0f;419float y = (float)otherValue / 16.0f;420swprintf(dest, 255, L"%fx%f", x, y);421}422break;423424case CMD_FMT_VERTEXTYPE:425{426char buffer[256];427GeDescribeVertexType(value, buffer);428swprintf(dest, 255, L"%S", buffer);429}430break;431432case CMD_FMT_TEXFMT:433{434static const char *texformats[] = {435"5650",436"5551",437"4444",438"8888",439"CLUT4",440"CLUT8",441"CLUT16",442"CLUT32",443"DXT1",444"DXT3",445"DXT5",446};447if (value < (u32)ARRAY_SIZE(texformats)) {448swprintf(dest, 255, L"%S", texformats[value]);449}450else if ((value & 0xF) < (u32)ARRAY_SIZE(texformats)) {451swprintf(dest, 255, L"%S (extra bits %06x)", texformats[value & 0xF], value & ~0xF);452}453else {454swprintf(dest, 255, L"%06x", value);455}456}457break;458459case CMD_FMT_CLUTFMT:460{461const char *clutformats[] = {462"BGR 5650",463"ABGR 1555",464"ABGR 4444",465"ABGR 8888",466};467const u8 palette = (value >> 0) & 3;468const u8 shift = (value >> 2) & 0x3F;469const u8 mask = (value >> 8) & 0xFF;470const u8 offset = (value >> 16) & 0xFF;471if (offset < 0x20 && shift < 0x20) {472if (offset == 0 && shift == 0) {473swprintf(dest, 255, L"%S ind & %02x", clutformats[palette], mask);474} else {475swprintf(dest, 255, L"%S (ind >> %d) & %02x, offset +%d", clutformats[palette], shift, mask, offset);476}477} else {478swprintf(dest, 255, L"%06x", value);479}480}481break;482483case CMD_FMT_COLORTEST:484{485static const char *colorTests[] = {"NEVER", "ALWAYS", " == ", " != "};486const u32 mask = otherValue2;487const u32 ref = otherValue;488if (value < (u32)ARRAY_SIZE(colorTests)) {489swprintf(dest, 255, L"pass if (c & %06x) %S (%06x & %06x)", mask, colorTests[value], ref, mask);490} else {491swprintf(dest, 255, L"%06x, ref=%06x, maks=%06x", value, ref, mask);492}493}494break;495496case CMD_FMT_ALPHATEST:497case CMD_FMT_STENCILTEST:498{499static const char *alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };500const u8 mask = (value >> 16) & 0xff;501const u8 ref = (value >> 8) & 0xff;502const u8 func = (value >> 0) & 0xff;503if (func < (u8)ARRAY_SIZE(alphaTestFuncs)) {504if (info.fmt == CMD_FMT_ALPHATEST) {505swprintf(dest, 255, L"pass if (a & %02x) %S (%02x & %02x)", mask, alphaTestFuncs[func], ref, mask);506} else if (info.fmt == CMD_FMT_STENCILTEST) {507// Stencil test is the other way around.508swprintf(dest, 255, L"pass if (%02x & %02x) %S (a & %02x)", ref, mask, alphaTestFuncs[func], mask);509}510} else {511swprintf(dest, 255, L"%06x", value);512}513}514break;515516case CMD_FMT_ZTEST:517{518static const char *zTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };519if (value < (u32)ARRAY_SIZE(zTestFuncs)) {520swprintf(dest, 255, L"pass if src %S dst", zTestFuncs[value]);521} else {522swprintf(dest, 255, L"%06x", value);523}524}525break;526527case CMD_FMT_OFFSETADDR:528swprintf(dest, 255, L"%08x", gpuDebug->GetRelativeAddress(0));529break;530531case CMD_FMT_VADDR:532swprintf(dest, 255, L"%08x", gpuDebug->GetVertexAddress());533break;534535case CMD_FMT_IADDR:536swprintf(dest, 255, L"%08x", gpuDebug->GetIndexAddress());537break;538539case CMD_FMT_MATERIALUPDATE:540{541static const char *materialTypes[] = {542"none",543"ambient",544"diffuse",545"ambient, diffuse",546"specular",547"ambient, specular",548"diffuse, specular",549"ambient, diffuse, specular",550};551if (value < (u32)ARRAY_SIZE(materialTypes)) {552swprintf(dest, 255, L"%S", materialTypes[value]);553} else {554swprintf(dest, 255, L"%06x", value);555}556}557break;558559case CMD_FMT_SHADEMODEL:560if (value == 0) {561swprintf(dest, 255, L"flat");562} else if (value == 1) {563swprintf(dest, 255, L"gouraud");564} else {565swprintf(dest, 255, L"%06x", value);566}567break;568569case CMD_FMT_STENCILOP:570{571static const char *stencilOps[] = { "KEEP", "ZERO", "REPLACE", "INVERT", "INCREMENT", "DECREMENT" };572const u8 sfail = (value >> 0) & 0xFF;573const u8 zfail = (value >> 8) & 0xFF;574const u8 pass = (value >> 16) & 0xFF;575const u8 totalValid = (u8)ARRAY_SIZE(stencilOps);576if (sfail < totalValid && zfail < totalValid && pass < totalValid) {577swprintf(dest, 255, L"fail=%S, pass/depthfail=%S, pass=%S", stencilOps[sfail], stencilOps[zfail], stencilOps[pass]);578} else {579swprintf(dest, 255, L"%06x", value);580}581}582break;583584case CMD_FMT_BLENDMODE:585{586const char *blendModes[] = {587"add",588"subtract",589"reverse subtract",590"min",591"max",592"abs subtract",593};594const char *blendFactorsA[] = {595"dst",596"1.0 - dst",597"src.a",598"1.0 - src.a",599"dst.a",600"1.0 - dst.a",601"2.0 * src.a",602"1.0 - 2.0 * src.a",603"2.0 * dst.a",604"1.0 - 2.0 * dst.a",605"fixed",606};607const char *blendFactorsB[] = {608"src",609"1.0 - src",610"src.a",611"1.0 - src.a",612"dst.a",613"1.0 - dst.a",614"2.0 * src.a",615"1.0 - 2.0 * src.a",616"2.0 * dst.a",617"1.0 - 2.0 * dst.a",618"fixed",619};620const u8 blendFactorA = (value >> 0) & 0xF;621const u8 blendFactorB = (value >> 4) & 0xF;622const u32 blendMode = (value >> 8);623624if (blendFactorA < (u8)ARRAY_SIZE(blendFactorsA) && blendFactorB < (u8)ARRAY_SIZE(blendFactorsB) && blendMode < (u32)ARRAY_SIZE(blendModes)) {625swprintf(dest, 255, L"%S: %S, %S", blendModes[blendMode], blendFactorsA[blendFactorA], blendFactorsB[blendFactorB]);626} else {627swprintf(dest, 255, L"%06x", value);628}629}630break;631632case CMD_FMT_CLEARMODE:633if (value == 0) {634swprintf(dest, 255, L"%d", value);635} else if ((value & ~(GE_CLEARMODE_ALL | 1)) == 0) {636const char *clearmodes[] = {637"1, write disabled",638"1, write color",639"1, write alpha/stencil",640"1, write color, alpha/stencil",641"1, write depth",642"1, write color, depth",643"1, write alpha/stencil, depth",644"1, write color, alpha/stencil, depth",645};646swprintf(dest, 255, L"%S", clearmodes[value >> 8]);647} else {648swprintf(dest, 255, L"%06x", value);649}650break;651652case CMD_FMT_TEXFUNC:653{654const char *texfuncs[] = {655"modulate",656"decal",657"blend",658"replace",659"add",660};661const u8 func = (value >> 0) & 0xFF;662const u8 rgba = (value >> 8) & 0xFF;663const u8 colorDouble = (value >> 16) & 0xFF;664665if (rgba <= 1 && colorDouble <= 1 && func < (u8)ARRAY_SIZE(texfuncs)) {666swprintf(dest, 255, L"%S, %S%S", texfuncs[func], rgba ? "RGBA" : "RGB", colorDouble ? ", color doubling" : "");667} else {668swprintf(dest, 255, L"%06x", value);669}670}671break;672673case CMD_FMT_TEXMODE:674{675const u8 swizzle = (value >> 0) & 0xFF;676const u8 clutLevels = (value >> 8) & 0xFF;677const u8 maxLevel = (value >> 16) & 0xFF;678679if (swizzle <= 1 && clutLevels <= 1 && maxLevel <= 7) {680swprintf(dest, 255, L"%S%d levels%S", swizzle ? "swizzled, " : "", maxLevel + 1, clutLevels ? ", CLUT per level" : "");681} else {682swprintf(dest, 255, L"%06x", value);683}684}685break;686687case CMD_FMT_LOGICOP:688{689const char *logicOps[] = {690"clear",691"and",692"reverse and",693"copy",694"inverted and",695"noop",696"xor",697"or",698"negated or",699"equivalence",700"inverted",701"reverse or",702"inverted copy",703"inverted or",704"negated and",705"set",706};707708if (value < ARRAY_SIZE(logicOps)) {709swprintf(dest, 255, L"%S", logicOps[value]);710} else {711swprintf(dest, 255, L"%06x", value);712}713}714break;715716case CMD_FMT_TEXWRAP:717{718if ((value & ~0x0101) == 0) {719const bool clampS = (value & 0x0001) != 0;720const bool clampT = (value & 0x0100) != 0;721swprintf(dest, 255, L"%S s, %S t", clampS ? "clamp" : "wrap", clampT ? "clamp" : "wrap");722} else {723swprintf(dest, 255, L"%06x", value);724}725}726break;727728case CMD_FMT_TEXLEVEL:729{730static constexpr std::array<const char*, 3> mipLevelModes = {731"auto + bias",732"bias",733"slope + bias",734};735const int mipLevel = value & 0xFFFF;736const int biasFixed = (s8)(value >> 16);737const float bias = (float)biasFixed / 16.0f;738739if (mipLevel == 0 || mipLevel == 1 || mipLevel == 2) {740swprintf(dest, 255, L"%S: %f", mipLevelModes[mipLevel], bias);741} else {742swprintf(dest, 255, L"%06x", value);743}744}745break;746747case CMD_FMT_TEXFILTER:748{749const char *textureFilters[] = {750"nearest",751"linear",752NULL,753NULL,754"nearest, mipmap nearest",755"linear, mipmap nearest",756"nearest, mipmap linear",757"linear, mipmap linear",758};759if ((value & ~0x0107) == 0 && textureFilters[value & 7] != NULL) {760const int min = (value & 0x0007) >> 0;761const int mag = (value & 0x0100) >> 8;762swprintf(dest, 255, L"min: %S, mag: %S", textureFilters[min], textureFilters[mag]);763} else {764swprintf(dest, 255, L"%06x", value);765}766}767break;768769case CMD_FMT_TEXMAPMODE:770{771static constexpr std::array<const char*, 4> uvGenModes = {772"tex coords",773"tex matrix",774"tex env map",775"unknown (tex coords?)",776};777static constexpr std::array<const char*, 4> uvProjModes = {778"pos",779"uv",780"normalized normal",781"normal",782};783if ((value & ~0x0303) == 0) {784const int uvGen = (value & 0x0003) >> 0;785const int uvProj = (value & 0x0300) >> 8;786swprintf(dest, 255, L"gen: %S, proj: %S", uvGenModes[uvGen], uvProjModes[uvProj]);787} else {788swprintf(dest, 255, L"%06x", value);789}790}791break;792793case CMD_FMT_TEXSHADELS:794if ((value & ~0x0303) == 0) {795const int sLight = (value & 0x0003) >> 0;796const int tLight = (value & 0x0300) >> 8;797swprintf(dest, 255, L"s: %d, t: %d", sLight, tLight);798} else {799swprintf(dest, 255, L"%06x", value);800}801break;802803case CMD_FMT_LIGHTMODE:804if (value == 0) {805swprintf(dest, 255, L"mixed color");806} else if (value == 1) {807swprintf(dest, 255, L"separate specular");808} else {809swprintf(dest, 255, L"%06x", value);810}811break;812813case CMD_FMT_LIGHTTYPE:814{815static constexpr std::array<const char*, 4> lightComputations = {816"diffuse",817"diffuse + spec",818"pow(diffuse)",819"unknown (diffuse?)",820};821static constexpr std::array<const char*, 4> lightTypes = {822"directional",823"point",824"spot",825"unknown (directional?)",826};827if ((value & ~0x0303) == 0) {828const int comp = (value & 0x0003) >> 0;829const int type = (value & 0x0300) >> 8;830swprintf(dest, 255, L"type: %S, comp: %S", lightTypes[type], lightComputations[comp]);831} else {832swprintf(dest, 255, L"%06x", value);833}834}835break;836837case CMD_FMT_CULL:838if (value == 0) {839swprintf(dest, 255, L"front (CW)");840} else if (value == 1) {841swprintf(dest, 255, L"back (CCW)");842} else {843swprintf(dest, 255, L"%06x", value);844}845break;846847case CMD_FMT_PATCHPRIMITIVE:848{849const char *patchPrims[] = {850"triangles",851"lines",852"points",853};854if (value < (u32)ARRAY_SIZE(patchPrims)) {855swprintf(dest, 255, L"%S", patchPrims[value]);856} else {857swprintf(dest, 255, L"%06x", value);858}859}860break;861862case CMD_FMT_FLAG:863if ((value & ~1) == 0) {864swprintf(dest, 255, L"%d", value);865} else {866swprintf(dest, 255, L"%06x", value);867}868break;869870default:871swprintf(dest, 255, L"BAD FORMAT %06x", value);872}873874// TODO: Turn row grey or some such?875if (!enabled) {876wcscat(dest, L" (disabled)");877}878}879880void CtrlStateValues::GetColumnText(wchar_t *dest, int row, int col) {881if (row < 0 || row >= rowCount_) {882return;883}884885switch (col) {886case STATEVALUES_COL_BREAKPOINT:887wcscpy(dest, L" ");888break;889890case STATEVALUES_COL_NAME:891wcscpy(dest, rows_[row].title);892break;893894case STATEVALUES_COL_VALUE:895{896if (gpuDebug == NULL) {897wcscpy(dest, L"N/A");898break;899}900901const auto info = rows_[row];902const auto state = gpuDebug->GetGState();903const bool enabled = info.enableCmd == 0 || (state.cmdmem[info.enableCmd] & 1) == 1;904const u32 value = state.cmdmem[info.cmd] & 0xFFFFFF;905const u32 otherValue = state.cmdmem[info.otherCmd] & 0xFFFFFF;906const u32 otherValue2 = state.cmdmem[info.otherCmd2] & 0xFFFFFF;907908FormatStateRow(dest, info, value, enabled, otherValue, otherValue2);909break;910}911}912}913914void CtrlStateValues::OnDoubleClick(int row, int column) {915if (gpuDebug == nullptr || row >= rowCount_) {916return;917}918919const auto info = rows_[row];920921if (column == STATEVALUES_COL_BREAKPOINT) {922bool proceed = true;923if (GetCmdBreakpointCond(info.cmd, nullptr)) {924int ret = MessageBox(GetHandle(), L"This breakpoint has a custom condition.\nDo you want to remove it?", L"Confirmation", MB_YESNO);925proceed = ret == IDYES;926}927if (proceed)928SetItemState(row, ToggleBreakpoint(info) ? 1 : 0);929return;930}931932switch (info.fmt) {933case CMD_FMT_FLAG:934{935const auto state = gpuDebug->GetGState();936u32 newValue = state.cmdmem[info.cmd] ^ 1;937SetCmdValue(newValue);938}939break;940941default:942{943wchar_t title[1024];944const auto state = gpuDebug->GetGState();945946u32 newValue = state.cmdmem[info.cmd] & 0x00FFFFFF;947swprintf(title, 1023, L"New value for %s", info.title);948if (PromptStateValue(info, GetHandle(), title, newValue)) {949newValue |= state.cmdmem[info.cmd] & 0xFF000000;950SetCmdValue(newValue);951952if (info.otherCmd) {953newValue = state.cmdmem[info.otherCmd] & 0x00FFFFFF;954swprintf(title, 1023, L"New value for %s (secondary)", info.title);955if (PromptStateValue(info, GetHandle(), title, newValue)) {956newValue |= state.cmdmem[info.otherCmd] & 0xFF000000;957SetCmdValue(newValue);958959if (info.otherCmd2) {960newValue = state.cmdmem[info.otherCmd2] & 0x00FFFFFF;961swprintf(title, 1023, L"New value for %s (tertiary)", info.title);962if (PromptStateValue(info, GetHandle(), title, newValue)) {963newValue |= state.cmdmem[info.otherCmd2] & 0xFF000000;964SetCmdValue(newValue);965}966}967}968}969}970}971break;972}973}974975void CtrlStateValues::OnRightClick(int row, int column, const POINT &point) {976if (gpuDebug == nullptr) {977return;978}979980const auto info = rows_[row];981const auto state = gpuDebug->GetGState();982983POINT screenPt(point);984ClientToScreen(GetHandle(), &screenPt);985986HMENU subMenu = GetContextMenu(ContextMenuID::GEDBG_STATE);987SetMenuDefaultItem(subMenu, ID_REGLIST_CHANGE, FALSE);988EnableMenuItem(subMenu, ID_GEDBG_SETCOND, GPUBreakpoints::IsCmdBreakpoint(info.cmd) ? MF_ENABLED : MF_GRAYED);989990// Ehh, kinda ugly.991if (!watchList.empty() && rows_ == &watchList[0]) {992ModifyMenu(subMenu, ID_GEDBG_WATCH, MF_BYCOMMAND | MF_STRING, ID_GEDBG_WATCH, L"Remove Watch");993} else {994ModifyMenu(subMenu, ID_GEDBG_WATCH, MF_BYCOMMAND | MF_STRING, ID_GEDBG_WATCH, L"Add Watch");995}996if (info.fmt == CMD_FMT_FLAG) {997ModifyMenu(subMenu, ID_REGLIST_CHANGE, MF_BYCOMMAND | MF_STRING, ID_REGLIST_CHANGE, L"Toggle Flag");998} else {999ModifyMenu(subMenu, ID_REGLIST_CHANGE, MF_BYCOMMAND | MF_STRING, ID_REGLIST_CHANGE, L"Change...");1000}10011002switch (TriggerContextMenu(ContextMenuID::GEDBG_STATE, GetHandle(), ContextPoint::FromClient(point)))1003{1004case ID_DISASM_TOGGLEBREAKPOINT: {1005bool proceed = true;1006if (GetCmdBreakpointCond(info.cmd, nullptr)) {1007int ret = MessageBox(GetHandle(), L"This breakpoint has a custom condition.\nDo you want to remove it?", L"Confirmation", MB_YESNO);1008proceed = ret == IDYES;1009}1010if (proceed)1011SetItemState(row, ToggleBreakpoint(info) ? 1 : 0);1012break;1013}10141015case ID_GEDBG_SETCOND:1016PromptBreakpointCond(info);1017break;10181019case ID_DISASM_COPYINSTRUCTIONHEX: {1020char temp[16];1021snprintf(temp, sizeof(temp), "%08x", gstate.cmdmem[info.cmd] & 0x00FFFFFF);1022W32Util::CopyTextToClipboard(GetHandle(), temp);1023break;1024}10251026case ID_DISASM_COPYINSTRUCTIONDISASM: {1027const bool enabled = info.enableCmd == 0 || (state.cmdmem[info.enableCmd] & 1) == 1;1028const u32 value = state.cmdmem[info.cmd] & 0xFFFFFF;1029const u32 otherValue = state.cmdmem[info.otherCmd] & 0xFFFFFF;1030const u32 otherValue2 = state.cmdmem[info.otherCmd2] & 0xFFFFFF;10311032wchar_t dest[512];1033FormatStateRow(dest, info, value, enabled, otherValue, otherValue2);1034W32Util::CopyTextToClipboard(GetHandle(), dest);1035break;1036}10371038case ID_GEDBG_COPYALL:1039CopyRows(0, GetRowCount());1040break;10411042case ID_REGLIST_CHANGE:1043OnDoubleClick(row, STATEVALUES_COL_VALUE);1044break;10451046case ID_GEDBG_WATCH:1047ToggleWatchList(info);1048SendMessage(GetParent(GetParent(GetHandle())), WM_GEDBG_UPDATE_WATCH, 0, 0);1049break;1050}1051}10521053bool CtrlStateValues::OnRowPrePaint(int row, LPNMLVCUSTOMDRAW msg) {1054if (gpuDebug && RowValuesChanged(row)) {1055msg->clrText = RGB(255, 0, 0);1056return true;1057}1058return false;1059}10601061void CtrlStateValues::SetCmdValue(u32 op) {1062SendMessage(GetParent(GetParent(GetHandle())), WM_GEDBG_SETCMDWPARAM, op, NULL);1063Update();1064}10651066bool CtrlStateValues::RowValuesChanged(int row) {1067_assert_(gpuDebug != nullptr && row >= 0 && row < rowCount_);10681069const auto info = rows_[row];1070const auto state = gpuDebug->GetGState();1071const auto lastState = GPUStepping::LastState();10721073if (state.cmdmem[info.cmd] != lastState.cmdmem[info.cmd])1074return true;1075if (info.otherCmd && state.cmdmem[info.otherCmd] != lastState.cmdmem[info.otherCmd])1076return true;1077if (info.otherCmd2 && state.cmdmem[info.otherCmd2] != lastState.cmdmem[info.otherCmd2])1078return true;10791080return false;1081}10821083void CtrlStateValues::PromptBreakpointCond(const TabStateRow &info) {1084std::string expression;1085GPUBreakpoints::GetCmdBreakpointCond(info.cmd, &expression);1086if (!InputBox_GetString(GetModuleHandle(NULL), GetHandle(), L"Expression", expression, expression))1087return;10881089std::string error;1090if (!GPUBreakpoints::SetCmdBreakpointCond(info.cmd, expression, &error)) {1091MessageBox(GetHandle(), ConvertUTF8ToWString(error).c_str(), L"Invalid expression", MB_OK | MB_ICONEXCLAMATION);1092} else {1093if (info.otherCmd)1094GPUBreakpoints::SetCmdBreakpointCond(info.otherCmd, expression, &error);1095if (info.otherCmd2)1096GPUBreakpoints::SetCmdBreakpointCond(info.otherCmd2, expression, &error);1097}10981099}11001101TabStateValues::TabStateValues(const TabStateRow *rows, int rowCount, LPCSTR dialogID, HINSTANCE _hInstance, HWND _hParent)1102: Dialog(dialogID, _hInstance, _hParent) {1103values = new CtrlStateValues(rows, rowCount, GetDlgItem(m_hDlg, IDC_GEDBG_VALUES));1104}11051106TabStateValues::~TabStateValues() {1107delete values;1108}11091110void TabStateValues::UpdateSize(WORD width, WORD height) {1111struct Position {1112int x,y;1113int w,h;1114};11151116Position position;1117static const int borderMargin = 5;11181119position.x = borderMargin;1120position.y = borderMargin;1121position.w = width - 2 * borderMargin;1122position.h = height - 2 * borderMargin;11231124HWND handle = GetDlgItem(m_hDlg,IDC_GEDBG_VALUES);1125MoveWindow(handle, position.x, position.y, position.w, position.h, TRUE);1126}11271128BOOL TabStateValues::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {1129switch (message) {1130case WM_INITDIALOG:1131return TRUE;11321133case WM_SIZE:1134UpdateSize(LOWORD(lParam), HIWORD(lParam));1135return TRUE;11361137case WM_NOTIFY:1138switch (wParam)1139{1140case IDC_GEDBG_VALUES:1141SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, values->HandleNotify(lParam));1142return TRUE;1143}1144break;1145}11461147return FALSE;1148}11491150TabStateFlags::TabStateFlags(HINSTANCE _hInstance, HWND _hParent)1151: TabStateValues(stateFlagsRows, ARRAY_SIZE(stateFlagsRows), (LPCSTR)IDD_GEDBG_TAB_VALUES, _hInstance, _hParent) {1152}11531154TabStateLighting::TabStateLighting(HINSTANCE _hInstance, HWND _hParent)1155: TabStateValues(stateLightingRows, ARRAY_SIZE(stateLightingRows), (LPCSTR)IDD_GEDBG_TAB_VALUES, _hInstance, _hParent) {1156}11571158TabStateSettings::TabStateSettings(HINSTANCE _hInstance, HWND _hParent)1159: TabStateValues(stateSettingsRows, ARRAY_SIZE(stateSettingsRows), (LPCSTR)IDD_GEDBG_TAB_VALUES, _hInstance, _hParent) {1160}11611162TabStateTexture::TabStateTexture(HINSTANCE _hInstance, HWND _hParent)1163: TabStateValues(stateTextureRows, ARRAY_SIZE(stateTextureRows), (LPCSTR)IDD_GEDBG_TAB_VALUES, _hInstance, _hParent) {1164}11651166TabStateWatch::TabStateWatch(HINSTANCE _hInstance, HWND _hParent)1167: TabStateValues(nullptr, 0, (LPCSTR)IDD_GEDBG_TAB_VALUES, _hInstance, _hParent) {1168}11691170void TabStateWatch::Update() {1171if (watchList.empty()) {1172values->UpdateRows(nullptr, 0);1173} else {1174values->UpdateRows(&watchList[0], (int)watchList.size());1175}1176TabStateValues::Update();1177}117811791180