Process Hacker
gpuprprp.c
Go to the documentation of this file.
1 /*
2  * Process Hacker Extended Tools -
3  * GPU process properties page
4  *
5  * Copyright (C) 2011 wj32
6  * Copyright (C) 2015 dmex
7  *
8  * This file is part of Process Hacker.
9  *
10  * Process Hacker is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Process Hacker is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "exttools.h"
25 #include "resource.h"
26 
27 #define MSG_UPDATE (WM_APP + 1)
28 
29 static RECT NormalGraphTextMargin = { 5, 5, 5, 5 };
30 static RECT NormalGraphTextPadding = { 3, 3, 3, 3 };
31 
32 typedef struct _ET_GPU_CONTEXT
33 {
34  HWND WindowHandle;
35  PET_PROCESS_BLOCK Block;
36  PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
37  BOOLEAN Enabled;
38  PH_LAYOUT_MANAGER LayoutManager;
39 
40  HWND GpuGroupBox;
41  HWND MemGroupBox;
42  HWND SharedGroupBox;
43 
44  HWND GpuGraphHandle;
45  HWND MemGraphHandle;
46  HWND SharedGraphHandle;
47  HWND PanelHandle;
48 
49  FLOAT CurrentGpuUsage;
50  ULONG CurrentMemUsage;
51  ULONG CurrentMemSharedUsage;
52 
53  PH_GRAPH_STATE GpuGraphState;
54  PH_GRAPH_STATE MemoryGraphState;
55  PH_GRAPH_STATE MemorySharedGraphState;
56 
57  PH_CIRCULAR_BUFFER_FLOAT GpuHistory;
58  PH_CIRCULAR_BUFFER_ULONG MemoryHistory;
59  PH_CIRCULAR_BUFFER_ULONG MemorySharedHistory;
61 
62 static INT_PTR CALLBACK GpuPanelDialogProc(
63  _In_ HWND hwndDlg,
64  _In_ UINT uMsg,
65  _In_ WPARAM wParam,
66  _In_ LPARAM lParam
67  )
68 {
69  return FALSE;
70 }
71 
72 static VOID GpuPropCreateGraphs(
73  _In_ PET_GPU_CONTEXT Context
74  )
75 {
76  Context->GpuGraphHandle = CreateWindow(
78  NULL,
79  WS_VISIBLE | WS_CHILD | WS_BORDER,
80  0,
81  0,
82  3,
83  3,
84  Context->WindowHandle,
85  NULL,
86  NULL,
87  NULL
88  );
89  Graph_SetTooltip(Context->GpuGraphHandle, TRUE);
90 
91  Context->MemGraphHandle = CreateWindow(
93  NULL,
94  WS_VISIBLE | WS_CHILD | WS_BORDER,
95  0,
96  0,
97  3,
98  3,
99  Context->WindowHandle,
100  NULL,
101  NULL,
102  NULL
103  );
104  Graph_SetTooltip(Context->MemGraphHandle, TRUE);
105 
106  Context->SharedGraphHandle = CreateWindow(
108  NULL,
109  WS_VISIBLE | WS_CHILD | WS_BORDER,
110  0,
111  0,
112  3,
113  3,
114  Context->WindowHandle,
115  NULL,
116  NULL,
117  NULL
118  );
119  Graph_SetTooltip(Context->SharedGraphHandle, TRUE);
120 }
121 
122 static VOID GpuPropCreatePanel(
123  _In_ PET_GPU_CONTEXT Context
124  )
125 {
126  RECT margin;
127 
128  Context->PanelHandle = CreateDialogParam(
130  MAKEINTRESOURCE(IDD_PROCGPU_PANEL),
131  Context->WindowHandle,
132  GpuPanelDialogProc,
133  (LPARAM)Context
134  );
135 
136  SetWindowPos(
137  Context->PanelHandle,
138  NULL,
139  10, 0, 0, 0,
140  SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER
141  );
142 
143  ShowWindow(Context->PanelHandle, SW_SHOW);
144 
145  margin.left = 0;
146  margin.top = 0;
147  margin.right = 0;
148  margin.bottom = 10;
149  MapDialogRect(Context->WindowHandle, &margin);
150 
152  &Context->LayoutManager,
153  Context->PanelHandle,
154  NULL,
156  margin
157  );
158 
159  SendMessage(Context->WindowHandle, WM_SIZE, 0, 0);
160 }
161 
162 static VOID GpuPropLayoutGraphs(
163  _In_ PET_GPU_CONTEXT Context
164  )
165 {
166  HDWP deferHandle;
167  RECT clientRect;
168  RECT panelRect;
169  RECT margin = { 13, 13, 13, 13 };
170  RECT innerMargin = { 10, 20, 10, 10 };
171  LONG between = 3;
172  ULONG graphWidth;
173  ULONG graphHeight;
174 
175  PhLayoutManagerLayout(&Context->LayoutManager);
176 
177  Context->GpuGraphState.Valid = FALSE;
178  Context->MemoryGraphState.Valid = FALSE;
179  Context->MemorySharedGraphState.Valid = FALSE;
180 
181  GetClientRect(Context->WindowHandle, &clientRect);
182 
183  // Limit the rectangle bottom to the top of the panel.
184  GetWindowRect(Context->PanelHandle, &panelRect);
185  MapWindowPoints(NULL, Context->WindowHandle, (PPOINT)&panelRect, 2);
186  clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing
187 
188  graphWidth = clientRect.right - margin.left - margin.right;
189  graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3;
190 
191  deferHandle = BeginDeferWindowPos(6);
192 
193  deferHandle = DeferWindowPos(deferHandle, Context->GpuGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
194  deferHandle = DeferWindowPos(
195  deferHandle,
196  Context->GpuGraphHandle,
197  NULL,
198  margin.left + innerMargin.left,
199  margin.top + innerMargin.top,
200  graphWidth - innerMargin.left - innerMargin.right,
201  graphHeight - innerMargin.top - innerMargin.bottom,
202  SWP_NOACTIVATE | SWP_NOZORDER
203  );
204 
205  deferHandle = DeferWindowPos(deferHandle, Context->MemGroupBox, NULL, margin.left, margin.top + graphHeight + between, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
206  deferHandle = DeferWindowPos(
207  deferHandle,
208  Context->MemGraphHandle,
209  NULL,
210  margin.left + innerMargin.left,
211  margin.top + graphHeight + between + innerMargin.top,
212  graphWidth - innerMargin.left - innerMargin.right,
213  graphHeight - innerMargin.top - innerMargin.bottom,
214  SWP_NOACTIVATE | SWP_NOZORDER
215  );
216 
217  deferHandle = DeferWindowPos(deferHandle, Context->SharedGroupBox, NULL, margin.left, margin.top + (graphHeight + between) * 2, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
218  deferHandle = DeferWindowPos(
219  deferHandle,
220  Context->SharedGraphHandle,
221  NULL,
222  margin.left + innerMargin.left,
223  margin.top + (graphHeight + between) * 2 + innerMargin.top,
224  graphWidth - innerMargin.left - innerMargin.right,
225  graphHeight - innerMargin.top - innerMargin.bottom,
226  SWP_NOACTIVATE | SWP_NOZORDER
227  );
228 
229  EndDeferWindowPos(deferHandle);
230 }
231 
232 static VOID GpuPropUpdateGraphs(
233  _In_ PET_GPU_CONTEXT Context
234  )
235 {
236  Context->GpuGraphState.Valid = FALSE;
237  Context->GpuGraphState.TooltipIndex = -1;
238  Graph_MoveGrid(Context->GpuGraphHandle, 1);
239  Graph_Draw(Context->GpuGraphHandle);
240  Graph_UpdateTooltip(Context->GpuGraphHandle);
241  InvalidateRect(Context->GpuGraphHandle, NULL, FALSE);
242 
243  Context->MemoryGraphState.Valid = FALSE;
244  Context->MemoryGraphState.TooltipIndex = -1;
245  Graph_MoveGrid(Context->MemGraphHandle, 1);
246  Graph_Draw(Context->MemGraphHandle);
247  Graph_UpdateTooltip(Context->MemGraphHandle);
248  InvalidateRect(Context->MemGraphHandle, NULL, FALSE);
249 
250  Context->MemorySharedGraphState.Valid = FALSE;
251  Context->MemorySharedGraphState.TooltipIndex = -1;
252  Graph_MoveGrid(Context->SharedGraphHandle, 1);
253  Graph_Draw(Context->SharedGraphHandle);
254  Graph_UpdateTooltip(Context->SharedGraphHandle);
255  InvalidateRect(Context->SharedGraphHandle, NULL, FALSE);
256 }
257 
258 static VOID GpuPropUpdatePanel(
259  _Inout_ PET_GPU_CONTEXT Context
260  )
261 {
262  ET_PROCESS_GPU_STATISTICS statistics;
263  WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A";
264 
265  if (Context->Block->ProcessItem->QueryHandle)
266  EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &statistics);
267  else
268  memset(&statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS));
269 
270  PhPrintTimeSpan(runningTimeString, statistics.RunningTime * 10, PH_TIMESPAN_HMSM);
271 
272  SetDlgItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString);
273  SetDlgItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(statistics.ContextSwitches, TRUE)->Buffer);
274  SetDlgItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(statistics.NodeCount, TRUE)->Buffer);
275 
276  SetDlgItemText(Context->PanelHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(statistics.DedicatedCommitted, -1)->Buffer);
277  SetDlgItemText(Context->PanelHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(statistics.SharedCommitted, -1)->Buffer);
278  SetDlgItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(statistics.SegmentCount, TRUE)->Buffer);
279  SetDlgItemText(Context->PanelHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(statistics.BytesAllocated, -1)->Buffer);
280  SetDlgItemText(Context->PanelHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(statistics.BytesReserved, -1)->Buffer);
281  SetDlgItemText(Context->PanelHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(statistics.WriteCombinedBytesAllocated, -1)->Buffer);
282  SetDlgItemText(Context->PanelHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(statistics.WriteCombinedBytesReserved, -1)->Buffer);
283  SetDlgItemText(Context->PanelHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(statistics.CachedBytesAllocated, -1)->Buffer);
284  SetDlgItemText(Context->PanelHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(statistics.CachedBytesReserved, -1)->Buffer);
285  SetDlgItemText(Context->PanelHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(statistics.SectionBytesAllocated, -1)->Buffer);
286  SetDlgItemText(Context->PanelHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(statistics.SectionBytesReserved, -1)->Buffer);
287 }
288 
289 static VOID GpuPropUpdateInfo(
290  _In_ PET_GPU_CONTEXT Context
291  )
292 {
293  PET_PROCESS_BLOCK block = Context->Block;
294 
295  Context->CurrentGpuUsage = block->GpuNodeUsage;
296  Context->CurrentMemUsage = (ULONG)(block->GpuDedicatedUsage / PAGE_SIZE);
297  Context->CurrentMemSharedUsage = (ULONG)(block->GpuSharedUsage / PAGE_SIZE);
298 
299  PhAddItemCircularBuffer_FLOAT(&Context->GpuHistory, Context->CurrentGpuUsage);
300  PhAddItemCircularBuffer_ULONG(&Context->MemoryHistory, Context->CurrentMemUsage);
301  PhAddItemCircularBuffer_ULONG(&Context->MemorySharedHistory, Context->CurrentMemSharedUsage);
302 }
303 
304 static VOID NTAPI ProcessesUpdatedHandler(
305  _In_opt_ PVOID Parameter,
306  _In_opt_ PVOID Context
307  )
308 {
309  PET_GPU_CONTEXT context = Context;
310 
311  if (!context->Enabled)
312  return;
313 
314  if (context->WindowHandle)
315  {
316  PostMessage(context->WindowHandle, MSG_UPDATE, 0, 0);
317  }
318 }
319 
320 INT_PTR CALLBACK EtpGpuPageDlgProc(
321  _In_ HWND hwndDlg,
322  _In_ UINT uMsg,
323  _In_ WPARAM wParam,
324  _In_ LPARAM lParam
325  )
326 {
327  LPPROPSHEETPAGE propSheetPage;
328  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
329  PPH_PROCESS_ITEM processItem;
330  PET_GPU_CONTEXT context;
331 
332  if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))
333  {
334  context = propPageContext->Context;
335  }
336  else
337  {
338  return FALSE;
339  }
340 
341  switch (uMsg)
342  {
343  case WM_INITDIALOG:
344  {
345  ULONG sampleCount;
346 
347  sampleCount = PhGetIntegerSetting(L"SampleCount");
348 
349  context = PhAllocate(sizeof(ET_GPU_CONTEXT));
350  memset(context, 0, sizeof(ET_GPU_CONTEXT));
351 
352  context->WindowHandle = hwndDlg;
353  context->Block = EtGetProcessBlock(processItem);
354  context->Enabled = TRUE;
355  context->GpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPGPU);
356  context->MemGroupBox = GetDlgItem(hwndDlg, IDC_GROUPMEM);
357  context->SharedGroupBox = GetDlgItem(hwndDlg, IDC_GROUPSHARED);
358  propPageContext->Context = context;
359 
360  PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
361 
362  PhInitializeGraphState(&context->GpuGraphState);
363  PhInitializeGraphState(&context->MemoryGraphState);
364  PhInitializeGraphState(&context->MemorySharedGraphState);
365 
366  PhInitializeCircularBuffer_FLOAT(&context->GpuHistory, sampleCount);
367  PhInitializeCircularBuffer_ULONG(&context->MemoryHistory, sampleCount);
368  PhInitializeCircularBuffer_ULONG(&context->MemorySharedHistory, sampleCount);
369 
370  GpuPropCreateGraphs(context);
371  GpuPropCreatePanel(context);
372  GpuPropUpdateInfo(context);
373  GpuPropUpdatePanel(context);
374 
377  ProcessesUpdatedHandler,
378  context,
379  &context->ProcessesUpdatedRegistration
380  );
381  }
382  break;
383  case WM_DESTROY:
384  {
385  PhDeleteLayoutManager(&context->LayoutManager);
386 
387  PhDeleteGraphState(&context->GpuGraphState);
388  PhDeleteGraphState(&context->MemoryGraphState);
389  PhDeleteGraphState(&context->MemorySharedGraphState);
390 
391  PhDeleteCircularBuffer_FLOAT(&context->GpuHistory);
392  PhDeleteCircularBuffer_ULONG(&context->MemoryHistory);
393  PhDeleteCircularBuffer_ULONG(&context->MemorySharedHistory);
394 
395  if (context->GpuGraphHandle)
396  DestroyWindow(context->GpuGraphHandle);
397  if (context->MemGraphHandle)
398  DestroyWindow(context->MemGraphHandle);
399  if (context->SharedGraphHandle)
400  DestroyWindow(context->SharedGraphHandle);
401  if (context->PanelHandle)
402  DestroyWindow(context->PanelHandle);
403 
404  PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration);
405  PhFree(context);
406 
407  PhPropPageDlgProcDestroy(hwndDlg);
408  }
409  break;
410  case WM_SHOWWINDOW:
411  {
412  if (PhBeginPropPageLayout(hwndDlg, propPageContext))
413  PhEndPropPageLayout(hwndDlg, propPageContext);
414  }
415  break;
416  case WM_NOTIFY:
417  {
418  LPNMHDR header = (LPNMHDR)lParam;
419 
420  switch (header->code)
421  {
422  case PSN_SETACTIVE:
423  context->Enabled = TRUE;
424  break;
425  case PSN_KILLACTIVE:
426  context->Enabled = FALSE;
427  break;
428  case GCN_GETDRAWINFO:
429  {
430  PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;
431  PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
432 
433  if (header->hwndFrom == context->GpuGraphHandle)
434  {
435  if (PhGetIntegerSetting(L"GraphShowText"))
436  {
437  HDC hdc;
438 
439  PhMoveReference(&context->GpuGraphState.Text, PhFormatString(
440  L"%.2f%%",
441  context->CurrentGpuUsage * 100
442  ));
443 
444  hdc = Graph_GetBufferedContext(context->GpuGraphHandle);
445  SelectObject(hdc, PhApplicationFont);
446  PhSetGraphText(hdc, drawInfo, &context->GpuGraphState.Text->sr,
447  &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
448  }
449  else
450  {
451  drawInfo->Text.Buffer = NULL;
452  }
453 
454  drawInfo->Flags = PH_GRAPH_USE_GRID;
455  PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
456  PhGraphStateGetDrawInfo(&context->GpuGraphState, getDrawInfo, context->GpuHistory.Count);
457 
458  if (!context->GpuGraphState.Valid)
459  {
460  PhCopyCircularBuffer_FLOAT(&context->GpuHistory, context->GpuGraphState.Data1, drawInfo->LineDataCount);
461  context->GpuGraphState.Valid = TRUE;
462  }
463  }
464  else if (header->hwndFrom == context->MemGraphHandle)
465  {
466  if (PhGetIntegerSetting(L"GraphShowText"))
467  {
468  HDC hdc;
469 
470  PhMoveReference(&context->MemoryGraphState.Text, PhFormatString(
471  L"%s",
472  PhaFormatSize(UInt32x32To64(context->CurrentMemUsage, PAGE_SIZE), -1)->Buffer
473  ));
474 
475  hdc = Graph_GetBufferedContext(context->MemGraphHandle);
476  SelectObject(hdc, PhApplicationFont);
478  hdc,
479  drawInfo,
480  &context->MemoryGraphState.Text->sr,
481  &NormalGraphTextMargin,
482  &NormalGraphTextPadding,
484  );
485  }
486  else
487  {
488  drawInfo->Text.Buffer = NULL;
489  }
490 
491  drawInfo->Flags = PH_GRAPH_USE_GRID;
492  PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0);
494  &context->MemoryGraphState,
495  getDrawInfo,
496  context->MemoryHistory.Count
497  );
498 
499  if (!context->MemoryGraphState.Valid)
500  {
501  ULONG i = 0;
502 
503  for (i = 0; i < drawInfo->LineDataCount; i++)
504  {
505  context->MemoryGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemoryHistory, i);
506  }
507 
508  if (EtGpuDedicatedLimit != 0)
509  {
511  context->MemoryGraphState.Data1,
513  drawInfo->LineDataCount
514  );
515  }
516 
517  context->MemoryGraphState.Valid = TRUE;
518  }
519  }
520  else if (header->hwndFrom == context->SharedGraphHandle)
521  {
522  if (PhGetIntegerSetting(L"GraphShowText"))
523  {
524  HDC hdc;
525 
526  PhMoveReference(&context->MemorySharedGraphState.Text, PhFormatString(
527  L"%s",
528  PhaFormatSize(UInt32x32To64(context->CurrentMemSharedUsage, PAGE_SIZE), -1)->Buffer
529  ));
530 
531  hdc = Graph_GetBufferedContext(context->SharedGraphHandle);
532  SelectObject(hdc, PhApplicationFont);
533  PhSetGraphText(hdc, drawInfo, &context->MemorySharedGraphState.Text->sr,
534  &NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
535  }
536  else
537  {
538  drawInfo->Text.Buffer = NULL;
539  }
540 
541  drawInfo->Flags = PH_GRAPH_USE_GRID;
542  PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0);
544  &context->MemorySharedGraphState,
545  getDrawInfo,
546  context->MemorySharedHistory.Count
547  );
548 
549  if (!context->MemorySharedGraphState.Valid)
550  {
551  ULONG i = 0;
552 
553  for (i = 0; i < drawInfo->LineDataCount; i++)
554  {
555  context->MemorySharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemorySharedHistory, i);
556  }
557 
558  if (EtGpuSharedLimit != 0)
559  {
561  context->MemorySharedGraphState.Data1,
562  (FLOAT)EtGpuSharedLimit / PAGE_SIZE,
563  drawInfo->LineDataCount
564  );
565  }
566 
567  context->MemorySharedGraphState.Valid = TRUE;
568  }
569  }
570  }
571  break;
572  case GCN_GETTOOLTIPTEXT:
573  {
574  PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam;
575 
576  if (getTooltipText->Index < getTooltipText->TotalCount)
577  {
578  if (header->hwndFrom == context->GpuGraphHandle)
579  {
580  if (context->GpuGraphState.TooltipIndex != getTooltipText->Index)
581  {
582  FLOAT gpuUsage = PhGetItemCircularBuffer_FLOAT(
583  &context->GpuHistory,
584  getTooltipText->Index
585  );
586 
587  PhMoveReference(&context->GpuGraphState.TooltipText, PhFormatString(
588  L"%.2f%%",
589  gpuUsage * 100
590  ));
591  }
592 
593  getTooltipText->Text = context->GpuGraphState.TooltipText->sr;
594  }
595  else if (header->hwndFrom == context->MemGraphHandle)
596  {
597  if (context->MemoryGraphState.TooltipIndex != getTooltipText->Index)
598  {
599  ULONG gpuMemory = PhGetItemCircularBuffer_ULONG(
600  &context->MemoryHistory,
601  getTooltipText->Index
602  );
603 
604  PhMoveReference(&context->MemoryGraphState.TooltipText,
605  PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), -1)
606  );
607  }
608 
609  getTooltipText->Text = context->MemoryGraphState.TooltipText->sr;
610  }
611  else if (header->hwndFrom == context->SharedGraphHandle)
612  {
613  if (context->MemorySharedGraphState.TooltipIndex != getTooltipText->Index)
614  {
615  ULONG gpuSharedMemory = PhGetItemCircularBuffer_ULONG(
616  &context->MemorySharedHistory,
617  getTooltipText->Index
618  );
619 
620  PhMoveReference(&context->MemorySharedGraphState.TooltipText,
621  PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), -1)
622  );
623  }
624 
625  getTooltipText->Text = context->MemorySharedGraphState.TooltipText->sr;
626  }
627  }
628  }
629  break;
630  }
631  }
632  break;
633  case MSG_UPDATE:
634  {
635  GpuPropUpdateInfo(context);
636  GpuPropUpdateGraphs(context);
637  GpuPropUpdatePanel(context);
638  }
639  break;
640  case WM_SIZE:
641  {
642  GpuPropLayoutGraphs(context);
643  }
644  break;
645  }
646 
647  return FALSE;
648 }
649 
651  _In_ PVOID Parameter
652  )
653 {
654  PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter;
655 
656  if (EtGpuEnabled)
657  {
659  propContext->PropContext,
661  );
662  }
663 }