2025-05-13 19:45:22 +03:00

767 lines
26 KiB
C

/*
* Process Hacker Extended Tools -
* GPU process properties page
*
* Copyright (C) 2011 wj32
* Copyright (C) 2015-2016 dmex
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
typedef struct _ET_GPU_CONTEXT
{
HWND WindowHandle;
HWND PanelHandle;
HWND DetailsHandle;
PET_PROCESS_BLOCK Block;
PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
BOOLEAN Enabled;
PH_LAYOUT_MANAGER LayoutManager;
HWND GpuGroupBox;
HWND MemGroupBox;
HWND SharedGroupBox;
HWND GpuGraphHandle;
HWND MemGraphHandle;
HWND SharedGraphHandle;
FLOAT CurrentGpuUsage;
ULONG CurrentMemUsage;
ULONG CurrentMemSharedUsage;
PH_GRAPH_STATE GpuGraphState;
PH_GRAPH_STATE MemoryGraphState;
PH_GRAPH_STATE MemorySharedGraphState;
PH_CIRCULAR_BUFFER_FLOAT GpuHistory;
PH_CIRCULAR_BUFFER_ULONG MemoryHistory;
PH_CIRCULAR_BUFFER_ULONG MemorySharedHistory;
} ET_GPU_CONTEXT, *PET_GPU_CONTEXT;
static RECT NormalGraphTextMargin = { 5, 5, 5, 5 };
static RECT NormalGraphTextPadding = { 3, 3, 3, 3 };
VOID GpuPropUpdatePanel(
_Inout_ PET_GPU_CONTEXT Context
);
INT_PTR CALLBACK GpuDetailsDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PET_GPU_CONTEXT context = NULL;
if (uMsg == WM_INITDIALOG)
{
context = (PET_GPU_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
{
context->DetailsHandle = NULL;
RemoveProp(hwndDlg, L"Context");
}
}
if (context == NULL)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
context->DetailsHandle = hwndDlg;
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
GpuPropUpdatePanel(context);
}
break;
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lparam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK GpuPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PET_GPU_CONTEXT context = NULL;
if (uMsg == WM_INITDIALOG)
{
context = (PET_GPU_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
{
RemoveProp(hwndDlg, L"Context");
}
}
if (context == NULL)
return FALSE;
switch (uMsg)
{
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lparam))
{
case IDC_GPUDETAILS:
{
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_PROCGPU_DETAILS),
hwndDlg,
GpuDetailsDialogProc,
(LPARAM)context
);
}
break;
}
}
break;
}
return FALSE;
}
VOID GpuPropCreateGraphs(
_In_ PET_GPU_CONTEXT Context
)
{
Context->GpuGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
Context->WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(Context->GpuGraphHandle, TRUE);
Context->MemGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
Context->WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(Context->MemGraphHandle, TRUE);
Context->SharedGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
Context->WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(Context->SharedGraphHandle, TRUE);
}
VOID GpuPropCreatePanel(
_In_ PET_GPU_CONTEXT Context
)
{
RECT margin;
Context->PanelHandle = CreateDialogParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_PROCGPU_PANEL),
Context->WindowHandle,
GpuPanelDialogProc,
(LPARAM)Context
);
SetWindowPos(
Context->PanelHandle,
NULL,
10, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER
);
ShowWindow(Context->PanelHandle, SW_SHOW);
margin.left = 0;
margin.top = 0;
margin.right = 0;
margin.bottom = 10;
MapDialogRect(Context->WindowHandle, &margin);
PhAddLayoutItemEx(
&Context->LayoutManager,
Context->PanelHandle,
NULL,
PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT,
margin
);
SendMessage(Context->WindowHandle, WM_SIZE, 0, 0);
}
VOID GpuPropLayoutGraphs(
_In_ PET_GPU_CONTEXT Context
)
{
HDWP deferHandle;
RECT clientRect;
RECT panelRect;
RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) };
RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) };
LONG between = ET_SCALE_DPI(3);
ULONG graphWidth;
ULONG graphHeight;
PhLayoutManagerLayout(&Context->LayoutManager);
Context->GpuGraphState.Valid = FALSE;
Context->MemoryGraphState.Valid = FALSE;
Context->MemorySharedGraphState.Valid = FALSE;
GetClientRect(Context->WindowHandle, &clientRect);
// Limit the rectangle bottom to the top of the panel.
GetWindowRect(Context->PanelHandle, &panelRect);
MapWindowPoints(NULL, Context->WindowHandle, (PPOINT)&panelRect, 2);
clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing
graphWidth = clientRect.right - margin.left - margin.right;
graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3;
deferHandle = BeginDeferWindowPos(6);
deferHandle = DeferWindowPos(deferHandle, Context->GpuGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
Context->GpuGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + innerMargin.top,
graphWidth - innerMargin.left - innerMargin.right,
graphHeight - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
deferHandle = DeferWindowPos(deferHandle, Context->MemGroupBox, NULL, margin.left, margin.top + graphHeight + between, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
Context->MemGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + graphHeight + between + innerMargin.top,
graphWidth - innerMargin.left - innerMargin.right,
graphHeight - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
deferHandle = DeferWindowPos(deferHandle, Context->SharedGroupBox, NULL, margin.left, margin.top + (graphHeight + between) * 2, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
Context->SharedGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + (graphHeight + between) * 2 + innerMargin.top,
graphWidth - innerMargin.left - innerMargin.right,
graphHeight - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
EndDeferWindowPos(deferHandle);
}
VOID GpuPropUpdateGraphs(
_In_ PET_GPU_CONTEXT Context
)
{
Context->GpuGraphState.Valid = FALSE;
Context->GpuGraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->GpuGraphHandle, 1);
Graph_Draw(Context->GpuGraphHandle);
Graph_UpdateTooltip(Context->GpuGraphHandle);
InvalidateRect(Context->GpuGraphHandle, NULL, FALSE);
Context->MemoryGraphState.Valid = FALSE;
Context->MemoryGraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->MemGraphHandle, 1);
Graph_Draw(Context->MemGraphHandle);
Graph_UpdateTooltip(Context->MemGraphHandle);
InvalidateRect(Context->MemGraphHandle, NULL, FALSE);
Context->MemorySharedGraphState.Valid = FALSE;
Context->MemorySharedGraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->SharedGraphHandle, 1);
Graph_Draw(Context->SharedGraphHandle);
Graph_UpdateTooltip(Context->SharedGraphHandle);
InvalidateRect(Context->SharedGraphHandle, NULL, FALSE);
}
VOID GpuPropUpdatePanel(
_Inout_ PET_GPU_CONTEXT Context
)
{
ET_PROCESS_GPU_STATISTICS statistics;
WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A";
if (Context->Block->ProcessItem->QueryHandle)
EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &statistics);
else
memset(&statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS));
PhPrintTimeSpan(runningTimeString, statistics.RunningTime * 10, PH_TIMESPAN_HMSM);
SetDlgItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString);
SetDlgItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(statistics.ContextSwitches, TRUE)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(statistics.NodeCount, TRUE)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(statistics.SegmentCount, TRUE)->Buffer);
if (Context->DetailsHandle)
{
// Note: no lock is needed because we only ever update the 'details' dialog text on this same thread.
SetDlgItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(statistics.DedicatedCommitted, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(statistics.SharedCommitted, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(statistics.BytesAllocated, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(statistics.BytesReserved, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(statistics.WriteCombinedBytesAllocated, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(statistics.WriteCombinedBytesReserved, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(statistics.CachedBytesAllocated, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(statistics.CachedBytesReserved, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(statistics.SectionBytesAllocated, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(statistics.SectionBytesReserved, -1)->Buffer);
}
}
VOID GpuPropUpdateInfo(
_In_ PET_GPU_CONTEXT Context
)
{
PET_PROCESS_BLOCK block = Context->Block;
Context->CurrentGpuUsage = block->GpuNodeUsage;
Context->CurrentMemUsage = (ULONG)(block->GpuDedicatedUsage / PAGE_SIZE);
Context->CurrentMemSharedUsage = (ULONG)(block->GpuSharedUsage / PAGE_SIZE);
PhAddItemCircularBuffer_FLOAT(&Context->GpuHistory, Context->CurrentGpuUsage);
PhAddItemCircularBuffer_ULONG(&Context->MemoryHistory, Context->CurrentMemUsage);
PhAddItemCircularBuffer_ULONG(&Context->MemorySharedHistory, Context->CurrentMemSharedUsage);
}
VOID NTAPI ProcessesUpdatedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PET_GPU_CONTEXT context = Context;
if (!context->Enabled)
return;
if (context->WindowHandle)
{
PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0);
}
}
INT_PTR CALLBACK EtpGpuPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
LPPROPSHEETPAGE propSheetPage;
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
PPH_PROCESS_ITEM processItem;
PET_GPU_CONTEXT context;
if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))
{
context = propPageContext->Context;
}
else
{
return FALSE;
}
switch (uMsg)
{
case WM_INITDIALOG:
{
ULONG sampleCount;
sampleCount = PhGetIntegerSetting(L"SampleCount");
context = PhAllocate(sizeof(ET_GPU_CONTEXT));
memset(context, 0, sizeof(ET_GPU_CONTEXT));
context->WindowHandle = hwndDlg;
context->Block = EtGetProcessBlock(processItem);
context->Enabled = TRUE;
context->GpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPGPU);
context->MemGroupBox = GetDlgItem(hwndDlg, IDC_GROUPMEM);
context->SharedGroupBox = GetDlgItem(hwndDlg, IDC_GROUPSHARED);
propPageContext->Context = context;
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhInitializeGraphState(&context->GpuGraphState);
PhInitializeGraphState(&context->MemoryGraphState);
PhInitializeGraphState(&context->MemorySharedGraphState);
PhInitializeCircularBuffer_FLOAT(&context->GpuHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&context->MemoryHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&context->MemorySharedHistory, sampleCount);
GpuPropCreateGraphs(context);
GpuPropCreatePanel(context);
GpuPropUpdateInfo(context);
GpuPropUpdatePanel(context);
PhRegisterCallback(
&PhProcessesUpdatedEvent,
ProcessesUpdatedHandler,
context,
&context->ProcessesUpdatedRegistration
);
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&context->LayoutManager);
PhDeleteGraphState(&context->GpuGraphState);
PhDeleteGraphState(&context->MemoryGraphState);
PhDeleteGraphState(&context->MemorySharedGraphState);
PhDeleteCircularBuffer_FLOAT(&context->GpuHistory);
PhDeleteCircularBuffer_ULONG(&context->MemoryHistory);
PhDeleteCircularBuffer_ULONG(&context->MemorySharedHistory);
if (context->GpuGraphHandle)
DestroyWindow(context->GpuGraphHandle);
if (context->MemGraphHandle)
DestroyWindow(context->MemGraphHandle);
if (context->SharedGraphHandle)
DestroyWindow(context->SharedGraphHandle);
if (context->PanelHandle)
DestroyWindow(context->PanelHandle);
PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration);
PhFree(context);
PhPropPageDlgProcDestroy(hwndDlg);
}
break;
case WM_SHOWWINDOW:
{
if (PhBeginPropPageLayout(hwndDlg, propPageContext))
PhEndPropPageLayout(hwndDlg, propPageContext);
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case PSN_SETACTIVE:
context->Enabled = TRUE;
break;
case PSN_KILLACTIVE:
context->Enabled = FALSE;
break;
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
if (header->hwndFrom == context->GpuGraphHandle)
{
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc;
PhMoveReference(&context->GpuGraphState.Text, PhFormatString(
L"%.2f%%",
context->CurrentGpuUsage * 100
));
hdc = Graph_GetBufferedContext(context->GpuGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &context->GpuGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
PhGraphStateGetDrawInfo(&context->GpuGraphState, getDrawInfo, context->GpuHistory.Count);
if (!context->GpuGraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&context->GpuHistory, context->GpuGraphState.Data1, drawInfo->LineDataCount);
context->GpuGraphState.Valid = TRUE;
}
}
else if (header->hwndFrom == context->MemGraphHandle)
{
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc;
PhMoveReference(&context->MemoryGraphState.Text, PhFormatString(
L"%s",
PhaFormatSize(UInt32x32To64(context->CurrentMemUsage, PAGE_SIZE), -1)->Buffer
));
hdc = Graph_GetBufferedContext(context->MemGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(
hdc,
drawInfo,
&context->MemoryGraphState.Text->sr,
&NormalGraphTextMargin,
&NormalGraphTextPadding,
PH_ALIGN_TOP | PH_ALIGN_LEFT
);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0);
PhGraphStateGetDrawInfo(
&context->MemoryGraphState,
getDrawInfo,
context->MemoryHistory.Count
);
if (!context->MemoryGraphState.Valid)
{
ULONG i = 0;
for (i = 0; i < drawInfo->LineDataCount; i++)
{
context->MemoryGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemoryHistory, i);
}
if (EtGpuDedicatedLimit != 0)
{
PhDivideSinglesBySingle(
context->MemoryGraphState.Data1,
(FLOAT)EtGpuDedicatedLimit / PAGE_SIZE,
drawInfo->LineDataCount
);
}
context->MemoryGraphState.Valid = TRUE;
}
}
else if (header->hwndFrom == context->SharedGraphHandle)
{
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc;
PhMoveReference(&context->MemorySharedGraphState.Text, PhFormatString(
L"%s",
PhaFormatSize(UInt32x32To64(context->CurrentMemSharedUsage, PAGE_SIZE), -1)->Buffer
));
hdc = Graph_GetBufferedContext(context->SharedGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &context->MemorySharedGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0);
PhGraphStateGetDrawInfo(
&context->MemorySharedGraphState,
getDrawInfo,
context->MemorySharedHistory.Count
);
if (!context->MemorySharedGraphState.Valid)
{
ULONG i = 0;
for (i = 0; i < drawInfo->LineDataCount; i++)
{
context->MemorySharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemorySharedHistory, i);
}
if (EtGpuSharedLimit != 0)
{
PhDivideSinglesBySingle(
context->MemorySharedGraphState.Data1,
(FLOAT)EtGpuSharedLimit / PAGE_SIZE,
drawInfo->LineDataCount
);
}
context->MemorySharedGraphState.Valid = TRUE;
}
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (header->hwndFrom == context->GpuGraphHandle)
{
if (context->GpuGraphState.TooltipIndex != getTooltipText->Index)
{
FLOAT gpuUsage = PhGetItemCircularBuffer_FLOAT(
&context->GpuHistory,
getTooltipText->Index
);
PhMoveReference(&context->GpuGraphState.TooltipText, PhFormatString(
L"%.2f%%",
gpuUsage * 100
));
}
getTooltipText->Text = context->GpuGraphState.TooltipText->sr;
}
else if (header->hwndFrom == context->MemGraphHandle)
{
if (context->MemoryGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG gpuMemory = PhGetItemCircularBuffer_ULONG(
&context->MemoryHistory,
getTooltipText->Index
);
PhMoveReference(&context->MemoryGraphState.TooltipText,
PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), -1)
);
}
getTooltipText->Text = context->MemoryGraphState.TooltipText->sr;
}
else if (header->hwndFrom == context->SharedGraphHandle)
{
if (context->MemorySharedGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG gpuSharedMemory = PhGetItemCircularBuffer_ULONG(
&context->MemorySharedHistory,
getTooltipText->Index
);
PhMoveReference(&context->MemorySharedGraphState.TooltipText,
PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), -1)
);
}
getTooltipText->Text = context->MemorySharedGraphState.TooltipText->sr;
}
}
}
break;
}
}
break;
case UPDATE_MSG:
{
if (context->Enabled)
{
GpuPropUpdateInfo(context);
GpuPropUpdateGraphs(context);
GpuPropUpdatePanel(context);
}
}
break;
case WM_SIZE:
{
GpuPropLayoutGraphs(context);
}
break;
}
return FALSE;
}
VOID EtProcessGpuPropertiesInitializing(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter;
if (EtGpuEnabled)
{
PhAddProcessPropPage(
propContext->PropContext,
PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCGPU), EtpGpuPageDlgProc, NULL)
);
}
}