2016-05-09 10:18:40 -04:00
|
|
|
#include "GsPacketListView.h"
|
2015-05-06 01:27:59 -04:00
|
|
|
#include "../../FrameDump.h"
|
|
|
|
#include "string_cast.h"
|
|
|
|
#include "string_format.h"
|
|
|
|
#include "win32/DpiUtils.h"
|
2017-02-16 08:52:21 -05:00
|
|
|
#include "../WinUtils.h"
|
2015-05-06 01:27:59 -04:00
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
CGsPacketListView::CGsPacketListView(HWND parentWnd, const RECT& rect)
|
2018-04-30 21:01:23 +01:00
|
|
|
: m_frameDump(nullptr)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
Create(0, Framework::Win32::CDefaultWndClass::GetName(), _T(""), WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPCHILDREN,
|
|
|
|
Framework::Win32::CRect(0, 0, 1024, 768), parentWnd, nullptr);
|
2015-05-06 01:27:59 -04:00
|
|
|
SetClassPtr();
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
m_packetsTreeView = std::make_unique<Framework::Win32::CTreeView>(m_hWnd,
|
|
|
|
Framework::Win32::PointsToPixels(Framework::Win32::CRect(0, 0, 300, 300)),
|
|
|
|
TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_HASLINES);
|
2015-05-06 01:27:59 -04:00
|
|
|
|
|
|
|
{
|
|
|
|
LOGFONT fontInfo;
|
|
|
|
HFONT packetsTreeViewFont = m_packetsTreeView->GetFont();
|
|
|
|
GetObject(packetsTreeViewFont, sizeof(LOGFONT), &fontInfo);
|
|
|
|
fontInfo.lfWeight = FW_BOLD;
|
|
|
|
m_drawCallItemFont = CreateFontIndirect(&fontInfo);
|
|
|
|
}
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
m_prevDrawKickButton = std::make_unique<Framework::Win32::CButton>(_T("Prev Draw Kick"),
|
|
|
|
m_hWnd, Framework::Win32::PointsToPixels(Framework::Win32::CRect(0, 0, 100, 25)));
|
|
|
|
m_nextDrawKickButton = std::make_unique<Framework::Win32::CButton>(_T("Next Draw Kick"),
|
|
|
|
m_hWnd, Framework::Win32::PointsToPixels(Framework::Win32::CRect(100, 0, 200, 25)));
|
2015-05-06 01:27:59 -04:00
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
CGsPacketListView::~CGsPacketListView()
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
void CGsPacketListView::SetFrameDump(CFrameDump* frameDump)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
m_frameDump = frameDump;
|
|
|
|
|
|
|
|
m_packetsTreeView->SetSelection(NULL);
|
2017-04-12 09:44:04 -04:00
|
|
|
m_packetsTreeView->SetRedraw(FALSE);
|
2015-05-06 01:27:59 -04:00
|
|
|
m_packetsTreeView->DeleteAllItems();
|
2017-04-12 09:44:04 -04:00
|
|
|
m_packetsTreeView->SetRedraw(TRUE);
|
2015-05-06 01:27:59 -04:00
|
|
|
m_packetInfos.clear();
|
|
|
|
m_writeInfos.clear();
|
|
|
|
|
|
|
|
if(m_frameDump == nullptr) return;
|
|
|
|
|
|
|
|
m_packetsTreeView->SetRedraw(false);
|
|
|
|
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
|
|
|
|
|
|
|
m_packetInfos.reserve(m_frameDump->GetPackets().size());
|
|
|
|
|
|
|
|
uint32 packetIndex = 0, cmdIndex = 0;
|
|
|
|
const auto& drawingKicks = m_frameDump->GetDrawingKicks();
|
|
|
|
for(const auto& packet : m_frameDump->GetPackets())
|
|
|
|
{
|
2016-05-06 21:33:10 -04:00
|
|
|
bool isRegisterPacket = packet.imageData.empty();
|
|
|
|
|
2015-05-06 01:27:59 -04:00
|
|
|
auto lowerBoundIterator = drawingKicks.upper_bound(cmdIndex);
|
2016-05-06 21:33:10 -04:00
|
|
|
auto upperBoundIterator = drawingKicks.lower_bound(cmdIndex + packet.registerWrites.size());
|
2015-05-06 01:27:59 -04:00
|
|
|
|
|
|
|
int kickCount = static_cast<int>(std::distance(lowerBoundIterator, upperBoundIterator));
|
2018-04-30 21:01:23 +01:00
|
|
|
|
2016-05-06 21:33:10 -04:00
|
|
|
std::tstring packetDescription;
|
|
|
|
|
|
|
|
if(isRegisterPacket)
|
|
|
|
{
|
2018-08-30 07:43:26 -04:00
|
|
|
packetDescription = string_cast<std::tstring>(string_format("%d: Register Packet (Write Count: %d, Draw Count: %d, Path: %d)",
|
|
|
|
packetIndex, packet.registerWrites.size(), kickCount, packet.metadata.pathIndex));
|
2016-05-06 21:33:10 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-08-30 07:43:26 -04:00
|
|
|
packetDescription = string_cast<std::tstring>(string_format("%d: Image Packet (Size: 0x%08X)",
|
|
|
|
packetIndex, packet.imageData.size()));
|
2016-05-06 21:33:10 -04:00
|
|
|
}
|
2015-05-06 01:27:59 -04:00
|
|
|
|
|
|
|
TVINSERTSTRUCT insertStruct = {};
|
2018-04-30 21:01:23 +01:00
|
|
|
insertStruct.hParent = TVI_ROOT;
|
|
|
|
insertStruct.item.pszText = const_cast<LPWSTR>(packetDescription.c_str());
|
|
|
|
insertStruct.item.cChildren = 1;
|
|
|
|
insertStruct.item.lParam = packetIndex;
|
|
|
|
insertStruct.item.mask = TVIF_TEXT | TVIF_PARAM;
|
2016-05-06 21:33:10 -04:00
|
|
|
if(isRegisterPacket) insertStruct.item.mask |= TVIF_CHILDREN;
|
2015-05-06 01:27:59 -04:00
|
|
|
HTREEITEM packetRootItem = m_packetsTreeView->InsertItem(&insertStruct);
|
|
|
|
|
|
|
|
PACKETINFO packetInfo;
|
|
|
|
packetInfo.cmdIndexStart = cmdIndex;
|
|
|
|
packetInfo.treeViewItem = packetRootItem;
|
|
|
|
m_packetInfos.push_back(packetInfo);
|
|
|
|
|
2016-05-06 21:33:10 -04:00
|
|
|
cmdIndex += packet.registerWrites.size();
|
2015-05-06 01:27:59 -04:00
|
|
|
packetIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_writeInfos.resize(cmdIndex, WRITEINFO());
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#endif //DEBUGGER_INCLUDED
|
2015-05-06 01:27:59 -04:00
|
|
|
|
|
|
|
m_packetsTreeView->SetRedraw(true);
|
|
|
|
|
|
|
|
RedrawWindow(*m_packetsTreeView, nullptr, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
uint32 CGsPacketListView::GetSelectedItemIndex() const
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
HTREEITEM selectedItem = m_packetsTreeView->GetSelection();
|
|
|
|
if(selectedItem == nullptr) return -1;
|
|
|
|
TVITEM item = {};
|
|
|
|
item.mask |= LVIF_PARAM;
|
|
|
|
m_packetsTreeView->GetItem(selectedItem, &item);
|
|
|
|
return GetItemIndexFromTreeViewItem(&item);
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
long CGsPacketListView::OnSize(unsigned int, unsigned int, unsigned int)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
auto clientRect = GetClientRect();
|
2018-04-30 21:01:23 +01:00
|
|
|
Framework::Win32::CRect packetsTreeViewRect(0, Framework::Win32::PointsToPixels(30),
|
|
|
|
clientRect.Right(), clientRect.Bottom());
|
2015-05-06 01:27:59 -04:00
|
|
|
m_packetsTreeView->SetSizePosition(packetsTreeViewRect);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
long CGsPacketListView::OnCommand(unsigned short, unsigned short, HWND senderWnd)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
if(CWindow::IsCommandSource(m_prevDrawKickButton.get(), senderWnd))
|
|
|
|
{
|
|
|
|
OnPrevDrawKick();
|
|
|
|
}
|
|
|
|
else if(CWindow::IsCommandSource(m_nextDrawKickButton.get(), senderWnd))
|
|
|
|
{
|
|
|
|
OnNextDrawKick();
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-01-09 22:01:09 -05:00
|
|
|
LRESULT CGsPacketListView::OnNotify(WPARAM param, NMHDR* header)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
if(CWindow::IsNotifySource(m_packetsTreeView.get(), header))
|
|
|
|
{
|
|
|
|
switch(header->code)
|
|
|
|
{
|
|
|
|
case NM_CUSTOMDRAW:
|
|
|
|
return OnPacketsTreeViewCustomDraw(reinterpret_cast<NMTVCUSTOMDRAW*>(header));
|
|
|
|
break;
|
|
|
|
case TVN_ITEMEXPANDING:
|
|
|
|
OnPacketsTreeViewItemExpanding(reinterpret_cast<NMTREEVIEW*>(header));
|
|
|
|
break;
|
|
|
|
case TVN_SELCHANGED:
|
|
|
|
OnPacketsTreeViewSelChanged(reinterpret_cast<NMTREEVIEW*>(header));
|
|
|
|
break;
|
2017-02-16 08:52:21 -05:00
|
|
|
case TVN_KEYDOWN:
|
|
|
|
OnPacketsTreeViewKeyDown(reinterpret_cast<NMTVKEYDOWN*>(header));
|
|
|
|
break;
|
2015-05-06 01:27:59 -04:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-02-16 08:52:21 -05:00
|
|
|
long CGsPacketListView::OnCopy()
|
|
|
|
{
|
|
|
|
HTREEITEM selectedItem = m_packetsTreeView->GetSelection();
|
|
|
|
if(selectedItem == NULL) return TRUE;
|
|
|
|
|
|
|
|
TVITEM treeViewItem = {};
|
|
|
|
treeViewItem.mask = TVIF_PARAM | TVIF_HANDLE;
|
|
|
|
m_packetsTreeView->GetItem(selectedItem, &treeViewItem);
|
|
|
|
|
|
|
|
uint32 selectedItemIndex = GetItemIndexFromTreeViewItem(&treeViewItem);
|
|
|
|
const auto& writeInfo = m_writeInfos[selectedItemIndex];
|
|
|
|
const auto& registerWrite = writeInfo.registerWrite;
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
auto text = string_format(_T("0x%02X -> 0x%016llX\r\n"),
|
|
|
|
registerWrite.first, registerWrite.second);
|
2017-02-16 08:52:21 -05:00
|
|
|
|
|
|
|
WinUtils::CopyStringToClipboard(text);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
long CGsPacketListView::OnPacketsTreeViewCustomDraw(NMTVCUSTOMDRAW* customDraw)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
if(customDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
|
|
|
|
{
|
|
|
|
return CDRF_NOTIFYITEMDRAW;
|
|
|
|
}
|
|
|
|
else if(customDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
|
|
|
|
{
|
|
|
|
HTREEITEM drawItem = reinterpret_cast<HTREEITEM>(customDraw->nmcd.dwItemSpec);
|
|
|
|
HTREEITEM drawItemParent = m_packetsTreeView->GetItemParent(drawItem);
|
|
|
|
if(drawItemParent == nullptr) return CDRF_DODEFAULT;
|
|
|
|
uint32 drawItemPacketIndex = m_packetsTreeView->GetItemParam<uint32>(drawItem);
|
|
|
|
const auto& drawingKicks = m_frameDump->GetDrawingKicks();
|
|
|
|
if(drawingKicks.find(drawItemPacketIndex) != std::end(drawingKicks))
|
|
|
|
{
|
|
|
|
SelectObject(customDraw->nmcd.hdc, m_drawCallItemFont);
|
|
|
|
return CDRF_DODEFAULT | CDRF_NEWFONT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return CDRF_DODEFAULT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return CDRF_DODEFAULT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
uint32 CGsPacketListView::GetItemIndexFromTreeViewItem(TVITEM* item) const
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
HTREEITEM itemParent = m_packetsTreeView->GetItemParent(item->hItem);
|
|
|
|
if(itemParent == nullptr)
|
|
|
|
{
|
|
|
|
const auto& packetInfo = m_packetInfos[item->lParam];
|
|
|
|
return packetInfo.cmdIndexStart;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return item->lParam;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
void CGsPacketListView::OnPacketsTreeViewItemExpanding(NMTREEVIEW* treeView)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
if((treeView->itemNew.state & TVIS_EXPANDEDONCE) == 0)
|
|
|
|
{
|
|
|
|
uint32 packetIndex = treeView->itemNew.lParam;
|
|
|
|
const auto& packet = m_frameDump->GetPackets()[packetIndex];
|
|
|
|
const auto& packetInfo = m_packetInfos[packetIndex];
|
|
|
|
|
|
|
|
uint32 cmdIndex = packetInfo.cmdIndexStart;
|
|
|
|
|
2016-05-06 21:33:10 -04:00
|
|
|
for(const auto& registerWrite : packet.registerWrites)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
auto packetWriteDescription = CGSHandler::DisassembleWrite(registerWrite.first, registerWrite.second);
|
2017-05-29 06:01:32 +01:00
|
|
|
auto treeItemText = string_format("%04X: %s", cmdIndex - packetInfo.cmdIndexStart, packetWriteDescription.c_str());
|
2015-05-06 01:27:59 -04:00
|
|
|
HTREEITEM newItem = m_packetsTreeView->InsertItem(treeView->itemNew.hItem, string_cast<std::tstring>(treeItemText).c_str());
|
|
|
|
|
|
|
|
auto& writeInfo = m_writeInfos[cmdIndex];
|
2018-04-30 21:01:23 +01:00
|
|
|
writeInfo.treeViewItem = newItem;
|
2017-02-16 08:52:21 -05:00
|
|
|
writeInfo.registerWrite = registerWrite;
|
2015-05-06 01:27:59 -04:00
|
|
|
|
|
|
|
m_packetsTreeView->SetItemParam(newItem, cmdIndex++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
void CGsPacketListView::OnPacketsTreeViewSelChanged(NMTREEVIEW* treeView)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
uint32 selectedCmdIndex = GetItemIndexFromTreeViewItem(&treeView->itemNew);
|
|
|
|
SELCHANGED_INFO selchangedInfo;
|
|
|
|
memset(&selchangedInfo, 0, sizeof(SELCHANGED_INFO));
|
2018-04-30 21:01:23 +01:00
|
|
|
selchangedInfo.code = NOTIFICATION_SELCHANGED;
|
|
|
|
selchangedInfo.hwndFrom = m_hWnd;
|
2015-05-06 01:27:59 -04:00
|
|
|
selchangedInfo.selectedCmdIndex = selectedCmdIndex;
|
|
|
|
SendMessage(GetParent(), WM_NOTIFY, reinterpret_cast<WPARAM>(m_hWnd), reinterpret_cast<LPARAM>(&selchangedInfo));
|
|
|
|
}
|
|
|
|
|
2017-02-16 08:52:21 -05:00
|
|
|
void CGsPacketListView::OnPacketsTreeViewKeyDown(const NMTVKEYDOWN* keyDown)
|
|
|
|
{
|
|
|
|
switch(keyDown->wVKey)
|
|
|
|
{
|
|
|
|
case 'C':
|
|
|
|
if(GetAsyncKeyState(VK_CONTROL))
|
|
|
|
{
|
|
|
|
SendMessage(m_hWnd, WM_COPY, 0, 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
void CGsPacketListView::GoToWrite(uint32 writeIndex)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
auto packetInfoIterator = std::lower_bound(std::begin(m_packetInfos), std::end(m_packetInfos), writeIndex,
|
|
|
|
[](const PACKETINFO& p1, uint32 i2) { return p1.cmdIndexStart < i2; });
|
2015-05-06 01:27:59 -04:00
|
|
|
packetInfoIterator = std::prev(packetInfoIterator);
|
|
|
|
assert(packetInfoIterator != std::end(m_packetInfos));
|
|
|
|
|
|
|
|
const auto& packetInfo = *packetInfoIterator;
|
|
|
|
|
|
|
|
m_packetsTreeView->Expand(packetInfo.treeViewItem);
|
|
|
|
|
|
|
|
const auto& writeInfo = m_writeInfos[writeIndex];
|
|
|
|
assert(writeInfo.treeViewItem != nullptr);
|
|
|
|
m_packetsTreeView->SetSelection(writeInfo.treeViewItem);
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
void CGsPacketListView::OnPrevDrawKick()
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
if(m_frameDump == nullptr) return;
|
|
|
|
|
|
|
|
unsigned int selectedItemIndex = 0;
|
|
|
|
|
|
|
|
HTREEITEM selectedItem = m_packetsTreeView->GetSelection();
|
|
|
|
if(selectedItem != nullptr)
|
|
|
|
{
|
|
|
|
TVITEM treeViewItem;
|
|
|
|
memset(&treeViewItem, 0, sizeof(TVITEM));
|
|
|
|
treeViewItem.mask = TVIF_PARAM | TVIF_HANDLE;
|
|
|
|
m_packetsTreeView->GetItem(selectedItem, &treeViewItem);
|
|
|
|
selectedItemIndex = GetItemIndexFromTreeViewItem(&treeViewItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto& drawingKicks = m_frameDump->GetDrawingKicks();
|
|
|
|
if(drawingKicks.empty()) return;
|
|
|
|
|
|
|
|
auto prevKickIndexIterator = std::prev(drawingKicks.lower_bound(selectedItemIndex));
|
|
|
|
if(prevKickIndexIterator == std::end(drawingKicks))
|
|
|
|
{
|
|
|
|
//Nothing to do here
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GoToWrite(prevKickIndexIterator->first);
|
|
|
|
}
|
|
|
|
|
2016-05-09 10:18:40 -04:00
|
|
|
void CGsPacketListView::OnNextDrawKick()
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
if(m_frameDump == nullptr) return;
|
|
|
|
|
|
|
|
unsigned int selectedItemIndex = 0;
|
|
|
|
|
|
|
|
HTREEITEM selectedItem = m_packetsTreeView->GetSelection();
|
|
|
|
if(selectedItem != nullptr)
|
|
|
|
{
|
|
|
|
TVITEM treeViewItem;
|
|
|
|
memset(&treeViewItem, 0, sizeof(TVITEM));
|
|
|
|
treeViewItem.mask = TVIF_PARAM | TVIF_HANDLE;
|
|
|
|
m_packetsTreeView->GetItem(selectedItem, &treeViewItem);
|
|
|
|
selectedItemIndex = GetItemIndexFromTreeViewItem(&treeViewItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto& drawingKicks = m_frameDump->GetDrawingKicks();
|
|
|
|
auto nextKickIndexIterator = drawingKicks.upper_bound(selectedItemIndex);
|
|
|
|
if(nextKickIndexIterator == std::end(drawingKicks))
|
|
|
|
{
|
|
|
|
//Nothing to do here
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GoToWrite(nextKickIndexIterator->first);
|
|
|
|
}
|