diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index a9ac468e81..d868a408f9 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -32,6 +32,7 @@ #include "Core/Config.h" #include #include +#include "TabDisplayLists.h" enum PauseAction { PAUSE_CONTINUE, @@ -129,6 +130,9 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) HWND wnd = tabs->AddTabWindow(L"CtrlDisplayListView",L"Display List"); displayList = CtrlDisplayListView::getFrom(wnd); + lists = new TabDisplayLists(_hInstance,m_hDlg); + tabs->AddTabDialog(lists,L"Lists"); + // set window position int x = g_Config.iGEWindowX == -1 ? windowRect.left : g_Config.iGEWindowX; int y = g_Config.iGEWindowY == -1 ? windowRect.top : g_Config.iGEWindowY; @@ -186,6 +190,8 @@ void CGEDebugger::UpdatePreviews() { if (gpuDebug->GetCurrentDisplayList(list)) { displayList->setDisplayList(list); } + + lists->Update(); } void CGEDebugger::UpdateSize(WORD width, WORD height) diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index d50a273ebc..5660065f8a 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -31,6 +31,7 @@ enum { }; class CtrlDisplayListView; +class TabDisplayLists; class CGEDebugger : public Dialog { public: @@ -48,6 +49,7 @@ private: void SavePosition(); CtrlDisplayListView* displayList; + TabDisplayLists* lists; SimpleGLWindow *frameWindow; SimpleGLWindow *texWindow; TabControl* tabs; diff --git a/Windows/GEDebugger/TabDisplayLists.cpp b/Windows/GEDebugger/TabDisplayLists.cpp new file mode 100644 index 0000000000..899d2b7228 --- /dev/null +++ b/Windows/GEDebugger/TabDisplayLists.cpp @@ -0,0 +1,269 @@ +#include "Windows/GEDebugger/TabDisplayLists.h" +#include "Windows/GEDebugger/GEDebugger.h" +#include "Windows/GEDebugger/CtrlDisplayListView.h" +#include "Windows/WindowsHost.h" +#include "Windows/WndMainWindow.h" +#include "Windows/main.h" +#include "GPU/GPUInterface.h" +#include "GPU/Common/GPUDebugInterface.h" +#include "GPU/GPUState.h" +#include "Core/Config.h" +#include +#include + +enum { WM_GEDBG_LISTS_CHANGELIST = WM_USER+400, WM_GEDBG_LISTS_GOTOSTACKPC }; + +// +// CtrlDisplayListStack +// + +enum { DLS_PC = 0, DLS_BASE, DLS_OFFSET, DLS_COLUMNCOUNT }; + +const GenericListViewColumn displayListStackColumns[3] = { + { L"PC", 0.34f }, + { L"Base", 0.33f }, + { L"Offset", 0.33f }, +}; + +CtrlDisplayListStack::CtrlDisplayListStack(HWND hwnd): GenericListControl(hwnd,displayListStackColumns,DLS_COLUMNCOUNT) +{ + list.stackptr = 0; + Update(); +} + +void CtrlDisplayListStack::GetColumnText(wchar_t* dest, int row, int col) +{ + DisplayListStackEntry value = list.stack[row]; + + switch (col) + { + case DLS_BASE: + wsprintf(dest,L"0x%08X",value.baseAddr); + break; + case DLS_OFFSET: + wsprintf(dest,L"0x%08X",value.offsetAddr); + break; + case DLS_PC: + wsprintf(dest,L"0x%08X",value.pc); + break; + } +} + +void CtrlDisplayListStack::OnDoubleClick(int itemIndex, int column) +{ + SendMessage(GetParent(GetHandle()),WM_GEDBG_LISTS_GOTOSTACKPC,itemIndex,0); +} + + +// +// CtrlDisplayListStack +// + +enum { ADL_STARTPC = 0, ADL_PC, ADL_STALL, ADL_STATE, APL_STARTED, APL_INTERRUPTED, ADL_COLUMNCOUNT }; + +const GenericListViewColumn allDisplayListsColumns[ADL_COLUMNCOUNT] = { + { L"Start PC", 0.18f }, + { L"PC", 0.18f }, + { L"Stall", 0.18f }, + { L"State", 0.16f }, + { L"Started", 0.15f }, + { L"Interrupted", 0.15f }, +}; + +CtrlAllDisplayLists::CtrlAllDisplayLists(HWND hwnd): GenericListControl(hwnd,allDisplayListsColumns,ADL_COLUMNCOUNT) +{ + Update(); +} + +void CtrlAllDisplayLists::GetColumnText(wchar_t* dest, int row, int col) +{ + DisplayList& list = lists[row]; + + switch (col) + { + case ADL_STALL: + wsprintf(dest,L"0x%08X",list.stall); + break; + case ADL_PC: + wsprintf(dest,L"0x%08X",list.pc); + break; + case ADL_STARTPC: + wsprintf(dest,L"0x%08X",list.startpc); + break; + case ADL_STATE: + switch (list.state) + { + case PSP_GE_DL_STATE_NONE: + wcscpy(dest,L"None"); + break; + case PSP_GE_DL_STATE_QUEUED: + wcscpy(dest,L"Queued"); + break; + case PSP_GE_DL_STATE_RUNNING: + wcscpy(dest,L"Running"); + break; + case PSP_GE_DL_STATE_COMPLETED: + wcscpy(dest,L"Completed"); + break; + case PSP_GE_DL_STATE_PAUSED: + wcscpy(dest,L"Paused"); + break; + } + break; + case APL_STARTED: + wcscpy(dest,list.started ? L"Yes" : L"No"); + break; + case APL_INTERRUPTED: + wcscpy(dest,list.interrupted ? L"Yes" : L"No"); + break; + } +} + +bool CtrlAllDisplayLists::WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue) +{ + switch (msg) + { + case WM_KEYDOWN: + if (wParam == VK_RETURN) + { + int item = GetSelectedIndex(); + SendMessage(GetParent(GetHandle()),WM_GEDBG_LISTS_CHANGELIST,item,0); + } + break; + case WM_GETDLGCODE: + if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN) + { + if (wParam == VK_RETURN) + { + returnValue = DLGC_WANTMESSAGE; + return true; + } + } + } + + return false; +} + +void CtrlAllDisplayLists::OnDoubleClick(int itemIndex, int column) +{ + SendMessage(GetParent(GetHandle()),WM_GEDBG_LISTS_CHANGELIST,itemIndex,0); +} + + +// +// TabDisplayLists +// + +TabDisplayLists::TabDisplayLists(HINSTANCE _hInstance, HWND _hParent) + : Dialog((LPCSTR)IDD_TABDISPLAYLISTS, _hInstance, _hParent) +{ + displayList = CtrlDisplayListView::getFrom(GetDlgItem(m_hDlg,IDC_GEDBG_LISTS_SELECTEDLIST)); + + stack = new CtrlDisplayListStack(GetDlgItem(m_hDlg,IDC_GEDBG_LISTS_STACK)); + allLists = new CtrlAllDisplayLists(GetDlgItem(m_hDlg,IDC_GEDBG_LISTS_ALLLISTS)); + + activeList = -1; +} + +TabDisplayLists::~TabDisplayLists() +{ + delete stack; + delete allLists; +} + +void TabDisplayLists::UpdateSize(WORD width, WORD height) +{ + struct Position + { + int x,y; + int w,h; + }; + + Position positions[3]; + int borderMargin = 5; + int betweenControlsMargin = 5; + + // All Lists + positions[0].x = borderMargin; + positions[0].y = borderMargin; + positions[0].w = width*2/3; + positions[0].h = min(height*2/5,200); + + // Stack + positions[1].x = positions[0].x+positions[0].w+betweenControlsMargin; + positions[1].y = borderMargin; + positions[1].w = width-positions[1].x-borderMargin; + positions[1].h = positions[0].h; + + // Current List + positions[2].x = borderMargin; + positions[2].y = positions[0].y+positions[0].h+betweenControlsMargin; + positions[2].w = width-2*borderMargin; + positions[2].h = height-positions[2].y-borderMargin; + + HWND handles[3] = { + GetDlgItem(m_hDlg,IDC_GEDBG_LISTS_ALLLISTS), + GetDlgItem(m_hDlg,IDC_GEDBG_LISTS_STACK), + GetDlgItem(m_hDlg,IDC_GEDBG_LISTS_SELECTEDLIST) + }; + + for (int i = 0; i < 3; i++) + { + MoveWindow(handles[i],positions[i].x,positions[i].y,positions[i].w,positions[i].h,TRUE); + } +} + +void TabDisplayLists::Update(bool reload) +{ + if (reload) + { + lists = gpuDebug->ActiveDisplayLists(); + } + + if (activeList != -1) + { + DisplayList currentList = lists[activeList]; + + displayList->setDisplayList(currentList); + stack->setDisplayList(currentList); + } + + allLists->setDisplayLists(lists); +} + +BOOL TabDisplayLists::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_INITDIALOG: + return TRUE; + + case WM_SIZE: + UpdateSize(LOWORD(lParam), HIWORD(lParam)); + return TRUE; + + case WM_NOTIFY: + switch (wParam) + { + case IDC_GEDBG_LISTS_STACK: + stack->HandleNotify(lParam); + break; + case IDC_GEDBG_LISTS_ALLLISTS: + allLists->HandleNotify(lParam); + break; + } + break; + + case WM_GEDBG_LISTS_CHANGELIST: + activeList = wParam; + Update(); + break; + + case WM_GEDBG_LISTS_GOTOSTACKPC: + { + u32 pc = lists[activeList].stack[wParam].pc; + displayList->gotoAddr(pc); + } + break; + } + + return FALSE; +} diff --git a/Windows/GEDebugger/TabDisplayLists.h b/Windows/GEDebugger/TabDisplayLists.h new file mode 100644 index 0000000000..9909d04e1f --- /dev/null +++ b/Windows/GEDebugger/TabDisplayLists.h @@ -0,0 +1,56 @@ +#pragma once + +#include "Common/CommonWindows.h" +#include "Globals.h" +#include "Windows/resource.h" +#include "Windows/W32Util/DialogManager.h" +#include "Windows/W32Util/Misc.h" +#include "GPU/Common/GPUDebugInterface.h" + +class CtrlDisplayListView; + +class CtrlDisplayListStack: public GenericListControl +{ +public: + CtrlDisplayListStack(HWND hwnd); + void setDisplayList(DisplayList& _list) { list = _list; Update(); } +protected: + virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue) { return false; }; + virtual void GetColumnText(wchar_t* dest, int row, int col); + virtual int GetRowCount() { return list.stackptr; }; + virtual void OnDoubleClick(int itemIndex, int column); +private: + DisplayList list; +}; + +class CtrlAllDisplayLists: public GenericListControl +{ +public: + CtrlAllDisplayLists(HWND hwnd); + void setDisplayLists(std::vector& _lists) { lists = _lists; Update(); }; +protected: + virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue); + virtual void GetColumnText(wchar_t* dest, int row, int col); + virtual int GetRowCount() { return (int) lists.size(); }; + virtual void OnDoubleClick(int itemIndex, int column); +private: + std::vector lists; +}; + +class TabDisplayLists : public Dialog +{ +public: + TabDisplayLists(HINSTANCE _hInstance, HWND _hParent); + ~TabDisplayLists(); + void Update(bool reload = true); +protected: + BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); +private: + void UpdateSize(WORD width, WORD height); + + CtrlDisplayListView* displayList; + CtrlDisplayListStack* stack; + CtrlAllDisplayLists* allLists; + std::vector lists; + int activeList; +}; diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 53d56b2f44..7b513ed6a5 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -284,6 +284,7 @@ + @@ -329,6 +330,7 @@ + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 03023ca09d..5ec0cf02fc 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -125,6 +125,9 @@ Windows\W32Util + + Windows\GE Debugger + @@ -224,6 +227,9 @@ Windows\W32Util + + Windows\GE Debugger + diff --git a/Windows/W32Util/Misc.cpp b/Windows/W32Util/Misc.cpp index e3891bcc9f..ebf8d652a8 100644 --- a/Windows/W32Util/Misc.cpp +++ b/Windows/W32Util/Misc.cpp @@ -2,6 +2,7 @@ #include #include "Misc.h" #include "util/text/utf8.h" +#include namespace W32Util { @@ -85,4 +86,134 @@ namespace W32Util SetWindowPos(hwnd, style, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); } +} + + + +GenericListControl::GenericListControl(HWND hwnd, const GenericListViewColumn* _columns, int _columnCount) + : handle(hwnd), columns(_columns),columnCount(_columnCount),valid(false) +{ + DWORD style = GetWindowLong(handle,GWL_STYLE) | LVS_REPORT; + SetWindowLong(handle, GWL_STYLE, style); + + SetWindowLongPtr(handle,GWLP_USERDATA,(LONG_PTR)this); + oldProc = (WNDPROC) SetWindowLongPtr(handle,GWLP_WNDPROC,(LONG_PTR)wndProc); + + SendMessage(handle, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); + + LVCOLUMN lvc; + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvc.iSubItem = 0; + lvc.fmt = LVCFMT_LEFT; + + RECT rect; + GetClientRect(handle,&rect); + + int totalListSize = rect.right-rect.left; + for (int i = 0; i < columnCount; i++) { + lvc.cx = columns[i].size * totalListSize; + lvc.pszText = columns[i].name; + ListView_InsertColumn(handle, i, &lvc); + } + + valid = true; +} + +void GenericListControl::HandleNotify(LPARAM lParam) +{ + LPNMHDR mhdr = (LPNMHDR) lParam; + + if (mhdr->code == NM_DBLCLK) + { + LPNMITEMACTIVATE item = (LPNMITEMACTIVATE) lParam; + OnDoubleClick(item->iItem,item->iSubItem); + return; + } + + if (mhdr->code == NM_RCLICK) + { + const LPNMITEMACTIVATE item = (LPNMITEMACTIVATE)lParam; + OnRightClick(item->iItem,item->iSubItem); + return; + } + + if (mhdr->code == LVN_GETDISPINFO) + { + NMLVDISPINFO* dispInfo = (NMLVDISPINFO*)lParam; + + stringBuffer[0] = 0; + GetColumnText(stringBuffer,dispInfo->item.iItem,dispInfo->item.iSubItem); + + if (stringBuffer[0] == 0) + wcscat(stringBuffer,L"Invalid"); + + dispInfo->item.pszText = stringBuffer; + return; + } +} + +void GenericListControl::Update() +{ + int newRows = GetRowCount(); + + int items = ListView_GetItemCount(handle); + while (items < newRows) + { + LVITEM lvI; + lvI.pszText = LPSTR_TEXTCALLBACK; // Sends an LVN_GETDISPINFO message. + lvI.mask = LVIF_TEXT | LVIF_IMAGE |LVIF_STATE; + lvI.stateMask = 0; + lvI.iSubItem = 0; + lvI.state = 0; + lvI.iItem = items; + lvI.iImage = items; + + ListView_InsertItem(handle, &lvI); + items++; + } + + while (items > newRows) + { + ListView_DeleteItem(handle,--items); + } + + ResizeColumns(); + + InvalidateRect(handle,NULL,true); + UpdateWindow(handle); +} + +void GenericListControl::ResizeColumns() +{ + RECT rect; + GetClientRect(handle,&rect); + + int totalListSize = rect.right-rect.left; + for (int i = 0; i < columnCount; i++) + { + ListView_SetColumnWidth(handle,i,columns[i].size * totalListSize); + } +} + +LRESULT CALLBACK GenericListControl::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + GenericListControl* list = (GenericListControl*) GetWindowLongPtr(hwnd,GWLP_USERDATA); + + LRESULT returnValue; + if (list->valid && list->WindowMessage(msg,wParam,lParam,returnValue) == true) + return returnValue; + + switch (msg) + { + case WM_SIZE: + list->ResizeColumns(); + break; + } + + return (LRESULT)CallWindowProc((WNDPROC)list->oldProc,hwnd,msg,wParam,lParam); +} + +int GenericListControl::GetSelectedIndex() +{ + return ListView_GetNextItem(handle, -1, LVNI_SELECTED); } \ No newline at end of file diff --git a/Windows/W32Util/Misc.h b/Windows/W32Util/Misc.h index addcd3892a..666892973f 100644 --- a/Windows/W32Util/Misc.h +++ b/Windows/W32Util/Misc.h @@ -9,4 +9,36 @@ namespace W32Util void NiceSizeFormat(size_t size, char *out); BOOL CopyTextToClipboard(HWND hwnd, const char *text); void MakeTopMost(HWND hwnd, bool topMost); -} \ No newline at end of file +} + +struct GenericListViewColumn +{ + wchar_t *name; + float size; +}; + +class GenericListControl +{ +public: + GenericListControl(HWND hwnd, const GenericListViewColumn* _columns, int _columnCount); + void HandleNotify(LPARAM lParam); + void Update(); + int GetSelectedIndex(); + HWND GetHandle() { return handle; }; +protected: + virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue) = 0; + virtual void GetColumnText(wchar_t* dest, int row, int col) = 0; + virtual int GetRowCount() = 0; + virtual void OnDoubleClick(int itemIndex, int column) { }; + virtual void OnRightClick(int itemIndex, int column) { }; +private: + static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + void ResizeColumns(); + + HWND handle; + WNDPROC oldProc; + const GenericListViewColumn* columns; + int columnCount; + wchar_t stringBuffer[256]; + bool valid; +}; \ No newline at end of file diff --git a/Windows/W32Util/TabControl.cpp b/Windows/W32Util/TabControl.cpp index ff269ee65a..667f847e41 100644 --- a/Windows/W32Util/TabControl.cpp +++ b/Windows/W32Util/TabControl.cpp @@ -106,7 +106,7 @@ void TabControl::PreviousTab(bool cycle) { int index = TabCtrl_GetCurSel(hwnd); if (index == 0 && cycle) - index = tabs.size()-1; + index = (int) tabs.size()-1; ShowTab(index); } @@ -127,7 +127,7 @@ void TabControl::OnResize() GetWindowRect(hwnd,&tabRect); MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2); - InvalidateRect(hwnd,NULL,FALSE); + InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); // now resize tab children @@ -137,11 +137,11 @@ void TabControl::OnResize() for (size_t i = 0; i < tabs.size(); i++) { InvalidateRect(tabs[i],NULL,FALSE); - MoveWindow(tabs[i],tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,FALSE); + MoveWindow(tabs[i],tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE); if (i == current) { - InvalidateRect(tabs[i],NULL,FALSE); + InvalidateRect(tabs[i],NULL,TRUE); UpdateWindow(tabs[i]); } } diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 64952cd5b7..63eb00aac5 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -177,6 +177,17 @@ BEGIN CONTROL "",IDC_GEDBG_MAINTAB,"SysTabControl32",TCS_TABS ,10,216,480,180 END + +IDD_TABDISPLAYLISTS DIALOGEX 0, 0, 316, 183 +STYLE DS_SETFONT | DS_FIXEDSYS +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_GEDBG_LISTS_ALLLISTS,"SysListView32",LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_REPORT | WS_BORDER | WS_TABSTOP,7,7,217,86 + CONTROL "",IDC_GEDBG_LISTS_STACK,"SysListView32",LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_REPORT | WS_BORDER | WS_TABSTOP,7,95,302,81 + CONTROL "",IDC_GEDBG_LISTS_SELECTEDLIST,"CtrlDisplayListView",WS_BORDER,225,7,84,89 +END + #include "aboutbox.rc" IDD_MEMORY DIALOGEX 0, 0, 566, 287 diff --git a/Windows/resource.h b/Windows/resource.h index b0de116eaa..d4a78012ef 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -77,6 +77,7 @@ #define ID_DEBUG_DSIPLAYFUNCTIONLIST 248 #define ID_MEMVIEW_COPYADDRESS 249 #define IDD_GEDEBUGGER 250 +#define IDD_TABDISPLAYLISTS 251 #define IDC_STOPGO 1001 #define IDC_ADDRESS 1002 @@ -265,6 +266,9 @@ #define IDC_GEDBG_MAINTAB 40120 #define IDC_GEDBG_TEX 40121 #define IDC_GEDBG_STEP 40122 +#define IDC_GEDBG_LISTS_ALLLISTS 40123 +#define IDC_GEDBG_LISTS_STACK 40124 +#define IDC_GEDBG_LISTS_SELECTEDLIST 40125 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 @@ -276,8 +280,8 @@ // Next default values for new objects #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 251 -#define _APS_NEXT_COMMAND_VALUE 40123 +#define _APS_NEXT_RESOURCE_VALUE 252 +#define _APS_NEXT_COMMAND_VALUE 40126 #define _APS_NEXT_CONTROL_VALUE 1181 #define _APS_NEXT_SYMED_VALUE 101 #endif