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
25TypeHandle WinGraphicsPipe::_type_handle;
26
27#ifndef MAXIMUM_PROCESSORS
28#define MAXIMUM_PROCESSORS 32
29#endif
30
31typedef 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
37typedef 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
46typedef BOOL (WINAPI *GetProcessMemoryInfoType) (HANDLE Process, PROCESS_MEMORY_COUNTERS *ppsmemCounters, DWORD cb);
47typedef long (__stdcall *CallNtPowerInformationType) (POWER_INFORMATION_LEVEL information_level, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength);
48
49static int initialize = false;
50static HMODULE psapi_dll = 0;
51static GetProcessMemoryInfoType GetProcessMemoryInfoFunction = 0;
52static CallNtPowerInformationType CallNtPowerInformationFunction = 0;
53
54void 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
98int 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
153void
154count_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 */
220WinGraphicsPipe::
221WinGraphicsPipe() {
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) {
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 */
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 */
403WinGraphicsPipe::
404~WinGraphicsPipe() {
405}
This class contains various display information.
Parameters used for searching display capabilities.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual void lookup_cpu_data()
Looks up the detailed CPU information and stores it in _display_information, if supported by the OS.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int count_bits_in_word(unsigned short x)
Returns the number of 1 bits in the indicated word.
Definition: pbitops.I:18
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.