Panda3D
winGraphicsPipe.cxx
1 // Filename: winGraphicsPipe.cxx
2 // Created by: drose (20Dec02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "winGraphicsPipe.h"
16 #include "config_windisplay.h"
17 #include "displaySearchParameters.h"
18 #include "displayInformation.h"
19 #include "dtool_config.h"
20 #include "pbitops.h"
21 
22 #include "psapi.h"
23 #include "powrprof.h"
24 
25 #ifdef _WIN64
26 #include <intrin.h>
27 #endif
28 
29 TypeHandle WinGraphicsPipe::_type_handle;
30 
31 #ifndef MAXIMUM_PROCESSORS
32 #define MAXIMUM_PROCESSORS 32
33 #endif
34 
35 typedef enum _Process_DPI_Awareness {
36  Process_DPI_Unaware = 0,
37  Process_System_DPI_Aware = 1,
38  Process_Per_Monitor_DPI_Aware = 2
39 } Process_DPI_Awareness;
40 
42  ULONG Number;
43  ULONG MaxMhz;
44  ULONG CurrentMhz;
45  ULONG MhzLimit;
46  ULONG MaxIdleState;
47  ULONG CurrentIdleState;
48 } PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
49 
50 typedef BOOL (WINAPI *GetProcessMemoryInfoType) (HANDLE Process, PROCESS_MEMORY_COUNTERS *ppsmemCounters, DWORD cb);
51 typedef BOOL (WINAPI *GlobalMemoryStatusExType) (LPMEMORYSTATUSEX lpBuffer);
52 typedef long (__stdcall *CallNtPowerInformationType) (POWER_INFORMATION_LEVEL information_level, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength);
53 
54 static int initialize = false;
55 static HMODULE psapi_dll = 0;
56 static HMODULE kernel32_dll = 0;
57 static HMODULE power_dll = 0;
58 static GetProcessMemoryInfoType GetProcessMemoryInfoFunction = 0;
59 static GlobalMemoryStatusExType GlobalMemoryStatusExFunction = 0;
60 static CallNtPowerInformationType CallNtPowerInformationFunction = 0;
61 
62 void get_memory_information (DisplayInformation *display_information) {
63  if (initialize == false) {
64  psapi_dll = LoadLibrary("psapi.dll");
65  if (psapi_dll) {
66  GetProcessMemoryInfoFunction = (GetProcessMemoryInfoType) GetProcAddress(psapi_dll, "GetProcessMemoryInfo");
67  }
68 
69  kernel32_dll = LoadLibrary("kernel32.dll");
70  if (kernel32_dll) {
71  GlobalMemoryStatusExFunction = (GlobalMemoryStatusExType) GetProcAddress(kernel32_dll, "GlobalMemoryStatusEx");
72  }
73 
74  initialize = true;
75  }
76 
77  if (GlobalMemoryStatusExFunction) {
78  MEMORYSTATUSEX memory_status;
79 
80  memory_status.dwLength = sizeof(MEMORYSTATUSEX);
81  if (GlobalMemoryStatusExFunction(&memory_status)) {
82  display_information->_physical_memory = memory_status.ullTotalPhys;
83  display_information->_available_physical_memory = memory_status.ullAvailPhys;
84  display_information->_page_file_size = memory_status.ullTotalPageFile;
85  display_information->_available_page_file_size = memory_status.ullAvailPageFile;
86  display_information->_process_virtual_memory = memory_status.ullTotalVirtual;
87  display_information->_available_process_virtual_memory = memory_status.ullAvailVirtual;
88  display_information->_memory_load = memory_status.dwMemoryLoad;
89  }
90  } else {
91  MEMORYSTATUS memory_status;
92 
93  memory_status.dwLength = sizeof(MEMORYSTATUS);
94  GlobalMemoryStatus (&memory_status);
95 
96  display_information->_physical_memory = memory_status.dwTotalPhys;
97  display_information->_available_physical_memory = memory_status.dwAvailPhys;
98  display_information->_page_file_size = memory_status.dwTotalPageFile;
99  display_information->_available_page_file_size = memory_status.dwAvailPageFile;
100  display_information->_process_virtual_memory = memory_status.dwTotalVirtual;
101  display_information->_available_process_virtual_memory = memory_status.dwAvailVirtual;
102  display_information->_memory_load = memory_status.dwMemoryLoad;
103  }
104 
105  if (GetProcessMemoryInfoFunction) {
106  HANDLE process;
107  DWORD process_id;
108  PROCESS_MEMORY_COUNTERS process_memory_counters;
109 
110  process_id = GetCurrentProcessId();
111  process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_id);
112  if (process) {
113  if (GetProcessMemoryInfoFunction (process, &process_memory_counters, sizeof(PROCESS_MEMORY_COUNTERS))) {
114  display_information->_page_fault_count = process_memory_counters.PageFaultCount;
115  display_information->_process_memory = process_memory_counters.WorkingSetSize;
116  display_information->_peak_process_memory = process_memory_counters.PeakWorkingSetSize;
117  display_information->_page_file_usage = process_memory_counters.PagefileUsage;
118  display_information->_peak_page_file_usage = process_memory_counters.PeakPagefileUsage;
119  }
120 
121  CloseHandle(process);
122  }
123  }
124 }
125 
126 typedef union {
127  PN_uint64 long_integer;
128 }
130 
131 PN_uint64 cpu_time_function (void) {
132 #ifdef _WIN64
133  return __rdtsc();
134 #else
135  LONG_INTEGER long_integer;
136  LONG_INTEGER *long_integer_pointer;
137 
138  long_integer_pointer = &long_integer;
139 
140  __asm {
141  mov ebx,[long_integer_pointer]
142  rdtsc
143  mov [ebx + 0], eax
144  mov [ebx + 4], edx
145  }
146 
147  return long_integer.long_integer;
148 #endif
149 }
150 
151 typedef union {
152  struct {
153  union {
154  struct {
155  unsigned char al;
156  unsigned char ah;
157  };
158  unsigned int eax;
159  };
160  unsigned int ebx;
161  unsigned int ecx;
162  unsigned int edx;
163  };
165 
166 typedef struct {
167  union {
168  struct {
169  int maximum_cpu_id_input;
170  char cpu_vendor [16];
171  };
172 
173  CPU_ID_REGISTERS cpu_id_registers_0;
174  };
175 
176  union {
177  CPU_ID_REGISTERS cpu_id_registers_1;
178 
179  struct {
180  // eax
181  union {
182  unsigned int eax;
183  unsigned int version_information;
184  struct {
185  unsigned int stepping_id : 4;
186  unsigned int model : 4;
187  unsigned int family : 4;
188  unsigned int processor_type : 2;
189  unsigned int reserved_0 : 2;
190  unsigned int extended_model_id : 4;
191  unsigned int extended_family_id : 8;
192  unsigned int reserved_1 : 4;
193  };
194  };
195 
196  // ebx
197  union {
198  unsigned int ebx;
199  struct {
200  unsigned int brand_index : 8;
201  unsigned int clflush : 8;
202  unsigned int maximum_logical_processors : 8;
203  unsigned int initial_apic_id : 8;
204  };
205  };
206 
207  // ecx
208  union {
209  unsigned int ecx;
210  struct {
211  unsigned int sse3 : 1;
212  unsigned int reserved_1_to_2 : 2;
213  unsigned int monitor : 1;
214  unsigned int ds_cpl : 1;
215  unsigned int vmx : 1;
216  unsigned int reserved_6 : 1;
217  unsigned int est : 1;
218  unsigned int tm2 : 1;
219  unsigned int reserved_9 : 1;
220  unsigned int cnxt_id : 1;
221  unsigned int reserved_11_to_12 : 2;
222  unsigned int cmpxchg16b : 1;
223  unsigned int xtpr_disable : 1;
224  unsigned int reserved_15_to_31 : 17;
225  };
226  };
227 
228  // edx
229  union {
230  unsigned int edx;
231  struct {
232  unsigned int fpu : 1;
233  unsigned int vme : 1;
234  unsigned int de : 1;
235  unsigned int pse : 1;
236  unsigned int tsc : 1;
237  unsigned int msr : 1;
238  unsigned int pae : 1;
239  unsigned int mce : 1;
240  unsigned int cx8 : 1;
241  unsigned int apic : 1;
242  unsigned int reserved_10 : 1;
243  unsigned int sep : 1;
244  unsigned int mtrr : 1;
245  unsigned int pge : 1;
246  unsigned int mca : 1;
247  unsigned int cmov : 1;
248  unsigned int pat : 1;
249  unsigned int pse_36 : 1;
250  unsigned int psn : 1;
251  unsigned int cflush : 1;
252  unsigned int reserved_20 : 1;
253  unsigned int ds : 1;
254  unsigned int acpi : 1;
255  unsigned int mmx : 1;
256  unsigned int fxsr : 1;
257  unsigned int sse : 1;
258  unsigned int sse2 : 1;
259  unsigned int ss : 1;
260  unsigned int htt : 1;
261  unsigned int tm : 1;
262  unsigned int reserved_30 : 1;
263  unsigned int pbe : 1;
264  };
265  };
266  };
267  };
268 
269  #define MAXIMUM_2 8
270  #define MAXIMUM_CHARACTERS (MAXIMUM_2 * sizeof(CPU_ID_REGISTERS))
271 
272  union {
273  CPU_ID_REGISTERS cpu_id_registers_2;
274  unsigned char character_array_2 [MAXIMUM_CHARACTERS];
275  CPU_ID_REGISTERS cpu_id_registers_2_array [MAXIMUM_2];
276  };
277 
278  union {
279  CPU_ID_REGISTERS cpu_id_registers_0x80000000;
280  };
281 
282  union {
283  CPU_ID_REGISTERS cpu_id_registers_0x80000001;
284  };
285 
286  union {
287  char cpu_brand_string [sizeof(CPU_ID_REGISTERS) * 3];
288  struct {
289  CPU_ID_REGISTERS cpu_id_registers_0x80000002;
290  CPU_ID_REGISTERS cpu_id_registers_0x80000003;
291  CPU_ID_REGISTERS cpu_id_registers_0x80000004;
292  };
293  };
294 
295  union {
296  struct {
297  unsigned int eax;
298  unsigned int ebx;
299  union {
300  unsigned int ecx;
301  struct {
302  unsigned int l1_data_cache_line_size : 8;
303  unsigned int l1_data_reserved_8_to_15 : 8;
304  unsigned int l1_data_associativity : 8;
305  unsigned int l1_data_cache_size : 8;
306  };
307  };
308  union {
309  unsigned int edx;
310  struct {
311  unsigned int l1_code_cache_line_size : 8;
312  unsigned int l1_code_reserved_8_to_15 : 8;
313  unsigned int l1_code_associativity : 8;
314  unsigned int l1_code_cache_size : 8;
315  };
316  };
317  };
318  CPU_ID_REGISTERS cpu_id_registers_0x80000005;
319  };
320 
321  union {
322  struct {
323  unsigned int eax;
324  unsigned int ebx;
325  union {
326  unsigned int ecx;
327  struct {
328  unsigned int l2_cache_line_size : 8;
329  unsigned int l2_reserved_8_to_11 : 4;
330  unsigned int l2_associativity : 4;
331  unsigned int l2_cache_size : 16;
332  };
333  };
334  unsigned int edx;
335  };
336  CPU_ID_REGISTERS cpu_id_registers_0x80000006;
337  };
338 
339  CPU_ID_REGISTERS cpu_id_registers_0x80000008;
340 
341  unsigned int cache_line_size;
342  unsigned int log_base_2_cache_line_size;
343 } CPU_ID;
344 
345 typedef struct {
346  CPU_ID_REGISTERS cpu_id_registers_0;
347  CPU_ID_REGISTERS cpu_id_registers_1;
348 
349  CPU_ID_REGISTERS cpu_id_registers_0x80000000;
350  CPU_ID_REGISTERS cpu_id_registers_0x80000001;
351  CPU_ID_REGISTERS cpu_id_registers_0x80000002;
352  CPU_ID_REGISTERS cpu_id_registers_0x80000003;
353  CPU_ID_REGISTERS cpu_id_registers_0x80000004;
354 
355  CPU_ID_REGISTERS cpu_id_registers_0x80000006;
356 
357  CPU_ID_REGISTERS cpu_id_registers_0x80000008;
359 
360 void cpu_id_to_cpu_id_binary_data (CPU_ID *cpu_id, CPU_ID_BINARY_DATA *cpu_id_binary_data) {
361  cpu_id_binary_data->cpu_id_registers_0 = cpu_id->cpu_id_registers_0;
362  cpu_id_binary_data->cpu_id_registers_1 = cpu_id->cpu_id_registers_1;
363  cpu_id_binary_data->cpu_id_registers_0x80000000 = cpu_id->cpu_id_registers_0x80000000;
364  cpu_id_binary_data->cpu_id_registers_0x80000001 = cpu_id->cpu_id_registers_0x80000001;
365  cpu_id_binary_data->cpu_id_registers_0x80000002 = cpu_id->cpu_id_registers_0x80000002;
366  cpu_id_binary_data->cpu_id_registers_0x80000003 = cpu_id->cpu_id_registers_0x80000003;
367  cpu_id_binary_data->cpu_id_registers_0x80000004 = cpu_id->cpu_id_registers_0x80000004;
368  cpu_id_binary_data->cpu_id_registers_0x80000006 = cpu_id->cpu_id_registers_0x80000006;
369  cpu_id_binary_data->cpu_id_registers_0x80000008 = cpu_id->cpu_id_registers_0x80000008;
370 }
371 
372 void cpu_id_binary_data_to_cpu_id (CPU_ID_BINARY_DATA *cpu_id_binary_data, CPU_ID *cpu_id) {
373  memset (cpu_id, 0, sizeof(CPU_ID));
374 
375  cpu_id->cpu_id_registers_0 = cpu_id_binary_data->cpu_id_registers_0;
376  cpu_id->cpu_id_registers_1 = cpu_id_binary_data->cpu_id_registers_1;
377  cpu_id->cpu_id_registers_0x80000000 = cpu_id_binary_data->cpu_id_registers_0x80000000;
378  cpu_id->cpu_id_registers_0x80000001 = cpu_id_binary_data->cpu_id_registers_0x80000001;
379  cpu_id->cpu_id_registers_0x80000002 = cpu_id_binary_data->cpu_id_registers_0x80000002;
380  cpu_id->cpu_id_registers_0x80000003 = cpu_id_binary_data->cpu_id_registers_0x80000003;
381  cpu_id->cpu_id_registers_0x80000004 = cpu_id_binary_data->cpu_id_registers_0x80000004;
382  cpu_id->cpu_id_registers_0x80000006 = cpu_id_binary_data->cpu_id_registers_0x80000006;
383  cpu_id->cpu_id_registers_0x80000008 = cpu_id_binary_data->cpu_id_registers_0x80000008;
384 }
385 
386 int cpuid(int input_eax, CPU_ID_REGISTERS *cpu_id_registers) {
387  int state;
388 
389  state = false;
390  __try {
391  if (input_eax == 0) {
392  // the order of ecx and edx is swapped when saved to make a proper vendor string
393 #ifdef _WIN64
394  __cpuid((int*)cpu_id_registers, input_eax);
395  unsigned int tmp = cpu_id_registers->edx;
396  cpu_id_registers->edx = cpu_id_registers->ecx;
397  cpu_id_registers->ecx = tmp;
398 #else
399  __asm {
400  mov eax, [input_eax]
401  mov edi, [cpu_id_registers]
402 
403  cpuid
404 
405  mov [edi + 0], eax
406  mov [edi + 4], ebx
407  mov [edi + 8], edx
408  mov [edi + 12], ecx
409  }
410 #endif
411  } else {
412 #ifdef _WIN64
413  __cpuid((int*)cpu_id_registers, input_eax);
414 #else
415  __asm {
416  mov eax, [input_eax]
417  mov edi, [cpu_id_registers]
418 
419  cpuid
420 
421  mov [edi + 0], eax
422  mov [edi + 4], ebx
423  mov [edi + 8], ecx
424  mov [edi + 12], edx
425  }
426 #endif
427  }
428 
429  state = true;
430  }
431  __except (1) {
432  state = false;
433  }
434 
435  return state;
436 }
437 
438 void parse_cpu_id(CPU_ID *cpu_id) {
439  printf("CPUID\n");
440  printf(" vendor = %s\n", cpu_id->cpu_vendor);
441  printf(" brand string %s\n", cpu_id->cpu_brand_string);
442  printf(" maximum_cpu_id_input = %u\n", cpu_id->maximum_cpu_id_input);
443  printf(" maximum extended information = 0x%X\n", cpu_id->cpu_id_registers_0x80000000.eax);
444 
445  printf(" MMX = %u\n", cpu_id->mmx);
446  printf(" SSE = %u\n", cpu_id->sse);
447  printf(" SSE2 = %u\n", cpu_id->sse2);
448  printf(" SSE3 = %u\n", cpu_id->sse3);
449 
450  printf(" EST = %u\n", cpu_id->est);
451 
452  if (cpu_id->maximum_cpu_id_input >= 1) {
453  printf(" version_information\n");
454  printf(" stepping_id %u\n", cpu_id->stepping_id);
455  printf(" model %u\n", cpu_id->model);
456  printf(" family %u\n", cpu_id->family);
457  printf(" processor_type %u\n", cpu_id->processor_type);
458  printf(" extended_model_id %u\n", cpu_id->extended_model_id);
459  printf(" extended_family_id %u\n", cpu_id->extended_family_id);
460 
461  printf(" brand_index %u\n", cpu_id->brand_index);
462  printf(" clflush %u\n", cpu_id->clflush);
463  printf(" maximum_logical_processors %u\n", cpu_id->maximum_logical_processors);
464  printf(" initial_apic_id %u\n", cpu_id->initial_apic_id);
465 
466 // printf(" cache_line_size %u\n", cpu_id->cache_line_size);
467 // printf(" log_base_2_cache_line_size %u\n", cpu_id->log_base_2_cache_line_size);
468  }
469 
470  if (cpu_id->cpu_id_registers_0x80000000.eax >= 0x80000005) {
471  printf(" l1_data_cache_line_size %d\n", cpu_id->l1_data_cache_line_size);
472  printf(" l1_data_associativity %d\n", cpu_id->l1_data_associativity);
473  printf(" l1_data_cache_size %dK\n", cpu_id->l1_data_cache_size);
474 
475  printf(" l1_code_cache_line_size %d\n", cpu_id->l1_code_cache_line_size);
476  printf(" l1_code_associativity %d\n", cpu_id->l1_code_associativity);
477  printf(" l1_code_cache_size %dK\n", cpu_id->l1_code_cache_size);
478  }
479 
480  if (cpu_id->cpu_id_registers_0x80000000.eax >= 0x80000006) {
481  printf(" l2_cache_line_size %d\n", cpu_id->l2_cache_line_size);
482  printf(" l2_associativity %d\n", cpu_id->l2_associativity);
483  printf(" l2_cache_size %dK\n", cpu_id->l2_cache_size);
484  }
485 }
486 
487 int initialize_cpu_id(CPU_ID *cpu_id) {
488  int debug = false;
489  memset(cpu_id, 0, sizeof(CPU_ID));
490 
491  if (cpuid(0, &cpu_id->cpu_id_registers_0)) {
492  if (cpu_id->maximum_cpu_id_input >= 1) {
493  cpuid(1, &cpu_id->cpu_id_registers_1);
494  }
495  if (cpu_id->maximum_cpu_id_input >= 2) {
496  unsigned int index;
497 
498  cpuid(2, &cpu_id->cpu_id_registers_2);
499  if (debug) {
500  printf(" al = %u\n", cpu_id->cpu_id_registers_2.al);
501  }
502 
503  for (index = 1; index < cpu_id->cpu_id_registers_2.al && index < MAXIMUM_2; index++) {
504  cpuid(2, &cpu_id->cpu_id_registers_2_array [index]);
505  }
506 
507  for (index = 1; index < MAXIMUM_CHARACTERS; index++) {
508  if (cpu_id->character_array_2 [index]) {
509  if (debug) {
510  printf(" cache/TLB byte = %X\n", cpu_id->character_array_2 [index]);
511  }
512  switch (cpu_id->character_array_2 [index]) {
513  case 0x0A:
514  case 0x0C:
515  cpu_id->cache_line_size = 32;
516  cpu_id->log_base_2_cache_line_size = 5;
517  break;
518 
519  case 0x2C:
520  case 0x60:
521  case 0x66:
522  case 0x67:
523  case 0x68:
524  cpu_id->cache_line_size = 64;
525  cpu_id->log_base_2_cache_line_size = 6;
526  break;
527  }
528  }
529  }
530  }
531 
532  cpuid(0x80000000, &cpu_id->cpu_id_registers_0x80000000);
533 
534  if (cpu_id->cpu_id_registers_0x80000000.eax >= 0x80000001) {
535  cpuid(0x80000001, &cpu_id->cpu_id_registers_0x80000001);
536  }
537 
538  if (cpu_id->cpu_id_registers_0x80000000.eax >= 0x80000004) {
539  cpuid(0x80000002, &cpu_id->cpu_id_registers_0x80000002);
540  cpuid(0x80000003, &cpu_id->cpu_id_registers_0x80000003);
541  cpuid(0x80000004, &cpu_id->cpu_id_registers_0x80000004);
542  }
543 
544  if (cpu_id->cpu_id_registers_0x80000000.eax >= 0x80000005) {
545  cpuid(0x80000005, &cpu_id->cpu_id_registers_0x80000005);
546  }
547 
548  if (cpu_id->cpu_id_registers_0x80000000.eax >= 0x80000006) {
549  cpuid(0x80000006, &cpu_id->cpu_id_registers_0x80000006);
550  }
551 
552  if (cpu_id->cpu_id_registers_0x80000000.eax >= 0x80000008) {
553  cpuid(0x80000008, &cpu_id->cpu_id_registers_0x80000008);
554  }
555 
556  return true;
557  }
558 
559  return false;
560 }
561 
562 int update_cpu_frequency_function(int processor_number, DisplayInformation *display_information) {
563  int update;
564 
565  update = false;
566  display_information->_maximum_cpu_frequency = 0;
567  display_information->_current_cpu_frequency = 0;
568 
569  if (CallNtPowerInformationFunction) {
570 
571  int i;
572  PVOID input_buffer;
573  PVOID output_buffer;
574  ULONG input_buffer_size;
575  ULONG output_buffer_size;
576  POWER_INFORMATION_LEVEL information_level;
577  PROCESSOR_POWER_INFORMATION *processor_power_information;
578  PROCESSOR_POWER_INFORMATION processor_power_information_array [MAXIMUM_PROCESSORS];
579 
580  memset(processor_power_information_array, 0, sizeof(PROCESSOR_POWER_INFORMATION) * MAXIMUM_PROCESSORS);
581 
582  processor_power_information = processor_power_information_array;
583  for (i = 0; i < MAXIMUM_PROCESSORS; i++) {
584  processor_power_information->Number = 0xFFFFFFFF;
585  processor_power_information++;
586  }
587 
588  information_level = ProcessorInformation;
589  input_buffer = NULL;
590  output_buffer = processor_power_information_array;
591  input_buffer_size = 0;
592  output_buffer_size = sizeof(PROCESSOR_POWER_INFORMATION) * MAXIMUM_PROCESSORS;
593  if (CallNtPowerInformationFunction(information_level, input_buffer, input_buffer_size, output_buffer, output_buffer_size) == 0) {
594  processor_power_information = processor_power_information_array;
595  for (i = 0; i < MAXIMUM_PROCESSORS; i++) {
596  if (processor_power_information->Number == processor_number) {
597  PN_uint64 value;
598 
599  value = processor_power_information->MaxMhz;
600  display_information->_maximum_cpu_frequency = value * 1000000;
601 
602  value = processor_power_information->CurrentMhz;
603  display_information->_current_cpu_frequency = value * 1000000;
604  update = true;
605 
606  break;
607  }
608 
609  processor_power_information++;
610  }
611  }
612  }
613 
614  return update;
615 }
616 
617 void
618 count_number_of_cpus(DisplayInformation *display_information) {
619  int num_cpu_cores = 0;
620  int num_logical_cpus = 0;
621 
622  // Get a pointer to the GetLogicalProcessorInformation function.
623  typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,
624  PDWORD);
625  LPFN_GLPI glpi;
626  glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")),
627  "GetLogicalProcessorInformation");
628  if (glpi == NULL) {
629  windisplay_cat.info()
630  << "GetLogicalProcessorInformation is not supported.\n";
631  return;
632  }
633 
634  // Allocate a buffer to hold the result of the
635  // GetLogicalProcessorInformation call.
636  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
637  DWORD buffer_length = 0;
638  DWORD rc = glpi(buffer, &buffer_length);
639  while (!rc) {
640  if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
641  if (buffer != NULL) {
642  PANDA_FREE_ARRAY(buffer);
643  }
644 
645  buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)PANDA_MALLOC_ARRAY(buffer_length);
646  nassertv(buffer != NULL);
647  } else {
648  windisplay_cat.info()
649  << "GetLogicalProcessorInformation failed: " << GetLastError()
650  << "\n";
651  return;
652  }
653  rc = glpi(buffer, &buffer_length);
654  }
655 
656  // Now get the results.
657  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer;
658  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION end = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)((char *)buffer + buffer_length);
659 
660  while (ptr < end) {
661  if (ptr->Relationship == RelationProcessorCore) {
662  num_cpu_cores++;
663 
664  // A hyperthreaded core supplies more than one logical processor.
665  num_logical_cpus += count_bits_in_word((PN_uint64)(ptr->ProcessorMask));
666  }
667  ++ptr;
668  }
669 
670  PANDA_FREE_ARRAY(buffer);
671 
672  windisplay_cat.info()
673  << num_cpu_cores << " CPU cores, with "
674  << num_logical_cpus << " logical processors.\n";
675 
676  display_information->_num_cpu_cores = num_cpu_cores;
677  display_information->_num_logical_cpus = num_logical_cpus;
678 }
679 
680 
681 ////////////////////////////////////////////////////////////////////
682 // Function: WinGraphicsPipe::Constructor
683 // Access: Public
684 // Description:
685 ////////////////////////////////////////////////////////////////////
686 WinGraphicsPipe::
687 WinGraphicsPipe() {
688  char string [512];
689 
690  _supported_types = OT_window | OT_fullscreen_window;
691 
692  // these fns arent defined on win95, so get dynamic ptrs to them
693  // to avoid ugly DLL loader failures on w95
694  _pfnTrackMouseEvent = NULL;
695 
696  _hUser32 = (HINSTANCE)LoadLibrary("user32.dll");
697  if (_hUser32 != NULL) {
698  _pfnTrackMouseEvent =
699  (PFN_TRACKMOUSEEVENT)GetProcAddress(_hUser32, "TrackMouseEvent");
700 
701  if (dpi_aware) {
702  typedef HRESULT (WINAPI *PFN_SETPROCESSDPIAWARENESS)(Process_DPI_Awareness);
703  PFN_SETPROCESSDPIAWARENESS pfnSetProcessDpiAwareness =
704  (PFN_SETPROCESSDPIAWARENESS)GetProcAddress(_hUser32, "SetProcessDpiAwarenessInternal");
705 
706  if (pfnSetProcessDpiAwareness == NULL) {
707  if (windisplay_cat.is_debug()) {
708  windisplay_cat.debug() << "Unable to find SetProcessDpiAwareness in user32.dll.\n";
709  }
710  } else {
711  if (windisplay_cat.is_debug()) {
712  windisplay_cat.debug() << "Calling SetProcessDpiAwareness().\n";
713  }
714  pfnSetProcessDpiAwareness(Process_Per_Monitor_DPI_Aware);
715  }
716  }
717  }
718 
719 #ifdef HAVE_DX9
720  // Use D3D to get display info. This is disabled by default as it is slow.
721  if (request_dxdisplay_information) {
722  if (windisplay_cat.is_debug()) {
723  windisplay_cat.debug() << "Using Direct3D 9 to fetch display information.\n";
724  }
725  DisplaySearchParameters display_search_parameters_dx9;
726  int dx9_display_information (DisplaySearchParameters &display_search_parameters_dx9, DisplayInformation *display_information);
727  dx9_display_information(display_search_parameters_dx9, _display_information);
728  } else
729 #endif
730  {
731  // Use the Win32 API to query the available display modes.
732  if (windisplay_cat.is_debug()) {
733  windisplay_cat.debug() << "Using EnumDisplaySettings to fetch display information.\n";
734  }
735  pvector<DisplayMode> display_modes;
736  DEVMODE dm = {0};
737  dm.dmSize = sizeof(dm);
738  for (int i = 0; EnumDisplaySettings(NULL, i, &dm) != 0; ++i) {
739  DisplayMode mode;
740  mode.width = dm.dmPelsWidth;
741  mode.height = dm.dmPelsHeight;
742  mode.bits_per_pixel = dm.dmBitsPerPel;
743  mode.refresh_rate = dm.dmDisplayFrequency;
744  mode.fullscreen_only = 0;
745  if (i == 0 || mode != display_modes.back()) {
746  display_modes.push_back(mode);
747  }
748  }
749 
750  // Copy this information to the DisplayInformation object.
751  _display_information->_total_display_modes = display_modes.size();
752  if (!display_modes.empty()) {
753  _display_information->_display_mode_array = new DisplayMode[display_modes.size()];
754  std::copy(display_modes.begin(), display_modes.end(),
755  _display_information->_display_mode_array);
756  }
757  }
758 
759  if (auto_cpu_data) {
760  lookup_cpu_data();
761  }
762 
763  OSVERSIONINFO version_info;
764 
765  version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
766  if (GetVersionEx(&version_info)) {
767  if (windisplay_cat.is_info()) {
768  sprintf(string, "OS version: %d.%d.%d.%d\n", version_info.dwMajorVersion, version_info.dwMinorVersion, version_info.dwPlatformId, version_info.dwBuildNumber);
769  windisplay_cat.info() << string;
770  windisplay_cat.info() << " " << version_info.szCSDVersion << "\n";
771  }
772 
773  _display_information->_os_version_major = version_info.dwMajorVersion;
774  _display_information->_os_version_minor = version_info.dwMinorVersion;
775  _display_information->_os_version_build = version_info.dwBuildNumber;
776  _display_information->_os_platform_id = version_info.dwPlatformId;
777  }
778  // Screen size
779  _display_width = GetSystemMetrics(SM_CXSCREEN);
780  _display_height = GetSystemMetrics(SM_CYSCREEN);
781 
782  HMODULE power_dll;
783 
784  power_dll = LoadLibrary("PowrProf.dll");
785  if (power_dll) {
786  CallNtPowerInformationFunction = (CallNtPowerInformationType) GetProcAddress(power_dll, "CallNtPowerInformation");
787  if (CallNtPowerInformationFunction) {
788 
789  _display_information->_update_cpu_frequency_function = update_cpu_frequency_function;
790  update_cpu_frequency_function(0, _display_information);
791 
792  sprintf(string, "max Mhz %I64d, current Mhz %I64d\n", _display_information->_maximum_cpu_frequency, _display_information->_current_cpu_frequency);
793 
794  windisplay_cat.info() << string;
795  }
796  }
797 }
798 
799 ////////////////////////////////////////////////////////////////////
800 // Function: WinGraphicsPipe::lookup_cpu_data
801 // Access: Public, Virtual
802 // Description: Looks up the detailed CPU information and stores it
803 // in _display_information, if supported by the OS.
804 // This may take a second or two.
805 ////////////////////////////////////////////////////////////////////
808  char string [512];
809 
810  // set callback for memory function
811  _display_information->_get_memory_information_function = get_memory_information;
812 
813  // set callback for cpu time function
814  _display_information->_cpu_time_function = cpu_time_function;
815 
816  // determine CPU frequency
817  PN_uint64 time;
818  PN_uint64 end_time;
819  LARGE_INTEGER counter;
820  LARGE_INTEGER end;
821  LARGE_INTEGER frequency;
822 
823  time = 0;
824  end_time = 0;
825  counter.QuadPart = 0;
826  end.QuadPart = 0;
827  frequency.QuadPart = 0;
828 
829  int priority;
830  HANDLE thread;
831 
832  windisplay_cat.info() << "begin QueryPerformanceFrequency\n";
833  thread = GetCurrentThread();
834  priority = GetThreadPriority (thread);
835  SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL);
836 
837  if (QueryPerformanceFrequency(&frequency)) {
838  if (frequency.QuadPart > 0) {
839  if (QueryPerformanceCounter (&counter)) {
840  time = cpu_time_function();
841  end.QuadPart = counter.QuadPart + frequency.QuadPart;
842  while (QueryPerformanceCounter (&counter) && counter.QuadPart < end.QuadPart) {
843 
844  }
845  end_time = cpu_time_function();
846 
847  _display_information->_cpu_frequency = end_time - time;
848  }
849  }
850  }
851 
852  SetThreadPriority(thread, priority);
853  sprintf(string, "QueryPerformanceFrequency: %I64d\n", frequency.QuadPart);
854  windisplay_cat.info() << string;
855  sprintf(string, "CPU frequency: %I64d\n", _display_information->_cpu_frequency);
856  windisplay_cat.info() << string;
857 
858 
859  // CPUID
860  CPU_ID cpu_id;
861 
862  windisplay_cat.info() << "start CPU ID\n";
863 
864  if (initialize_cpu_id(&cpu_id)) {
865  CPU_ID_BINARY_DATA *cpu_id_binary_data;
866 
867  cpu_id_binary_data = new (CPU_ID_BINARY_DATA);
868  if (cpu_id_binary_data) {
869  cpu_id_to_cpu_id_binary_data(&cpu_id, cpu_id_binary_data);
870  _display_information->_cpu_id_size = sizeof(CPU_ID_BINARY_DATA) / sizeof(unsigned int);
871  _display_information->_cpu_id_data = (unsigned int *) cpu_id_binary_data;
872 
873  _display_information->_cpu_vendor_string = strdup(cpu_id.cpu_vendor);
874  _display_information->_cpu_brand_string = strdup(cpu_id.cpu_brand_string);
875  _display_information->_cpu_version_information = cpu_id.version_information;
876  _display_information->_cpu_brand_index = cpu_id.brand_index;
877 
878  if (windisplay_cat.is_debug()) {
879  windisplay_cat.debug()
880  << hex << _display_information->_cpu_id_version << dec << "|";
881 
882  int index;
883  for (index = 0; index < _display_information->_cpu_id_size; ++index) {
884  unsigned int data;
885  data = _display_information->_cpu_id_data[index];
886 
887  windisplay_cat.debug(false)
888  << hex << data << dec;
889  if (index < _display_information->_cpu_id_size - 1) {
890  windisplay_cat.debug(false)
891  << "|";
892  }
893  }
894  windisplay_cat.debug(false)
895  << "\n";
896  }
897  }
898 
899  if (windisplay_cat.is_debug()) {
900  parse_cpu_id(&cpu_id);
901  }
902  }
903 
904  windisplay_cat.info() << "end CPU ID\n";
905 
906  // Number of CPU's
907  count_number_of_cpus(_display_information);
908 }
909 
910 ////////////////////////////////////////////////////////////////////
911 // Function: WinGraphicsPipe::Destructor
912 // Access: Public, Virtual
913 // Description:
914 ////////////////////////////////////////////////////////////////////
915 WinGraphicsPipe::
916 ~WinGraphicsPipe() {
917  if (_hUser32 != NULL) {
918  FreeLibrary(_hUser32);
919  _hUser32 = NULL;
920  }
921 }
922 
923 bool MyGetProcAddr(HINSTANCE hDLL, FARPROC *pFn, const char *szExportedFnName) {
924  *pFn = (FARPROC) GetProcAddress(hDLL, szExportedFnName);
925  if (*pFn == NULL) {
926  windisplay_cat.error() << "GetProcAddr failed for " << szExportedFnName << ", error=" << GetLastError() <<endl;
927  return false;
928  }
929  return true;
930 }
931 
932 bool MyLoadLib(HINSTANCE &hDLL, const char *DLLname) {
933  hDLL = LoadLibrary(DLLname);
934  if(hDLL == NULL) {
935  windisplay_cat.error() << "LoadLibrary failed for " << DLLname << ", error=" << GetLastError() <<endl;
936  return false;
937  }
938  return true;
939 }
This class contains various display information.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
Parameters used for searching display capabilities.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
virtual void lookup_cpu_data()
Looks up the detailed CPU information and stores it in _display_information, if supported by the OS...