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  }
244  }
245 
246 #ifdef HAVE_DX9
247  // Use D3D to get display info. This is disabled by default as it is slow.
248  if (request_dxdisplay_information) {
249  if (windisplay_cat.is_debug()) {
250  windisplay_cat.debug() << "Using Direct3D 9 to fetch display information.\n";
251  }
252  DisplaySearchParameters display_search_parameters_dx9;
253  int dx9_display_information (DisplaySearchParameters &display_search_parameters_dx9, DisplayInformation *display_information);
254  dx9_display_information(display_search_parameters_dx9, _display_information);
255  } else
256 #endif
257  {
258  // Use the Win32 API to query the available display modes.
259  if (windisplay_cat.is_debug()) {
260  windisplay_cat.debug() << "Using EnumDisplaySettings to fetch display information.\n";
261  }
262  pvector<DisplayMode> display_modes;
263  DEVMODE dm{};
264  dm.dmSize = sizeof(dm);
265  for (int i = 0; EnumDisplaySettings(nullptr, i, &dm) != 0; ++i) {
266  DisplayMode mode;
267  mode.width = dm.dmPelsWidth;
268  mode.height = dm.dmPelsHeight;
269  mode.bits_per_pixel = dm.dmBitsPerPel;
270  mode.refresh_rate = dm.dmDisplayFrequency;
271  mode.fullscreen_only = 0;
272  if (i == 0 || mode != display_modes.back()) {
273  display_modes.push_back(mode);
274  }
275  }
276 
277  // Copy this information to the DisplayInformation object.
278  _display_information->_total_display_modes = display_modes.size();
279  if (!display_modes.empty()) {
280  _display_information->_display_mode_array = new DisplayMode[display_modes.size()];
281  std::copy(display_modes.begin(), display_modes.end(),
282  _display_information->_display_mode_array);
283  }
284  }
285 
286  if (auto_cpu_data) {
287  lookup_cpu_data();
288  }
289 
290  OSVERSIONINFO version_info;
291 
292  version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
293  if (GetVersionEx(&version_info)) {
294  if (windisplay_cat.is_info()) {
295  sprintf(string, "OS version: %lu.%lu.%lu.%lu\n", version_info.dwMajorVersion, version_info.dwMinorVersion, version_info.dwPlatformId, version_info.dwBuildNumber);
296  windisplay_cat.info() << string;
297  windisplay_cat.info() << " " << version_info.szCSDVersion << "\n";
298  }
299 
300  _display_information->_os_version_major = version_info.dwMajorVersion;
301  _display_information->_os_version_minor = version_info.dwMinorVersion;
302  _display_information->_os_version_build = version_info.dwBuildNumber;
303  _display_information->_os_platform_id = version_info.dwPlatformId;
304  }
305  // Screen size
306  _display_width = GetSystemMetrics(SM_CXSCREEN);
307  _display_height = GetSystemMetrics(SM_CYSCREEN);
308 
309  HMODULE power_dll;
310 
311  power_dll = LoadLibrary("PowrProf.dll");
312  if (power_dll) {
313  CallNtPowerInformationFunction = (CallNtPowerInformationType) GetProcAddress(power_dll, "CallNtPowerInformation");
314  if (CallNtPowerInformationFunction) {
315 
316  _display_information->_update_cpu_frequency_function = update_cpu_frequency_function;
317  update_cpu_frequency_function(0, _display_information);
318 
319  sprintf(string, "max Mhz %I64d, current Mhz %I64d\n", _display_information->_maximum_cpu_frequency, _display_information->_current_cpu_frequency);
320 
321  windisplay_cat.info() << string;
322  }
323  }
324 }
325 
326 /**
327  * Looks up the detailed CPU information and stores it in
328  * _display_information, if supported by the OS. This may take a second or
329  * two.
330  */
332 lookup_cpu_data() {
333  char string [512];
334 
335  // set callback for memory function
336  _display_information->_get_memory_information_function = get_memory_information;
337 
338  // determine CPU frequency
339  uint64_t time;
340  uint64_t end_time;
341  LARGE_INTEGER counter;
342  LARGE_INTEGER end;
343  LARGE_INTEGER frequency;
344 
345  time = 0;
346  end_time = 0;
347  counter.QuadPart = 0;
348  end.QuadPart = 0;
349  frequency.QuadPart = 0;
350 
351  int priority;
352  HANDLE thread;
353 
354  windisplay_cat.info() << "begin QueryPerformanceFrequency\n";
355  thread = GetCurrentThread();
356  priority = GetThreadPriority (thread);
357  SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL);
358 
359  if (QueryPerformanceFrequency(&frequency)) {
360  if (frequency.QuadPart > 0) {
361  if (QueryPerformanceCounter (&counter)) {
362  time = __rdtsc();
363  end.QuadPart = counter.QuadPart + frequency.QuadPart;
364  while (QueryPerformanceCounter (&counter) && counter.QuadPart < end.QuadPart) {
365 
366  }
367  end_time = __rdtsc();
368 
369  _display_information->_cpu_frequency = end_time - time;
370  }
371  }
372  }
373 
374  SetThreadPriority(thread, priority);
375  sprintf(string, "QueryPerformanceFrequency: %I64d\n", frequency.QuadPart);
376  windisplay_cat.info() << string;
377  sprintf(string, "CPU frequency: %I64d\n", _display_information->_cpu_frequency);
378  windisplay_cat.info() << string;
379 
380  // Number of CPU's
381  count_number_of_cpus(_display_information);
382 }
383 
384 /**
385  *
386  */
387 WinGraphicsPipe::
388 ~WinGraphicsPipe() {
389 }
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:332
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