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