Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
VideoDX9Enum.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: nGenEx.lib
6  FILE: VideoDX9Enum.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Direct3D Video class for DirectX 9
13 */
14 
15 #include "MemDebug.h"
16 #include "VideoDX9Enum.h"
17 #include "VideoSettings.h"
18 #include "Color.h"
19 
20 // +--------------------------------------------------------------------+
21 
22 void Print(const char* msg, ...);
23 char* DDErrStr(HRESULT dderr);
24 void VideoDX9Error(const char* msg, HRESULT dderr);
26 
27 #ifndef RELEASE
28 #define RELEASE(x) if (x) { x->Release(); x=NULL; }
29 #endif
30 
31 
32 // +--------------------------------------------------------------------+
33 
34 static UINT GetBitsPerPixel(D3DFORMAT fmt)
35 {
36  switch (fmt) {
37  case D3DFMT_A8R8G8B8: return 32;
38  case D3DFMT_X8R8G8B8: return 32;
39  case D3DFMT_A2B10G10R10: return 32;
40  case D3DFMT_A2R10G10B10: return 32;
41  case D3DFMT_R8G8B8: return 24;
42  case D3DFMT_R5G6B5: return 16;
43  case D3DFMT_X1R5G5B5: return 16;
44  case D3DFMT_A1R5G5B5: return 16;
45  case D3DFMT_A4R4G4B4: return 16;
46  case D3DFMT_A8R3G3B2: return 16;
47  case D3DFMT_X4R4G4B4: return 16;
48  case D3DFMT_R3G3B2: return 8;
49  default: return 0;
50  }
51 }
52 
53 // +--------------------------------------------------------------------+
54 
55 static UINT GetColorChannelBits(D3DFORMAT fmt)
56 {
57  switch (fmt) {
58  case D3DFMT_A2B10G10R10: return 10;
59  case D3DFMT_A2R10G10B10: return 10;
60  case D3DFMT_R8G8B8: return 8;
61  case D3DFMT_A8R8G8B8: return 8;
62  case D3DFMT_X8R8G8B8: return 8;
63  case D3DFMT_R5G6B5: return 6;
64  case D3DFMT_X1R5G5B5: return 5;
65  case D3DFMT_A1R5G5B5: return 5;
66  case D3DFMT_A4R4G4B4: return 4;
67  case D3DFMT_R3G3B2: return 2;
68  case D3DFMT_A8R3G3B2: return 2;
69  case D3DFMT_X4R4G4B4: return 4;
70  default: return 0;
71  }
72 }
73 
74 // +--------------------------------------------------------------------+
75 
76 static UINT GetAlphaChannelBits(D3DFORMAT fmt)
77 {
78  switch (fmt) {
79  case D3DFMT_R8G8B8: return 0;
80  case D3DFMT_A8R8G8B8: return 8;
81  case D3DFMT_X8R8G8B8: return 0;
82  case D3DFMT_R5G6B5: return 0;
83  case D3DFMT_X1R5G5B5: return 0;
84  case D3DFMT_A1R5G5B5: return 1;
85  case D3DFMT_A4R4G4B4: return 4;
86  case D3DFMT_R3G3B2: return 0;
87  case D3DFMT_A8R3G3B2: return 8;
88  case D3DFMT_X4R4G4B4: return 0;
89  case D3DFMT_A2B10G10R10: return 2;
90  case D3DFMT_A2R10G10B10: return 2;
91  default: return 0;
92  }
93 }
94 
95 // +--------------------------------------------------------------------+
96 
97 static UINT GetDepthBits(D3DFORMAT fmt)
98 {
99  switch (fmt) {
100  case D3DFMT_D16: return 16;
101  case D3DFMT_D15S1: return 15;
102  case D3DFMT_D24X8: return 24;
103  case D3DFMT_D24S8: return 24;
104  case D3DFMT_D24X4S4: return 24;
105  case D3DFMT_D32: return 32;
106  default: return 0;
107  }
108 }
109 
110 // +--------------------------------------------------------------------+
111 
112 static UINT GetStencilBits(D3DFORMAT fmt)
113 {
114  switch (fmt) {
115  case D3DFMT_D16: return 0;
116  case D3DFMT_D15S1: return 1;
117  case D3DFMT_D24X8: return 0;
118  case D3DFMT_D24S8: return 8;
119  case D3DFMT_D24X4S4: return 4;
120  case D3DFMT_D32: return 0;
121  default: return 0;
122  }
123 }
124 
125 // +--------------------------------------------------------------------+
126 //
127 // This routine prints a text description of the indicated driver
128 // into the error log file.
129 
130 static void DescribeGUID(GUID* lpGUID)
131 {
132  if (lpGUID)
133  Print(" GUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
134  lpGUID->Data1, lpGUID->Data2, lpGUID->Data3,
135  lpGUID->Data4[0], lpGUID->Data4[1],
136  lpGUID->Data4[2], lpGUID->Data4[3],
137  lpGUID->Data4[4], lpGUID->Data4[5],
138  lpGUID->Data4[6], lpGUID->Data4[7]);
139  else
140  Print(" GUID IS NULL!\n");
141 }
142 
143 
144 // +--------------------------------------------------------------------+
145 
146 VideoDX9Enum::VideoDX9Enum(IDirect3D9* d3d9)
147 {
148  if (d3d9) {
149  d3d = d3d9;
150  d3d->AddRef();
151  }
152 
153  min_width = 640;
154  min_height = 480;
155  min_color_bits = 5;
156  min_alpha_bits = 0;
157  min_depth_bits = 16;
158  min_stencil_bits = 0;
159 
160  uses_depth_buffer = false;
161  uses_mixed_vp = false;
162  req_windowed = false;
163  req_fullscreen = false;
164 
165  adapter_index = 0;
166 }
167 
169 {
170  adapter_info_list.destroy();
171  RELEASE(d3d);
172 }
173 
174 void
175 VideoDX9Enum::SetDirect3D9(IDirect3D9* d3d9)
176 {
177  RELEASE(d3d);
178 
179  if (d3d9) {
180  d3d = d3d9;
181  d3d->AddRef();
182  }
183 }
184 
185 
186 // +--------------------------------------------------------------------+
187 
188 void
190 {
191  if (index >= 0 && index < adapter_info_list.size())
192  adapter_index = index;
193 }
194 
197 {
198  if (adapter_index >= 0 && adapter_index < adapter_info_list.size())
199  return adapter_info_list[adapter_index];
200 
201  return 0;
202 }
203 
206 {
207  if (adapter_index >= 0 && adapter_index < adapter_info_list.size()) {
208  VideoDX9AdapterInfo* adapter = adapter_info_list[adapter_index];
209 
210  if (adapter) {
212  while (++iter) {
213  VideoDX9DeviceInfo* dev_info = iter.value();
214 
215  if (dev_info->device_type == (D3DDEVTYPE) devtype)
216  return dev_info;
217  }
218  }
219  }
220 
221  return 0;
222 }
223 
224 bool
225 VideoDX9Enum::IsModeSupported(int w, int h, int b) const
226 {
227  if (adapter_index >= 0 && adapter_index < adapter_info_list.size()) {
228  VideoDX9AdapterInfo* adapter = adapter_info_list[adapter_index];
229 
231  while (++mode_iter) {
232  VideoDX9DisplayMode* mode = mode_iter.value();
233 
234  if (mode->width == (UINT) w &&
235  mode->height == (UINT) h &&
236  GetBitsPerPixel(mode->format) == (UINT) b) {
237 
238  return true;
239  }
240  }
241  }
242 
243  return false;
244 }
245 
246 // +--------------------------------------------------------------------+
247 
248 HRESULT
250 {
251  HRESULT hr = E_FAIL;
252 
253  if (!d3d)
254  return hr;
255 
256  if (VD3D_describe_things > 0) {
257  Print("Video DX9 Enumerate Adapters and Devices\n");
258  Print("----------------------------------------\n\n");
259  }
260 
261  allowed_adapter_format_list.push_back(D3DFMT_X8R8G8B8);
262  allowed_adapter_format_list.push_back(D3DFMT_X1R5G5B5);
263  allowed_adapter_format_list.push_back(D3DFMT_R5G6B5);
264  allowed_adapter_format_list.push_back(D3DFMT_A2R10G10B10);
265 
266  VideoDX9AdapterInfo* adapter_info = 0;
267  std::vector<D3DFORMAT> adapter_format_list;
268  UINT num_adapters = d3d->GetAdapterCount();
269 
270  for (UINT ordinal = 0; ordinal < num_adapters; ordinal++) {
271  adapter_info = new(__FILE__,__LINE__) VideoDX9AdapterInfo;
272  if (!adapter_info)
273  return E_OUTOFMEMORY;
274 
275  adapter_info->adapter_ordinal = ordinal;
276  d3d->GetAdapterIdentifier(ordinal, 0, &adapter_info->adapter_identifier);
277 
278  // Get list of all display modes on this adapter.
279  // Also build a temporary list of all display adapter formats.
280  adapter_format_list.clear();
281 
282  for (size_t iaaf = 0; iaaf < allowed_adapter_format_list.size(); iaaf++) {
283  D3DFORMAT allowed_adapter_format = allowed_adapter_format_list[iaaf];
284  UINT num_adapter_modes = d3d->GetAdapterModeCount(ordinal, allowed_adapter_format);
285 
286  for (UINT mode = 0; mode < num_adapter_modes; mode++) {
287  D3DDISPLAYMODE display_mode;
288  d3d->EnumAdapterModes(ordinal, allowed_adapter_format, mode, &display_mode);
289 
290  if (display_mode.Width < min_width ||
291  display_mode.Height < min_height ||
292  GetColorChannelBits(display_mode.Format) < min_color_bits) {
293  continue;
294  }
295 
296  VideoDX9DisplayMode* dx9_display_mode = new(__FILE__,__LINE__) VideoDX9DisplayMode(display_mode);
297 
298  if (!dx9_display_mode) {
299  delete adapter_info;
300  return E_OUTOFMEMORY;
301  }
302 
303  adapter_info->display_mode_list.append(dx9_display_mode);
304 
305  bool contains_display_mode = false;
306  for (auto afli = adapter_format_list.begin(); afli != adapter_format_list.end(); ++afli) {
307  if (*afli == display_mode.Format) {
308  contains_display_mode = true;
309  break;
310  }
311  }
312  if (!contains_display_mode)
313  adapter_format_list.push_back(display_mode.Format);
314 
315  }
316  }
317 
318  // Sort displaymode list
319  adapter_info->display_mode_list.sort();
320 
321  if (VD3D_describe_things > 0) {
322  Print("Adapter %d. %s\n", ordinal, adapter_info->adapter_identifier.Description);
323  DescribeGUID(&adapter_info->adapter_identifier.DeviceIdentifier);
324 
325  if (VD3D_describe_things > 4) {
326  ListIter<VideoDX9DisplayMode> m_iter = adapter_info->display_mode_list;
327  while (++m_iter) {
328  VideoDX9DisplayMode* m = m_iter.value();
329 
330  Print(" Mode %3d %s\n", m_iter.index(), m->GetDescription());
331  }
332 
333  Print("\n");
334  }
335  }
336 
337  // Get info for each device on this adapter
338  if (FAILED(hr = EnumerateDevices(adapter_info, adapter_format_list))) {
339  delete adapter_info;
340  return hr;
341  }
342 
343  // If at least one device on this adapter is available and compatible
344  // with the app, add the adapterInfo to the list
345  if (adapter_info->device_info_list.size() == 0)
346  delete adapter_info;
347  else
348  adapter_info_list.append(adapter_info);
349 
350  if (VD3D_describe_things > 0) {
351  Print("\n");
352  }
353  }
354 
355  return S_OK;
356 }
357 
358 // +--------------------------------------------------------------------+
359 
360 HRESULT
361 VideoDX9Enum::EnumerateDevices(VideoDX9AdapterInfo* adapter_info, std::vector<D3DFORMAT>& adapter_format_list)
362 {
363  HRESULT hr = E_FAIL;
364  const D3DDEVTYPE dtypes[3] = { D3DDEVTYPE_HAL, D3DDEVTYPE_SW, D3DDEVTYPE_REF };
365  const char* dtypestr[3] = { "D3DDEVTYPE_HAL", "D3DDEVTYPE_SW", "D3DDEVTYPE_REF" };
366  VideoDX9DeviceInfo* device_info = 0;
367 
368  for (int i = 0; i < 3; i++ ) {
369  device_info = new(__FILE__,__LINE__) VideoDX9DeviceInfo;
370  if (!device_info)
371  return E_OUTOFMEMORY;
372 
373  device_info->adapter_ordinal = adapter_info->adapter_ordinal;
374  device_info->device_type = dtypes[i];
375 
376  if (FAILED(d3d->GetDeviceCaps(adapter_info->adapter_ordinal,
377  device_info->device_type,
378  &device_info->caps))) {
379  delete device_info;
380  continue;
381  }
382 
383  if (VD3D_describe_things > 1) {
384  Print(" Device %d - %s\n", i, dtypestr[i]);
385  Print(" Max Texture Width: %d\n", device_info->caps.MaxTextureWidth);
386  Print(" Max Texture Height: %d\n", device_info->caps.MaxTextureHeight);
387  }
388 
389  // Get info for each device combo on this device
390  if (FAILED(hr = EnumerateDeviceCombos(device_info, adapter_format_list))) {
391  delete device_info;
392  return hr;
393  }
394 
395  // make sure at least one devicecombo for this device was found
396  if (device_info->device_combo_list.size() < 1) {
397  delete device_info;
398  continue;
399  }
400 
401  adapter_info->device_info_list.append(device_info);
402  }
403 
404  return S_OK;
405 }
406 
407 // +--------------------------------------------------------------------+
408 
409 HRESULT
410 VideoDX9Enum::EnumerateDeviceCombos(VideoDX9DeviceInfo* device_info, std::vector<D3DFORMAT>& adapter_format_list)
411 {
412  const D3DFORMAT back_buffer_formats[] = {
413  D3DFMT_A8R8G8B8,
414  D3DFMT_X8R8G8B8,
415  D3DFMT_R8G8B8,
416  D3DFMT_R5G6B5,
417  D3DFMT_A1R5G5B5,
418  D3DFMT_X1R5G5B5
419  };
420 
421  bool is_windowed[] = { false, true };
422 
423  // See which adapter formats are supported by this device
424  D3DFORMAT a_fmt;
425  for (size_t i = 0; i < adapter_format_list.size(); i++) {
426  a_fmt = adapter_format_list[i];
427 
428  D3DFORMAT b_fmt;
429  for (int n = 0; n < 6; n++) {
430  b_fmt = back_buffer_formats[n];
431 
432  if (GetAlphaChannelBits(b_fmt) < min_alpha_bits)
433  continue;
434 
435  bool win;
436  for (int w = 0; w < 2; w++) {
437  win = is_windowed[w];
438 
439  if (!win && req_windowed)
440  continue;
441 
442  if (win && req_fullscreen)
443  continue;
444 
445  if (FAILED(d3d->CheckDeviceType(device_info->adapter_ordinal,
446  device_info->device_type,
447  a_fmt,
448  b_fmt,
449  win))) {
450  continue;
451  }
452 
453  // At this point, we have an adapter/device/adapterformat/backbufferformat/iswindowed
454  // DeviceCombo that is supported by the system. We still need to confirm that it's
455  // compatible with the app, and find one or more suitable depth/stencil buffer format,
456  // multisample type, vertex processing type, and present interval.
457 
458  VideoDX9DeviceCombo* device_combo = 0;
459  device_combo = new(__FILE__,__LINE__) VideoDX9DeviceCombo;
460  if (!device_combo)
461  return E_OUTOFMEMORY;
462 
463  device_combo->adapter_ordinal = device_info->adapter_ordinal;
464  device_combo->device_type = device_info->device_type;
465  device_combo->adapter_format = a_fmt;
466  device_combo->back_buffer_format = b_fmt;
467  device_combo->is_windowed = win;
468 
469  if (uses_depth_buffer) {
470  BuildDepthStencilFormatList(device_combo);
471  if (device_combo->depth_stencil_fmt_list.size() < 1) {
472  delete device_combo;
473  continue;
474  }
475  }
476 
477  BuildMultiSampleTypeList(device_combo);
478  if (device_combo->multisample_type_list.size() < 1) {
479  delete device_combo;
480  continue;
481  }
482 
483  BuildDSMSConflictList(device_combo);
484 
485  BuildVertexProcessingTypeList(device_info, device_combo);
486  if (device_combo->vertex_processing_list.size() < 1) {
487  delete device_combo;
488  continue;
489  }
490 
491  BuildPresentIntervalList(device_info, device_combo);
492 
493  device_info->device_combo_list.append(device_combo);
494  }
495  }
496  }
497 
498  return S_OK;
499 }
500 
501 void
502 VideoDX9Enum::BuildDepthStencilFormatList(VideoDX9DeviceCombo* device_combo)
503 {
504  const D3DFORMAT depth_stencil_formats[] = {
505  D3DFMT_D32,
506  D3DFMT_D24S8,
507  D3DFMT_D24X4S4,
508  D3DFMT_D24X8,
509  D3DFMT_D16,
510  D3DFMT_D15S1,
511  };
512 
513  for (int i = 0; i < 6; i++) {
514  D3DFORMAT fmt = depth_stencil_formats[i];
515 
516  if (GetDepthBits(fmt) < min_depth_bits)
517  continue;
518 
519  if (GetStencilBits(fmt) < min_stencil_bits)
520  continue;
521 
522  if (SUCCEEDED(d3d->CheckDeviceFormat(device_combo->adapter_ordinal,
523  device_combo->device_type,
524  device_combo->adapter_format,
525  D3DUSAGE_DEPTHSTENCIL,
526  D3DRTYPE_SURFACE,
527  fmt))) {
528 
529  if (SUCCEEDED(d3d->CheckDepthStencilMatch(device_combo->adapter_ordinal,
530  device_combo->device_type,
531  device_combo->adapter_format,
532  device_combo->back_buffer_format,
533  fmt))) {
534 
535  device_combo->depth_stencil_fmt_list.push_back(fmt);
536  }
537  }
538  }
539 }
540 
541 void
542 VideoDX9Enum::BuildMultiSampleTypeList(VideoDX9DeviceCombo* device_combo)
543 {
544  const D3DMULTISAMPLE_TYPE multisample_type_array[] = {
545  D3DMULTISAMPLE_NONE,
546  D3DMULTISAMPLE_NONMASKABLE,
547  D3DMULTISAMPLE_2_SAMPLES,
548  D3DMULTISAMPLE_3_SAMPLES,
549  D3DMULTISAMPLE_4_SAMPLES,
550  D3DMULTISAMPLE_5_SAMPLES,
551  D3DMULTISAMPLE_6_SAMPLES,
552  D3DMULTISAMPLE_7_SAMPLES,
553  D3DMULTISAMPLE_8_SAMPLES,
554  D3DMULTISAMPLE_9_SAMPLES,
555  D3DMULTISAMPLE_10_SAMPLES,
556  D3DMULTISAMPLE_11_SAMPLES,
557  D3DMULTISAMPLE_12_SAMPLES,
558  D3DMULTISAMPLE_13_SAMPLES,
559  D3DMULTISAMPLE_14_SAMPLES,
560  D3DMULTISAMPLE_15_SAMPLES,
561  D3DMULTISAMPLE_16_SAMPLES,
562  };
563 
564  for (int i = 0; i < 17; i++) {
565  D3DMULTISAMPLE_TYPE multisample_type = multisample_type_array[i];
566  DWORD multisample_qual = 0;
567 
568  if (SUCCEEDED(d3d->CheckDeviceMultiSampleType(device_combo->adapter_ordinal,
569  device_combo->device_type,
570  device_combo->back_buffer_format,
571  device_combo->is_windowed,
572  multisample_type,
573  &multisample_qual))) {
574 
575  device_combo->multisample_type_list.push_back(multisample_type);
576  device_combo->multisample_qual_list.push_back(multisample_qual);
577  }
578  }
579 }
580 
581 void
582 VideoDX9Enum::BuildDSMSConflictList(VideoDX9DeviceCombo* device_combo)
583 {
584  for (size_t i = 0; i < device_combo->depth_stencil_fmt_list.size(); i++) {
585  D3DFORMAT depth_format = (D3DFORMAT) device_combo->depth_stencil_fmt_list[i];
586 
587  for (size_t n = 0; n < device_combo->multisample_type_list.size(); n++) {
588  D3DMULTISAMPLE_TYPE multisample_type = (D3DMULTISAMPLE_TYPE) device_combo->multisample_type_list[n];
589 
590  if (FAILED(d3d->CheckDeviceMultiSampleType(device_combo->adapter_ordinal,
591  device_combo->device_type,
592  depth_format,
593  device_combo->is_windowed,
594  multisample_type,
595  NULL))) {
596 
597  VideoDX9FormatConflict* conflict = new(__FILE__,__LINE__) VideoDX9FormatConflict;
598 
599  conflict->ds_format = depth_format;
600  conflict->multisample_type = multisample_type;
601 
602  device_combo->conflict_list.append(conflict);
603  }
604  }
605  }
606 }
607 
608 void
609 VideoDX9Enum::BuildVertexProcessingTypeList(VideoDX9DeviceInfo* device_info, VideoDX9DeviceCombo* device_combo)
610 {
611  if ((device_info->caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0) {
612  if ((device_info->caps.DevCaps & D3DDEVCAPS_PUREDEVICE) != 0) {
613  device_combo->vertex_processing_list.push_back(PURE_HARDWARE_VP);
614  }
615 
616  device_combo->vertex_processing_list.push_back(HARDWARE_VP);
617 
618  if (uses_mixed_vp) {
619  device_combo->vertex_processing_list.push_back(MIXED_VP);
620  }
621  }
622 
623  device_combo->vertex_processing_list.push_back(SOFTWARE_VP);
624 }
625 
626 void
627 VideoDX9Enum::BuildPresentIntervalList(VideoDX9DeviceInfo* device_info, VideoDX9DeviceCombo* device_combo)
628 {
629  const DWORD present_interval_array[] = {
630  D3DPRESENT_INTERVAL_IMMEDIATE,
631  D3DPRESENT_INTERVAL_DEFAULT,
632  D3DPRESENT_INTERVAL_ONE,
633  D3DPRESENT_INTERVAL_TWO,
634  D3DPRESENT_INTERVAL_THREE,
635  D3DPRESENT_INTERVAL_FOUR,
636  };
637 
638  for (int i = 0; i < 6; i++) {
639  DWORD interval = present_interval_array[i];
640 
641  if (device_combo->is_windowed && i > 2) {
642  // none of the remaining intervals are supported in windowed mode.
643  break;
644  }
645 
646  // Note that D3DPRESENT_INTERVAL_DEFAULT is zero, so you
647  // can't do a caps check for it -- it is always available.
648 
649  if (interval == D3DPRESENT_INTERVAL_DEFAULT ||
650  (device_info->caps.PresentationIntervals & interval)) {
651 
652  device_combo->present_interval_list.push_back(interval);
653  }
654  }
655 }
656 
657 bool
659 {
660  if (!vs)
661  return false;
662 
663  // Get display mode of primary adapter (which is assumed to be where the window
664  // will appear)
665  D3DDISPLAYMODE desktop_display_mode;
666  d3d->GetAdapterDisplayMode(0, &desktop_display_mode);
667 
668  VideoDX9AdapterInfo* best_adapter_info = 0;
669  VideoDX9DeviceInfo* best_device_info = 0;
670  VideoDX9DeviceCombo* best_device_combo = 0;
671  int best_adapter_index = 0;
672  int best_device_index = 0;
673 
674  ListIter<VideoDX9AdapterInfo> a_iter = adapter_info_list;
675  while (++a_iter) {
676  VideoDX9AdapterInfo* adapter_info = a_iter.value();
677 
678  ListIter<VideoDX9DeviceInfo> d_iter = adapter_info->device_info_list;
679  while (++d_iter) {
680  VideoDX9DeviceInfo* device_info = d_iter.value();
681 
682  ListIter<VideoDX9DeviceCombo> c_iter = device_info->device_combo_list;
683  while (++c_iter) {
684  VideoDX9DeviceCombo* device_combo = c_iter.value();
685 
686  bool formats_match = (device_combo->back_buffer_format == device_combo->adapter_format);
687 
688  if (!device_combo->is_windowed)
689  continue;
690 
691  if (device_combo->adapter_format != desktop_display_mode.Format)
692  continue;
693 
694  // If we haven't found a compatible DeviceCombo yet, or if this set
695  // is better (because it's a HAL, and/or because formats match better),
696  // save it
697  if (best_device_combo == NULL ||
698  best_device_combo->device_type != D3DDEVTYPE_HAL && device_combo->device_type == D3DDEVTYPE_HAL ||
699  device_combo->device_type == D3DDEVTYPE_HAL && formats_match) {
700 
701  best_adapter_info = adapter_info;
702  best_adapter_index = a_iter.index();
703  best_device_info = device_info;
704  best_device_index = d_iter.index();
705  best_device_combo = device_combo;
706 
707  if (device_combo->device_type == D3DDEVTYPE_HAL && formats_match) {
708  // This windowed device combo looks great -- take it
709  goto EndWindowedDeviceComboSearch;
710  }
711 
712  // Otherwise keep looking for a better windowed device combo
713  }
714  }
715  }
716  }
717 
718 EndWindowedDeviceComboSearch:
719  if (best_device_combo == NULL)
720  return false;
721 
722  VideoDeviceInfo* win_device = &vs->windowed_device;
723 
724  vs->is_windowed = true;
725  vs->windowed_mode.width = desktop_display_mode.Width;
726  vs->windowed_mode.height = desktop_display_mode.Height;
727  vs->windowed_mode.refresh = desktop_display_mode.RefreshRate;
728  vs->windowed_mode.format = desktop_display_mode.Format;
729 
730  win_device->adapter_index = best_adapter_index;
731  win_device->device_index = best_device_index;
732  win_device->device_type = best_device_info->device_type;
733  win_device->back_buffer_format = best_device_combo->back_buffer_format;
734  win_device->depth_buffer_bits = GetDepthBits((D3DFORMAT) best_device_combo->depth_stencil_fmt_list[0]);
735  win_device->depth_stencil_format = best_device_combo->depth_stencil_fmt_list[0];
736  win_device->multisample_type = best_device_combo->multisample_type_list[0];
737  win_device->multisample_qual = best_device_combo->multisample_qual_list[0];
738  win_device->vertex_processing = best_device_combo->vertex_processing_list[0];
739 
740  return true;
741 }
742 
743 bool
745 {
746  if (!vs)
747  return false;
748 
749  WORD desired_width = vs->fullscreen_mode.width;
750  WORD desired_height = vs->fullscreen_mode.height;
751 
752  // For fullscreen, default to first HAL DeviceCombo that supports the current desktop
753  // display mode, or any display mode if HAL is not compatible with the desktop mode, or
754  // non-HAL if no HAL is available
755  D3DDISPLAYMODE desktop_display_mode;
756  D3DDISPLAYMODE best_desktop_display_mode;
757 
758  best_desktop_display_mode.Width = 0;
759  best_desktop_display_mode.Height = 0;
760  best_desktop_display_mode.Format = D3DFMT_UNKNOWN;
761  best_desktop_display_mode.RefreshRate = 0;
762 
763  VideoDX9AdapterInfo* best_adapter_info = 0;
764  VideoDX9DeviceInfo* best_device_info = 0;
765  VideoDX9DeviceCombo* best_device_combo = 0;
766  int best_adapter_index = 0;
767  int best_device_index = 0;
768 
769  ListIter<VideoDX9AdapterInfo> a_iter = adapter_info_list;
770  while (++a_iter) {
771  VideoDX9AdapterInfo* adapter_info = a_iter.value();
772  d3d->GetAdapterDisplayMode(adapter_info->adapter_ordinal, &desktop_display_mode);
773 
774  ListIter<VideoDX9DeviceInfo> d_iter = adapter_info->device_info_list;
775  while (++d_iter) {
776  VideoDX9DeviceInfo* device_info = d_iter.value();
777 
778  ListIter<VideoDX9DeviceCombo> c_iter = device_info->device_combo_list;
779  while (++c_iter) {
780  VideoDX9DeviceCombo* device_combo = c_iter.value();
781 
782  bool bAdapterMatchesBB = (device_combo->back_buffer_format == device_combo->adapter_format);
783  bool bAdapterMatchesDesktop = (device_combo->adapter_format == desktop_display_mode.Format);
784 
785  if (device_combo->is_windowed)
786  continue;
787 
788  // If we haven't found a compatible set yet, or if this set
789  // is better (because it's a HAL, and/or because formats match better),
790  // save it
791  if (best_device_combo == NULL ||
792  best_device_combo->device_type != D3DDEVTYPE_HAL && device_info->device_type == D3DDEVTYPE_HAL ||
793  device_combo->device_type == D3DDEVTYPE_HAL && best_device_combo->adapter_format != desktop_display_mode.Format && bAdapterMatchesDesktop ||
794  device_combo->device_type == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB ) {
795 
796  best_desktop_display_mode = desktop_display_mode;
797  best_adapter_info = adapter_info;
798  best_device_info = device_info;
799  best_device_combo = device_combo;
800 
801  if (device_info->device_type == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB) {
802  // This fullscreen device combo looks great -- take it
803  goto EndFullscreenDeviceComboSearch;
804  }
805 
806  // Otherwise keep looking for a better fullscreen device combo
807  }
808  }
809  }
810  }
811 
812 EndFullscreenDeviceComboSearch:
813  if (best_device_combo == NULL)
814  return false;
815 
816  // Need to find a display mode on the best adapter that uses best_device_combo->adapter_format
817  // and is as close to best_desktop_display_mode's res as possible
818  VideoDX9DisplayMode best_display_mode;
819 
820  ListIter<VideoDX9DisplayMode> m_iter = best_adapter_info->display_mode_list;
821  while (++m_iter) {
822  VideoDX9DisplayMode* display_mode = m_iter.value();
823 
824  if (display_mode->format != best_device_combo->adapter_format)
825  continue;
826 
827  if (display_mode->width == desired_width && //best_desktop_display_mode.Width &&
828  display_mode->height == desired_height && //best_desktop_display_mode.Height &&
829  display_mode->refresh == best_desktop_display_mode.RefreshRate) {
830 
831  // found a perfect match, so stop
832  best_display_mode = *display_mode;
833  break;
834  }
835  else if (display_mode->width == desired_width && //best_desktop_display_mode.Width &&
836  display_mode->height == desired_height && //best_desktop_display_mode.Height &&
837  display_mode->refresh > best_desktop_display_mode.RefreshRate) {
838  // refresh rate doesn't match, but width/height match, so keep this
839  // and keep looking
840  best_display_mode = *display_mode;
841  }
842  else if (display_mode->width == desired_width) { //best_desktop_display_mode.Width) {
843  // width matches, so keep this and keep looking
844  best_display_mode = *display_mode;
845  }
846  else if (best_display_mode.width == 0)
847  {
848  // we don't have anything better yet, so keep this and keep looking
849  best_display_mode = *display_mode;
850  }
851  }
852 
853  VideoDeviceInfo* fs_device = &vs->fullscreen_device;
854 
855  vs->is_windowed = false;
856  vs->fullscreen_mode.width = best_display_mode.width;
857  vs->fullscreen_mode.height = best_display_mode.height;
858  vs->fullscreen_mode.refresh = best_display_mode.refresh;
859  vs->fullscreen_mode.format = best_display_mode.format;
860 
861  fs_device->adapter_index = best_adapter_index;
862  fs_device->device_index = best_device_index;
863  fs_device->device_type = best_device_info->device_type;
864  fs_device->back_buffer_format = best_device_combo->back_buffer_format;
865  fs_device->depth_buffer_bits = GetDepthBits((D3DFORMAT) best_device_combo->depth_stencil_fmt_list[0]);
866  fs_device->depth_stencil_format = best_device_combo->depth_stencil_fmt_list[0];
867  fs_device->multisample_type = best_device_combo->multisample_type_list[0];
868  fs_device->multisample_qual = best_device_combo->multisample_qual_list[0];
869  fs_device->vertex_processing = best_device_combo->vertex_processing_list[0];
870 
871  return true;
872 }
873 
874 
875 // +--------------------------------------------------------------------+
876 // +--------------------------------------------------------------------+
877 // +--------------------------------------------------------------------+
878 
880 : width(0), height(0), refresh(0), format(D3DFMT_UNKNOWN)
881 { }
882 
884 : width(m.width), height(m.height), refresh(m.refresh), format(m.format)
885 { }
886 
888 : width(m.Width), height(m.Height), refresh(m.RefreshRate), format(m.Format)
889 { }
890 
891 int
893 {
894  if (width < m.width)
895  return 1;
896 
897  if (width > m.width)
898  return 0;
899 
900  if (height < m.height)
901  return 1;
902 
903  if (height > m.height)
904  return 0;
905 
906  if (format < m.format)
907  return 1;
908 
909  if (format > m.format)
910  return 0;
911 
912  if (refresh < m.refresh)
913  return 1;
914 
915  return 0;
916 }
917 
918 int
920 {
921  // if less than ...
922  if (*this < m)
923  return 1;
924 
925  // ... or equal to ...
926  if (width == m.width &&
927  height == m.height &&
928  format == m.format &&
929  refresh == m.refresh)
930  return 1;
931 
932  // must be greater than
933  return 0;
934 }
935 
936 const char*
938 {
939  static char desc[32];
940 
941  sprintf_s(desc, "%4d x %4d %-12s %d Hz",
942  width,
943  height,
945  refresh);
946 
947  return desc;
948 }
949 
950 const char*
952 {
953  const char* str = "Unknown Format";
954 
955  switch (format) {
956  case D3DFMT_UNKNOWN: str = "UNKNOWN"; break;
957  case D3DFMT_R8G8B8: str = "R8G8B8"; break;
958  case D3DFMT_A8R8G8B8: str = "A8R8G8B8"; break;
959  case D3DFMT_X8R8G8B8: str = "X8R8G8B8"; break;
960  case D3DFMT_R5G6B5: str = "R5G6B5"; break;
961  case D3DFMT_X1R5G5B5: str = "X1R5G5B5"; break;
962  case D3DFMT_A1R5G5B5: str = "A1R5G5B5"; break;
963  case D3DFMT_A4R4G4B4: str = "A4R4G4B4"; break;
964  case D3DFMT_R3G3B2: str = "R3G3B2"; break;
965  case D3DFMT_A8: str = "A8"; break;
966  case D3DFMT_A8R3G3B2: str = "A8R3G3B2"; break;
967  case D3DFMT_X4R4G4B4: str = "X4R4G4B4"; break;
968  case D3DFMT_A2B10G10R10: str = "A2B10G10R10"; break;
969  case D3DFMT_A8B8G8R8: str = "A8B8G8R8"; break;
970  case D3DFMT_X8B8G8R8: str = "X8B8G8R8"; break;
971  case D3DFMT_G16R16: str = "G16R16"; break;
972  case D3DFMT_A2R10G10B10: str = "A2R10G10B10"; break;
973  case D3DFMT_A16B16G16R16: str = "A16B16G16R16"; break;
974  case D3DFMT_A8P8: str = "A8P8"; break;
975  case D3DFMT_P8: str = "P8"; break;
976  case D3DFMT_L8: str = "L8"; break;
977  case D3DFMT_A8L8: str = "A8L8"; break;
978  case D3DFMT_A4L4: str = "A4L4"; break;
979  case D3DFMT_V8U8: str = "V8U8"; break;
980  case D3DFMT_L6V5U5: str = "L6V5U5"; break;
981  case D3DFMT_X8L8V8U8: str = "X8L8V8U8"; break;
982  case D3DFMT_Q8W8V8U8: str = "Q8W8V8U8"; break;
983  case D3DFMT_V16U16: str = "V16U16"; break;
984  case D3DFMT_A2W10V10U10: str = "A2W10V10U10"; break;
985  case D3DFMT_UYVY: str = "UYVY"; break;
986  case D3DFMT_YUY2: str = "YUY2"; break;
987  case D3DFMT_DXT1: str = "DXT1"; break;
988  case D3DFMT_DXT2: str = "DXT2"; break;
989  case D3DFMT_DXT3: str = "DXT3"; break;
990  case D3DFMT_DXT4: str = "DXT4"; break;
991  case D3DFMT_DXT5: str = "DXT5"; break;
992  case D3DFMT_D16_LOCKABLE: str = "D16_LOCKABLE"; break;
993  case D3DFMT_D32: str = "D32"; break;
994  case D3DFMT_D15S1: str = "D15S1"; break;
995  case D3DFMT_D24S8: str = "D24S8"; break;
996  case D3DFMT_D24X8: str = "D24X8"; break;
997  case D3DFMT_D24X4S4: str = "D24X4S4"; break;
998  case D3DFMT_D16: str = "D16"; break;
999  case D3DFMT_L16: str = "L16"; break;
1000  case D3DFMT_VERTEXDATA: str = "VERTEXDATA"; break;
1001  case D3DFMT_INDEX16: str = "INDEX16"; break;
1002  case D3DFMT_INDEX32: str = "INDEX32"; break;
1003  case D3DFMT_Q16W16V16U16: str = "Q16W16V16U16"; break;
1004  case D3DFMT_MULTI2_ARGB8: str = "MULTI2_ARGB8"; break;
1005  case D3DFMT_R16F: str = "R16F"; break;
1006  case D3DFMT_G16R16F: str = "G16R16F"; break;
1007  case D3DFMT_A16B16G16R16F: str = "A16B16G16R16F"; break;
1008  case D3DFMT_R32F: str = "R32F"; break;
1009  case D3DFMT_G32R32F: str = "G32R32F"; break;
1010  case D3DFMT_A32B32G32R32F: str = "A32B32G32R32F"; break;
1011  case D3DFMT_CxV8U8: str = "CxV8U8"; break;
1012  default: str = "Unknown format"; break;
1013  }
1014 
1015  return str;
1016 }
1017 
1018 
1019 // +--------------------------------------------------------------------+
1020 
1022 : adapter_ordinal(0)
1023 {
1024  ZeroMemory(&adapter_identifier, sizeof(adapter_identifier));
1025 }
1026 
1028 {
1031 }
1032 
1033 const char*
1035 {
1036  return adapter_identifier.Description;
1037 }
1038 
1039 // +--------------------------------------------------------------------+
1040 
1042 : adapter_ordinal(0), device_type(D3DDEVTYPE_HAL)
1043 {
1044  ZeroMemory(&caps, sizeof(caps));
1045 }
1046 
1048 {
1050 }
1051 
1052 // +--------------------------------------------------------------------+
1053 
1055 : adapter_ordinal(0), device_type(D3DDEVTYPE_HAL),
1056 adapter_format((D3DFORMAT) 0),
1057 back_buffer_format((D3DFORMAT) 0),
1058 is_windowed(false)
1059 {
1060 }
1061 
1063 {
1065 }