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