Panda3D
winGraphicsPipe.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file winGraphicsPipe.cxx
10  * @author drose
11  * @date 2002-12-20
12  */
13 
14 #include "winGraphicsPipe.h"
15 #include "config_windisplay.h"
17 #include "displayInformation.h"
18 #include "dtool_config.h"
19 #include "pbitops.h"
20 
21 #include <psapi.h>
22 #include <powrprof.h>
23 #include <intrin.h>
24 
25 TypeHandle WinGraphicsPipe::_type_handle;
26 
27 #ifndef MAXIMUM_PROCESSORS
28 #define MAXIMUM_PROCESSORS 32
29 #endif
30 
31 typedef enum _Process_DPI_Awareness {
32  Process_DPI_Unaware = 0,
33  Process_System_DPI_Aware = 1,
34  Process_Per_Monitor_DPI_Aware = 2
35 } Process_DPI_Awareness;
36 
37 typedef struct _PROCESSOR_POWER_INFORMATION {
38  ULONG Number;
39  ULONG MaxMhz;
40  ULONG CurrentMhz;
41  ULONG MhzLimit;
42  ULONG MaxIdleState;
43  ULONG CurrentIdleState;
44 } PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
45 
46 typedef BOOL (WINAPI *GetProcessMemoryInfoType) (HANDLE Process, PROCESS_MEMORY_COUNTERS *ppsmemCounters, DWORD cb);
47 typedef long (__stdcall *CallNtPowerInformationType) (POWER_INFORMATION_LEVEL information_level, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength);
48 
49 static int initialize = false;
50 static HMODULE psapi_dll = 0;
51 static GetProcessMemoryInfoType GetProcessMemoryInfoFunction = 0;
52 static CallNtPowerInformationType CallNtPowerInformationFunction = 0;
53 
54 void get_memory_information (DisplayInformation *display_information) {
55  if (initialize == false) {
56  psapi_dll = LoadLibrary("psapi.dll");
57  if (psapi_dll) {
58  GetProcessMemoryInfoFunction = (GetProcessMemoryInfoType) GetProcAddress(psapi_dll, "GetProcessMemoryInfo");
59  }
60 
61  initialize = true;
62  }
63 
64  MEMORYSTATUSEX memory_status;
65 
66  memory_status.dwLength = sizeof(MEMORYSTATUSEX);
67  if (GlobalMemoryStatusEx(&memory_status)) {
68  display_information->_physical_memory = memory_status.ullTotalPhys;
69  display_information->_available_physical_memory = memory_status.ullAvailPhys;
70  display_information->_page_file_size = memory_status.ullTotalPageFile;
71  display_information->_available_page_file_size = memory_status.ullAvailPageFile;
72  display_information->_process_virtual_memory = memory_status.ullTotalVirtual;
73  display_information->_available_process_virtual_memory = memory_status.ullAvailVirtual;
74  display_information->_memory_load = memory_status.dwMemoryLoad;
75  }
76 
77  if (GetProcessMemoryInfoFunction) {
78  HANDLE process;
79  DWORD process_id;
80  PROCESS_MEMORY_COUNTERS process_memory_counters;
81 
82  process_id = GetCurrentProcessId();
83  process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_id);
84  if (process) {
85  if (GetProcessMemoryInfoFunction (process, &process_memory_counters, sizeof(PROCESS_MEMORY_COUNTERS))) {
86  display_information->_page_fault_count = process_memory_counters.PageFaultCount;
87  display_information->_process_memory = process_memory_counters.WorkingSetSize;
88  display_information->_peak_process_memory = process_memory_counters.PeakWorkingSetSize;
89  display_information->_page_file_usage = process_memory_counters.PagefileUsage;
90  display_information->_peak_page_file_usage = process_memory_counters.PeakPagefileUsage;
91  }
92 
93  CloseHandle(process);
94  }
95  }
96 }
97 
98 int update_cpu_frequency_function(int processor_number, DisplayInformation *display_information) {
99  int update;
100 
101  update = false;
102  display_information->_maximum_cpu_frequency = 0;
103  display_information->_current_cpu_frequency = 0;
104 
105  if (CallNtPowerInformationFunction) {
106 
107  int i;
108  PVOID input_buffer;
109  PVOID output_buffer;
110  ULONG input_buffer_size;
111  ULONG output_buffer_size;
112  POWER_INFORMATION_LEVEL information_level;
113  PROCESSOR_POWER_INFORMATION *processor_power_information;
114  PROCESSOR_POWER_INFORMATION processor_power_information_array [MAXIMUM_PROCESSORS];
115 
116  memset(processor_power_information_array, 0, sizeof(PROCESSOR_POWER_INFORMATION) * MAXIMUM_PROCESSORS);
117 
118  processor_power_information = processor_power_information_array;
119  for (i = 0; i < MAXIMUM_PROCESSORS; i++) {
120  processor_power_information->Number = 0xFFFFFFFF;
121  processor_power_information++;
122  }
123 
124  information_level = ProcessorInformation;
125  input_buffer = nullptr;
126  output_buffer = processor_power_information_array;
127  input_buffer_size = 0;
128  output_buffer_size = sizeof(PROCESSOR_POWER_INFORMATION) * MAXIMUM_PROCESSORS;
129  if (CallNtPowerInformationFunction(information_level, input_buffer, input_buffer_size, output_buffer, output_buffer_size) == 0) {
130  processor_power_information = processor_power_information_array;
131  for (i = 0; i < MAXIMUM_PROCESSORS; i++) {
132  if (processor_power_information->Number == processor_number) {
133  uint64_t value;
134 
135  value = processor_power_information->MaxMhz;
136  display_information->_maximum_cpu_frequency = value * 1000000;
137 
138  value = processor_power_information->CurrentMhz;
139  display_information->_current_cpu_frequency = value * 1000000;
140  update = true;
141 
142  break;
143  }
144 
145  processor_power_information++;
146  }
147  }
148  }
149 
150  return update;
151 }
152 
153 void
154 count_number_of_cpus(DisplayInformation *display_information) {
155  int num_cpu_cores = 0;
156  int num_logical_cpus = 0;
157 
158  // Get a pointer to the GetLogicalProcessorInformation function.
159  typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,
160  PDWORD);
161  LPFN_GLPI glpi;
162  glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")),
163  "GetLogicalProcessorInformation");
164  if (glpi == nullptr) {
165  windisplay_cat.info()
166  << "GetLogicalProcessorInformation is not supported.\n";
167  return;
168  }
169 
170  // Allocate a buffer to hold the result of the
171  // GetLogicalProcessorInformation call.
172  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = nullptr;
173  DWORD buffer_length = 0;
174  DWORD rc = glpi(buffer, &buffer_length);
175  while (!rc) {
176  if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
177  if (buffer != nullptr) {
178  PANDA_FREE_ARRAY(buffer);
179  }
180 
181  buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)PANDA_MALLOC_ARRAY(buffer_length);
182  nassertv(buffer != nullptr);
183  } else {
184  windisplay_cat.info()
185  << "GetLogicalProcessorInformation failed: " << GetLastError()
186  << "\n";
187  return;
188  }
189  rc = glpi(buffer, &buffer_length);
190  }
191 
192  // Now get the results.
193  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer;
194  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION end = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)((char *)buffer + buffer_length);
195 
196  while (ptr < end) {
197  if (ptr->Relationship == RelationProcessorCore) {
198  num_cpu_cores++;
199 
200  // A hyperthreaded core supplies more than one logical processor.
201  num_logical_cpus += count_bits_in_word((uint64_t)(ptr->ProcessorMask));
202  }
203  ++ptr;
204  }
205 
206  PANDA_FREE_ARRAY(buffer);
207 
208  windisplay_cat.info()
209  << num_cpu_cores << " CPU cores, with "
210  << num_logical_cpus << " logical processors.\n";
211 
212  display_information->_num_cpu_cores = num_cpu_cores;
213  display_information->_num_logical_cpus = num_logical_cpus;
214 }
215 
216 
217 /**
218  *
219  */
220 WinGraphicsPipe::
221 WinGraphicsPipe() {
222  char string [512];
223 
224  _supported_types = OT_window | OT_fullscreen_window;
225 
226  HMODULE user32 = GetModuleHandleA("user32.dll");
227  if (user32 != nullptr) {
228  if (dpi_aware) {
229  typedef HRESULT (WINAPI *PFN_SETPROCESSDPIAWARENESS)(Process_DPI_Awareness);
230  PFN_SETPROCESSDPIAWARENESS pfnSetProcessDpiAwareness =
231  (PFN_SETPROCESSDPIAWARENESS)GetProcAddress(user32, "SetProcessDpiAwarenessInternal");
232 
233  if (pfnSetProcessDpiAwareness == nullptr) {
234  if (windisplay_cat.is_debug()) {
235  windisplay_cat.debug() << "Unable to find SetProcessDpiAwareness in user32.dll.\n";
236  }
237  } else {
238  if (windisplay_cat.is_debug()) {
239  windisplay_cat.debug() << "Calling SetProcessDpiAwareness().\n";
240  }
241  pfnSetProcessDpiAwareness(Process_Per_Monitor_DPI_Aware);
242 
243  HDC dc = GetDC(nullptr);
244  if (dc) {
245  int dpi = GetDeviceCaps(dc, LOGPIXELSX);
246  if (dpi > 0) {
247  PN_stdfloat zoom = (double)dpi / 96.0;
248  set_detected_display_zoom(zoom);
249 
250  if (windisplay_cat.is_debug()) {
251  windisplay_cat.debug()
252  << "Determined display zoom to be " << zoom
253  << " based on LOGPIXELSX " << dpi << "\n";
254  }
255  }
256  ReleaseDC(nullptr, dc);
257  }
258  }
259  }
260  }
261 
262 #ifdef HAVE_DX9
263  // Use D3D to get display info. This is disabled by default as it is slow.
264  if (request_dxdisplay_information) {
265  if (windisplay_cat.is_debug()) {
266  windisplay_cat.debug() << "Using Direct3D 9 to fetch display information.\n";
267  }
268  DisplaySearchParameters display_search_parameters_dx9;
269  int dx9_display_information (DisplaySearchParameters &display_search_parameters_dx9, DisplayInformation *display_information);
270  dx9_display_information(display_search_parameters_dx9, _display_information);
271  } else
272 #endif
273  {
274  // Use the Win32 API to query the available display modes.
275  if (windisplay_cat.is_debug()) {
276  windisplay_cat.debug() << "Using EnumDisplaySettings to fetch display information.\n";
277  }
278  pvector<DisplayMode> display_modes;
279  DEVMODE dm{};
280  dm.dmSize = sizeof(dm);
281  for (int i = 0; EnumDisplaySettings(nullptr, i, &dm) != 0; ++i) {
282  DisplayMode mode;
283  mode.width = dm.dmPelsWidth;
284  mode.height = dm.dmPelsHeight;
285  mode.bits_per_pixel = dm.dmBitsPerPel;
286  mode.refresh_rate = dm.dmDisplayFrequency;
287  mode.fullscreen_only = 0;
288  if (i == 0 || mode != display_modes.back()) {
289  display_modes.push_back(mode);
290  }
291  }
292 
293  // Copy this information to the DisplayInformation object.
294  _display_information->_total_display_modes = display_modes.size();
295  if (!display_modes.empty()) {
296  _display_information->_display_mode_array = new DisplayMode[display_modes.size()];
297  std::copy(display_modes.begin(), display_modes.end(),
298  _display_information->_display_mode_array);
299  }
300  }
301 
302  if (auto_cpu_data) {
303  lookup_cpu_data();
304  }
305 
306  OSVERSIONINFO version_info;
307 
308  version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
309  if (GetVersionEx(&version_info)) {
310  if (windisplay_cat.is_info()) {
311  sprintf(string, "OS version: %lu.%lu.%lu.%lu\n", version_info.dwMajorVersion, version_info.dwMinorVersion, version_info.dwPlatformId, version_info.dwBuildNumber);
312  windisplay_cat.info() << string;
313  windisplay_cat.info() << " " << version_info.szCSDVersion << "\n";
314  }
315 
316  _display_information->_os_version_major = version_info.dwMajorVersion;
317  _display_information->_os_version_minor = version_info.dwMinorVersion;
318  _display_information->_os_version_build = version_info.dwBuildNumber;
319  _display_information->_os_platform_id = version_info.dwPlatformId;
320  }
321  // Screen size
322  _display_width = GetSystemMetrics(SM_CXSCREEN);
323  _display_height = GetSystemMetrics(SM_CYSCREEN);
324 
325  HMODULE power_dll;
326 
327  power_dll = LoadLibrary("PowrProf.dll");
328  if (power_dll) {
329  CallNtPowerInformationFunction = (CallNtPowerInformationType) GetProcAddress(power_dll, "CallNtPowerInformation");
330  if (CallNtPowerInformationFunction) {
331 
332  _display_information->_update_cpu_frequency_function = update_cpu_frequency_function;
333  update_cpu_frequency_function(0, _display_information);
334 
335  sprintf(string, "max Mhz %I64d, current Mhz %I64d\n", _display_information->_maximum_cpu_frequency, _display_information->_current_cpu_frequency);
336 
337  windisplay_cat.info() << string;
338  }
339  }
340 }
341 
342 /**
343  * Looks up the detailed CPU information and stores it in
344  * _display_information, if supported by the OS. This may take a second or
345  * two.
346  */
348 lookup_cpu_data() {
349  char string [512];
350 
351  // set callback for memory function
352  _display_information->_get_memory_information_function = get_memory_information;
353 
354  // determine CPU frequency
355  uint64_t time;
356  uint64_t end_time;
357  LARGE_INTEGER counter;
358  LARGE_INTEGER end;
359  LARGE_INTEGER frequency;
360 
361  time = 0;
362  end_time = 0;
363  counter.QuadPart = 0;
364  end.QuadPart = 0;
365  frequency.QuadPart = 0;
366 
367  int priority;
368  HANDLE thread;
369 
370  windisplay_cat.info() << "begin QueryPerformanceFrequency\n";
371  thread = GetCurrentThread();
372  priority = GetThreadPriority (thread);
373  SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL);
374 
375  if (QueryPerformanceFrequency(&frequency)) {
376  if (frequency.QuadPart > 0) {
377  if (QueryPerformanceCounter (&counter)) {
378  time = __rdtsc();
379  end.QuadPart = counter.QuadPart + frequency.QuadPart;
380  while (QueryPerformanceCounter (&counter) && counter.QuadPart < end.QuadPart) {
381 
382  }
383  end_time = __rdtsc();
384 
385  _display_information->_cpu_frequency = end_time - time;
386  }
387  }
388  }
389 
390  SetThreadPriority(thread, priority);
391  sprintf(string, "QueryPerformanceFrequency: %I64d\n", frequency.QuadPart);
392  windisplay_cat.info() << string;
393  sprintf(string, "CPU frequency: %I64d\n", _display_information->_cpu_frequency);
394  windisplay_cat.info() << string;
395 
396  // Number of CPU's
397  count_number_of_cpus(_display_information);
398 }
399 
400 /**
401  *
402  */
403 WinGraphicsPipe::
404 ~WinGraphicsPipe() {
405 }
pbitops.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
winGraphicsPipe.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DisplayMode
Definition: displayInformation.h:20
DisplaySearchParameters
Parameters used for searching display capabilities.
Definition: displaySearchParameters.h:22
displaySearchParameters.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
config_windisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DisplayInformation
This class contains various display information.
Definition: displayInformation.h:36
WinGraphicsPipe::lookup_cpu_data
virtual void lookup_cpu_data()
Looks up the detailed CPU information and stores it in _display_information, if supported by the OS.
Definition: winGraphicsPipe.cxx:348
displayInformation.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
count_bits_in_word
int count_bits_in_word(unsigned short x)
Returns the number of 1 bits in the indicated word.
Definition: pbitops.I:18