Panda3D
wdxGraphicsWindow9.cxx
1 // Filename: wdxGraphicsWindow9.cxx
2 // Created by: mike (09Jan00)
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 "wdxGraphicsWindow9.h"
17 #include "config_dxgsg9.h"
18 #include "config_display.h"
19 #include "keyboardButton.h"
20 #include "mouseButton.h"
21 #include "throw_event.h"
22 #include "pStatTimer.h"
23 #include "pmap.h"
24 #include <ddraw.h>
25 #include <errno.h>
26 #include <time.h>
27 #include <math.h>
28 #include <tchar.h>
29 
30 TypeHandle wdxGraphicsWindow9::_type_handle;
31 
32 ////////////////////////////////////////////////////////////////////
33 // Function: wdxGraphicsWindow9::Constructor
34 // Access: Public
35 // Description:
36 ////////////////////////////////////////////////////////////////////
37 wdxGraphicsWindow9::
38 wdxGraphicsWindow9(GraphicsEngine *engine, GraphicsPipe *pipe,
39  const string &name,
40  const FrameBufferProperties &fb_prop,
41  const WindowProperties &win_prop,
42  int flags,
44  GraphicsOutput *host):
45  WinGraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
46 {
47  // don't actually create the window in the constructor. reason:
48  // multi-threading requires panda C++ window object to exist in
49  // separate thread from actual API window
50 
51  _dxgsg = DCAST(DXGraphicsStateGuardian9, gsg);
52  _depth_buffer_bpp = 0;
53  _awaiting_restore = false;
54  ZeroMemory(&_wcontext, sizeof(_wcontext));
55 }
56 
57 ////////////////////////////////////////////////////////////////////
58 // Function: wdxGraphicsWindow9::Destructor
59 // Access: Public, Virtual
60 // Description:
61 ////////////////////////////////////////////////////////////////////
62 wdxGraphicsWindow9::
63 ~wdxGraphicsWindow9() {
64 }
65 
66 ////////////////////////////////////////////////////////////////////
67 // Function: wdxGraphicsWindow9::make_current
68 // Access: Public, Virtual
69 // Description:
70 ////////////////////////////////////////////////////////////////////
71 void wdxGraphicsWindow9::
72 make_current() {
73  PStatTimer timer(_make_current_pcollector);
74 
75  _dxgsg->set_context(&_wcontext);
76 
77  // Now that we have made the context current to a window, we can
78  // reset the GSG state if this is the first time it has been used.
79  // (We can't just call reset() when we construct the GSG, because
80  // reset() requires having a current context.)
81  _dxgsg->reset_if_new();
82 }
83 
84 ////////////////////////////////////////////////////////////////////
85 // Function: wdxGraphicsWindow9::begin_frame
86 // Access: Public, Virtual
87 // Description: This function will be called within the draw thread
88 // before beginning rendering for a given frame. It
89 // should do whatever setup is required, and return true
90 // if the frame should be rendered, or false if it
91 // should be skipped.
92 ////////////////////////////////////////////////////////////////////
94 begin_frame(FrameMode mode, Thread *current_thread) {
95  begin_frame_spam(mode);
96  if (_gsg == (GraphicsStateGuardian *)NULL) {
97  return false;
98  }
99 
100  if (!get_unexposed_draw() && !_got_expose_event) {
101  if (wdxdisplay9_cat.is_spam()) {
102  wdxdisplay9_cat.spam()
103  << "Not drawing " << this << ": unexposed.\n";
104  }
105  return false;
106  }
107 
108  if (_awaiting_restore) {
109  // The fullscreen window was recently restored; we can't continue
110  // until the GSG says we can.
111  if (!_dxgsg->check_cooperative_level()) {
112  // Keep waiting.
113  return false;
114  }
115  _awaiting_restore = false;
116  init_resized_window();
117  }
118 
119  make_current();
120 
121  if (mode == FM_render) {
122  clear_cube_map_selection();
123  }
124 
125  _gsg->set_current_properties(&get_fb_properties());
126  bool return_val = _gsg->begin_frame(current_thread);
127  _dxgsg->set_render_target();
128  return return_val;
129 }
130 
131 ////////////////////////////////////////////////////////////////////
132 // Function: wdxGraphicsWindow9::end_frame
133 // Access: Public, Virtual
134 // Description: This function will be called within the draw thread
135 // after rendering is completed for a given frame. It
136 // should do whatever finalization is required.
137 ////////////////////////////////////////////////////////////////////
139 end_frame(FrameMode mode, Thread *current_thread) {
140  end_frame_spam(mode);
141  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
142 
143  if (mode == FM_render) {
144  copy_to_textures();
145  }
146 
147  _gsg->end_frame(current_thread);
148 
149  if (mode == FM_render) {
150  trigger_flip();
151  clear_cube_map_selection();
152  }
153 }
154 
155 ////////////////////////////////////////////////////////////////////
156 // Function: wdxGraphicsWindow9::end_flip
157 // Access: Public, Virtual
158 // Description: This function will be called within the draw thread
159 // after begin_flip() has been called on all windows, to
160 // finish the exchange of the front and back buffers.
161 //
162 // This should cause the window to wait for the flip, if
163 // necessary.
164 ////////////////////////////////////////////////////////////////////
167  if (_dxgsg != (DXGraphicsStateGuardian9 *)NULL && is_active()) {
168  _dxgsg->show_frame();
169  }
171 }
172 
173 ////////////////////////////////////////////////////////////////////
174 // Function: wdxGraphicsWindow9::verify_window_sizes
175 // Access: Public, Virtual
176 // Description: Determines which of the indicated window sizes are
177 // supported by available hardware (e.g. in fullscreen
178 // mode).
179 //
180 // On entry, dimen is an array containing contiguous x, y
181 // pairs specifying possible display sizes; it is
182 // numsizes*2 words long. The function will zero out
183 // any invalid x, y size pairs. The return value is the
184 // number of valid sizes that were found.
185 ////////////////////////////////////////////////////////////////////
187 verify_window_sizes(int numsizes, int *dimen) {
188  // unfortunately this only works AFTER you make the window
189  // initially, so its really mostly useful for resizes only
190  nassertr(IS_VALID_PTR(_dxgsg), 0);
191 
192  int num_valid_modes = 0;
193 
194  wdxGraphicsPipe9 *dxpipe;
195  DCAST_INTO_R(dxpipe, _pipe, 0);
196 
197  // not requesting same refresh rate since changing res might not
198  // support same refresh rate at new size
199 
200  int *pCurDim = dimen;
201 
202  for (int i = 0; i < numsizes; i++, pCurDim += 2) {
203  int x_size = pCurDim[0];
204  int y_size = pCurDim[1];
205 
206  bool bIsGoodMode = false;
207  bool CouldntFindAnyValidZBuf;
208  D3DFORMAT newPixFmt = D3DFMT_UNKNOWN;
209 
210  if (dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) {
211  // bypass the test below for certain cards we know have valid modes
212  bIsGoodMode = true;
213 
214  } else {
215  if (_wcontext._is_low_memory_card) {
216  bIsGoodMode = ((x_size == 640) && (y_size == 480));
217  } else {
219  (_wcontext, x_size, y_size, _wcontext._presentation_params.EnableAutoDepthStencil != false,
220  IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat),
221  &_wcontext._supported_screen_depths_mask,
222  &CouldntFindAnyValidZBuf, &newPixFmt, dx_force_16bpp_zbuffer, true);
223  bIsGoodMode = (newPixFmt != D3DFMT_UNKNOWN);
224  }
225  }
226 
227  if (bIsGoodMode) {
228  num_valid_modes++;
229  } else {
230  // tell caller the mode is invalid
231  pCurDim[0] = 0;
232  pCurDim[1] = 0;
233  }
234 
235  if (wdxdisplay9_cat.is_spam()) {
236  wdxdisplay9_cat.spam()
237  << "Fullscrn Mode (" << x_size << ", " << y_size << ")\t"
238  << (bIsGoodMode ? "V" : "Inv") << "alid\n";
239  }
240  }
241 
242  return num_valid_modes;
243 }
244 
245 //////////////////////////////////////////////////////////////////
246 // Function: wdxGraphicsWindow::close_window
247 // Access: Public
248 // Description: Some cleanup is necessary for directx closeup of window.
249 // Handle close window events for this particular
250 // window.
251 ////////////////////////////////////////////////////////////////////
252 void wdxGraphicsWindow9::
253 close_window() {
254  if (wdxdisplay9_cat.is_debug()) {
255  wdxdisplay9_cat.debug()
256  << "wdxGraphicsWindow9::close_window() " << this << "\n";
257  }
258 
259  if (_gsg != (GraphicsStateGuardian *)NULL) {
260  _gsg.clear();
261  }
262 
264 
265  _dxgsg->release_swap_chain(&_wcontext);
266  WinGraphicsWindow::close_window();
267 }
268 
269 ////////////////////////////////////////////////////////////////////
270 // Function: wdxGraphicsWindow9::open_window
271 // Access: Protected, Virtual
272 // Description: Opens the window right now. Called from the window
273 // thread. Returns true if the window is successfully
274 // opened, or false if there was a problem.
275 ////////////////////////////////////////////////////////////////////
276 bool wdxGraphicsWindow9::
277 open_window() {
278  PT(DXGraphicsDevice9) dxdev;
279  WindowProperties props;
280 
281  // For now, let's make this configurable. If this is true, then you
282  // can't open multiple different windows with the same GSG, but you
283  // may have more luck opening different windows with different
284  // GSG's.
285  static ConfigVariableBool always_discard_device("always-discard-device", true);
286  bool discard_device = always_discard_device;
287 
288  if (_gsg == 0) {
289  _dxgsg = new DXGraphicsStateGuardian9(_engine, _pipe);
290  _gsg = _dxgsg;
291  } else {
292  DCAST_INTO_R(_dxgsg, _gsg, false);
293  }
294 
295  if (!choose_device()) {
296  return false;
297  }
298 
299  // Ensure the window properties get set to the actual size of the
300  // window.
301  {
302  WindowProperties resized_props;
303  resized_props.set_size(_wcontext._display_mode.Width,
304  _wcontext._display_mode.Height);
305  _properties.add_properties(resized_props);
306  }
307 
308  wdxdisplay9_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n";
309  if (!WinGraphicsWindow::open_window()) {
310  return false;
311  }
312  _wcontext._window = _hWnd;
313 
314  wdxdisplay9_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n";
315 
316  // Here check if a device already exists. If so, then this open_window
317  // call may be an extension to create multiple windows on same device
318  // In that case just create an additional swapchain for this window
319 
320  while (true) {
321  if (_dxgsg->get_pipe()->get_device() == NULL || discard_device) {
322  wdxdisplay9_cat.debug() << "device is null or fullscreen\n";
323 
324  // If device exists, free it
325  if (_dxgsg->get_pipe()->get_device()) {
326  _dxgsg->dx_cleanup();
327  }
328 
329  wdxdisplay9_cat.debug() << "device width " << _wcontext._display_mode.Width << "\n";
330  if (!create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer)) {
331  wdxdisplay9_cat.error() << "Unable to create window with specified parameters.\n";
332  close_window();
333  return false;
334  }
335  _dxgsg->get_pipe()->make_device((void*)(&_wcontext));
336  _dxgsg->copy_pres_reset(&_wcontext);
337  _dxgsg->create_swap_chain(&_wcontext);
338  break;
339 
340  } else {
341  // fill in the DXScreenData from dxdevice here and change the
342  // reference to _window.
343  wdxdisplay9_cat.debug() << "device is not null\n";
344 
345  dxdev = (DXGraphicsDevice9*)_dxgsg->get_pipe()->get_device();
346  memcpy(&_wcontext, &dxdev->_Scrn, sizeof(DXScreenData));
347 
348  _wcontext._presentation_params.Windowed = !is_fullscreen();
349  _wcontext._presentation_params.hDeviceWindow = _wcontext._window = _hWnd;
350  _wcontext._presentation_params.BackBufferWidth = _wcontext._display_mode.Width = _properties.get_x_size();
351  _wcontext._presentation_params.BackBufferHeight = _wcontext._display_mode.Height = _properties.get_y_size();
352 
353  wdxdisplay9_cat.debug() << "device width " << _wcontext._presentation_params.BackBufferWidth << "\n";
354  if (!_dxgsg->create_swap_chain(&_wcontext)) {
355  discard_device = true;
356  continue; // try again
357  }
358  init_resized_window();
359  break;
360  }
361  }
362  wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n";
363  return true;
364 }
365 
366 ////////////////////////////////////////////////////////////////////
367 // Function: wdxGraphicsWindow9::reset_window
368 // Access: Public, Virtual
369 // Description: Resets the window framebuffer right now. Called
370 // from graphicsEngine. It releases the current swap
371 // chain / creates a new one. If this is the initial
372 // window and swapchain is false, then it calls reset_
373 // main_device to Reset the device.
374 ////////////////////////////////////////////////////////////////////
375 void wdxGraphicsWindow9::
376 reset_window(bool swapchain) {
377  if (swapchain) {
378  if (_wcontext._swap_chain) {
379  _dxgsg->create_swap_chain(&_wcontext);
380  wdxdisplay9_cat.debug() << "created swapchain " << _wcontext._swap_chain << "\n";
381  }
382  }
383  else {
384  if (_wcontext._swap_chain) {
385  _dxgsg->release_swap_chain(&_wcontext);
386  wdxdisplay9_cat.debug() << "released swapchain " << _wcontext._swap_chain << "\n";
387  }
388  }
389 }
390 
391 ////////////////////////////////////////////////////////////////////
392 // Function: wdxGraphicsWindow9::fullscreen_restored
393 // Access: Protected, Virtual
394 // Description: This is a hook for derived classes to do something
395 // special, if necessary, when a fullscreen window has
396 // been restored after being minimized. The given
397 // WindowProperties struct will be applied to this
398 // window's properties after this function returns.
399 ////////////////////////////////////////////////////////////////////
400 void wdxGraphicsWindow9::
401 fullscreen_restored(WindowProperties &properties) {
402  // In DX8, unlike DX7, for some reason we can't immediately start
403  // rendering as soon as the window is restored, even though
404  // BeginScene() says we can. Instead, we have to wait until
405  // TestCooperativeLevel() lets us in. We need to set a flag so we
406  // can handle this special case in begin_frame().
407  if (_dxgsg != NULL) {
408  _awaiting_restore = true;
409  }
410 }
411 
412 ////////////////////////////////////////////////////////////////////
413 // Function: wdxGraphicsWindow9::handle_reshape
414 // Access: Protected, Virtual
415 // Description: Called in the window thread when the window size or
416 // location is changed, this updates the properties
417 // structure accordingly.
418 ////////////////////////////////////////////////////////////////////
419 void wdxGraphicsWindow9::
420 handle_reshape() {
421  GdiFlush();
422  WinGraphicsWindow::handle_reshape();
423 
424  if (_dxgsg != NULL && _dxgsg->_d3d_device != NULL) {
425  // create the new resized rendertargets
427  int x_size = props.get_x_size();
428  int y_size = props.get_y_size();
429 
430  if (_wcontext._presentation_params.BackBufferWidth != x_size ||
431  _wcontext._presentation_params.BackBufferHeight != y_size) {
432  bool resize_succeeded = reset_device_resize_window(x_size, y_size);
433 
434  if (wdxdisplay9_cat.is_debug()) {
435  if (!resize_succeeded) {
436  wdxdisplay9_cat.debug()
437  << "windowed_resize to size: (" << x_size << ", " << y_size
438  << ") failed due to out-of-memory\n";
439  } else {
440  int x_origin = props.get_x_origin();
441  int y_origin = props.get_y_origin();
442  wdxdisplay9_cat.debug()
443  << "windowed_resize to origin: (" << x_origin << ", "
444  << y_origin << "), size: (" << x_size
445  << ", " << y_size << ")\n";
446  }
447  }
448  }
449  }
450 }
451 
452 ////////////////////////////////////////////////////////////////////
453 // Function: wdxGraphicsWindow9::do_fullscreen_resize
454 // Access: Protected, Virtual
455 // Description: Called in the window thread to resize a fullscreen
456 // window.
457 ////////////////////////////////////////////////////////////////////
458 bool wdxGraphicsWindow9::
459 do_fullscreen_resize(int x_size, int y_size) {
460  if (!WinGraphicsWindow::do_fullscreen_resize(x_size, y_size)) {
461  return false;
462  }
463 
464  bool bCouldntFindValidZBuf;
465  D3DFORMAT pixFmt;
466  bool bNeedZBuffer = (_wcontext._presentation_params.EnableAutoDepthStencil != false);
467  bool bNeedStencilBuffer = IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat);
468 
469  wdxGraphicsPipe9 *dxpipe;
470  DCAST_INTO_R(dxpipe, _pipe, false);
471 
472  bool bIsGoodMode = false;
473  bool bResizeSucceeded = false;
474 
475  if (!dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) {
476  // bypass the lowvidmem test below for certain "lowmem" cards we know have valid modes
477 
478  if (_wcontext._is_low_memory_card && (!((x_size == 640) && (y_size == 480)))) {
479  wdxdisplay9_cat.error() << "resize() failed: will not try to resize low vidmem device #" << _wcontext._card_id << " to non-640x480!\n";
480  return bResizeSucceeded;
481  }
482  }
483 
484  // must ALWAYS use search_for_valid_displaymode even if we know
485  // a-priori that res is valid so we can get a valid pixfmt
486  dxpipe->search_for_valid_displaymode(_wcontext, x_size, y_size,
487  bNeedZBuffer, bNeedStencilBuffer,
488  &_wcontext._supported_screen_depths_mask,
489  &bCouldntFindValidZBuf,
490  &pixFmt, dx_force_16bpp_zbuffer, true);
491  bIsGoodMode = (pixFmt != D3DFMT_UNKNOWN);
492 
493  if (!bIsGoodMode) {
494  wdxdisplay9_cat.error() << "resize() failed: "
495  << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
496  << " at " << x_size << "x" << y_size << " for device #" << _wcontext._card_id << endl;
497  return bResizeSucceeded;
498  }
499 
500  // reset_device_resize_window handles both windowed & fullscrn,
501  // so need to set new displaymode manually here
502  _wcontext._display_mode.Width = x_size;
503  _wcontext._display_mode.Height = y_size;
504  _wcontext._display_mode.Format = pixFmt;
505  _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT;
506  // keep the previous setting for _wcontext._presentation_params.BackBufferFormat
507 
508  bResizeSucceeded = reset_device_resize_window(x_size, y_size);
509 
510  if (!bResizeSucceeded) {
511  wdxdisplay9_cat.error() << "resize() failed with OUT-OF-MEMORY error!\n";
512 
513  if ((!IS_16BPP_DISPLAY_FORMAT(_wcontext._presentation_params.BackBufferFormat)) &&
514  (_wcontext._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) {
515  // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers
516  _wcontext._display_mode.Format = ((_wcontext._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5);
517  dx_force_16bpp_zbuffer = true;
518  if (wdxdisplay9_cat.info())
519  wdxdisplay9_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #" << _wcontext._card_id << endl;
520 
521  bResizeSucceeded = reset_device_resize_window(x_size, y_size); // create the new resized rendertargets
522  }
523  }
524 
525  return bResizeSucceeded;
526 }
527 
528 ////////////////////////////////////////////////////////////////////
529 // Function: wdxGraphicsWindow9::create_screen_buffers_and_device
530 // Access: Private
531 // Description: Called whenever the window is resized, this recreates
532 // the necessary buffers for rendering.
533 //
534 // Sets _depth_buffer_bpp appropriately.
535 ////////////////////////////////////////////////////////////////////
536 bool wdxGraphicsWindow9::
537 create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer) {
538  wdxGraphicsPipe9 *dxpipe;
539  DCAST_INTO_R(dxpipe, _pipe, false);
540 
541  DWORD dwRenderWidth = display._display_mode.Width;
542  DWORD dwRenderHeight = display._display_mode.Height;
543  DWORD dwBehaviorFlags = 0x0;
544  LPDIRECT3D9 _d3d9 = display._d3d9;
545  D3DCAPS9 *pD3DCaps = &display._d3dcaps;
546  D3DPRESENT_PARAMETERS* presentation_params = &display._presentation_params;
547  RECT view_rect;
548  UINT adapter;
549  D3DDEVTYPE device_type;
550  HRESULT hr;
551 
552  adapter = display._card_id;
553  device_type = D3DDEVTYPE_HAL;
554 
555  // NVIDIA NVPerfHUD
556  if (dx_use_nvperfhud) {
557  UINT adapter_id;
558  UINT total_adapters;
559 
560  total_adapters = _d3d9 -> GetAdapterCount ( );
561  for (adapter_id = 0; adapter_id < total_adapters; adapter_id++) {
562  D3DADAPTER_IDENTIFIER9 identifier;
563 
564  _d3d9 -> GetAdapterIdentifier (adapter_id, 0, &identifier);
565  if (strcmp ("NVIDIA NVPerfHUD", identifier.Description) == 0) {
566  adapter = adapter_id;
567  device_type = D3DDEVTYPE_REF;
568  break;
569  }
570  }
571  }
572 
573  wdxdisplay9_cat.debug() << "Display Width " << dwRenderWidth << " and PresParam Width " << _wcontext._presentation_params.BackBufferWidth << "\n";
574 
575  // BUGBUG: need to change panda to put frame buffer properties with GraphicsWindow, not GSG!!
576  // Update: Did I fix the bug? - Josh
577  bool bWantStencil = (_fb_properties.get_stencil_bits() > 0);
578  bool bWantAlpha = (_fb_properties.get_alpha_bits() > 0);
579 
580  PRINT_REFCNT(wdxdisplay9, _d3d9);
581 
582  nassertr(_d3d9 != NULL, false);
583  nassertr(pD3DCaps->DevCaps & D3DDEVCAPS_HWRASTERIZATION, false);
584 
585  bool do_sync = sync_video;
586 
587  if (do_sync && !(pD3DCaps->Caps & D3DCAPS_READ_SCANLINE)) {
588  wdxdisplay9_cat.info()
589  << "HW doesnt support syncing to vertical refresh, ignoring sync-video\n";
590  do_sync = false;
591  }
592 
593  presentation_params->BackBufferFormat = display._display_mode.Format;
594 
595  // check for D3DFMT_A8R8G8B8 first
596  if (bWantAlpha) {
597  if (!FAILED(_d3d9->CheckDeviceFormat(adapter, device_type, display._display_mode.Format, D3DUSAGE_RENDERTARGET,
598  D3DRTYPE_SURFACE, D3DFMT_A8R8G8B8))) {
599  if (!FAILED(_d3d9->CheckDeviceType(adapter, device_type, display._display_mode.Format, D3DFMT_A8R8G8B8,
600  is_fullscreen()))) {
601  // We can accept D3DFMT_A8R8G8B8, so use it.
602  presentation_params->BackBufferFormat = D3DFMT_A8R8G8B8;
603  }
604  }
605  }
606 
607  // check for same format as display_mode
608  // verify the rendertarget fmt
609  if (FAILED(_d3d9->CheckDeviceFormat(adapter, device_type, display._display_mode.Format, D3DUSAGE_RENDERTARGET,
610  D3DRTYPE_SURFACE, presentation_params->BackBufferFormat))) {
611  wdxdisplay9_cat.error() << "adapter #" << adapter << " CheckDeviceFmt failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl;
612  goto Fallback_to_16bpp_buffers;
613  }
614 
615  if (FAILED(_d3d9->CheckDeviceType(adapter, device_type, display._display_mode.Format, presentation_params->BackBufferFormat,
616  is_fullscreen()))) {
617  wdxdisplay9_cat.error() << "adapter #" << adapter << " CheckDeviceType failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl;
618  goto Fallback_to_16bpp_buffers;
619  }
620 
621  if (display._presentation_params.EnableAutoDepthStencil) {
622  if (!dxpipe->find_best_depth_format(display, display._display_mode,
623  &display._presentation_params.AutoDepthStencilFormat,
624  bWantStencil, false)) {
625  wdxdisplay9_cat.error()
626  << "find_best_depth_format failed in CreateScreenBuffers for device #"
627  << adapter << endl;
628  goto Fallback_to_16bpp_buffers;
629  }
630  _depth_buffer_bpp = D3DFMT_to_DepthBits(display._presentation_params.AutoDepthStencilFormat);
631  } else {
632  _depth_buffer_bpp = 0;
633  }
634 
635  presentation_params->Windowed = !is_fullscreen();
636 
637  int supported_multisamples = 0;
638  if (framebuffer_multisample.get_value()){
639  supported_multisamples = multisamples.get_value();
640  }
641 
642  while (supported_multisamples > 1){
643  // need to check both rendertarget and zbuffer fmts
644  hr = _d3d9->CheckDeviceMultiSampleType(adapter, D3DDEVTYPE_HAL, display._display_mode.Format,
645  is_fullscreen(), D3DMULTISAMPLE_TYPE(supported_multisamples), NULL);
646  if (FAILED(hr)) {
647  supported_multisamples--;
648  continue;
649  }
650 
651  if (display._presentation_params.EnableAutoDepthStencil) {
652  hr = _d3d9->CheckDeviceMultiSampleType(adapter, D3DDEVTYPE_HAL, display._presentation_params.AutoDepthStencilFormat,
653  is_fullscreen(), D3DMULTISAMPLE_TYPE(supported_multisamples), NULL);
654  if (FAILED(hr)) {
655  supported_multisamples--;
656  continue;
657  }
658  }
659 
660  presentation_params->MultiSampleType = D3DMULTISAMPLE_TYPE(supported_multisamples);
661 
662  if (wdxdisplay9_cat.is_info())
663  wdxdisplay9_cat.info() << "adapter #" << adapter << " using multisample antialiasing level: " << supported_multisamples <<
664  ". Requested level was: " << multisamples.get_value() << endl;
665  break;
666  }
667 
668  presentation_params->BackBufferCount = 1;
669  presentation_params->Flags = 0x0;
670  presentation_params->hDeviceWindow = display._window;
671  presentation_params->BackBufferWidth = display._display_mode.Width;
672  presentation_params->BackBufferHeight = display._display_mode.Height;
673 
674  if (_wcontext._is_tnl_device) {
675  dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
676  // note: we could create a pure device in this case if I
677  // eliminated the GetRenderState calls in dxgsg
678 
679  // also, no software vertex processing available since I specify
680  // D3DCREATE_HARDWARE_VERTEXPROCESSING and not
681  // D3DCREATE_MIXED_VERTEXPROCESSING
682  } else {
683  dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
684  }
685 
686  if (dx_preserve_fpu_state)
687  dwBehaviorFlags |= D3DCREATE_FPU_PRESERVE;
688 
689  // if window is not foreground in exclusive mode, ddraw thinks you
690  // are 'not active', so it changes your WM_ACTIVATEAPP from true to
691  // false, causing us to go into a 'wait-for WM_ACTIVATEAPP true'
692  // loop, and the event never comes so we hang in fullscreen wait.
693  // also doing this for windowed mode since it was requested.
694  if (!SetForegroundWindow(display._window)) {
695  wdxdisplay9_cat.warning() << "SetForegroundWindow() failed!\n";
696  }
697 
698  if (dx_use_multithread) {
699  dwBehaviorFlags |= D3DCREATE_MULTITHREADED;
700  }
701  if (dx_use_puredevice) {
702  dwBehaviorFlags |= D3DCREATE_PUREDEVICE;
703  }
704 
705  if (dx_disable_driver_management) {
706  dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT;
707  }
708  if (dx_disable_driver_management_ex) {
709  dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX;
710  }
711 
712  if (is_fullscreen()) {
713  // CREATE FULLSCREEN BUFFERS
714 
715  presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; // we don't care about preserving contents of old frame
716  presentation_params->PresentationInterval = (do_sync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE);
717  presentation_params->FullScreen_RefreshRateInHz = display._display_mode.RefreshRate;
718 
719  ClearToBlack(display._window, get_properties());
720 
721  hr = _d3d9->CreateDevice(adapter, device_type, _hWnd,
722  dwBehaviorFlags, presentation_params, &display._d3d_device);
723 
724  if (FAILED(hr)) {
725  wdxdisplay9_cat.fatal() << "D3D CreateDevice failed for adapter #" << adapter << ", " << D3DERRORSTRING(hr);
726 
727  if (hr == D3DERR_OUTOFVIDEOMEMORY)
728  goto Fallback_to_16bpp_buffers;
729  else
730  return false;
731  }
732 
733  SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight);
734 
735  } else {
736  // CREATE WINDOWED BUFFERS
737 
738  D3DDISPLAYMODE dispmode;
739  hr = display._d3d9->GetAdapterDisplayMode(adapter, &dispmode);
740 
741  if (FAILED(hr)) {
742  wdxdisplay9_cat.fatal()
743  << "GetAdapterDisplayMode failed" << D3DERRORSTRING(hr);
744  return false;
745  }
746 
747  if (dispmode.Format == D3DFMT_P8) {
748  wdxdisplay9_cat.fatal()
749  << "Can't run windowed in an 8-bit or less display mode" << endl;
750  return false;
751  }
752 
753  //From d3d8caps.h
754  //D3DPRESENT_INTERVAL_DEFAULT = 0x00000000L
755  //#define D3DPRESENT_INTERVAL_ONE 0x00000001L
756  //Next line is really sloppy, should either be D3DPRESENT_INTERVAL_DEFAULT or D3DPRESENT_INTERVAL_ONE
757  //not a direct number! but I'm not going to touch it because it's working as is. Zhao 12/15/2011
758  presentation_params->PresentationInterval = 0;
759 
760  //ATI 5450 doesn't like D3DSWAPEFFECT_FLIP
761  presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
762  if (do_sync == false) {
763  presentation_params->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
764  }
765  // if (supported_multisamples<2) {
766  // if (do_sync) {
767  // // It turns out that COPY_VSYNC has real performance problems
768  // // on many nVidia cards--it syncs at some random interval,
769  // // possibly skipping over several video syncs. Screw it,
770  // // we'll effectively disable sync-video with windowed mode
771  // // using DirectX8.
772  // //presentation_params->SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
773  // presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
774  // } else {
775  // presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
776  // }
777 
778  // // override presentation parameters for windowed mode, render and display at maximum speed
779  // if (do_sync == false) {
780  // presentation_params->SwapEffect = D3DSWAPEFFECT_FLIP;
781  // presentation_params->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
782  // }
783  // } else {
784  // presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
785  // }
786 
787  //assert((dwRenderWidth == presentation_params->BackBufferWidth)&&(dwRenderHeight == presentation_params->BackBufferHeight));
788 
789  hr = _d3d9->CreateDevice(adapter, device_type, _hWnd,
790  dwBehaviorFlags, presentation_params, &display._d3d_device);
791 
792  if (FAILED(hr)) {
793  wdxdisplay9_cat.warning() << "presentation_params->BackBufferWidth : " << presentation_params->BackBufferWidth << endl;
794  wdxdisplay9_cat.warning() << "presentation_params->BackBufferHeight : " << presentation_params->BackBufferHeight << endl;
795  wdxdisplay9_cat.warning() << "presentation_params->BackBufferFormat : " << presentation_params->BackBufferFormat << endl;
796  wdxdisplay9_cat.warning() << "presentation_params->BackBufferCount : " << presentation_params->BackBufferCount << endl;
797  wdxdisplay9_cat.warning() << "D3D CreateDevice failed for adapter #" << adapter << D3DERRORSTRING(hr);
798  goto Fallback_to_16bpp_buffers;
799  }
800  } // end create windowed buffers
801 
802  // ========================================================
803 
804  PRINT_REFCNT(wdxdisplay9, _wcontext._d3d_device);
805 
806  if (presentation_params->EnableAutoDepthStencil) {
807  int depth_bits;
808  int stencil_bits;
809 
810  depth_bits = 1;
811  stencil_bits = 0;
812  switch (presentation_params->AutoDepthStencilFormat)
813  {
814  case D3DFMT_D16_LOCKABLE:
815  depth_bits = 16;
816  break;
817  case D3DFMT_D32:
818  depth_bits = 32;
819  break;
820  case D3DFMT_D15S1:
821  depth_bits = 15;
822  stencil_bits = 1;
823  break;
824  case D3DFMT_D24S8:
825  depth_bits = 24;
826  stencil_bits = 8;
827  break;
828  case D3DFMT_D24X8:
829  depth_bits = 24;
830  break;
831  case D3DFMT_D24X4S4:
832  depth_bits = 24;
833  stencil_bits = 4;
834  break;
835  case D3DFMT_D32F_LOCKABLE:
836  depth_bits = 32;
837  break;
838  case D3DFMT_D24FS8:
839  depth_bits = 24;
840  stencil_bits = 8;
841  break;
842  case D3DFMT_D16:
843  depth_bits = 16;
844  break;
845  default:
846  wdxdisplay9_cat.error() << "unknown depth stencil format " << presentation_params->AutoDepthStencilFormat;
847  break;
848  }
849 
850  _fb_properties.set_stencil_bits(stencil_bits);
851  _fb_properties.set_depth_bits(depth_bits);
852  } else {
853  _fb_properties.set_depth_bits(0);
854  _fb_properties.set_stencil_bits(0);
855  }
856 
857  init_resized_window();
858 
859  return true;
860 
861  Fallback_to_16bpp_buffers:
862  if ((!IS_16BPP_DISPLAY_FORMAT(presentation_params->BackBufferFormat)) &&
863  (display._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) {
864  // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers
865 
866  display._display_mode.Format = ((display._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5);
867 
868  if (wdxdisplay9_cat.info()) {
869  wdxdisplay9_cat.info()
870  << "CreateDevice failed with out-of-vidmem or invalid BackBufferFormat, retrying w/16bpp buffers on adapter #"
871  << adapter << endl;
872  }
873  return create_screen_buffers_and_device(display, true);
874  //return;
875 
876  } else if (!((dwRenderWidth == 640)&&(dwRenderHeight == 480))) {
877  if (wdxdisplay9_cat.info())
878  wdxdisplay9_cat.info() << "CreateDevice failed w/out-of-vidmem, retrying at 640x480 w/16bpp buffers on adapter #" << adapter << endl;
879  // try final fallback to 640x480x16
880  display._display_mode.Width = 640;
881  display._display_mode.Height = 480;
882  return create_screen_buffers_and_device(display, true);
883  //return;
884 
885  } else {
886  wdxdisplay9_cat.fatal()
887  << "Can't create any screen buffers, bailing out.\n";
888  return false;
889  }
890 }
891 
892 ////////////////////////////////////////////////////////////////////
893 // Function: wdxGraphicsWindow9::choose_device
894 // Access: Private
895 // Description: Looks at the list of available graphics adapters and
896 // chooses a suitable one for the window.
897 //
898 // Returns true if successful, false on failure.
899 ////////////////////////////////////////////////////////////////////
900 bool wdxGraphicsWindow9::
901 choose_device() {
902  HRESULT hr;
903 
904  wdxGraphicsPipe9 *dxpipe;
905  DCAST_INTO_R(dxpipe, _pipe, false);
906 
907  int num_adapters = dxpipe->__d3d9->GetAdapterCount();
908  DXDeviceInfoVec device_infos;
909 
910  for (int i = 0; i < num_adapters; i++) {
911  D3DADAPTER_IDENTIFIER9 adapter_info;
912  ZeroMemory(&adapter_info, sizeof(D3DADAPTER_IDENTIFIER9));
913  hr = dxpipe->__d3d9->GetAdapterIdentifier(i, 0, &adapter_info);
914  if (FAILED(hr)) {
915  wdxdisplay9_cat.fatal()
916  << "D3D GetAdapterID(" << i << ") failed: "
917  << D3DERRORSTRING(hr) << endl;
918  continue;
919  }
920 
921  LARGE_INTEGER *DrvVer = &adapter_info.DriverVersion;
922 
923  wdxdisplay9_cat.info()
924  << "D3D9." << (dxpipe->__is_dx9_1 ?"1":"0") << " Adapter[" << i << "]: " << adapter_info.Description
925  << ", Driver: " << adapter_info.Driver << ", DriverVersion: ("
926  << HIWORD(DrvVer->HighPart) << "." << LOWORD(DrvVer->HighPart) << "."
927  << HIWORD(DrvVer->LowPart) << "." << LOWORD(DrvVer->LowPart)
928  << ")\nVendorID: 0x" << (void*) adapter_info.VendorId
929  << " DeviceID: 0x" << (void*) adapter_info.DeviceId
930  << " SubsysID: 0x" << (void*) adapter_info.SubSysId
931  << " Revision: 0x" << (void*) adapter_info.Revision << endl;
932 
933  HMONITOR _monitor = dxpipe->__d3d9->GetAdapterMonitor(i);
934  if (_monitor == NULL) {
935  wdxdisplay9_cat.info()
936  << "D3D9 Adapter[" << i << "]: seems to be disabled, skipping it\n";
937  continue;
938  }
939 
940  DXDeviceInfo devinfo;
941  ZeroMemory(&devinfo, sizeof(devinfo));
942  memcpy(&devinfo.guidDeviceIdentifier, &adapter_info.DeviceIdentifier,
943  sizeof(GUID));
944  strncpy(devinfo.szDescription, adapter_info.Description,
945  MAX_DEVICE_IDENTIFIER_STRING);
946  strncpy(devinfo.szDriver, adapter_info.Driver,
947  MAX_DEVICE_IDENTIFIER_STRING);
948  devinfo.VendorID = adapter_info.VendorId;
949  devinfo.DeviceID = adapter_info.DeviceId;
950  devinfo._driver_version = adapter_info.DriverVersion;
951  devinfo._monitor = _monitor;
952  devinfo.cardID = i;
953 
954  device_infos.push_back(devinfo);
955  }
956 
957  if (device_infos.empty()) {
958  wdxdisplay9_cat.error()
959  << "No available D3D9 devices found.\n";
960  return false;
961  }
962 
963  // Since some adapters may have been disabled, we should re-obtain
964  // the number of available adapters.
965  num_adapters = (int)device_infos.size();
966 
967  // Now choose a suitable adapter.
968 
969  int adapter_num = D3DADAPTER_DEFAULT;
970 
971  // Eventually, we should have some interface for specifying a device
972  // index interactively, instead of only via Configrc.
973  if (dx_preferred_device_id != -1) {
974  if (dx_preferred_device_id < 0 || dx_preferred_device_id >= num_adapters) {
975  wdxdisplay9_cat.error()
976  << "invalid 'dx-preferred-device-id', valid values are 0-"
977  << num_adapters - 1 << ", using default adapter instead.\n";
978  } else {
979  adapter_num = dx_preferred_device_id;
980  }
981  }
982 
983  // Try to select the default or requested device.
984  if (adapter_num >= 0 && adapter_num < (int)device_infos.size()) {
985  if (consider_device(dxpipe, &device_infos[adapter_num])) {
986  wdxdisplay9_cat.info()
987  << "Selected device " << adapter_num << " (of "
988  << device_infos.size() << ", zero-based)\n";
989  return true;
990  }
991  wdxdisplay9_cat.info()
992  << "Could not select device " << adapter_num << "\n";
993  }
994 
995  // Iterate through all available devices to find the first suitable
996  // one.
997  for (UINT devnum = 0; devnum < device_infos.size(); ++devnum) {
998  if (consider_device(dxpipe, &device_infos[devnum])) {
999  wdxdisplay9_cat.info()
1000  << "Chose device " << devnum << " (of "
1001  << device_infos.size() << ", zero-based): first one that works.\n";
1002  return true;
1003  }
1004  }
1005 
1006  wdxdisplay9_cat.error() << "no usable display devices.\n";
1007  return false;
1008 }
1009 
1010 ////////////////////////////////////////////////////////////////////
1011 // Function: wdxGraphicsWindow9::consider_device
1012 // Access: Private
1013 // Description: If the specified device is acceptable, sets it as the
1014 // current device and returns true; otherwise, returns
1015 // false.
1016 ////////////////////////////////////////////////////////////////////
1017 bool wdxGraphicsWindow9::
1018 consider_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) {
1019 
1020  nassertr(dxpipe != NULL, false);
1021  WindowProperties properties = get_properties();
1022  DWORD dwRenderWidth = properties.get_x_size();
1023  DWORD dwRenderHeight = properties.get_y_size();
1024  HRESULT hr;
1025  LPDIRECT3D9 _d3d9 = dxpipe->__d3d9;
1026 
1027  nassertr(_dxgsg != NULL, false);
1028  _wcontext._d3d9 = _d3d9;
1029  _wcontext._is_dx9_1 = dxpipe->__is_dx9_1;
1030  _wcontext._card_id = device_info->cardID; // could this change by end?
1031 
1032  bool bWantStencil = (_fb_properties.get_stencil_bits() > 0);
1033 
1034  hr = _d3d9->GetAdapterIdentifier(device_info->cardID, 0,
1035  &_wcontext._dx_device_id);
1036  if (FAILED(hr)) {
1037  wdxdisplay9_cat.error()
1038  << "D3D GetAdapterID failed" << D3DERRORSTRING(hr);
1039  return false;
1040  }
1041 
1042  D3DCAPS9 _d3dcaps;
1043  hr = _d3d9->GetDeviceCaps(device_info->cardID, D3DDEVTYPE_HAL, &_d3dcaps);
1044  if (FAILED(hr)) {
1045  if ((hr == D3DERR_INVALIDDEVICE)||(hr == D3DERR_NOTAVAILABLE)) {
1046  wdxdisplay9_cat.error()
1047  << "No DirectX 9 D3D-capable 3D hardware detected for device # "
1048  << device_info->cardID << " (" << device_info->szDescription
1049  << ")!\n";
1050  } else {
1051  wdxdisplay9_cat.error()
1052  << "GetDeviceCaps failed: " << D3DERRORSTRING(hr) << endl;
1053  }
1054  return false;
1055  }
1056 
1057  //search_for_valid_displaymode needs these to be set
1058  memcpy(&_wcontext._d3dcaps, &_d3dcaps, sizeof(D3DCAPS9));
1059  _wcontext._card_id = device_info->cardID;
1060 
1061  _wcontext._max_available_video_memory = UNKNOWN_VIDMEM_SIZE;
1062  _wcontext._is_low_memory_card = false;
1063 
1064  // bugbug: wouldnt we like to do GetAVailVidMem so we can do
1065  // upper-limit memory computation for dx8 cards too? otherwise
1066  // verify_window_sizes cant do much
1067  if (_d3dcaps.MaxStreams == 0) {
1068  if (wdxdisplay9_cat.is_debug()) {
1069  wdxdisplay9_cat.debug()
1070  << "checking vidmem size\n";
1071  }
1072 
1073  UINT IDnum;
1074 
1075  // simple linear search to match DX7 card info w/DX8 card ID
1076  for (IDnum = 0; IDnum < dxpipe->_card_ids.size(); IDnum++) {
1077  if ((device_info->VendorID == dxpipe->_card_ids[IDnum].VendorID) &&
1078  (device_info->DeviceID == dxpipe->_card_ids[IDnum].DeviceID) &&
1079  (device_info->_monitor == dxpipe->_card_ids[IDnum]._monitor))
1080  break;
1081  }
1082 
1083  if (IDnum < dxpipe->_card_ids.size()) {
1084  _wcontext._max_available_video_memory = dxpipe->_card_ids[IDnum]._max_available_video_memory;
1085  _wcontext._is_low_memory_card = dxpipe->_card_ids[IDnum]._is_low_memory_card;
1086  } else {
1087  wdxdisplay9_cat.error()
1088  << "Error: couldnt find a CardID match in DX7 info, assuming card is not a lowmem card\n";
1089  }
1090  }
1091 
1092  if ((bWantStencil) && (_d3dcaps.StencilCaps == 0x0)) {
1093  wdxdisplay9_cat.fatal()
1094  << "Stencil ability requested, but device #" << device_info->cardID
1095  << " (" << _wcontext._dx_device_id.Description
1096  << "), has no stencil capability!\n";
1097  return false;
1098  }
1099 
1100  // just because TNL is true, it doesnt mean vtx shaders are
1101  // supported in HW (see GF2) for this case, you probably want MIXED
1102  // processing to use HW for fixed-fn vertex processing and SW for
1103  // vtx shaders
1104  _wcontext._is_tnl_device =
1105  ((_d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0);
1106  _wcontext._can_use_hw_vertex_shaders =
1107  (_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(1, 0));
1108  _wcontext._can_use_pixel_shaders =
1109  (_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(1, 0));
1110 
1111  bool bNeedZBuffer =
1112  ((!(_d3dcaps.RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) &&
1113  (_fb_properties.get_depth_bits() > 0));
1114 
1115  _wcontext._presentation_params.EnableAutoDepthStencil = bNeedZBuffer;
1116 
1117  D3DFORMAT pixFmt = D3DFMT_UNKNOWN;
1118 
1119  if (is_fullscreen()) {
1120  bool bCouldntFindValidZBuf;
1121 
1122  dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight,
1123  bNeedZBuffer, bWantStencil,
1124  &_wcontext._supported_screen_depths_mask,
1125  &bCouldntFindValidZBuf,
1126  &pixFmt, dx_force_16bpp_zbuffer, true);
1127 
1128  // note I'm not saving refresh rate, will just use adapter
1129  // default at given res for now
1130 
1131  if (pixFmt == D3DFMT_UNKNOWN) {
1132  wdxdisplay9_cat.error()
1133  << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
1134  << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _wcontext._card_id << endl;
1135  return false;
1136  }
1137  } else {
1138  // Windowed Mode
1139 
1140  D3DDISPLAYMODE dispmode;
1141  hr = _d3d9->GetAdapterDisplayMode(device_info->cardID, &dispmode);
1142  if (FAILED(hr)) {
1143  wdxdisplay9_cat.error()
1144  << "GetAdapterDisplayMode(" << device_info->cardID
1145  << ") failed" << D3DERRORSTRING(hr);
1146  return false;
1147  }
1148  pixFmt = dispmode.Format;
1149  }
1150 
1151  _wcontext._display_mode.Width = dwRenderWidth;
1152  _wcontext._display_mode.Height = dwRenderHeight;
1153  _wcontext._display_mode.Format = pixFmt;
1154  _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT;
1155  _wcontext._monitor = device_info->_monitor;
1156 
1157  if (strcmp(device_info->szDriver, "igdumd32.dll") == 0 &&
1158  device_info->_driver_version.QuadPart <= 0x0007000e000affffLL &&
1159  dx_intel_compressed_texture_bug) {
1160  // Disable compressed textures for this buggy driver (7.14.10.65535
1161  // and earlier--I don't know whether any other drivers also
1162  // exhibit the bug).
1163  _wcontext._intel_compressed_texture_bug = true;
1164  }
1165 
1166  return true;
1167 }
1168 
1169 ////////////////////////////////////////////////////////////////////
1170 // Function: wdxGraphicsWindow9::reset_device_resize_window
1171 // Access: Private
1172 // Description: Called after a window (either fullscreen or windowed)
1173 // has been resized, this recreates the D3D structures
1174 // to match the new size.
1175 ////////////////////////////////////////////////////////////////////
1176 bool wdxGraphicsWindow9::
1177 reset_device_resize_window(UINT new_xsize, UINT new_ysize) {
1178  bool retval = true;
1179 
1180  DXScreenData *screen = NULL;
1181  D3DPRESENT_PARAMETERS d3dpp;
1182  memcpy(&d3dpp, &_wcontext._presentation_params, sizeof(D3DPRESENT_PARAMETERS));
1183  _wcontext._presentation_params.BackBufferWidth = new_xsize;
1184  _wcontext._presentation_params.BackBufferHeight = new_ysize;
1185  make_current();
1186  HRESULT hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen);
1187 
1188  if (FAILED(hr)) {
1189  retval = false;
1190  wdxdisplay9_cat.error()
1191  << "reset_device_resize_window Reset() failed" << D3DERRORSTRING(hr);
1192  if (hr == D3DERR_OUTOFVIDEOMEMORY) {
1193  memcpy(&_wcontext._presentation_params, &d3dpp, sizeof(D3DPRESENT_PARAMETERS));
1194  hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen);
1195  if (FAILED(hr)) {
1196  wdxdisplay9_cat.error()
1197  << "reset_device_resize_window Reset() failed OutOfVidmem, then failed again doing Reset w/original params:" << D3DERRORSTRING(hr);
1198  throw_event("panda3d-render-error");
1199  return false;
1200 
1201  } else {
1202  if (wdxdisplay9_cat.is_info()) {
1203  wdxdisplay9_cat.info()
1204  << "reset of original size (" << _wcontext._presentation_params.BackBufferWidth
1205  << ", " << _wcontext._presentation_params.BackBufferHeight << ") succeeded\n";
1206  }
1207  }
1208  } else {
1209  wdxdisplay9_cat.fatal()
1210  << "Can't reset device, bailing out.\n";
1211  throw_event("panda3d-render-error");
1212  return false;
1213  }
1214  }
1215  // before you init_resized_window you need to copy certain changes to _wcontext
1216  if (screen) {
1217  _wcontext._swap_chain = screen->_swap_chain;
1218  }
1219  wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n";
1220  _gsg->mark_new();
1221  init_resized_window();
1222  return retval;
1223 }
1224 
1225 ////////////////////////////////////////////////////////////////////
1226 // Function: wdxGraphicsWindow9::init_resized_window
1227 // Access: Private
1228 // Description: Reinitializes the window after it has been resized,
1229 // or after it is first created.
1230 //
1231 // Assumes CreateDevice or Device->Reset() has just been
1232 // called, and the new size is specified in
1233 // _wcontext._presentation_params.
1234 ////////////////////////////////////////////////////////////////////
1235 void wdxGraphicsWindow9::
1236 init_resized_window() {
1237  HRESULT hr;
1238 
1239  DWORD newWidth = _wcontext._presentation_params.BackBufferWidth;
1240  DWORD newHeight = _wcontext._presentation_params.BackBufferHeight;
1241 
1242  nassertv((newWidth != 0) && (newHeight != 0));
1243  nassertv(_wcontext._window != NULL);
1244 
1245  if (_wcontext._presentation_params.Windowed) {
1246  POINT ul, lr;
1247  RECT client_rect;
1248 
1249  // need to figure out x, y origin offset of window client area on screen
1250  // (we already know the client area size)
1251 
1252  GetClientRect(_wcontext._window, &client_rect);
1253  ul.x = client_rect.left;
1254  ul.y = client_rect.top;
1255  lr.x = client_rect.right;
1256  lr.y = client_rect.bottom;
1257  ClientToScreen(_wcontext._window, &ul);
1258  ClientToScreen(_wcontext._window, &lr);
1259  client_rect.left = ul.x;
1260  client_rect.top = ul.y;
1261  client_rect.right = lr.x;
1262  client_rect.bottom = lr.y;
1263  }
1264 
1265  // clear window to black ASAP
1266  nassertv(_wcontext._window != NULL);
1267  ClearToBlack(_wcontext._window, get_properties());
1268 
1269  // clear textures and VB's out of video&AGP mem, so cache is reset
1270  hr = _wcontext._d3d_device->EvictManagedResources ( );
1271  if (FAILED(hr)) {
1272  wdxdisplay9_cat.error()
1273  << "EvictManagedResources failed for device #"
1274  << _wcontext._card_id << D3DERRORSTRING(hr);
1275  }
1276 
1277  make_current();
1278 
1279  // set render target before clearing
1280  _dxgsg->set_render_target ( );
1281 
1282  // clear back buffers
1283  DWORD flags;
1284  D3DCOLOR clear_color;
1285 
1286  flags = D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER;
1287  clear_color = 0x00000000;
1288  hr = _wcontext._d3d_device-> Clear (0, NULL, flags, clear_color, 0.0f, 0);
1289  if (FAILED(hr)) {
1290  wdxdisplay9_cat.error()
1291  << "Clear failed for device"
1292  << D3DERRORSTRING(hr);
1293  }
1294  hr = _wcontext._d3d_device-> Present (NULL, NULL, NULL, NULL);
1295  if (FAILED(hr)) {
1296  wdxdisplay9_cat.error()
1297  << "Present failed for device"
1298  << D3DERRORSTRING(hr);
1299  }
1300  hr = _wcontext._d3d_device-> Clear (0, NULL, flags, clear_color, 0.0f, 0);
1301  if (FAILED(hr)) {
1302  wdxdisplay9_cat.error()
1303  << "Clear failed for device"
1304  << D3DERRORSTRING(hr);
1305  }
1306 }
1307 
1308 ////////////////////////////////////////////////////////////////////
1309 // Function: wdxGraphicsWindow9::D3DFMT_to_DepthBits
1310 // Access: Private, Static
1311 // Description: Returns the number of depth bits represented by the
1312 // indicated D3DFORMAT value.
1313 ////////////////////////////////////////////////////////////////////
1314 int wdxGraphicsWindow9::
1315 D3DFMT_to_DepthBits(D3DFORMAT fmt) {
1316  switch(fmt) {
1317  case D3DFMT_D16:
1318  return 16;
1319 
1320  case D3DFMT_D24X8:
1321  case D3DFMT_D24X4S4:
1322  case D3DFMT_D24S8:
1323  return 24;
1324 
1325  case D3DFMT_D32:
1326  return 32;
1327 
1328  case D3DFMT_D15S1:
1329  return 15;
1330 
1331  default:
1332  wdxdisplay9_cat.debug()
1333  << "D3DFMT_DepthBits: unhandled D3DFMT!\n";
1334  return 0;
1335  }
1336 }
1337 
1338 ////////////////////////////////////////////////////////////////////
1339 // Function: wdxGraphicsWindow9::is_badvidmem_card
1340 // Access: Private, Static
1341 // Description: Returns true if the indicated video adapter card is
1342 // known to report an inaccurate figure for available
1343 // video memory.
1344 ////////////////////////////////////////////////////////////////////
1345 bool wdxGraphicsWindow9::
1346 is_badvidmem_card(D3DADAPTER_IDENTIFIER9 *pDevID) {
1347  // don't trust Intel cards since they often use regular memory as vidmem
1348  if (pDevID->VendorId == 0x00008086) {
1349  return true;
1350  }
1351 
1352  return false;
1353 }
1354 
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
A GraphicsStateGuardian for rendering into DirectX9 contexts.
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame...
GraphicsPipe * get_pipe() const
Returns the graphics pipe on which this GSG was created.
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
This is a convenience class to specialize ConfigVariable as a boolean type.
bool reset_if_new()
Calls reset() to initialize the GSG, but only if it hasn&#39;t been called yet.
void set_size(const LVector2i &size)
Specifies the requested size of the window, in pixels.
A GraphicsDevice necessary for multi-window rendering in DX.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
int get_y_origin() const
Returns the y coordinate of the window&#39;s top-left corner, not including decorations.
const WindowProperties get_properties() const
Returns the current properties of the window.
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.
bool get_unexposed_draw() const
See set_unexposed_draw().
virtual bool is_active() const
Returns true if the window is ready to be rendered into, false otherwise.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
A container for the various kinds of properties we might ask to have on a graphics window before we o...
An abstract base class for glGraphicsWindow and dxGraphicsWindow (and, in general, graphics windows that interface with the Microsoft Windows API).
bool special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size, UINT y_size)
overrides of the general estimator for known working cases
static void set_cg_device(LPDIRECT3DDEVICE9 cg_device)
Sets the global Cg device pointer.
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...
virtual int verify_window_sizes(int numsizes, int *dimen)
Determines which of the indicated window sizes are supported by available hardware (e...
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame...
A thread; that is, a lightweight process.
Definition: thread.h:51
Encapsulates all the communication with a particular instance of a given rendering backend...
int get_value() const
Returns the variable&#39;s value.
This graphics pipe represents the interface for creating DirectX9 graphics windows.
This class is the main interface to controlling the render process.
int get_y_size() const
Returns size in pixels in the y dimension of the useful part of the window, not including decorations...
int get_x_size() const
Returns size in pixels in the x dimension of the useful part of the window, not including decorations...
bool get_value() const
Returns the variable&#39;s value.
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...
GraphicsDevice * get_device() const
Returns a pointer to device object.
Definition: graphicsPipe.I:102
bool is_fullscreen() const
Returns true if the window has been opened as a fullscreen window, false otherwise.
int get_x_origin() const
Returns the x coordinate of the window&#39;s top-left corner, not including decorations.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.