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  */
153 end_flip() {
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 }
This is a convenience class to specialize ConfigVariable as a boolean type.
get_value
Returns the variable's value.
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 GraphicsStateGuardian for rendering into DirectX9 contexts.
static void set_cg_device(LPDIRECT3DDEVICE9 cg_device)
Sets the global Cg device pointer.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
Encapsulates all the communication with a particular instance of a given rendering backend.
get_pipe
Returns the graphics pipe on which this GSG was created.
bool reset_if_new()
Calls reset() to initialize the GSG, but only if it hasn't been called yet.
get_unexposed_draw
See set_unexposed_draw().
get_properties
Returns the current properties of the window.
bool is_fullscreen() const
Returns true if the window has been opened as a fullscreen window, false otherwise.
virtual bool is_active() const
Returns true if the window is ready to be rendered into, false otherwise.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
A thread; that is, a lightweight process.
Definition: thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
An abstract base class for glGraphicsWindow and dxGraphicsWindow (and, in general,...
A container for the various kinds of properties we might ask to have on a graphics window before we o...
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...
int get_y_origin() const
Returns the y coordinate of the window's top-left corner, not including decorations.
set_size
Specifies the requested size of the window, in pixels.
int get_x_origin() const
Returns the x coordinate of the window's top-left corner, not including decorations.
This graphics pipe represents the interface for creating DirectX9 graphics windows.
bool special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size, UINT y_size)
overrides of the general estimator for known working cases
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 begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame.
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_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.