Panda3D
wdxGraphicsPipe9.cxx
1 // Filename: wdxGraphicsPipe9.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 "wdxGraphicsPipe9.h"
16 #include "dxGraphicsDevice9.h"
17 #include "wdxGraphicsWindow9.h"
18 #include "wdxGraphicsBuffer9.h"
19 #include "config_dxgsg9.h"
20 
21 TypeHandle wdxGraphicsPipe9::_type_handle;
22 
23 #define LOWVIDMEMTHRESHOLD 5700000 // 4MB cards should fall below this
24 #define CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 1000000 // if # is > 1MB, card is lying and I cant tell what it is
25 #define UNKNOWN_VIDMEM_SIZE 0xFFFFFFFF
26 
27 ////////////////////////////////////////////////////////////////////
28 // Function: wdxGraphicsPipe9::Constructor
29 // Access: Public
30 // Description:
31 ////////////////////////////////////////////////////////////////////
32 wdxGraphicsPipe9::
33 wdxGraphicsPipe9() {
34  _hDDrawDLL = NULL;
35  _hD3D9_DLL = NULL;
36  __d3d9 = NULL;
37  _is_valid = init();
38 }
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: wdxGraphicsPipe9::Destructor
42 // Access: Public, Virtual
43 // Description:
44 ////////////////////////////////////////////////////////////////////
45 wdxGraphicsPipe9::
46 ~wdxGraphicsPipe9() {
47  RELEASE(__d3d9, wdxdisplay9, "ID3D9", RELEASE_DOWN_TO_ZERO);
48  SAFE_FREELIB(_hD3D9_DLL);
49  SAFE_FREELIB(_hDDrawDLL);
50 }
51 
52 ////////////////////////////////////////////////////////////////////
53 // Function: wdxGraphicsPipe9::get_interface_name
54 // Access: Published, Virtual
55 // Description: Returns the name of the rendering interface
56 // associated with this GraphicsPipe. This is used to
57 // present to the user to allow him/her to choose
58 // between several possible GraphicsPipes available on a
59 // particular platform, so the name should be meaningful
60 // and unique for a given platform.
61 ////////////////////////////////////////////////////////////////////
62 string wdxGraphicsPipe9::
64  return "DirectX9";
65 }
66 
67 ////////////////////////////////////////////////////////////////////
68 // Function: wdxGraphicsPipe9::pipe_constructor
69 // Access: Public, Static
70 // Description: This function is passed to the GraphicsPipeSelection
71 // object to allow the user to make a default
72 // wdxGraphicsPipe9.
73 ////////////////////////////////////////////////////////////////////
74 PT(GraphicsPipe) wdxGraphicsPipe9::
75 pipe_constructor() {
76  return new wdxGraphicsPipe9;
77 }
78 
79 ////////////////////////////////////////////////////////////////////
80 // Function: wdxGraphicsPipe9::make_output
81 // Access: Protected, Virtual
82 // Description: Creates a new window on the pipe, if possible.
83 ////////////////////////////////////////////////////////////////////
84 PT(GraphicsOutput) wdxGraphicsPipe9::
85 make_output(const string &name,
86  const FrameBufferProperties &fb_prop,
87  const WindowProperties &win_prop,
88  int flags,
89  GraphicsEngine *engine,
91  GraphicsOutput *host,
92  int retry,
93  bool &precertify) {
94 
95  if (!_is_valid) {
96  return NULL;
97  }
98 
99  DXGraphicsStateGuardian9 *wdxgsg = 0;
100  if (gsg != 0) {
101  DCAST_INTO_R(wdxgsg, gsg, NULL);
102  }
103 
104  // First thing to try: a visible window.
105 
106  if (retry == 0) {
107  if (((flags&BF_require_parasite)!=0)||
108  ((flags&BF_refuse_window)!=0)||
109  ((flags&BF_resizeable)!=0)||
110  ((flags&BF_size_track_host)!=0)||
111  ((flags&BF_rtt_cumulative)!=0)||
112  ((flags&BF_can_bind_color)!=0)||
113  ((flags&BF_can_bind_every)!=0)) {
114  return NULL;
115  }
116  // Early failure - if we are sure that this buffer WONT
117  // meet specs, we can bail out early.
118  if ((flags & BF_fb_props_optional) == 0) {
119  if ((fb_prop.get_aux_rgba() > 0)||
120  (fb_prop.get_aux_rgba() > 0)||
121  (fb_prop.get_aux_float() > 0)) {
122  return NULL;
123  }
124  }
125  return new wdxGraphicsWindow9(engine, this, name, fb_prop, win_prop,
126  flags, gsg, host);
127  }
128 
129  // Second thing to try: a wdxGraphicsBuffer9
130 
131  if (retry == 1) {
132  if ((!support_render_texture)||
133  ((flags&BF_require_parasite)!=0)||
134  ((flags&BF_require_window)!=0)||
135  ((flags&BF_rtt_cumulative)!=0)||
136  ((flags&BF_can_bind_every)!=0)) {
137  return NULL;
138  }
139  // Early failure - if we are sure that this buffer WONT
140  // meet specs, we can bail out early.
141  if ((flags & BF_fb_props_optional) == 0) {
142  if (fb_prop.get_indexed_color() ||
143  (fb_prop.get_back_buffers() > 0)||
144  (fb_prop.get_accum_bits() > 0)||
145  (fb_prop.get_multisamples() > 0)) {
146  return NULL;
147  }
148  }
149 
150  // Early success - if we are sure that this buffer WILL
151  // meet specs, we can precertify it.
152  // This looks rather overly optimistic -- ie, buggy.
153  if ((wdxgsg != NULL) && wdxgsg->is_valid() && !wdxgsg->needs_reset() &&
154  wdxgsg->get_supports_render_texture()) {
155  precertify = true;
156  }
157  return new wdxGraphicsBuffer9(engine, this, name, fb_prop, win_prop,
158  flags, gsg, host);
159  }
160 
161  // Nothing else left to try.
162  return NULL;
163 }
164 
165 ////////////////////////////////////////////////////////////////////
166 // Function: wdxGraphicsPipe9::init
167 // Access: Private
168 // Description: Performs some initialization steps to load up
169 // function pointers from the relevant DLL's, and
170 // determine the number and type of available graphics
171 // adapters, etc. Returns true on success, false on
172 // failure.
173 ////////////////////////////////////////////////////////////////////
174 bool wdxGraphicsPipe9::
175 init() {
176  if (!MyLoadLib(_hDDrawDLL, "ddraw.dll")) {
177  goto error;
178  }
179 
180  if (!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawCreateEx, "DirectDrawCreateEx")) {
181  goto error;
182  }
183 
184  if (!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawEnumerateExA, "DirectDrawEnumerateExA")) {
185  goto error;
186  }
187 
188  if (!MyLoadLib(_hD3D9_DLL, "d3d9.dll")) {
189  goto error;
190  }
191 
192  if (!MyGetProcAddr(_hD3D9_DLL, (FARPROC*)&_Direct3DCreate9, "Direct3DCreate9")) {
193  goto error;
194  }
195 
196  // Create a Direct3D object.
197 
198  // these were taken from the 8.0 and 8.1 d3d8.h SDK headers
199  __is_dx9_1 = false;
200 
201 #define D3D_SDK_VERSION_9_0 D3D_SDK_VERSION
202 #define D3D_SDK_VERSION_9_1 D3D_SDK_VERSION
203 
204  // are we using 9.0 or 9.1?
205  WIN32_FIND_DATA TempFindData;
206  HANDLE hFind;
207  char tmppath[_MAX_PATH + 128];
208  GetSystemDirectory(tmppath, MAX_PATH);
209  strcat(tmppath, "\\dpnhpast.dll");
210  hFind = FindFirstFile (tmppath, &TempFindData);
211  if (hFind != INVALID_HANDLE_VALUE) {
212  FindClose(hFind);
213 // ??? This was from DX8
214 // __is_dx9_1 = true;
215  __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9_1);
216  } else {
217  __is_dx9_1 = false;
218  __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9_0);
219  }
220  if (__d3d9 == NULL) {
221  wdxdisplay9_cat.error() << "Direct3DCreate9(9." << (__is_dx9_1 ? "1" : "0") << ") failed!, error = " << GetLastError() << endl;
222  //release_gsg();
223  goto error;
224  }
225 
226  Init_D3DFORMAT_map();
227 
228  if (dx_count_all_cards_memory){
229  return find_all_card_memavails();
230  }
231 
232  return true;
233 
234  error:
235  return false;
236 }
237 
238 ////////////////////////////////////////////////////////////////////
239 // Function: wdxGraphicsPipe9::find_all_card_memavails
240 // Access: Private
241 // Description: Uses DX7 calls to determine how much video memory is
242 // available for each video adapter in the system.
243 // Returns true on success, false on failure.
244 ////////////////////////////////////////////////////////////////////
245 bool wdxGraphicsPipe9::
246 find_all_card_memavails() {
247  HRESULT hr;
248 
249  hr = (*_DirectDrawEnumerateExA)(dx7_driver_enum_callback, this,
250  DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES);
251  if (FAILED(hr)) {
252  wdxdisplay9_cat.fatal()
253  << "DirectDrawEnumerateEx failed" << D3DERRORSTRING(hr);
254  return false;
255  }
256 
257  if (_card_ids.empty()) {
258  wdxdisplay9_cat.error()
259  << "DirectDrawEnumerateEx enum'ed no devices!\n";
260  return false;
261  }
262 
263  GUID ZeroGUID;
264  ZeroMemory(&ZeroGUID, sizeof(GUID));
265 
266  if (_card_ids.size() > 1) {
267  assert(IsEqualGUID(ZeroGUID, _card_ids[0].DX7_DeviceGUID));
268  // delete enum of primary display (always the first), since it is
269  // duplicated by explicit entry
270  _card_ids.erase(_card_ids.begin());
271  }
272 
273  for (UINT i = 0; i < _card_ids.size(); i++) {
274  LPDIRECTDRAW7 pDD;
275  BYTE ddd_space[sizeof(DDDEVICEIDENTIFIER2)+4]; //bug in DX7 requires 4 extra bytes for GetDeviceID
276  DDDEVICEIDENTIFIER2 *pDX7DeviceID = (DDDEVICEIDENTIFIER2 *)&ddd_space[0];
277  GUID *pGUID = &(_card_ids[i].DX7_DeviceGUID);
278 
279  if (IsEqualGUID(*pGUID, ZeroGUID)) {
280  pGUID = NULL;
281  }
282 
283  // Create the Direct Draw Object
284  hr = (*_DirectDrawCreateEx)(pGUID, (void **)&pDD, IID_IDirectDraw7, NULL);
285  if (FAILED(hr)) {
286  wdxdisplay9_cat.error()
287  << "DirectDrawCreateEx failed for device (" << i
288  << ")" << D3DERRORSTRING(hr);
289  continue;
290  }
291 
292  ZeroMemory(ddd_space, sizeof(DDDEVICEIDENTIFIER2));
293 
294  hr = pDD->GetDeviceIdentifier(pDX7DeviceID, 0x0);
295  if (FAILED(hr)) {
296  wdxdisplay9_cat.error()
297  << "GetDeviceID failed for device (" << i << ")" << D3DERRORSTRING(hr);
298  continue;
299  }
300 
301  _card_ids[i].DeviceID = pDX7DeviceID->dwDeviceId;
302  _card_ids[i].VendorID = pDX7DeviceID->dwVendorId;
303 
304  // Get Current VidMem avail. Note this is only an estimate, when
305  // we switch to fullscreen mode from desktop, more vidmem will be
306  // available (typically 1.2 meg). I don't want to switch to
307  // fullscreen more than once due to the annoying monitor flicker,
308  // so try to figure out optimal mode using this estimate
309  DDSCAPS2 ddsGAVMCaps;
310  DWORD dwVidMemTotal, dwVidMemFree;
311  dwVidMemTotal = dwVidMemFree = 0;
312  {
313  // print out total INCLUDING AGP just for information purposes
314  // and future use. The real value I'm interested in for
315  // purposes of measuring possible valid screen sizes shouldnt
316  // include AGP.
317  ZeroMemory(&ddsGAVMCaps, sizeof(DDSCAPS2));
318  ddsGAVMCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
319 
320  hr = pDD->GetAvailableVidMem(&ddsGAVMCaps, &dwVidMemTotal, &dwVidMemFree);
321  if (FAILED(hr)) {
322  wdxdisplay9_cat.error()
323  << "GetAvailableVidMem failed for device #" << i
324  << D3DERRORSTRING(hr);
325  //goto skip_device;
326  //exit(1); // probably want to exit, since it may be my fault
327  }
328  }
329 
330  wdxdisplay9_cat.info()
331  << "DX 9.0c GetAvailableVidMem (including AGP) returns Total: "
332  << dwVidMemTotal <<", Free: " << dwVidMemFree
333  << " for device #" << i << endl;
334 
335  ZeroMemory(&ddsGAVMCaps, sizeof(DDSCAPS2));
336 
337  // just want to measure localvidmem, not AGP texmem
338  ddsGAVMCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
339 
340  hr = pDD->GetAvailableVidMem(&ddsGAVMCaps, &dwVidMemTotal, &dwVidMemFree);
341  if (FAILED(hr)) {
342  wdxdisplay9_cat.error() << "GetAvailableVidMem failed for device #" << i<< D3DERRORSTRING(hr);
343  // sometimes GetAvailableVidMem fails with hr = DDERR_NODIRECTDRAWHW for some unknown reason (bad drivers?)
344  // see bugs: 15327, 18122, others. is it because D3D9 object has already been created?
345  if (hr == DDERR_NODIRECTDRAWHW)
346  continue;
347  exit(1); // probably want to exit, since it may be my fault
348  }
349 
350  wdxdisplay9_cat.info()
351  << "GetAvailableVidMem (no AGP) returns Total: " << dwVidMemTotal
352  << ", Free: " << dwVidMemFree << " for device #" << i<< endl;
353 
354  pDD->Release(); // release DD obj, since this is all we needed it for
355 
356  if (!dx_do_vidmemsize_check) {
357  // still calling the DD stuff to get deviceID, etc. is this necessary?
358  _card_ids[i]._max_available_video_memory = UNKNOWN_VIDMEM_SIZE;
359  _card_ids[i]._is_low_memory_card = false;
360  continue;
361  }
362 
363  if (dwVidMemTotal == 0) { // unreliable driver
364  dwVidMemTotal = UNKNOWN_VIDMEM_SIZE;
365  } else {
366  if (!ISPOW2(dwVidMemTotal)) {
367  // assume they wont return a proper max value, so
368  // round up to next pow of 2
369  UINT count = 0;
370  while ((dwVidMemTotal >> count) != 0x0) {
371  count++;
372  }
373  dwVidMemTotal = (1 << count);
374  }
375  }
376 
377  // after Set_display_mode, GetAvailVidMem totalmem seems to go down
378  // by 1.2 meg (contradicting above comment and what I think would
379  // be correct behavior (shouldnt FS mode release the desktop
380  // vidmem?), so this is the true value
381  _card_ids[i]._max_available_video_memory = dwVidMemTotal;
382 
383  // I can never get this stuff to work reliably, so I'm just
384  // rounding up to nearest pow2. Could try to get
385  // HardwareInformation.Memory_size MB number from registry like
386  // video control panel, but its not clear how to find the proper
387  // registry location for a given card
388 
389  // assume buggy drivers (this means you, FireGL2) may return zero
390  // (or small amts) for dwVidMemTotal, so ignore value if its < CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD
391  bool bLowVidMemFlag =
392  ((dwVidMemTotal > CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD) &&
393  (dwVidMemTotal< LOWVIDMEMTHRESHOLD));
394 
395  _card_ids[i]._is_low_memory_card = bLowVidMemFlag;
396  wdxdisplay9_cat.info()
397  << "SetLowVidMem flag to " << bLowVidMemFlag
398  << " based on adjusted VidMemTotal: " << dwVidMemTotal << endl;
399  }
400  return true;
401 }
402 
403 ////////////////////////////////////////////////////////////////////
404 // Function: wdxGraphicsPipe9::dx7_driver_enum_callback
405 // Access: Private, Static
406 // Description:
407 ////////////////////////////////////////////////////////////////////
408 BOOL WINAPI wdxGraphicsPipe9::
409 dx7_driver_enum_callback(GUID *pGUID, TCHAR *strDesc, TCHAR *strName,
410  VOID *argptr, HMONITOR hm) {
411  wdxGraphicsPipe9 *self = (wdxGraphicsPipe9 *)argptr;
412 
413  CardID card_id;
414  ZeroMemory(&card_id, sizeof(CardID));
415 
416  if (hm == NULL) {
417  card_id._monitor = MonitorFromWindow(GetDesktopWindow(),
418  MONITOR_DEFAULTTOPRIMARY);
419  } else {
420  card_id._monitor = hm;
421  }
422 
423  if (pGUID != NULL) {
424  memcpy(&card_id.DX7_DeviceGUID, pGUID, sizeof(GUID));
425  }
426 
427  card_id._max_available_video_memory = UNKNOWN_VIDMEM_SIZE;
428 
429  self->_card_ids.push_back(card_id);
430 
431  return DDENUMRET_OK;
432 }
433 
434 //////////////////////////////////////////////////////////////////
435 // Function: wdxGraphicsWindow9::find_best_depth_format
436 // Access: Private
437 // Description:
438 ////////////////////////////////////////////////////////////////////
439 bool wdxGraphicsPipe9::
440 find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &Test_display_mode,
441  D3DFORMAT *pBestFmt, bool bWantStencil,
442  bool bForce16bpp, bool bVerboseMode) const {
443  if (dxgsg9_cat.is_debug()) {
444  bVerboseMode = true;
445  }
446 
447  // list formats to try in order of preference.
448 
449 #define NUM_TEST_ZFMTS 6
450 #define FIRST_NON_STENCIL_ZFMT 3
451  static D3DFORMAT FormatPrefList[NUM_TEST_ZFMTS] = {
452  D3DFMT_D24S8, D3DFMT_D24X4S4, D3DFMT_D15S1, // with stencil
453  D3DFMT_D32, D3DFMT_D24X8, D3DFMT_D16 // without stencil
454  };
455 
456  // do not use Display._display_mode since that is probably not set yet, use Test_display_mode instead
457 
458  *pBestFmt = D3DFMT_UNKNOWN;
459  HRESULT hr;
460 
461  // nvidia likes zbuf depth to match rendertarget depth
462  bool bOnlySelect16bpp = (bForce16bpp ||
463  (IS_NVIDIA(Display._dx_device_id) && IS_16BPP_DISPLAY_FORMAT(Test_display_mode.Format)));
464 
465  if (bVerboseMode) {
466  wdxdisplay9_cat.info()
467  << "FindBestDepthFmt: bSelectOnly16bpp: " << bOnlySelect16bpp << endl;
468  }
469 
470  int first_format = (bWantStencil ? 0 : FIRST_NON_STENCIL_ZFMT);
471  for (int i = first_format; i < NUM_TEST_ZFMTS; i++) {
472  D3DFORMAT TestDepthFmt = FormatPrefList[i];
473 
474  if (bOnlySelect16bpp && !IS_16BPP_ZBUFFER(TestDepthFmt)) {
475  continue;
476  }
477 
478  hr = Display._d3d9->CheckDeviceFormat(Display._card_id,
479  D3DDEVTYPE_HAL,
480  Test_display_mode.Format,
481  D3DUSAGE_DEPTHSTENCIL,
482  D3DRTYPE_SURFACE, TestDepthFmt);
483 
484  if (FAILED(hr)) {
485  if (hr == D3DERR_NOTAVAILABLE) {
486  if (bVerboseMode)
487  wdxdisplay9_cat.info()
488  << "FindBestDepthFmt: ChkDevFmt returns NotAvail for "
489  << D3DFormatStr(TestDepthFmt) << endl;
490  continue;
491  }
492 
493  wdxdisplay9_cat.error()
494  << "unexpected CheckDeviceFormat failure" << D3DERRORSTRING(hr)
495  << endl;
496  exit(1);
497  }
498 
499  hr = Display._d3d9->CheckDepthStencilMatch(Display._card_id,
500  D3DDEVTYPE_HAL,
501  Test_display_mode.Format, // adapter format
502  Test_display_mode.Format, // backbuffer fmt (should be the same in my apps)
503  TestDepthFmt);
504  if (SUCCEEDED(hr)) {
505  *pBestFmt = TestDepthFmt;
506  break;
507  } else {
508  if (hr == D3DERR_NOTAVAILABLE) {
509  if (bVerboseMode) {
510  wdxdisplay9_cat.info()
511  << "FindBestDepthFmt: ChkDepMatch returns NotAvail for "
512  << D3DFormatStr(Test_display_mode.Format) << ", "
513  << D3DFormatStr(TestDepthFmt) << endl;
514  }
515  } else {
516  wdxdisplay9_cat.error()
517  << "unexpected CheckDepthStencilMatch failure for "
518  << D3DFormatStr(Test_display_mode.Format) << ", "
519  << D3DFormatStr(TestDepthFmt) << endl;
520  exit(1);
521  }
522  }
523  }
524 
525  if (bVerboseMode) {
526  wdxdisplay9_cat.info()
527  << "FindBestDepthFmt returns fmt " << D3DFormatStr(*pBestFmt) << endl;
528  }
529 
530  return (*pBestFmt != D3DFMT_UNKNOWN);
531 }
532 
533 
534 ////////////////////////////////////////////////////////////////////
535 // Function: wdxGraphicsWindow9::special_check_fullscreen_resolution
536 // Access: Private
537 // Description: overrides of the general estimator for known working
538 // cases
539 ////////////////////////////////////////////////////////////////////
541 special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size, UINT y_size) {
542  DWORD VendorId = scrn._dx_device_id.VendorId;
543  DWORD DeviceId = scrn._dx_device_id.DeviceId;
544 
545  switch (VendorId) {
546  case 0x8086: // Intel
547  if ((x_size == 640) && (y_size == 480)) {
548  return true;
549  }
550  if ((x_size == 800) && (y_size == 600)) {
551  return true;
552  }
553  if ((x_size == 1024) && (y_size == 768)) {
554  return true;
555  }
556  break;
557  }
558 
559  return false;
560 }
561 
562 ////////////////////////////////////////////////////////////////////
563 // Function: wdxGraphicsWindow9::search_for_valid_displaymode
564 // Access: Private
565 // Description: All ptr args are output parameters. If no valid mode
566 // found, returns *pSuggestedPixFmt = D3DFMT_UNKNOWN;
567 ////////////////////////////////////////////////////////////////////
570  UINT RequestedX_Size, UINT RequestedY_Size,
571  bool bWantZBuffer, bool bWantStencil,
572  UINT *p_supported_screen_depths_mask,
573  bool *pCouldntFindAnyValidZBuf,
574  D3DFORMAT *pSuggestedPixFmt,
575  bool bForce16bppZBuffer,
576  bool bVerboseMode) {
577  if (dxgsg9_cat.is_debug()) {
578  bVerboseMode = true;
579  }
580 
581  assert(IS_VALID_PTR(scrn._d3d9));
582 
583  HRESULT hr;
584 
585  *pSuggestedPixFmt = D3DFMT_UNKNOWN;
586  *p_supported_screen_depths_mask = 0x0;
587  *pCouldntFindAnyValidZBuf = false;
588 
589  #define TOTAL_D3D_FORMATS 5
590  static D3DFORMAT d3d_format_array [TOTAL_D3D_FORMATS] =
591  {
592  D3DFMT_X8R8G8B8,
593  D3DFMT_A8R8G8B8,
594  D3DFMT_R5G6B5,
595  D3DFMT_X1R5G5B5,
596  D3DFMT_A2R10G10B10, // we may want this first in the list for XBOX 360 or HDR
597  };
598 
599  // search for an adapter with a valid D3DFORMAT
600  int format_index;
601  for (format_index = 0; format_index < TOTAL_D3D_FORMATS; format_index++) {
602  D3DFORMAT d3d_format;
603 
604  d3d_format = d3d_format_array [format_index];
605 
606  int cNumModes = scrn._d3d9->GetAdapterModeCount(scrn._card_id, d3d_format);
607 
608  D3DDISPLAYMODE BestDispMode;
609  ZeroMemory(&BestDispMode, sizeof(BestDispMode));
610 
611  if (bVerboseMode) {
612  wdxdisplay9_cat.info()
613  << "searching for valid display modes at res: ("
614  << RequestedX_Size << ", " << RequestedY_Size
615  << "), TotalModes: " << cNumModes << endl;
616  }
617 
618  // ignore memory based checks for min res 640x480. some cards just
619  // don't give accurate memavails. (should I do the check anyway for
620  // 640x480 32bpp?)
621  bool bDoMemBasedChecks =
622  ((!((RequestedX_Size == 640)&&(RequestedY_Size == 480))) &&
623  (scrn._max_available_video_memory != UNKNOWN_VIDMEM_SIZE) &&
624  (!special_check_fullscreen_resolution(scrn, RequestedX_Size, RequestedY_Size)));
625 
626  if (bVerboseMode) {
627  wdxdisplay9_cat.info()
628  << "DoMemBasedChecks = " << bDoMemBasedChecks << endl;
629  }
630 
631  for (int i = 0; i < cNumModes; i++) {
632  D3DDISPLAYMODE dispmode;
633  hr = scrn._d3d9->EnumAdapterModes(scrn._card_id, d3d_format, i, &dispmode);
634  if (FAILED(hr)) {
635  wdxdisplay9_cat.error()
636  << "EnumAdapter_display_mode failed for device #"
637  << scrn._card_id << D3DERRORSTRING(hr);
638  continue;
639  }
640 
641  if ((dispmode.Width != RequestedX_Size) ||
642  (dispmode.Height != RequestedY_Size)) {
643  if (bVerboseMode) {
644  wdxdisplay9_cat.info()
645  << "Mode dimension " << dispmode.Width << "x" << dispmode.Height
646  << "; format " << D3DFormatStr(dispmode.Format)
647  << ": onto next mode\n";
648  }
649  continue;
650  }
651 
652  // disable refresh rate checking since SLI video cards may use
653  // refresh rates less than 60
654  if (0) {
655  if ((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) {
656  // don't want refresh rates under 60Hz, but 0 or 1 might indicate
657  // a default refresh rate, which is usually > = 60
658  if (bVerboseMode) {
659  wdxdisplay9_cat.info()
660  << "skipping mode[" << i << "], bad refresh rate: "
661  << dispmode.RefreshRate << endl;
662  }
663  continue;
664  }
665  }
666 
667  // Note no attempt is made to verify if format will work at
668  // requested size, so even if this call succeeds, could still get
669  // an out-of-video-mem error
670 
671  hr = scrn._d3d9->CheckDeviceFormat(scrn._card_id, D3DDEVTYPE_HAL, dispmode.Format,
672  D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE,
673  dispmode.Format);
674  if (FAILED(hr)) {
675  if (hr == D3DERR_NOTAVAILABLE) {
676  if (bVerboseMode) {
677  wdxdisplay9_cat.info()
678  << "skipping mode[" << i
679  << "], CheckDevFmt returns NotAvail for fmt: "
680  << D3DFormatStr(dispmode.Format) << endl;
681  }
682  continue;
683  } else {
684  wdxdisplay9_cat.error()
685  << "CheckDeviceFormat failed for device #"
686  << scrn._card_id << D3DERRORSTRING(hr);
687  continue;
688  }
689  }
690 
691  bool bIs16bppRenderTgt = IS_16BPP_DISPLAY_FORMAT(dispmode.Format);
692  PN_stdfloat RendTgtMinMemReqmt = 0.0f;
693 
694  // if we have a valid memavail value, try to determine if we have
695  // enough space
696  if (bDoMemBasedChecks) {
697  // assume user is testing fullscreen, not windowed, so use the
698  // dwTotal value see if 3 scrnbufs (front/back/z)at 16bpp at
699  // x_size*y_size will fit with a few extra megs for texmem
700 
701  // 8MB Rage Pro says it has 6.8 megs Total free and will run at
702  // 1024x768, so formula makes it so that is OK
703 
704  #define REQD_TEXMEM 1800000
705 
706  PN_stdfloat bytes_per_pixel = (bIs16bppRenderTgt ? 2 : 4);
707 
708  // *2 for double buffer
709 
710  RendTgtMinMemReqmt =
711  ((PN_stdfloat)RequestedX_Size) * ((PN_stdfloat)RequestedY_Size) *
712  bytes_per_pixel * 2 + REQD_TEXMEM;
713 
714  if (bVerboseMode)
715  wdxdisplay9_cat.info()
716  << "Testing Mode (" <<RequestedX_Size<<"x" << RequestedY_Size
717  << ", " << D3DFormatStr(dispmode.Format) << ")\nReqdVidMem: "
718  << (int)RendTgtMinMemReqmt << " AvailVidMem: "
719  << scrn._max_available_video_memory << endl;
720 
721  if (RendTgtMinMemReqmt > scrn._max_available_video_memory) {
722  if (bVerboseMode)
723  wdxdisplay9_cat.info()
724  << "not enough VidMem for render tgt, skipping display fmt "
725  << D3DFormatStr(dispmode.Format) << " ("
726  << (int)RendTgtMinMemReqmt << " > "
727  << scrn._max_available_video_memory << ")\n";
728  continue;
729  }
730  }
731 
732  if (bWantZBuffer) {
733  D3DFORMAT zformat;
734  if (!find_best_depth_format(scrn, dispmode, &zformat,
735  bWantStencil, bForce16bppZBuffer)) {
736  *pCouldntFindAnyValidZBuf = true;
737  continue;
738  }
739 
740  PN_stdfloat MinMemReqmt = 0.0f;
741 
742  if (bDoMemBasedChecks) {
743  // test memory again, this time including zbuf size
744  PN_stdfloat zbytes_per_pixel = (IS_16BPP_ZBUFFER(zformat) ? 2 : 4);
745  PN_stdfloat MinMemReqmt = RendTgtMinMemReqmt + ((PN_stdfloat)RequestedX_Size)*((PN_stdfloat)RequestedY_Size)*zbytes_per_pixel;
746 
747  if (bVerboseMode)
748  wdxdisplay9_cat.info()
749  << "Testing Mode w/Z (" << RequestedX_Size << "x"
750  << RequestedY_Size << ", " << D3DFormatStr(dispmode.Format)
751  << ")\nReqdVidMem: " << (int)MinMemReqmt << " AvailVidMem: "
752  << scrn._max_available_video_memory << endl;
753 
754  if (MinMemReqmt > scrn._max_available_video_memory) {
755  if (bVerboseMode)
756  wdxdisplay9_cat.info()
757  << "not enough VidMem for RendTgt+zbuf, skipping display fmt "
758  << D3DFormatStr(dispmode.Format) << " (" << (int)MinMemReqmt
759  << " > " << scrn._max_available_video_memory << ")\n";
760  continue;
761  }
762  }
763 
764 // Optimizing for 16-bit depth does not work in all cases so turn it off.
765  if (false) {
766  if ((!bDoMemBasedChecks) || (MinMemReqmt<scrn._max_available_video_memory)) {
767  if (!IS_16BPP_ZBUFFER(zformat)) {
768  // see if things fit with a 16bpp zbuffer
769 
770  if (!find_best_depth_format(scrn, dispmode, &zformat,
771  bWantStencil, true, bVerboseMode)) {
772  if (bVerboseMode)
773  wdxdisplay9_cat.info()
774  << "FindBestDepthFmt rejected Mode[" << i << "] ("
775  << RequestedX_Size << "x" << RequestedY_Size
776  << ", " << D3DFormatStr(dispmode.Format) << endl;
777  *pCouldntFindAnyValidZBuf = true;
778  continue;
779  }
780 
781  // right now I'm not going to use these flags, just let the
782  // create fail out-of-mem and retry at 16bpp
783  *p_supported_screen_depths_mask |=
784  (IS_16BPP_DISPLAY_FORMAT(dispmode.Format) ? DISPLAY_16BPP_REQUIRES_16BPP_ZBUFFER_FLAG : DISPLAY_32BPP_REQUIRES_16BPP_ZBUFFER_FLAG);
785  }
786  }
787  }
788  }
789 
790  if (bVerboseMode)
791  wdxdisplay9_cat.info()
792  << "Validated Mode (" << RequestedX_Size << "x"
793  << RequestedY_Size << ", " << D3DFormatStr(dispmode.Format) << endl;
794 
795  /*
796  // dx9 valid display modes for render targets.
797  D3DFMT_X1R5G5B5, D3DFMT_R5G6B5, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A2R10G10B10
798  */
799 
800  switch (dispmode.Format) {
801  case D3DFMT_X1R5G5B5:
802  *p_supported_screen_depths_mask |= X1R5G5B5_FLAG;
803  break;
804  case D3DFMT_X8R8G8B8:
805  *p_supported_screen_depths_mask |= X8R8G8B8_FLAG;
806  break;
807  case D3DFMT_A8R8G8B8:
808  *p_supported_screen_depths_mask |= A8R8G8B8_FLAG;
809  break;
810  case D3DFMT_R5G6B5:
811  *p_supported_screen_depths_mask |= R5G6B5_FLAG;
812  break;
813  case D3DFMT_A2R10G10B10:
814  *p_supported_screen_depths_mask |= A2B10G10R10_FLAG;
815  break;
816  default:
817  wdxdisplay9_cat.error()
818  << "unrecognized supported fmt " << D3DFormatStr(dispmode.Format)
819  << " returned by EnumAdapter_display_modes!\n";
820  }
821  }
822 
823  // note: this chooses 32bpp, which may not be preferred over 16 for
824  // memory & speed reasons on some older cards in particular
825  if (*p_supported_screen_depths_mask & X8R8G8B8_FLAG) {
826  *pSuggestedPixFmt = D3DFMT_X8R8G8B8;
827  } else if (*p_supported_screen_depths_mask & A8R8G8B8_FLAG) {
828  *pSuggestedPixFmt = D3DFMT_A8R8G8B8;
829  } else if (*p_supported_screen_depths_mask & R5G6B5_FLAG) {
830  *pSuggestedPixFmt = D3DFMT_R5G6B5;
831  } else if (*p_supported_screen_depths_mask & X1R5G5B5_FLAG) {
832  *pSuggestedPixFmt = D3DFMT_X1R5G5B5;
833  } else if (*p_supported_screen_depths_mask & A2B10G10R10_FLAG) {
834  *pSuggestedPixFmt = D3DFMT_A2R10G10B10;
835  }
836 
837  if (bVerboseMode) {
838  wdxdisplay9_cat.info()
839  << "search_for_valid_device returns fmt: "
840  << D3DFormatStr(*pSuggestedPixFmt) << endl;
841  }
842 
843  if (*pSuggestedPixFmt != D3DFMT_UNKNOWN) {
844  break;
845  }
846  }
847 }
848 
849 ////////////////////////////////////////////////////////////////////
850 // Function: wdxGraphicsPipew9::make_device
851 // Access: Public, Virtual
852 // Description: Creates a new reference to a particular hardware
853 // device and associates it with the pipe.
854 ////////////////////////////////////////////////////////////////////
855 PT(GraphicsDevice) wdxGraphicsPipe9::
856 make_device(void *scrn) {
857  PT(DXGraphicsDevice9) device = new DXGraphicsDevice9(this);
858  memcpy(&device->_Scrn, scrn, sizeof(device->_Scrn));
859  device->_d3d_device = device->_Scrn._d3d_device;
860 
861  _device = device;
862  wdxdisplay9_cat.info() << "walla: device" << device << "\n";
863 
864  return device.p();
865 }
866 
867 pmap<D3DFORMAT_FLAG, D3DFORMAT> g_D3DFORMATmap;
868 
869 void Init_D3DFORMAT_map() {
870  if (g_D3DFORMATmap.size() != 0)
871  return;
872 
873 #define INSERT_ELEM(XX) g_D3DFORMATmap[XX##_FLAG] = D3DFMT_##XX;
874 
875  INSERT_ELEM(R8G8B8);
876  INSERT_ELEM(A8R8G8B8);
877  INSERT_ELEM(X8R8G8B8);
878  INSERT_ELEM(R5G6B5);
879  INSERT_ELEM(X1R5G5B5);
880  INSERT_ELEM(A1R5G5B5);
881  INSERT_ELEM(A4R4G4B4);
882  INSERT_ELEM(R3G3B2);
883  INSERT_ELEM(A8);
884  INSERT_ELEM(A8R3G3B2);
885  INSERT_ELEM(X4R4G4B4);
886  INSERT_ELEM(A2B10G10R10);
887  INSERT_ELEM(G16R16);
888  INSERT_ELEM(A8P8);
889  INSERT_ELEM(P8);
890  INSERT_ELEM(L8);
891  INSERT_ELEM(A8L8);
892  INSERT_ELEM(A4L4);
893  INSERT_ELEM(V8U8);
894  INSERT_ELEM(L6V5U5);
895  INSERT_ELEM(X8L8V8U8);
896  INSERT_ELEM(Q8W8V8U8);
897  INSERT_ELEM(V16U16);
898 // NOT IN DX9
899 // INSERT_ELEM(W11V11U10);
900  INSERT_ELEM(A2W10V10U10);
901  INSERT_ELEM(UYVY);
902  INSERT_ELEM(YUY2);
903  INSERT_ELEM(DXT1);
904  INSERT_ELEM(DXT2);
905  INSERT_ELEM(DXT3);
906  INSERT_ELEM(DXT4);
907  INSERT_ELEM(DXT5);
908 }
909 
910 
911 
912 const char *D3DFormatStr(D3DFORMAT fmt) {
913 
914 #define CASESTR(XX) case XX: return #XX;
915  switch(fmt) {
916  CASESTR(D3DFMT_UNKNOWN);
917  CASESTR(D3DFMT_R8G8B8);
918  CASESTR(D3DFMT_A8R8G8B8);
919  CASESTR(D3DFMT_X8R8G8B8);
920  CASESTR(D3DFMT_R5G6B5);
921  CASESTR(D3DFMT_X1R5G5B5);
922  CASESTR(D3DFMT_A1R5G5B5);
923  CASESTR(D3DFMT_A4R4G4B4);
924  CASESTR(D3DFMT_R3G3B2);
925  CASESTR(D3DFMT_A8);
926  CASESTR(D3DFMT_A8R3G3B2);
927  CASESTR(D3DFMT_X4R4G4B4);
928  CASESTR(D3DFMT_A2B10G10R10);
929  CASESTR(D3DFMT_G16R16);
930  CASESTR(D3DFMT_A8P8);
931  CASESTR(D3DFMT_P8);
932  CASESTR(D3DFMT_L8);
933  CASESTR(D3DFMT_A8L8);
934  CASESTR(D3DFMT_A4L4);
935  CASESTR(D3DFMT_V8U8);
936  CASESTR(D3DFMT_L6V5U5);
937  CASESTR(D3DFMT_X8L8V8U8);
938  CASESTR(D3DFMT_Q8W8V8U8);
939  CASESTR(D3DFMT_V16U16);
940 // NOT IN DX9
941 // CASESTR(D3DFMT_W11V11U10);
942  CASESTR(D3DFMT_A2W10V10U10);
943  CASESTR(D3DFMT_UYVY);
944  CASESTR(D3DFMT_YUY2);
945  CASESTR(D3DFMT_DXT1);
946  CASESTR(D3DFMT_DXT2);
947  CASESTR(D3DFMT_DXT3);
948  CASESTR(D3DFMT_DXT4);
949  CASESTR(D3DFMT_DXT5);
950  CASESTR(D3DFMT_D16_LOCKABLE);
951  CASESTR(D3DFMT_D32);
952  CASESTR(D3DFMT_D15S1);
953  CASESTR(D3DFMT_D24S8);
954  CASESTR(D3DFMT_D16);
955  CASESTR(D3DFMT_D24X8);
956  CASESTR(D3DFMT_D24X4S4);
957  CASESTR(D3DFMT_VERTEXDATA);
958  CASESTR(D3DFMT_INDEX16);
959  CASESTR(D3DFMT_INDEX32);
960  CASESTR(D3DFMT_A16B16G16R16F);
961  CASESTR(D3DFMT_A32B32G32R32F);
962  }
963 
964  return "Invalid D3DFORMAT";
965 }
A GraphicsStateGuardian for rendering into DirectX9 contexts.
This is our own Panda specialization on the default STL map.
Definition: pmap.h:52
A GraphicsDevice necessary for multi-window rendering in DX.
virtual string get_interface_name() const
Returns the name of the rendering interface associated with this GraphicsPipe.
void search_for_valid_displaymode(DXScreenData &scrn, UINT RequestedX_Size, UINT RequestedY_Size, bool bWantZBuffer, bool bWantStencil, UINT *p_supported_screen_depths_mask, bool *pCouldntFindAnyValidZBuf, D3DFORMAT *pSuggestedPixFmt, bool bForce16bppZBuffer, bool bVerboseMode=false)
All ptr args are output parameters.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
An offscreen render buffer.
bool special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size, UINT y_size)
overrides of the general estimator for known working cases
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:58
bool get_supports_render_texture() const
Returns true if this particular GSG can render from a wdxGraphicsBuffer9 directly into a texture...
This is a base class for the various different classes that represent the result of a frame of render...
A single graphics window for rendering DirectX under Microsoft Windows.
An abstract device object that is part of Graphics Pipe.
Encapsulates all the communication with a particular instance of a given rendering backend...
bool is_valid() const
Returns true if the GSG has been correctly initialized within a graphics context, false if there has ...
bool needs_reset() const
Returns true if the gsg is marked as needing a reset.
This graphics pipe represents the interface for creating DirectX9 graphics windows.
This class is the main interface to controlling the render process.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...