Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/GEDebugger/CtrlDisplayListView.cpp
5659 views
1
#include <algorithm>
2
#include "Common/Data/Encoding/Utf8.h"
3
#include "Common/StringUtils.h"
4
#include "Common/System/Display.h"
5
#include "Windows/GEDebugger/CtrlDisplayListView.h"
6
#include "Windows/GEDebugger/GEDebugger.h"
7
#include "Windows/MainWindow.h"
8
#include "Windows/InputBox.h"
9
#include "Windows/W32Util/ContextMenu.h"
10
#include "Windows/main.h"
11
#include "Core/Config.h"
12
#include "GPU/Debugger/Breakpoints.h"
13
#include "GPU/GPUState.h"
14
15
constexpr const wchar_t *szWindowClass = L"CtrlDisplayListView";
16
17
void CtrlDisplayListView::registerClass()
18
{
19
WNDCLASSEX wndClass;
20
21
wndClass.cbSize = sizeof(wndClass);
22
wndClass.lpszClassName = szWindowClass;
23
wndClass.hInstance = GetModuleHandle(0);
24
wndClass.lpfnWndProc = wndProc;
25
wndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
26
wndClass.hIcon = 0;
27
wndClass.lpszMenuName = 0;
28
wndClass.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
29
wndClass.style = 0;
30
wndClass.cbClsExtra = 0;
31
wndClass.cbWndExtra = sizeof(CtrlDisplayListView*);
32
wndClass.hIconSm = 0;
33
34
RegisterClassEx(&wndClass);
35
}
36
37
CtrlDisplayListView::CtrlDisplayListView(HWND _wnd)
38
: wnd(_wnd)
39
{
40
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR) this);
41
SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL);
42
SetScrollRange(wnd, SB_VERT, -1,1,TRUE);
43
44
instructionSize = 4;
45
46
// In small window mode, g_dpi_scale may have been adjusted.
47
const float fontScale = 1.0f / g_display.dpi_scale_real_y;
48
int fontHeight = g_Config.iFontHeight * fontScale;
49
int charWidth = g_Config.iFontWidth * fontScale;
50
51
rowHeight = fontHeight + 2;
52
53
font = CreateFont(fontHeight,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,
54
L"Lucida Console");
55
boldfont = CreateFont(fontHeight,charWidth,0,0,FW_DEMIBOLD,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,
56
L"Lucida Console");
57
58
pixelPositions.addressStart = 16;
59
pixelPositions.opcodeStart = pixelPositions.addressStart + 19*charWidth;
60
61
hasFocus = false;
62
validDisplayList = false;
63
}
64
65
CtrlDisplayListView::~CtrlDisplayListView() {
66
DeleteObject(font);
67
DeleteObject(boldfont);
68
}
69
70
CtrlDisplayListView *CtrlDisplayListView::getFrom(HWND hwnd)
71
{
72
return (CtrlDisplayListView*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
73
}
74
75
LRESULT CALLBACK CtrlDisplayListView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
76
{
77
CtrlDisplayListView *win = CtrlDisplayListView::getFrom(hwnd);
78
79
switch(msg) {
80
case WM_NCCREATE:
81
// Allocate a new CustCtrl structure for this window.
82
win = new CtrlDisplayListView(hwnd);
83
84
// Continue with window creation.
85
return win != NULL;
86
case WM_NCDESTROY:
87
SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
88
delete win;
89
break;
90
case WM_SIZE:
91
win->redraw();
92
break;
93
case WM_PAINT:
94
win->onPaint(wParam,lParam);
95
break;
96
case WM_SETFOCUS:
97
SetFocus(hwnd);
98
win->hasFocus=true;
99
win->redraw();
100
break;
101
case WM_KILLFOCUS:
102
win->hasFocus=false;
103
win->redraw();
104
break;
105
case WM_VSCROLL:
106
win->onVScroll(wParam,lParam);
107
break;
108
case WM_MOUSEWHEEL:
109
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)
110
{
111
win->scrollWindow(-3);
112
} else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) {
113
win->scrollWindow(3);
114
}
115
break;
116
case WM_LBUTTONDOWN:
117
win->onMouseDown(wParam,lParam,1);
118
break;
119
case WM_RBUTTONDOWN:
120
win->onMouseDown(wParam,lParam,2);
121
break;
122
case WM_LBUTTONUP:
123
win->onMouseUp(wParam,lParam,1);
124
break;
125
case WM_RBUTTONUP:
126
win->onMouseUp(wParam,lParam,2);
127
break;
128
case WM_KEYDOWN:
129
case WM_SYSKEYDOWN:
130
win->onKeyDown(wParam,lParam);
131
return 0;
132
case WM_GETDLGCODE:
133
if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)
134
{
135
switch (wParam)
136
{
137
case VK_TAB:
138
return DLGC_WANTMESSAGE;
139
default:
140
return DLGC_WANTCHARS|DLGC_WANTARROWS;
141
}
142
}
143
return DLGC_WANTCHARS|DLGC_WANTARROWS;
144
}
145
146
return DefWindowProc(hwnd, msg, wParam, lParam);
147
}
148
149
void CtrlDisplayListView::redraw()
150
{
151
GetClientRect(wnd, &rect);
152
visibleRows = rect.bottom/rowHeight;
153
154
RedrawWindow(wnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_ALLCHILDREN);
155
}
156
157
158
void CtrlDisplayListView::onPaint(WPARAM wParam, LPARAM lParam)
159
{
160
if (!validDisplayList || !gpuDebug)
161
return;
162
163
PAINTSTRUCT ps;
164
HDC actualHdc = BeginPaint(wnd, &ps);
165
HDC hdc = CreateCompatibleDC(actualHdc);
166
HBITMAP hBM = CreateCompatibleBitmap(actualHdc, rect.right-rect.left, rect.bottom-rect.top);
167
SelectObject(hdc, hBM);
168
169
SetBkMode(hdc, TRANSPARENT);
170
171
HPEN nullPen=CreatePen(0,0,0xffffff);
172
HPEN condPen=CreatePen(0,0,0xFF3020);
173
HBRUSH nullBrush=CreateSolidBrush(0xffffff);
174
HBRUSH currentBrush=CreateSolidBrush(0xFFEfE8);
175
176
HPEN oldPen=(HPEN)SelectObject(hdc,nullPen);
177
HBRUSH oldBrush=(HBRUSH)SelectObject(hdc,nullBrush);
178
HFONT oldFont = (HFONT)SelectObject(hdc,(HGDIOBJ)font);
179
180
HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCWSTR)IDI_STOP);
181
182
auto disasm = gpuDebug->DisassembleOpRange(windowStart, windowStart + (visibleRows + 2) * instructionSize);
183
184
for (int i = 0; i < visibleRows+2; i++)
185
{
186
unsigned int address=windowStart + i*instructionSize;
187
bool stall = address == list.stall;
188
189
int rowY1 = rowHeight*i;
190
191
// draw background
192
COLORREF backgroundColor = stall ? 0xCCCCFF : 0xFFFFFF;
193
COLORREF textColor = 0x000000;
194
195
if (address >= selectRangeStart && address < selectRangeEnd)
196
{
197
if (hasFocus)
198
{
199
backgroundColor = address == curAddress ? 0xFF8822 : 0xFF9933;
200
textColor = 0xFFFFFF;
201
} else {
202
backgroundColor = 0xC0C0C0;
203
}
204
}
205
206
HBRUSH backgroundBrush = CreateSolidBrush(backgroundColor);
207
HPEN backgroundPen = CreatePen(0,0,backgroundColor);
208
SelectObject(hdc,backgroundBrush);
209
SelectObject(hdc,backgroundPen);
210
Rectangle(hdc,0,rowY1,rect.right,rowY1+rowHeight);
211
212
SelectObject(hdc,currentBrush);
213
SelectObject(hdc,nullPen);
214
215
DeleteObject(backgroundBrush);
216
DeleteObject(backgroundPen);
217
218
// display address/symbol
219
if (gpuDebug->GetBreakpoints()->IsAddressBreakpoint(address))
220
{
221
textColor = 0x0000FF;
222
int yOffset = std::max(-1,(rowHeight-14+1)/2);
223
DrawIconEx(hdc,2,rowY1+1+yOffset,breakPoint,32,32,0,0,DI_NORMAL);
224
}
225
SetTextColor(hdc,textColor);
226
227
GPUDebugOp op = i < (int)disasm.size() ? disasm[i] : GPUDebugOp();
228
229
char addressText[64];
230
snprintf(addressText,sizeof(addressText),"%08X %08X",op.pc,op.op);
231
TextOutA(hdc,pixelPositions.addressStart,rowY1+2,addressText,(int)strlen(addressText));
232
233
if (address == list.pc)
234
{
235
TextOut(hdc,pixelPositions.opcodeStart-8,rowY1,L"\x25A0",1);
236
}
237
238
const char* opcode = op.desc.c_str();
239
SelectObject(hdc,stall ? boldfont : font);
240
TextOutA(hdc,pixelPositions.opcodeStart,rowY1+2,opcode,(int)strlen(opcode));
241
SelectObject(hdc,font);
242
}
243
244
SelectObject(hdc,oldFont);
245
SelectObject(hdc,oldPen);
246
SelectObject(hdc,oldBrush);
247
248
// copy bitmap to the actual hdc
249
BitBlt(actualHdc, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);
250
DeleteObject(hBM);
251
DeleteDC(hdc);
252
253
DeleteObject(nullPen);
254
DeleteObject(condPen);
255
256
DeleteObject(nullBrush);
257
DeleteObject(currentBrush);
258
259
DestroyIcon(breakPoint);
260
261
EndPaint(wnd, &ps);
262
}
263
264
void CtrlDisplayListView::toggleBreakpoint()
265
{
266
SendMessage(GetParent(wnd),WM_GEDBG_TOGGLEPCBREAKPOINT,curAddress,0);
267
}
268
269
void CtrlDisplayListView::PromptBreakpointCond() {
270
std::string expression;
271
gpuDebug->GetBreakpoints()->GetAddressBreakpointCond(curAddress, &expression);
272
if (!InputBox_GetString(GetModuleHandle(NULL), wnd, L"Expression", expression, expression))
273
return;
274
275
std::string error;
276
if (!gpuDebug->GetBreakpoints()->SetAddressBreakpointCond(curAddress, expression, &error))
277
MessageBox(wnd, ConvertUTF8ToWString(error).c_str(), L"Invalid expression", MB_OK | MB_ICONEXCLAMATION);
278
}
279
280
void CtrlDisplayListView::onMouseDown(WPARAM wParam, LPARAM lParam, int button)
281
{
282
if (!validDisplayList || !gpuDebug) {
283
return;
284
}
285
286
int y = HIWORD(lParam);
287
288
int line = y/rowHeight;
289
u32 newAddress = windowStart + line*instructionSize;
290
291
bool extend = KeyDownAsync(VK_SHIFT);
292
if (button == 1)
293
{
294
if (newAddress == curAddress && hasFocus)
295
{
296
toggleBreakpoint();
297
}
298
} else if (button == 2)
299
{
300
// Maintain the current selection if right clicking into it.
301
if (newAddress >= selectRangeStart && newAddress < selectRangeEnd)
302
extend = true;
303
}
304
305
setCurAddress(newAddress,extend);
306
307
SetFocus(wnd);
308
redraw();
309
}
310
311
void CtrlDisplayListView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
312
{
313
if (!validDisplayList || !gpuDebug) {
314
return;
315
}
316
317
if (button == 2)
318
{
319
HMENU menu = GetContextMenu(ContextMenuID::DISPLAYLISTVIEW);
320
EnableMenuItem(menu, ID_GEDBG_SETCOND, gpuDebug->GetBreakpoints()->IsAddressBreakpoint(curAddress) ? MF_ENABLED : MF_GRAYED);
321
322
switch (TriggerContextMenu(ContextMenuID::DISPLAYLISTVIEW, wnd, ContextPoint::FromEvent(lParam)))
323
{
324
case ID_DISASM_GOTOINMEMORYVIEW:
325
if (memoryWindow)
326
memoryWindow->Goto(curAddress);
327
break;
328
case ID_DISASM_TOGGLEBREAKPOINT:
329
toggleBreakpoint();
330
redraw();
331
break;
332
case ID_GEDBG_SETCOND:
333
PromptBreakpointCond();
334
break;
335
case ID_DISASM_COPYINSTRUCTIONDISASM:
336
{
337
int space = 256 * (selectRangeEnd - selectRangeStart) / instructionSize;
338
char *temp = new char[space];
339
340
char *p = temp, *end = temp + space;
341
for (u32 pos = selectRangeStart; pos < selectRangeEnd && p < end; pos += instructionSize)
342
{
343
u32 opcode = Memory::Read_U32(pos);
344
GPUDebugOp op = gpuDebug->DisassembleOp(pos, opcode);
345
p += snprintf(p, end - p, "%s\r\n", op.desc.c_str());
346
}
347
348
W32Util::CopyTextToClipboard(wnd, temp);
349
delete [] temp;
350
}
351
break;
352
case ID_DISASM_COPYADDRESS:
353
{
354
char temp[16];
355
snprintf(temp,sizeof(temp),"%08X",curAddress);
356
W32Util::CopyTextToClipboard(wnd, temp);
357
}
358
break;
359
case ID_DISASM_SETPCTOHERE:
360
{
361
gpuDebug->ResetListPC(list.id,curAddress);
362
list.pc = curAddress;
363
redraw();
364
}
365
break;
366
case ID_GEDBG_SETSTALLADDR:
367
{
368
gpuDebug->ResetListStall(list.id,curAddress);
369
list.stall = curAddress;
370
redraw();
371
}
372
break;
373
case ID_DISASM_COPYINSTRUCTIONHEX:
374
{
375
int space = 24 * (selectRangeEnd - selectRangeStart) / instructionSize;
376
char *temp = new char[space];
377
378
char *p = temp, *end = temp + space;
379
for (u32 pos = selectRangeStart; pos < selectRangeEnd && p < end; pos += instructionSize)
380
p += snprintf(p, end - p, "%08X\r\n", Memory::ReadUnchecked_U32(pos));
381
382
W32Util::CopyTextToClipboard(wnd, temp);
383
delete [] temp;
384
}
385
break;
386
case ID_DISASM_RUNTOHERE:
387
{
388
SendMessage(GetParent(wnd),WM_GEDBG_RUNTOWPARAM,curAddress,0);
389
redraw();
390
}
391
break;
392
case ID_GEDBG_GOTOPC:
393
setCurAddress(list.pc);
394
scrollAddressIntoView();
395
redraw();
396
break;
397
case ID_GEDBG_GOTOADDR:
398
{
399
std::string expression = StringFromFormat("%08x", curAddress);
400
if (!InputBox_GetString(GetModuleHandle(NULL), wnd, L"Address", expression, expression, InputBoxFlags::Selected)) {
401
break;
402
}
403
uint32_t newAddress = curAddress;
404
if (!GPUDebugExecExpression(gpuDebug, expression.c_str(), newAddress)) {
405
MessageBox(wnd, ConvertUTF8ToWString(getExpressionError()).c_str(), L"Invalid expression", MB_OK | MB_ICONEXCLAMATION);
406
break;
407
}
408
if (!Memory::IsValidAddress(newAddress)) {
409
MessageBox(wnd, L"Address not in valid memory", L"Invalid address", MB_OK | MB_ICONEXCLAMATION);
410
break;
411
}
412
413
setCurAddress(newAddress);
414
scrollAddressIntoView();
415
redraw();
416
}
417
break;
418
}
419
return;
420
}
421
422
redraw();
423
}
424
425
void CtrlDisplayListView::onVScroll(WPARAM wParam, LPARAM lParam)
426
{
427
switch (wParam & 0xFFFF)
428
{
429
case SB_LINEDOWN:
430
windowStart += instructionSize;
431
break;
432
case SB_LINEUP:
433
windowStart -= instructionSize;
434
break;
435
case SB_PAGEDOWN:
436
windowStart += visibleRows*instructionSize;
437
break;
438
case SB_PAGEUP:
439
windowStart -= visibleRows*instructionSize;
440
break;
441
default:
442
return;
443
}
444
redraw();
445
}
446
447
void CtrlDisplayListView::onKeyDown(WPARAM wParam, LPARAM lParam)
448
{
449
u32 windowEnd = windowStart+visibleRows*instructionSize;
450
451
switch (wParam & 0xFFFF)
452
{
453
case VK_DOWN:
454
setCurAddress(curAddress + instructionSize, KeyDownAsync(VK_SHIFT));
455
scrollAddressIntoView();
456
break;
457
case VK_UP:
458
setCurAddress(curAddress - instructionSize, KeyDownAsync(VK_SHIFT));
459
scrollAddressIntoView();
460
break;
461
case VK_NEXT:
462
if (curAddress != windowEnd - instructionSize && curAddressIsVisible()) {
463
setCurAddress(windowEnd - instructionSize, KeyDownAsync(VK_SHIFT));
464
scrollAddressIntoView();
465
} else {
466
setCurAddress(curAddress + visibleRows * instructionSize, KeyDownAsync(VK_SHIFT));
467
scrollAddressIntoView();
468
}
469
break;
470
case VK_PRIOR:
471
if (curAddress != windowStart && curAddressIsVisible()) {
472
setCurAddress(windowStart, KeyDownAsync(VK_SHIFT));
473
scrollAddressIntoView();
474
} else {
475
setCurAddress(curAddress - visibleRows * instructionSize, KeyDownAsync(VK_SHIFT));
476
scrollAddressIntoView();
477
}
478
break;
479
case VK_LEFT:
480
gotoAddr(list.pc);
481
return;
482
case VK_SPACE:
483
toggleBreakpoint();
484
break;
485
case VK_F10:
486
case VK_F11:
487
SendMessage(GetParent(wnd),WM_GEDBG_STEPDISPLAYLIST,0,0);
488
break;
489
}
490
redraw();
491
}
492
493
void CtrlDisplayListView::scrollAddressIntoView()
494
{
495
u32 windowEnd = windowStart + visibleRows * instructionSize;
496
497
if (curAddress < windowStart)
498
windowStart = curAddress;
499
else if (curAddress >= windowEnd)
500
windowStart = curAddress - visibleRows * instructionSize + instructionSize;
501
}
502
503
bool CtrlDisplayListView::curAddressIsVisible()
504
{
505
u32 windowEnd = windowStart + visibleRows * instructionSize;
506
return curAddress >= windowStart && curAddress < windowEnd;
507
}
508
509