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/CtrlDisplayListView.cpp
Views: 1401
#include <algorithm>1#include <tchar.h>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"1415LPCTSTR CtrlDisplayListView::windowClass = _T("CtrlDisplayListView");1617void CtrlDisplayListView::registerClass()18{19WNDCLASSEX wndClass;2021wndClass.cbSize = sizeof(wndClass);22wndClass.lpszClassName = windowClass;23wndClass.hInstance = GetModuleHandle(0);24wndClass.lpfnWndProc = wndProc;25wndClass.hCursor = LoadCursor (NULL, IDC_ARROW);26wndClass.hIcon = 0;27wndClass.lpszMenuName = 0;28wndClass.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);29wndClass.style = 0;30wndClass.cbClsExtra = 0;31wndClass.cbWndExtra = sizeof(CtrlDisplayListView*);32wndClass.hIconSm = 0;3334RegisterClassEx(&wndClass);35}3637CtrlDisplayListView::CtrlDisplayListView(HWND _wnd)38: wnd(_wnd)39{40SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR) this);41SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL);42SetScrollRange(wnd, SB_VERT, -1,1,TRUE);4344instructionSize = 4;4546// In small window mode, g_dpi_scale may have been adjusted.47const float fontScale = 1.0f / g_display.dpi_scale_real_y;48int fontHeight = g_Config.iFontHeight * fontScale;49int charWidth = g_Config.iFontWidth * fontScale;5051rowHeight = fontHeight + 2;5253font = CreateFont(fontHeight,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,54L"Lucida Console");55boldfont = CreateFont(fontHeight,charWidth,0,0,FW_DEMIBOLD,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,56L"Lucida Console");5758pixelPositions.addressStart = 16;59pixelPositions.opcodeStart = pixelPositions.addressStart + 19*charWidth;6061hasFocus = false;62validDisplayList = false;63}6465CtrlDisplayListView::~CtrlDisplayListView() {66DeleteObject(font);67DeleteObject(boldfont);68}6970CtrlDisplayListView *CtrlDisplayListView::getFrom(HWND hwnd)71{72return (CtrlDisplayListView*) GetWindowLongPtr(hwnd, GWLP_USERDATA);73}7475LRESULT CALLBACK CtrlDisplayListView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)76{77CtrlDisplayListView *win = CtrlDisplayListView::getFrom(hwnd);7879switch(msg) {80case WM_NCCREATE:81// Allocate a new CustCtrl structure for this window.82win = new CtrlDisplayListView(hwnd);8384// Continue with window creation.85return win != NULL;86case WM_NCDESTROY:87SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);88delete win;89break;90case WM_SIZE:91win->redraw();92break;93case WM_PAINT:94win->onPaint(wParam,lParam);95break;96case WM_SETFOCUS:97SetFocus(hwnd);98win->hasFocus=true;99win->redraw();100break;101case WM_KILLFOCUS:102win->hasFocus=false;103win->redraw();104break;105case WM_VSCROLL:106win->onVScroll(wParam,lParam);107break;108case WM_MOUSEWHEEL:109if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)110{111win->scrollWindow(-3);112} else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) {113win->scrollWindow(3);114}115break;116case WM_LBUTTONDOWN:117win->onMouseDown(wParam,lParam,1);118break;119case WM_RBUTTONDOWN:120win->onMouseDown(wParam,lParam,2);121break;122case WM_LBUTTONUP:123win->onMouseUp(wParam,lParam,1);124break;125case WM_RBUTTONUP:126win->onMouseUp(wParam,lParam,2);127break;128case WM_KEYDOWN:129case WM_SYSKEYDOWN:130win->onKeyDown(wParam,lParam);131return 0;132case WM_GETDLGCODE:133if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)134{135switch (wParam)136{137case VK_TAB:138return DLGC_WANTMESSAGE;139default:140return DLGC_WANTCHARS|DLGC_WANTARROWS;141}142}143return DLGC_WANTCHARS|DLGC_WANTARROWS;144}145146return DefWindowProc(hwnd, msg, wParam, lParam);147}148149void CtrlDisplayListView::redraw()150{151GetClientRect(wnd, &rect);152visibleRows = rect.bottom/rowHeight;153154RedrawWindow(wnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_ALLCHILDREN);155}156157158void CtrlDisplayListView::onPaint(WPARAM wParam, LPARAM lParam)159{160if (!validDisplayList || !gpuDebug)161return;162163PAINTSTRUCT ps;164HDC actualHdc = BeginPaint(wnd, &ps);165HDC hdc = CreateCompatibleDC(actualHdc);166HBITMAP hBM = CreateCompatibleBitmap(actualHdc, rect.right-rect.left, rect.bottom-rect.top);167SelectObject(hdc, hBM);168169SetBkMode(hdc, TRANSPARENT);170171HPEN nullPen=CreatePen(0,0,0xffffff);172HPEN condPen=CreatePen(0,0,0xFF3020);173HBRUSH nullBrush=CreateSolidBrush(0xffffff);174HBRUSH currentBrush=CreateSolidBrush(0xFFEfE8);175176HPEN oldPen=(HPEN)SelectObject(hdc,nullPen);177HBRUSH oldBrush=(HBRUSH)SelectObject(hdc,nullBrush);178HFONT oldFont = (HFONT)SelectObject(hdc,(HGDIOBJ)font);179180HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCWSTR)IDI_STOP);181182auto disasm = gpuDebug->DissassembleOpRange(windowStart, windowStart + (visibleRows + 2) * instructionSize);183184for (int i = 0; i < visibleRows+2; i++)185{186unsigned int address=windowStart + i*instructionSize;187bool stall = address == list.stall;188189int rowY1 = rowHeight*i;190191// draw background192COLORREF backgroundColor = stall ? 0xCCCCFF : 0xFFFFFF;193COLORREF textColor = 0x000000;194195if (address >= selectRangeStart && address < selectRangeEnd)196{197if (hasFocus)198{199backgroundColor = address == curAddress ? 0xFF8822 : 0xFF9933;200textColor = 0xFFFFFF;201} else {202backgroundColor = 0xC0C0C0;203}204}205206HBRUSH backgroundBrush = CreateSolidBrush(backgroundColor);207HPEN backgroundPen = CreatePen(0,0,backgroundColor);208SelectObject(hdc,backgroundBrush);209SelectObject(hdc,backgroundPen);210Rectangle(hdc,0,rowY1,rect.right,rowY1+rowHeight);211212SelectObject(hdc,currentBrush);213SelectObject(hdc,nullPen);214215DeleteObject(backgroundBrush);216DeleteObject(backgroundPen);217218// display address/symbol219if (GPUBreakpoints::IsAddressBreakpoint(address))220{221textColor = 0x0000FF;222int yOffset = std::max(-1,(rowHeight-14+1)/2);223DrawIconEx(hdc,2,rowY1+1+yOffset,breakPoint,32,32,0,0,DI_NORMAL);224}225SetTextColor(hdc,textColor);226227GPUDebugOp op = i < (int)disasm.size() ? disasm[i] : GPUDebugOp();228229char addressText[64];230snprintf(addressText,sizeof(addressText),"%08X %08X",op.pc,op.op);231TextOutA(hdc,pixelPositions.addressStart,rowY1+2,addressText,(int)strlen(addressText));232233if (address == list.pc)234{235TextOut(hdc,pixelPositions.opcodeStart-8,rowY1,L"\x25A0",1);236}237238const char* opcode = op.desc.c_str();239SelectObject(hdc,stall ? boldfont : font);240TextOutA(hdc,pixelPositions.opcodeStart,rowY1+2,opcode,(int)strlen(opcode));241SelectObject(hdc,font);242}243244SelectObject(hdc,oldFont);245SelectObject(hdc,oldPen);246SelectObject(hdc,oldBrush);247248// copy bitmap to the actual hdc249BitBlt(actualHdc, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);250DeleteObject(hBM);251DeleteDC(hdc);252253DeleteObject(nullPen);254DeleteObject(condPen);255256DeleteObject(nullBrush);257DeleteObject(currentBrush);258259DestroyIcon(breakPoint);260261EndPaint(wnd, &ps);262}263264void CtrlDisplayListView::toggleBreakpoint()265{266SendMessage(GetParent(wnd),WM_GEDBG_TOGGLEPCBREAKPOINT,curAddress,0);267}268269void CtrlDisplayListView::PromptBreakpointCond() {270std::string expression;271GPUBreakpoints::GetAddressBreakpointCond(curAddress, &expression);272if (!InputBox_GetString(GetModuleHandle(NULL), wnd, L"Expression", expression, expression))273return;274275std::string error;276if (!GPUBreakpoints::SetAddressBreakpointCond(curAddress, expression, &error))277MessageBox(wnd, ConvertUTF8ToWString(error).c_str(), L"Invalid expression", MB_OK | MB_ICONEXCLAMATION);278}279280void CtrlDisplayListView::onMouseDown(WPARAM wParam, LPARAM lParam, int button)281{282if (!validDisplayList || !gpuDebug) {283return;284}285286int y = HIWORD(lParam);287288int line = y/rowHeight;289u32 newAddress = windowStart + line*instructionSize;290291bool extend = KeyDownAsync(VK_SHIFT);292if (button == 1)293{294if (newAddress == curAddress && hasFocus)295{296toggleBreakpoint();297}298} else if (button == 2)299{300// Maintain the current selection if right clicking into it.301if (newAddress >= selectRangeStart && newAddress < selectRangeEnd)302extend = true;303}304305setCurAddress(newAddress,extend);306307SetFocus(wnd);308redraw();309}310311void CtrlDisplayListView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)312{313if (!validDisplayList || !gpuDebug) {314return;315}316317if (button == 2)318{319HMENU menu = GetContextMenu(ContextMenuID::DISPLAYLISTVIEW);320EnableMenuItem(menu, ID_GEDBG_SETCOND, GPUBreakpoints::IsAddressBreakpoint(curAddress) ? MF_ENABLED : MF_GRAYED);321322switch (TriggerContextMenu(ContextMenuID::DISPLAYLISTVIEW, wnd, ContextPoint::FromEvent(lParam)))323{324case ID_DISASM_GOTOINMEMORYVIEW:325if (memoryWindow)326memoryWindow->Goto(curAddress);327break;328case ID_DISASM_TOGGLEBREAKPOINT:329toggleBreakpoint();330redraw();331break;332case ID_GEDBG_SETCOND:333PromptBreakpointCond();334break;335case ID_DISASM_COPYINSTRUCTIONDISASM:336{337int space = 256 * (selectRangeEnd - selectRangeStart) / instructionSize;338char *temp = new char[space];339340char *p = temp, *end = temp + space;341for (u32 pos = selectRangeStart; pos < selectRangeEnd && p < end; pos += instructionSize)342{343GPUDebugOp op = gpuDebug->DissassembleOp(pos);344p += snprintf(p, end - p, "%s\r\n", op.desc.c_str());345}346347W32Util::CopyTextToClipboard(wnd, temp);348delete [] temp;349}350break;351case ID_DISASM_COPYADDRESS:352{353char temp[16];354snprintf(temp,sizeof(temp),"%08X",curAddress);355W32Util::CopyTextToClipboard(wnd, temp);356}357break;358case ID_DISASM_SETPCTOHERE:359{360gpuDebug->ResetListPC(list.id,curAddress);361list.pc = curAddress;362redraw();363}364break;365case ID_GEDBG_SETSTALLADDR:366{367gpuDebug->ResetListStall(list.id,curAddress);368list.stall = curAddress;369redraw();370}371break;372case ID_DISASM_COPYINSTRUCTIONHEX:373{374int space = 24 * (selectRangeEnd - selectRangeStart) / instructionSize;375char *temp = new char[space];376377char *p = temp, *end = temp + space;378for (u32 pos = selectRangeStart; pos < selectRangeEnd && p < end; pos += instructionSize)379p += snprintf(p, end - p, "%08X\r\n", Memory::ReadUnchecked_U32(pos));380381W32Util::CopyTextToClipboard(wnd, temp);382delete [] temp;383}384break;385case ID_DISASM_RUNTOHERE:386{387SendMessage(GetParent(wnd),WM_GEDBG_RUNTOWPARAM,curAddress,0);388redraw();389}390break;391case ID_GEDBG_GOTOPC:392setCurAddress(list.pc);393scrollAddressIntoView();394redraw();395break;396case ID_GEDBG_GOTOADDR:397{398std::string expression = StringFromFormat("%08x", curAddress);399if (!InputBox_GetString(GetModuleHandle(NULL), wnd, L"Address", expression, expression, InputBoxFlags::Selected)) {400break;401}402uint32_t newAddress = curAddress;403if (!GPUDebugExecExpression(gpuDebug, expression.c_str(), newAddress)) {404MessageBox(wnd, ConvertUTF8ToWString(getExpressionError()).c_str(), L"Invalid expression", MB_OK | MB_ICONEXCLAMATION);405break;406}407if (!Memory::IsValidAddress(newAddress)) {408MessageBox(wnd, L"Address not in valid memory", L"Invalid address", MB_OK | MB_ICONEXCLAMATION);409break;410}411412setCurAddress(newAddress);413scrollAddressIntoView();414redraw();415}416break;417}418return;419}420421redraw();422}423424void CtrlDisplayListView::onVScroll(WPARAM wParam, LPARAM lParam)425{426switch (wParam & 0xFFFF)427{428case SB_LINEDOWN:429windowStart += instructionSize;430break;431case SB_LINEUP:432windowStart -= instructionSize;433break;434case SB_PAGEDOWN:435windowStart += visibleRows*instructionSize;436break;437case SB_PAGEUP:438windowStart -= visibleRows*instructionSize;439break;440default:441return;442}443redraw();444}445446void CtrlDisplayListView::onKeyDown(WPARAM wParam, LPARAM lParam)447{448u32 windowEnd = windowStart+visibleRows*instructionSize;449450switch (wParam & 0xFFFF)451{452case VK_DOWN:453setCurAddress(curAddress + instructionSize, KeyDownAsync(VK_SHIFT));454scrollAddressIntoView();455break;456case VK_UP:457setCurAddress(curAddress - instructionSize, KeyDownAsync(VK_SHIFT));458scrollAddressIntoView();459break;460case VK_NEXT:461if (curAddress != windowEnd - instructionSize && curAddressIsVisible()) {462setCurAddress(windowEnd - instructionSize, KeyDownAsync(VK_SHIFT));463scrollAddressIntoView();464} else {465setCurAddress(curAddress + visibleRows * instructionSize, KeyDownAsync(VK_SHIFT));466scrollAddressIntoView();467}468break;469case VK_PRIOR:470if (curAddress != windowStart && curAddressIsVisible()) {471setCurAddress(windowStart, KeyDownAsync(VK_SHIFT));472scrollAddressIntoView();473} else {474setCurAddress(curAddress - visibleRows * instructionSize, KeyDownAsync(VK_SHIFT));475scrollAddressIntoView();476}477break;478case VK_LEFT:479gotoAddr(list.pc);480return;481case VK_SPACE:482toggleBreakpoint();483break;484case VK_F10:485case VK_F11:486SendMessage(GetParent(wnd),WM_GEDBG_STEPDISPLAYLIST,0,0);487break;488}489redraw();490}491492void CtrlDisplayListView::scrollAddressIntoView()493{494u32 windowEnd = windowStart + visibleRows * instructionSize;495496if (curAddress < windowStart)497windowStart = curAddress;498else if (curAddress >= windowEnd)499windowStart = curAddress - visibleRows * instructionSize + instructionSize;500}501502bool CtrlDisplayListView::curAddressIsVisible()503{504u32 windowEnd = windowStart + visibleRows * instructionSize;505return curAddress >= windowStart && curAddress < windowEnd;506}507508509