Panda3D
winDetectDx.h
1 // Filename: winDetectDx.h
2 // Created by: aignacio (18Jan07)
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 <time.h>
16 
17 typedef struct {
18  D3DFORMAT d3d_format;
19  int bits_per_pixel;
20  int fullscreen_only;
21 }
23 
24 typedef union
25 {
26  struct
27  {
28  unsigned int day : 8;
29  unsigned int month : 8;
30  unsigned int year : 16;
31  };
32  DWORD whql;
33 }
34 WHQL;
35 
36 static DISPLAY_FORMAT display_format_array [ ] = {
37  D3DFMT_X8R8G8B8, 32, FALSE,
38  D3DFMT_R5G6B5, 16, FALSE,
39  D3DFMT_X1R5G5B5, 16, FALSE,
40 
41  D3DFMT_A2R10G10B10, 32, TRUE,
42 
43  // terminator
44  D3DFMT_UNKNOWN, 0, FALSE,
45 };
46 
47 typedef BOOL (WINAPI *GlobalMemoryStatusExType) (LPMEMORYSTATUSEX lpBuffer);
48 
49 static int d3d_format_to_bits_per_pixel (D3DFORMAT d3d_format) {
50  int format_index;
51  int bits_per_pixel;
52 
53  format_index = 0;
54  bits_per_pixel = 0;
55  while (display_format_array [format_index].d3d_format != D3DFMT_UNKNOWN) {
56  if (d3d_format == display_format_array [format_index].d3d_format) {
57  bits_per_pixel = display_format_array [format_index].bits_per_pixel;
58  break;
59  }
60 
61  format_index++;
62  }
63 
64  return bits_per_pixel;
65 }
66 
67 static DWORD _GetLastError (char *message_prefix) {
68  LPVOID ptr;
69  DWORD error;
70 
71  ptr = 0;
72  error = GetLastError ( );
73  if (FormatMessage (
74  FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM,
75  NULL, error, MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
76  (LPTSTR)&ptr,0, NULL)) {
77  cout << "ERROR: "<< message_prefix << " result = " << (char*) ptr << "\n";
78  LocalFree( ptr );
79  }
80 
81  return error;
82 }
83 
84 static LRESULT CALLBACK window_procedure (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
85  return DefWindowProc(hwnd, msg, wparam, lparam);
86 }
87 
88 static DWORD print_GetLastError (char *message_prefix)
89 {
90  LPVOID ptr;
91  DWORD error;
92 
93  ptr = 0;
94  error = GetLastError ( );
95  if (FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
96  FORMAT_MESSAGE_FROM_SYSTEM,
97  NULL,
98  error,
99  MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
100  (LPTSTR)&ptr,
101  0, NULL))
102  {
103  cout << "ERROR: "<< message_prefix << " result = " << (char*) ptr << "\n";
104  LocalFree( ptr );
105  }
106 
107  return error;
108 }
109 
110 static int get_display_information (DisplaySearchParameters &display_search_parameters, DisplayInformation *display_information) {
111 
112  int debug = false;
113 
114  int success;
115  DisplayInformation::DetectionState state;
116  int get_adapter_display_mode_state;
117  int get_device_caps_state;
118 
119  int shader_model;
120  UINT minimum_width;
121  UINT maximum_width;
122  UINT minimum_height;
123  UINT maximum_height;
124  int minimum_bits_per_pixel;
125  int maximum_bits_per_pixel;
126 
127  UINT texture_memory;
128  UINT video_memory;
129 
130  int window_width;
131  int window_height;
132  int window_bits_per_pixel;
133  int total_display_modes;
134  DisplayMode *display_mode_array;
135 
136  PN_uint64 physical_memory;
137  PN_uint64 available_physical_memory;
138 
139  int vendor_id;
140  int device_id;
141 
142  int product;
143  int version;
144  int sub_version;
145  int build;
146 
147  int month;
148  int day;
149  int year;
150 
151  success = false;
152  window_width = 0;
153  window_height = 0;
154  window_bits_per_pixel = 0;
155  total_display_modes = 0;
156  display_mode_array = NULL;
157 
158  minimum_width = display_search_parameters._minimum_width;
159  minimum_height = display_search_parameters._minimum_height;
160  maximum_width = display_search_parameters._maximum_width;
161  maximum_height = display_search_parameters._maximum_height;
162  minimum_bits_per_pixel = display_search_parameters._minimum_bits_per_pixel;
163  maximum_bits_per_pixel = display_search_parameters._maximum_bits_per_pixel;
164 
165  shader_model = GraphicsStateGuardian::SM_00;
166  video_memory = 0;
167  texture_memory = 0;
168 
169  state = DisplayInformation::DS_unknown;
170  get_adapter_display_mode_state = false;
171  get_device_caps_state = false;
172 
173  physical_memory = 0;
174  available_physical_memory = 0;
175 
176  vendor_id = 0;
177  device_id = 0;
178 
179  product = 0;
180  version = 0;
181  sub_version = 0;
182  build = 0;
183 
184  month = 0;
185  day = 0;
186  year = 0;
187 
188  HMODULE d3d_dll;
189  DIRECT_3D_CREATE Direct3DCreate;
190 
191  d3d_dll = LoadLibrary (d3d_dll_name);
192  if (d3d_dll) {
193  Direct3DCreate = (DIRECT_3D_CREATE) GetProcAddress (d3d_dll, direct_3d_create_function_name);
194  if (Direct3DCreate) {
195  DIRECT_3D direct_3d;
196 
197  direct_3d = Direct3DCreate (D3D_SDK_VERSION);
198  if (direct_3d != NULL) {
199  DWORD flags;
200  UINT adapter;
201  D3DDEVTYPE device_type;
202  D3DDISPLAYMODE current_d3d_display_mode;
203  D3DADAPTER_IDENTIFIER d3d_adapter_identifier;
204  D3DCAPS d3d_caps;
205 
206  adapter = D3DADAPTER_DEFAULT;
207  device_type = D3DDEVTYPE_HAL;
208 
209  // windowed mode max res and format
210  if (direct_3d -> GetAdapterDisplayMode (adapter, &current_d3d_display_mode) == D3D_OK) {
211  if (debug) {
212  printf ("current mode w = %d h = %d r = %d f = %d \n",
213  current_d3d_display_mode.Width,
214  current_d3d_display_mode.Height,
215  current_d3d_display_mode.RefreshRate,
216  current_d3d_display_mode.Format);
217  }
218 
219  window_width = current_d3d_display_mode.Width;
220  window_height = current_d3d_display_mode.Height;
221  window_bits_per_pixel = d3d_format_to_bits_per_pixel (current_d3d_display_mode.Format);
222 
223  get_adapter_display_mode_state = true;
224  }
225  else {
226  get_adapter_display_mode_state = false;
227  }
228 
229  flags = 0;
230  if (direct_3d -> GetAdapterIdentifier (adapter, flags, &d3d_adapter_identifier) == D3D_OK) {
231  // print adapter info
232  d3d_adapter_identifier.Driver;
233  d3d_adapter_identifier.Description;
234  d3d_adapter_identifier.DeviceName;
235  d3d_adapter_identifier.DriverVersion;
236  d3d_adapter_identifier.VendorId;
237  d3d_adapter_identifier.DeviceId;
238  d3d_adapter_identifier.SubSysId;
239  d3d_adapter_identifier.Revision;
240  d3d_adapter_identifier.DeviceIdentifier;
241  d3d_adapter_identifier.WHQLLevel;
242 
243  if (debug) {
244  printf ("Driver: %s\n", d3d_adapter_identifier.Driver);
245  printf ("Description: %s\n", d3d_adapter_identifier.Description);
246  }
247 
248  char system_directory [MAX_PATH];
249  char dll_file_path [MAX_PATH];
250 
251  // find the dll in the system directory if possible and get the date of the file
252  if (GetSystemDirectory (system_directory, MAX_PATH) > 0) {
253  if (debug) {
254  printf ("system_directory = %s \n", system_directory);
255  }
256  sprintf (dll_file_path, "%s\\%s", system_directory, d3d_adapter_identifier.Driver);
257 
258  intptr_t find;
259  struct _finddata_t find_data;
260 
261  find = _findfirst (dll_file_path, &find_data);
262  if (find != -1) {
263  struct tm *dll_time;
264 
265  dll_time = localtime(&find_data.time_write);
266 
267  month = dll_time -> tm_mon + 1;
268  day = dll_time -> tm_mday;
269  year = dll_time -> tm_year + 1900;
270 
271  if (debug) {
272  printf ("Driver Date: %d/%d/%d\n", month, day, year);
273  }
274 
275  _findclose (find);
276  }
277  }
278 
279  /*
280  HMODULE driver_dll;
281 
282  driver_dll = LoadLibrary (d3d_adapter_identifier.Driver);
283  if (driver_dll)
284  {
285  DWORD length;
286  TCHAR file_path [MAX_PATH];
287 
288  length = GetModuleFileName(driver_dll, file_path, MAX_PATH);
289  if (length > 0)
290  {
291  printf ("DLL file path = %s \n", file_path);
292  }
293  else
294  {
295  printf ("ERROR: could not get GetModuleFileName for %s \n", d3d_adapter_identifier.Driver);
296  }
297 
298  FreeLibrary (driver_dll);
299  }
300  else
301  {
302  print_GetLastError ("");
303  printf ("ERROR: could not load = %s \n", d3d_adapter_identifier.Driver);
304  }
305  */
306 
307  if (debug) {
308  printf ("VendorId = 0x%x\n", d3d_adapter_identifier.VendorId);
309  printf ("DeviceId = 0x%x\n", d3d_adapter_identifier.DeviceId);
310  }
311 
312  vendor_id = d3d_adapter_identifier.VendorId;
313  device_id = d3d_adapter_identifier.DeviceId;
314 
315  product = HIWORD(d3d_adapter_identifier.DriverVersion.HighPart);
316  version = LOWORD(d3d_adapter_identifier.DriverVersion.HighPart);
317  sub_version = HIWORD(d3d_adapter_identifier.DriverVersion.LowPart);
318  build = LOWORD(d3d_adapter_identifier.DriverVersion.LowPart);
319 
320  if (debug) {
321  printf ("DRIVER VERSION: %d.%d.%d.%d \n", product, version, sub_version, build);
322  }
323 
324  WHQL whql;
325 
326  whql.whql= d3d_adapter_identifier.WHQLLevel;
327 
328  if (debug) {
329  printf ("WHQL: %d %d %d \n", whql.day, whql.day, whql.year);
330  }
331  }
332 
333  if (direct_3d -> GetDeviceCaps (adapter, device_type, &d3d_caps) == D3D_OK) {
334 
335  int vertex_shader_version_major;
336  int vertex_shader_version_minor;
337  int pixel_shader_version_major;
338  int pixel_shader_version_minor;
339 
340  vertex_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.VertexShaderVersion);
341  vertex_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.VertexShaderVersion);
342  pixel_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.PixelShaderVersion);
343  pixel_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.PixelShaderVersion);
344 
345  switch (pixel_shader_version_major)
346  {
347  case 0:
348  shader_model = GraphicsStateGuardian::SM_00;
349  break;
350  case 1:
351  shader_model = GraphicsStateGuardian::SM_11;
352  break;
353  case 2:
354  // minimim specification for pixel shader 2.0 is 96 instruction slots
355  shader_model = GraphicsStateGuardian::SM_20;
356  if (d3d_caps.PS20Caps.NumInstructionSlots >= 512) {
357  shader_model = GraphicsStateGuardian::SM_2X;
358  }
359  break;
360  case 3:
361  shader_model = GraphicsStateGuardian::SM_30;
362  break;
363  case 4:
364  default:
365  shader_model = GraphicsStateGuardian::SM_40;
366  break;
367  }
368 
369  if (debug) {
370  printf ("shader_model = %d \n", shader_model);
371  }
372  get_device_caps_state = true;
373  }
374  else {
375  get_device_caps_state = false;
376  }
377 
378  // count display modes
379  int format_index;
380  int maximum_display_modes;
381  UINT display_mode_count;
382  D3DFORMAT d3d_format;
383 
384  format_index = 0;
385  maximum_display_modes = 0;
386 
387  while (display_format_array [format_index].d3d_format != D3DFMT_UNKNOWN) {
388  d3d_format = display_format_array [format_index].d3d_format;
389 
390  display_mode_count = direct_3d -> GetAdapterModeCount (adapter, d3d_format);
391  if (display_mode_count > 0) {
392  UINT mode_index;
393  D3DDISPLAYMODE d3d_display_mode;
394 
395  for (mode_index = 0; mode_index < display_mode_count; mode_index++) {
396  if (direct_3d -> EnumAdapterModes (adapter, d3d_format, mode_index, &d3d_display_mode) == D3D_OK) {
397  if (d3d_display_mode.Width >= minimum_width && d3d_display_mode.Height >= minimum_height &&
398  d3d_display_mode.Width <= maximum_width && d3d_display_mode.Height <= maximum_height) {
399  if (display_format_array [format_index].bits_per_pixel >= minimum_bits_per_pixel &&
400  display_format_array [format_index].bits_per_pixel <= maximum_bits_per_pixel) {
401  if (d3d_format == d3d_display_mode.Format) {
402  maximum_display_modes++;
403  }
404  }
405  }
406  }
407  }
408  }
409 
410  format_index++;
411  }
412 
413  if (debug) {
414  printf ("maximum_display_modes %d \n", maximum_display_modes);
415  }
416 
417  display_mode_array = new DisplayMode [maximum_display_modes];
418 
419  format_index = 0;
420  while (display_format_array [format_index].d3d_format != D3DFMT_UNKNOWN) {
421  d3d_format = display_format_array [format_index].d3d_format;
422  display_mode_count = direct_3d -> GetAdapterModeCount (adapter, d3d_format);
423  if (display_mode_count > 0) {
424  UINT mode_index;
425  D3DDISPLAYMODE d3d_display_mode;
426 
427  for (mode_index = 0; mode_index < display_mode_count; mode_index++) {
428  if (direct_3d -> EnumAdapterModes (adapter, d3d_format, mode_index, &d3d_display_mode) == D3D_OK) {
429  if (d3d_display_mode.Width >= minimum_width && d3d_display_mode.Height >= minimum_height &&
430  d3d_display_mode.Width <= maximum_width && d3d_display_mode.Height <= maximum_height) {
431  if (display_format_array [format_index].bits_per_pixel >= minimum_bits_per_pixel &&
432  display_format_array [format_index].bits_per_pixel <= maximum_bits_per_pixel) {
433  if (debug) {
434  printf ("w = %d h = %d r = %d f = %d \n",
435  d3d_display_mode.Width,
436  d3d_display_mode.Height,
437  d3d_display_mode.RefreshRate,
438  d3d_display_mode.Format);
439  }
440 
441  if (d3d_format == d3d_display_mode.Format) {
442  DisplayMode *display_mode;
443 
444  display_mode = &display_mode_array [total_display_modes];
445  display_mode -> width = d3d_display_mode.Width;
446  display_mode -> height = d3d_display_mode.Height;
447  display_mode -> bits_per_pixel = display_format_array [format_index].bits_per_pixel;
448  display_mode -> refresh_rate = d3d_display_mode.RefreshRate;
449  display_mode -> fullscreen_only = display_format_array [format_index].fullscreen_only;
450 
451  total_display_modes++;
452  }
453  }
454  }
455  }
456  }
457  }
458 
459  format_index++;
460  }
461 
462  UINT width;
463  UINT height;
464 
465  width = 640;
466  height = 480;
467 
468  // make a window
469  WNDCLASSEX window_class =
470  {
471  sizeof (WNDCLASSEX), CS_CLASSDC, window_procedure, 0L, 0L,
472  GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
473  "class_name", NULL
474  };
475  RegisterClassEx (&window_class);
476 
477  HWND window_handle;
478 
479  window_handle = CreateWindow ("class_name", "window_name", WS_DISABLED, 0, 0, width, height, (HWND) NULL, (HMENU) NULL, window_class.hInstance, NULL);
480  if (window_handle != NULL) {
481  ShowWindow (window_handle, SW_HIDE);
482 
483  DIRECT_3D_DEVICE direct_3d_device;
484  D3DPRESENT_PARAMETERS present_parameters;
485  DWORD behavior_flags;
486 
487  direct_3d_device = 0;
488  memset (&present_parameters, 0, sizeof (D3DPRESENT_PARAMETERS));
489 
490  present_parameters.BackBufferWidth = width;
491  present_parameters.BackBufferHeight = height;
492  present_parameters.BackBufferFormat = D3DFMT_X8R8G8B8;
493  present_parameters.BackBufferCount = 1;
494 
495  present_parameters.SwapEffect = D3DSWAPEFFECT_FLIP;
496  present_parameters.hDeviceWindow = window_handle;
497 
498  present_parameters.Windowed = true;
499  present_parameters.EnableAutoDepthStencil = true;
500  present_parameters.AutoDepthStencilFormat = D3DFMT_D24S8;
501 
502  present_parameters.FullScreen_RefreshRateInHz;
503  present_parameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
504 
505  if (d3d_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
506  behavior_flags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
507  }
508  else {
509  behavior_flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
510  }
511  // This is important to prevent DirectX from forcing the FPU into single-precision mode.
512  behavior_flags |= D3DCREATE_FPU_PRESERVE;
513 
514  HRESULT result;
515 
516  result = direct_3d -> CreateDevice (adapter, device_type, window_handle, behavior_flags, &present_parameters, &direct_3d_device);
517  if (result == D3D_OK) {
518 
519  // allocate 512x512 32-bit textures (1MB size) until we run out or hit the limit
520  #define MAXIMUM_TEXTURES (2048 - 1)
521 
522  int total_textures;
523  HRESULT texture_result;
524  IDirect3DTexture9 *texture_array [MAXIMUM_TEXTURES];
525 
526  total_textures = 0;
527  while (total_textures < MAXIMUM_TEXTURES) {
528 
529  texture_result = direct_3d_device -> CreateTexture (
530  512,
531  512,
532  1,
533  D3DUSAGE_RENDERTARGET,
534  D3DFMT_A8R8G8B8,
535  D3DPOOL_DEFAULT,
536  &texture_array [total_textures],
537  NULL);
538  if (texture_result == D3D_OK) {
539  total_textures++;
540  }
541  else {
542  if (texture_result == D3DERR_OUTOFVIDEOMEMORY) {
543  if (debug) {
544  printf ("D3DERR_OUTOFVIDEOMEMORY \n");
545  }
546  }
547  break;
548  }
549  }
550 
551  // free all allocated textures
552  int index;
553  for (index = 0; index < total_textures; index++) {
554  texture_array [index] -> Release ( );
555  }
556 
557  video_memory = (total_textures * 1024 * 1024);
558 
559  if (debug) {
560  printf ("video_memory = %d \n", video_memory);
561  }
562 
563  texture_memory = direct_3d_device -> GetAvailableTextureMem ( );
564  if (debug) {
565  printf ("texture_memory = %d \n", texture_memory);
566  }
567 
568  direct_3d_device -> Release ( );
569 
570  state = DisplayInformation::DS_success;
571  success = true;
572  }
573  else
574  {
575  if (debug) {
576  printf ("CreateDevice failed.\n");
577  }
578 
579  state = DisplayInformation::DS_create_device_error;
580  success = true;
581  }
582 
583  DestroyWindow (window_handle);
584  }
585  else {
586  _GetLastError ("CreateWindow");
587  state = DisplayInformation::DS_create_window_error;
588  }
589 
590  direct_3d -> Release ( );
591  }
592  else {
593  state = DisplayInformation::DS_direct_3d_create_error;
594  }
595  }
596  else {
597  state = DisplayInformation::DS_direct_3d_create_error;
598  }
599 
600  FreeLibrary (d3d_dll);
601  }
602  else {
603  state = DisplayInformation::DS_direct_3d_create_error;
604  }
605 
606  if (success) {
607  display_information -> _state = state;
608  display_information -> _get_adapter_display_mode_state = get_adapter_display_mode_state;
609  display_information -> _get_device_caps_state = get_device_caps_state;
610  display_information -> _maximum_window_width = window_width;
611  display_information -> _maximum_window_height = window_height;
612  display_information -> _window_bits_per_pixel = window_bits_per_pixel;
613  display_information -> _total_display_modes = total_display_modes;
614  display_information -> _display_mode_array = display_mode_array;
615  display_information -> _shader_model = shader_model;
616  display_information -> _video_memory = video_memory;
617  display_information -> _texture_memory = texture_memory;
618  display_information -> _vendor_id = vendor_id;
619  display_information -> _device_id = device_id;
620  display_information -> _driver_product = product;
621  display_information -> _driver_version = version;
622  display_information -> _driver_sub_version = sub_version;
623  display_information -> _driver_build = build;
624 
625  display_information -> _driver_date_month = month;
626  display_information -> _driver_date_day = day;
627  display_information -> _driver_date_year = year;
628  }
629 
630  // memory
631  bool memory_state;
632  HMODULE kernel32_dll;
633 
634  memory_state = false;
635  kernel32_dll = LoadLibrary ("kernel32.dll");
636  if (kernel32_dll) {
637  GlobalMemoryStatusExType GlobalMemoryStatusExFunction;
638 
639  GlobalMemoryStatusExFunction = (GlobalMemoryStatusExType) GetProcAddress (kernel32_dll, "GlobalMemoryStatusEx");
640  if (GlobalMemoryStatusExFunction) {
641  MEMORYSTATUSEX memory_status;
642 
643  memory_status.dwLength = sizeof (MEMORYSTATUSEX);
644  if (GlobalMemoryStatusExFunction (&memory_status)) {
645  physical_memory = memory_status.ullTotalPhys;
646  available_physical_memory = memory_status.ullAvailPhys;
647  memory_state = true;
648  }
649  }
650  FreeLibrary (kernel32_dll);
651  }
652  if (memory_state == false) {
653  MEMORYSTATUS memory_status;
654 
655  memory_status.dwLength = sizeof (MEMORYSTATUS);
656  GlobalMemoryStatus (&memory_status);
657 
658  physical_memory = memory_status.dwTotalPhys;
659  available_physical_memory = memory_status.dwAvailPhys;
660  }
661 
662  if (debug) {
663  printf ("physical_memory %I64d \n", physical_memory);
664  printf ("available_physical_memory %I64d \n", available_physical_memory);
665  }
666 
667  display_information -> _physical_memory = physical_memory;
668  display_information -> _available_physical_memory = available_physical_memory;
669 
670  return success;
671 }
This class contains various display information.
Parameters used for searching display capabilities.