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