Panda3D
 All Classes Functions Variables Enumerations
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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
bool is_valid() const
Returns true if the GSG has been correctly initialized within a graphics context, false if there has ...
A GraphicsDevice necessary for multi-window rendering in DX.
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
This is a base class for the various different classes that represent the result of a frame of render...
bool get_supports_render_texture() const
Returns true if this particular GSG can render from a wdxGraphicsBuffer9 directly into a texture...
A single graphics window for rendering DirectX under Microsoft Windows.
bool needs_reset() const
Returns true if the gsg is marked as needing a reset.
An abstract device object that is part of Graphics Pipe.
Encapsulates all the communication with a particular instance of a given rendering backend...
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...
virtual string get_interface_name() const
Returns the name of the rendering interface associated with this GraphicsPipe.