wdxGraphicsWindow8.cxx

00001 // Filename: wdxGraphicsWindow8.cxx
00002 // Created by:  mike (09Jan00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "wdxGraphicsPipe8.h"
00016 #include "wdxGraphicsWindow8.h"
00017 #include "config_dxgsg8.h"
00018 #include "config_display.h"
00019 #include "keyboardButton.h"
00020 #include "mouseButton.h"
00021 #include "throw_event.h"
00022 #include "pStatTimer.h"
00023 #include "pmap.h"
00024 #include <ddraw.h>
00025 #include <errno.h>
00026 #include <time.h>
00027 #include <math.h>
00028 #include <tchar.h>
00029 
00030 TypeHandle wdxGraphicsWindow8::_type_handle;
00031 
00032 ////////////////////////////////////////////////////////////////////
00033 //     Function: wdxGraphicsWindow8::Constructor
00034 //       Access: Public
00035 //  Description:
00036 ////////////////////////////////////////////////////////////////////
00037 wdxGraphicsWindow8::
00038 wdxGraphicsWindow8(GraphicsEngine *engine, GraphicsPipe *pipe,
00039                    const string &name,
00040                    const FrameBufferProperties &fb_prop,
00041                    const WindowProperties &win_prop,
00042                    int flags,
00043                    GraphicsStateGuardian *gsg,
00044                    GraphicsOutput *host):
00045   WinGraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00046 {
00047   // don't actually create the window in the constructor.  reason:
00048   // multi-threading requires panda C++ window object to exist in
00049   // separate thread from actual API window
00050 
00051   _dxgsg = DCAST(DXGraphicsStateGuardian8, gsg);
00052   _depth_buffer_bpp = 0;
00053   _awaiting_restore = false;
00054   ZeroMemory(&_wcontext, sizeof(_wcontext));
00055 }
00056 
00057 ////////////////////////////////////////////////////////////////////
00058 //     Function: wdxGraphicsWindow8::Destructor
00059 //       Access: Public, Virtual
00060 //  Description:
00061 ////////////////////////////////////////////////////////////////////
00062 wdxGraphicsWindow8::
00063 ~wdxGraphicsWindow8() {
00064 }
00065 
00066 ////////////////////////////////////////////////////////////////////
00067 //     Function: wdxGraphicsWindow8::begin_frame
00068 //       Access: Public, Virtual
00069 //  Description: This function will be called within the draw thread
00070 //               before beginning rendering for a given frame.  It
00071 //               should do whatever setup is required, and return true
00072 //               if the frame should be rendered, or false if it
00073 //               should be skipped.
00074 ////////////////////////////////////////////////////////////////////
00075 bool wdxGraphicsWindow8::
00076 begin_frame(FrameMode mode, Thread *current_thread) {
00077   begin_frame_spam(mode);
00078   if (_gsg == (GraphicsStateGuardian *)NULL) {
00079     return false;
00080   }
00081   
00082   if (_awaiting_restore) {
00083     // The fullscreen window was recently restored; we can't continue
00084     // until the GSG says we can.
00085     if (!_dxgsg->check_cooperative_level()) {
00086       // Keep waiting.
00087       return false;
00088     }
00089     _awaiting_restore = false;
00090     init_resized_window();
00091   }
00092 
00093   make_current();
00094 
00095   if (mode == FM_render) {
00096     clear_cube_map_selection();
00097   }
00098 
00099   _gsg->set_current_properties(&get_fb_properties());
00100   bool return_val = _gsg->begin_frame(current_thread);
00101   _dxgsg->set_render_target();
00102   return return_val;
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: wdxGraphicsWindow8::end_frame
00107 //       Access: Public, Virtual
00108 //  Description: This function will be called within the draw thread
00109 //               after rendering is completed for a given frame.  It
00110 //               should do whatever finalization is required.
00111 ////////////////////////////////////////////////////////////////////
00112 void wdxGraphicsWindow8::
00113 end_frame(FrameMode mode, Thread *current_thread) {
00114 
00115   end_frame_spam(mode);
00116   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00117 
00118   if (mode == FM_render) {
00119     copy_to_textures();
00120   }
00121 
00122   _gsg->end_frame(current_thread);
00123 
00124   if (mode == FM_render) {
00125     trigger_flip();
00126     if (_one_shot) {
00127       prepare_for_deletion();
00128     }
00129     clear_cube_map_selection();
00130   }
00131 }
00132 ////////////////////////////////////////////////////////////////////
00133 //     Function: wdxGraphicsWindow8::make_current
00134 //       Access: Private
00135 //  Description: 
00136 ////////////////////////////////////////////////////////////////////
00137 void wdxGraphicsWindow8::
00138 make_current() {
00139   PStatTimer timer(_make_current_pcollector);
00140 
00141   _dxgsg->set_context(&_wcontext);
00142 
00143   // Now that we have made the context current to a window, we can
00144   // reset the GSG state if this is the first time it has been used.
00145   // (We can't just call reset() when we construct the GSG, because
00146   // reset() requires having a current context.)
00147   _dxgsg->reset_if_new();
00148 }
00149 
00150 ////////////////////////////////////////////////////////////////////
00151 //     Function: wdxGraphicsWindow8::end_flip
00152 //       Access: Public, Virtual
00153 //  Description: This function will be called within the draw thread
00154 //               after begin_flip() has been called on all windows, to
00155 //               finish the exchange of the front and back buffers.
00156 //
00157 //               This should cause the window to wait for the flip, if
00158 //               necessary.
00159 ////////////////////////////////////////////////////////////////////
00160 void wdxGraphicsWindow8::
00161 end_flip() {
00162   if (_dxgsg != (DXGraphicsStateGuardian8 *)NULL && is_active()) {
00163     _dxgsg->show_frame();
00164   }
00165   GraphicsWindow::end_flip();
00166 }
00167 
00168 ////////////////////////////////////////////////////////////////////
00169 //     Function: wdxGraphicsWindow8::verify_window_sizes
00170 //       Access: Public, Virtual
00171 //  Description: Determines which of the indicated window sizes are
00172 //               supported by available hardware (e.g. in fullscreen
00173 //               mode).
00174 //
00175 //               On entry, dimen is an array containing contiguous x, y
00176 //               pairs specifying possible display sizes; it is
00177 //               numsizes*2 words long.  The function will zero out
00178 //               any invalid x, y size pairs.  The return value is the
00179 //               number of valid sizes that were found.
00180 ////////////////////////////////////////////////////////////////////
00181 int wdxGraphicsWindow8::
00182 verify_window_sizes(int numsizes, int *dimen) {
00183   // unfortunately this only works AFTER you make the window
00184   // initially, so its really mostly useful for resizes only
00185   nassertr(IS_VALID_PTR(_dxgsg), 0);
00186 
00187   int num_valid_modes = 0;
00188 
00189   wdxGraphicsPipe8 *dxpipe;
00190   DCAST_INTO_R(dxpipe, _pipe, 0);
00191 
00192   // not requesting same refresh rate since changing res might not
00193   // support same refresh rate at new size
00194 
00195   int *pCurDim = dimen;
00196 
00197   for (int i = 0; i < numsizes; i++, pCurDim += 2) {
00198     int x_size = pCurDim[0];
00199     int y_size = pCurDim[1];
00200 
00201     bool bIsGoodMode = false;
00202     bool CouldntFindAnyValidZBuf;
00203     D3DFORMAT newPixFmt = D3DFMT_UNKNOWN;
00204 
00205     if (dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) {
00206       // bypass the test below for certain cards we know have valid modes
00207       bIsGoodMode = true;
00208 
00209     } else {
00210       if (_wcontext._is_low_memory_card) {
00211         bIsGoodMode = ((x_size == 640) && (y_size == 480));
00212       } else  {
00213         dxpipe->search_for_valid_displaymode
00214           (_wcontext, x_size, y_size, _wcontext._presentation_params.EnableAutoDepthStencil != false,
00215            IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat),
00216            &_wcontext._supported_screen_depths_mask,
00217            &CouldntFindAnyValidZBuf, &newPixFmt, dx_force_16bpp_zbuffer);
00218         bIsGoodMode = (newPixFmt != D3DFMT_UNKNOWN);
00219       }
00220     }
00221 
00222     if (bIsGoodMode) {
00223       num_valid_modes++;
00224     } else {
00225       // tell caller the mode is invalid
00226       pCurDim[0] = 0;
00227       pCurDim[1] = 0;
00228     }
00229 
00230     if (wdxdisplay8_cat.is_spam()) {
00231       wdxdisplay8_cat.spam()
00232         << "Fullscrn Mode (" << x_size << ", " << y_size << ")\t"
00233         << (bIsGoodMode ? "V" : "Inv") << "alid\n";
00234     }
00235   }
00236 
00237   return num_valid_modes;
00238 }
00239 
00240 //////////////////////////////////////////////////////////////////
00241 //     Function: wdxGraphicsWindow::close_window
00242 //       Access: Public
00243 //  Description: Some cleanup is necessary for directx closeup of window.
00244 //               Handle close window events for this particular
00245 //               window.
00246 ////////////////////////////////////////////////////////////////////
00247 void wdxGraphicsWindow8::
00248 close_window() {
00249   if (wdxdisplay8_cat.is_debug()) {
00250     wdxdisplay8_cat.debug()
00251       << "wdxGraphicsWindow8::close_window() " << this << "\n";
00252   }
00253 
00254   if (_gsg != (GraphicsStateGuardian*)NULL) {
00255     _gsg.clear();
00256     _active = false;
00257   }
00258 
00259   _dxgsg->release_swap_chain(&_wcontext);
00260   WinGraphicsWindow::close_window();
00261 }
00262 
00263 ////////////////////////////////////////////////////////////////////
00264 //     Function: wdxGraphicsWindow8::open_window
00265 //       Access: Protected, Virtual
00266 //  Description: Opens the window right now.  Called from the window
00267 //               thread.  Returns true if the window is successfully
00268 //               opened, or false if there was a problem.
00269 ////////////////////////////////////////////////////////////////////
00270 bool wdxGraphicsWindow8::
00271 open_window() {
00272   PT(DXGraphicsDevice8) dxdev;
00273   WindowProperties props;
00274 
00275   // For now, let's make this configurable.  If this is true, then you
00276   // can't open multiple different windows with the same GSG, but you
00277   // may have more luck opening different windows with different
00278   // GSG's.
00279   static ConfigVariableBool always_discard_device("always-discard-device", true);
00280   bool discard_device = always_discard_device;
00281 
00282   // GSG creation/initialization.
00283   if (_gsg == 0) {
00284     _dxgsg = new DXGraphicsStateGuardian8(_engine, _pipe);
00285     _gsg = _dxgsg;
00286   } else {
00287     DCAST_INTO_R(_dxgsg, _gsg, false);
00288   }
00289   
00290   if (!choose_device()) {
00291     return false;
00292   }
00293 
00294   // Ensure the window properties get set to the actual size of the
00295   // window.
00296   {
00297     WindowProperties resized_props;
00298     resized_props.set_size(_wcontext._display_mode.Width, 
00299                            _wcontext._display_mode.Height);
00300     _properties.add_properties(resized_props);
00301   }
00302 
00303   wdxdisplay8_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n";
00304   if (!WinGraphicsWindow::open_window()) {
00305     return false;
00306   }
00307   _wcontext._window = _hWnd;
00308 
00309   wdxdisplay8_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n";
00310 
00311   // Here check if a device already exists. If so, then this open_window
00312   // call may be an extension to create multiple windows on same device
00313   // In that case just create an additional swapchain for this window
00314 
00315   while (true) {
00316     if (_dxgsg->get_pipe()->get_device() == NULL || discard_device) {
00317       wdxdisplay8_cat.debug() << "device is null or fullscreen\n";
00318 
00319       // If device exists, free it
00320       if (_dxgsg->get_pipe()->get_device()) {
00321         _dxgsg->dx_cleanup();
00322       }
00323 
00324       wdxdisplay8_cat.debug() << "device width " << _wcontext._display_mode.Width << "\n";
00325       if (!create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer)) {
00326         wdxdisplay8_cat.error() << "Unable to create window with specified parameters.\n";
00327         close_window();
00328         return false;
00329       }
00330       _dxgsg->get_pipe()->make_device((void*)(&_wcontext));
00331       _dxgsg->copy_pres_reset(&_wcontext);
00332       _dxgsg->create_swap_chain(&_wcontext);
00333       break;
00334 
00335     } else {
00336       // fill in the DXScreenData from dxdevice here and change the
00337       // reference to _window.
00338       wdxdisplay8_cat.debug() << "device is not null\n";
00339 
00340       dxdev = (DXGraphicsDevice8*)(_dxgsg->get_pipe()->get_device());
00341       props = get_properties();
00342       memcpy(&_wcontext, &dxdev->_Scrn, sizeof(DXScreenData));
00343 
00344       _wcontext._presentation_params.Windowed = !is_fullscreen();
00345       _wcontext._presentation_params.hDeviceWindow = _wcontext._window = _hWnd;
00346       _wcontext._presentation_params.BackBufferWidth = _wcontext._display_mode.Width = props.get_x_size();
00347       _wcontext._presentation_params.BackBufferHeight = _wcontext._display_mode.Height = props.get_y_size();
00348 
00349       wdxdisplay8_cat.debug() << "device width " << _wcontext._presentation_params.BackBufferWidth << "\n";
00350       if (!_dxgsg->create_swap_chain(&_wcontext)) {
00351         discard_device = true;
00352         continue; // try again
00353       }
00354       init_resized_window();
00355       break;
00356     }
00357   }
00358   wdxdisplay8_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n";
00359   return true;
00360 }
00361 
00362 ////////////////////////////////////////////////////////////////////
00363 //     Function: wdxGraphicsWindow8::reset_window
00364 //       Access: Public, Virtual
00365 //  Description: Resets the window framebuffer right now.  Called
00366 //               from graphicsEngine. It releases the current swap
00367 //               chain / creates a new one. If this is the initial
00368 //               window and swapchain is false, then it calls reset_
00369 //               main_device to Reset the device.
00370 ////////////////////////////////////////////////////////////////////
00371 void wdxGraphicsWindow8::
00372 reset_window(bool swapchain) {
00373   if (swapchain) {
00374     if (_wcontext._swap_chain) {
00375       _dxgsg->create_swap_chain(&_wcontext);
00376       wdxdisplay8_cat.debug() << "created swapchain " << _wcontext._swap_chain << "\n";
00377     }
00378   }
00379   else {
00380     if (_wcontext._swap_chain) {
00381       _dxgsg->release_swap_chain(&_wcontext);
00382       wdxdisplay8_cat.debug() << "released swapchain " << _wcontext._swap_chain << "\n";
00383     }
00384   }
00385 }
00386 
00387 ////////////////////////////////////////////////////////////////////
00388 //     Function: wdxGraphicsWindow8::fullscreen_restored
00389 //       Access: Protected, Virtual
00390 //  Description: This is a hook for derived classes to do something
00391 //               special, if necessary, when a fullscreen window has
00392 //               been restored after being minimized.  The given
00393 //               WindowProperties struct will be applied to this
00394 //               window's properties after this function returns.
00395 ////////////////////////////////////////////////////////////////////
00396 void wdxGraphicsWindow8::
00397 fullscreen_restored(WindowProperties &properties) {
00398   // In DX8, unlike DX7, for some reason we can't immediately start
00399   // rendering as soon as the window is restored, even though
00400   // BeginScene() says we can.  Instead, we have to wait until
00401   // TestCooperativeLevel() lets us in.  We need to set a flag so we
00402   // can handle this special case in begin_frame().
00403   if (_dxgsg != NULL) {
00404     _awaiting_restore = true;
00405   }
00406 }
00407 
00408 ////////////////////////////////////////////////////////////////////
00409 //     Function: wdxGraphicsWindow8::handle_reshape
00410 //       Access: Protected, Virtual
00411 //  Description: Called in the window thread when the window size or
00412 //               location is changed, this updates the properties
00413 //               structure accordingly.
00414 ////////////////////////////////////////////////////////////////////
00415 void wdxGraphicsWindow8::
00416 handle_reshape() {
00417   GdiFlush();
00418   WinGraphicsWindow::handle_reshape();
00419 
00420   if (_dxgsg != NULL) {
00421     // create the new resized rendertargets
00422     WindowProperties props = get_properties();
00423     int x_size = props.get_x_size();
00424     int y_size = props.get_y_size();
00425 
00426     if (_wcontext._presentation_params.BackBufferWidth != x_size ||
00427         _wcontext._presentation_params.BackBufferHeight != y_size) {
00428       bool resize_succeeded = reset_device_resize_window(x_size, y_size);
00429       
00430       if (wdxdisplay8_cat.is_debug()) {
00431         if (!resize_succeeded) {
00432           wdxdisplay8_cat.debug()
00433             << "windowed_resize to size: (" << x_size << ", " << y_size
00434             << ") failed due to out-of-memory\n";
00435         } else {
00436           int x_origin = props.get_x_origin();
00437           int y_origin = props.get_y_origin();
00438           wdxdisplay8_cat.debug()
00439             << "windowed_resize to origin: (" << x_origin << ", "
00440             << y_origin << "), size: (" << x_size
00441             << ", " << y_size << ")\n";
00442         }
00443       }
00444     }
00445   }
00446 }
00447 
00448 ////////////////////////////////////////////////////////////////////
00449 //     Function: wdxGraphicsWindow8::do_fullscreen_resize
00450 //       Access: Protected, Virtual
00451 //  Description: Called in the window thread to resize a fullscreen
00452 //               window.
00453 ////////////////////////////////////////////////////////////////////
00454 bool wdxGraphicsWindow8::
00455 do_fullscreen_resize(int x_size, int y_size) {
00456   if (!WinGraphicsWindow::do_fullscreen_resize(x_size, y_size)) {
00457     return false;
00458   }
00459 
00460   bool bCouldntFindValidZBuf;
00461   D3DFORMAT pixFmt;
00462   bool bNeedZBuffer = (_wcontext._presentation_params.EnableAutoDepthStencil != false);
00463   bool bNeedStencilBuffer = IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat);
00464 
00465   wdxGraphicsPipe8 *dxpipe;
00466   DCAST_INTO_R(dxpipe, _pipe, false);
00467 
00468   bool bIsGoodMode = false;
00469   bool bResizeSucceeded = false;
00470 
00471   if (!dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) {
00472     // bypass the lowvidmem test below for certain "lowmem" cards we know have valid modes
00473 
00474     if (_wcontext._is_low_memory_card && (!((x_size == 640) && (y_size == 480)))) {
00475       wdxdisplay8_cat.error() << "resize() failed: will not try to resize low vidmem device #" << _wcontext._card_id << " to non-640x480!\n";
00476       return bResizeSucceeded;
00477     }
00478   }
00479 
00480   // must ALWAYS use search_for_valid_displaymode even if we know
00481   // a-priori that res is valid so we can get a valid pixfmt
00482   dxpipe->search_for_valid_displaymode(_wcontext, x_size, y_size,
00483                                        bNeedZBuffer, bNeedStencilBuffer,
00484                                        &_wcontext._supported_screen_depths_mask,
00485                                        &bCouldntFindValidZBuf,
00486                                        &pixFmt, dx_force_16bpp_zbuffer);
00487   bIsGoodMode = (pixFmt != D3DFMT_UNKNOWN);
00488 
00489   if (!bIsGoodMode) {
00490     wdxdisplay8_cat.error() << "resize() failed: "
00491                             << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
00492                             << " at " << x_size << "x" << y_size << " for device #" << _wcontext._card_id << endl;
00493     return bResizeSucceeded;
00494   }
00495 
00496   // reset_device_resize_window handles both windowed & fullscrn,
00497   // so need to set new displaymode manually here
00498   _wcontext._display_mode.Width = x_size;
00499   _wcontext._display_mode.Height = y_size;
00500   _wcontext._display_mode.Format = pixFmt;
00501   _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT;
00502 
00503   _wcontext._presentation_params.BackBufferFormat = pixFmt;   // make reset_device_resize use presparams or displaymode??
00504 
00505   bResizeSucceeded = reset_device_resize_window(x_size, y_size);
00506 
00507   if (!bResizeSucceeded) {
00508     wdxdisplay8_cat.error() << "resize() failed with OUT-OF-MEMORY error!\n";
00509 
00510     if ((!IS_16BPP_DISPLAY_FORMAT(_wcontext._presentation_params.BackBufferFormat)) &&
00511         (_wcontext._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) {
00512       // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers
00513       _wcontext._display_mode.Format = ((_wcontext._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5);
00514       dx_force_16bpp_zbuffer = true;
00515       if (wdxdisplay8_cat.info())
00516         wdxdisplay8_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #" << _wcontext._card_id << endl;
00517 
00518       bResizeSucceeded = reset_device_resize_window(x_size, y_size);  // create the new resized rendertargets
00519     }
00520   }
00521 
00522   return bResizeSucceeded;
00523 }
00524 
00525 ////////////////////////////////////////////////////////////////////
00526 //     Function: wdxGraphicsWindow8::create_screen_buffers_and_device
00527 //       Access: Private
00528 //  Description: Called whenever the window is resized, this recreates
00529 //               the necessary buffers for rendering.
00530 //
00531 //               Sets _depth_buffer_bpp appropriately.
00532 ////////////////////////////////////////////////////////////////////
00533 bool wdxGraphicsWindow8::
00534 create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer) {
00535   wdxGraphicsPipe8 *dxpipe;
00536   DCAST_INTO_R(dxpipe, _pipe, false);
00537 
00538   DWORD dwRenderWidth = display._display_mode.Width;
00539   DWORD dwRenderHeight = display._display_mode.Height;
00540   DWORD dwBehaviorFlags = 0x0;
00541   LPDIRECT3D8 _d3d8 = display._d3d8;
00542   D3DCAPS8 *pD3DCaps = &display._d3dcaps;
00543   D3DPRESENT_PARAMETERS* presentation_params = &display._presentation_params;
00544   RECT view_rect;
00545   HRESULT hr;
00546 
00547   wdxdisplay8_cat.debug() << "Display Width " << dwRenderWidth << " and PresParam Width " << _wcontext._presentation_params.BackBufferWidth << "\n";
00548 
00549   bool bWantStencil = (_fb_properties.get_stencil_bits() > 0);
00550 
00551   PRINT_REFCNT(wdxdisplay8, _d3d8);
00552 
00553   nassertr(_d3d8 != NULL, false);
00554   nassertr(pD3DCaps->DevCaps & D3DDEVCAPS_HWRASTERIZATION, false);
00555 
00556   presentation_params->BackBufferFormat = display._display_mode.Format;  // don't need dest alpha, so just use adapter format
00557   cerr << "attempting " << D3DFormatStr(presentation_params->BackBufferFormat) << "\n";
00558 
00559   bool do_sync = sync_video;
00560 
00561   if (do_sync && !(pD3DCaps->Caps & D3DCAPS_READ_SCANLINE)) {
00562     wdxdisplay8_cat.info()
00563       << "HW doesnt support syncing to vertical refresh, ignoring sync-video\n";
00564     do_sync = false;
00565   }
00566 
00567   // verify the rendertarget fmt one last time
00568   if (FAILED(_d3d8->CheckDeviceFormat(display._card_id, D3DDEVTYPE_HAL, display._display_mode.Format, D3DUSAGE_RENDERTARGET,
00569                                       D3DRTYPE_SURFACE, presentation_params->BackBufferFormat))) {
00570     wdxdisplay8_cat.error() << "device #" << display._card_id << " CheckDeviceFmt failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl;
00571     goto Fallback_to_16bpp_buffers;
00572   }
00573 
00574   if (FAILED(_d3d8->CheckDeviceType(display._card_id, D3DDEVTYPE_HAL, display._display_mode.Format, presentation_params->BackBufferFormat,
00575                                     is_fullscreen()))) {
00576     wdxdisplay8_cat.error() << "device #" << display._card_id << " CheckDeviceType failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl;
00577     goto Fallback_to_16bpp_buffers;
00578   }
00579 
00580   if (display._presentation_params.EnableAutoDepthStencil) {
00581     if (!dxpipe->find_best_depth_format(display, display._display_mode,
00582                                         &display._presentation_params.AutoDepthStencilFormat,
00583                                         bWantStencil, false)) {
00584       wdxdisplay8_cat.error()
00585         << "find_best_depth_format failed in CreateScreenBuffers for device #"
00586         << display._card_id << endl;
00587       goto Fallback_to_16bpp_buffers;
00588     }
00589     _depth_buffer_bpp = D3DFMT_to_DepthBits(display._presentation_params.AutoDepthStencilFormat);
00590   } else {
00591     _depth_buffer_bpp = 0;
00592   }
00593 
00594   presentation_params->Windowed = !is_fullscreen();
00595 
00596   if (dx_multisample_antialiasing_level>1) {
00597     // need to check both rendertarget and zbuffer fmts
00598     hr = _d3d8->CheckDeviceMultiSampleType(display._card_id, D3DDEVTYPE_HAL, display._display_mode.Format,
00599                                            is_fullscreen(), D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level.get_value()));
00600     if (FAILED(hr)) {
00601       wdxdisplay8_cat.fatal() << "device #" << display._card_id << " doesnt support multisample level " << dx_multisample_antialiasing_level << "surface fmt " << D3DFormatStr(display._display_mode.Format) << endl;
00602       return false;
00603     }
00604 
00605     if (display._presentation_params.EnableAutoDepthStencil) {
00606       hr = _d3d8->CheckDeviceMultiSampleType(display._card_id, D3DDEVTYPE_HAL, display._presentation_params.AutoDepthStencilFormat,
00607                                              is_fullscreen(), D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level.get_value()));
00608       if (FAILED(hr)) {
00609         wdxdisplay8_cat.fatal() << "device #" << display._card_id << " doesnt support multisample level " << dx_multisample_antialiasing_level << "surface fmt " << D3DFormatStr(display._presentation_params.AutoDepthStencilFormat) << endl;
00610         return false;
00611       }
00612     }
00613 
00614     presentation_params->MultiSampleType = D3DMULTISAMPLE_TYPE(dx_multisample_antialiasing_level.get_value());
00615 
00616     if (wdxdisplay8_cat.is_info())
00617       wdxdisplay8_cat.info() << "device #" << display._card_id << " using multisample antialiasing level " << dx_multisample_antialiasing_level << endl;
00618   }
00619 
00620   presentation_params->BackBufferCount = 1;
00621   presentation_params->Flags = 0x0;
00622   presentation_params->hDeviceWindow = display._window;
00623   presentation_params->BackBufferWidth = display._display_mode.Width;
00624   presentation_params->BackBufferHeight = display._display_mode.Height;
00625 
00626   if (_wcontext._is_tnl_device) {
00627     dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
00628     // note: we could create a pure device in this case if I
00629     // eliminated the GetRenderState calls in dxgsg
00630 
00631     // also, no software vertex processing available since I specify
00632     // D3DCREATE_HARDWARE_VERTEXPROCESSING and not
00633     // D3DCREATE_MIXED_VERTEXPROCESSING
00634   } else {
00635     dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
00636   }
00637 
00638   if (dx_preserve_fpu_state)
00639     dwBehaviorFlags |= D3DCREATE_FPU_PRESERVE;
00640 
00641   // if window is not foreground in exclusive mode, ddraw thinks you
00642   // are 'not active', so it changes your WM_ACTIVATEAPP from true to
00643   // false, causing us to go into a 'wait-for WM_ACTIVATEAPP true'
00644   // loop, and the event never comes so we hang in fullscreen wait.
00645   // also doing this for windowed mode since it was requested.
00646   if (!SetForegroundWindow(display._window)) {
00647     wdxdisplay8_cat.warning() << "SetForegroundWindow() failed!\n";
00648   }
00649 
00650   if (is_fullscreen()) {
00651     // CREATE FULLSCREEN BUFFERS
00652 
00653     presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;  // we don't care about preserving contents of old frame
00654     presentation_params->FullScreen_PresentationInterval = (do_sync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE);
00655     presentation_params->FullScreen_RefreshRateInHz = display._display_mode.RefreshRate;
00656 
00657     ClearToBlack(display._window, get_properties());
00658 
00659     hr = _d3d8->CreateDevice(display._card_id, D3DDEVTYPE_HAL, _hWnd,
00660                              dwBehaviorFlags, presentation_params, &display._d3d_device);
00661 
00662     if (FAILED(hr)) {
00663       wdxdisplay8_cat.fatal() << "D3D CreateDevice failed for device #" << display._card_id << ", " << D3DERRORSTRING(hr);
00664 
00665       if (hr == D3DERR_OUTOFVIDEOMEMORY)
00666         goto Fallback_to_16bpp_buffers;
00667       else
00668         return false;
00669     }
00670 
00671     SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight);
00672 
00673   } else {
00674     // CREATE WINDOWED BUFFERS
00675 
00676     D3DDISPLAYMODE dispmode;
00677     hr = display._d3d8->GetAdapterDisplayMode(display._card_id, &dispmode);
00678 
00679     if (FAILED(hr)) {
00680       wdxdisplay8_cat.fatal()
00681         << "GetAdapterDisplayMode failed" << D3DERRORSTRING(hr);
00682       return false;
00683     }
00684 
00685     if (dispmode.Format == D3DFMT_P8) {
00686       wdxdisplay8_cat.fatal()
00687         << "Can't run windowed in an 8-bit or less display mode" << endl;
00688       return false;
00689     }
00690 
00691     presentation_params->FullScreen_PresentationInterval = 0;
00692 
00693     if (dx_multisample_antialiasing_level<2) {
00694       if (do_sync) {
00695         // It turns out that COPY_VSYNC has real performance problems
00696         // on many nVidia cards--it syncs at some random interval,
00697         // possibly skipping over several video syncs.  Screw it,
00698         // we'll effectively disable sync-video with windowed mode
00699         // using DirectX8.
00700         //presentation_params->SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
00701         presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
00702       } else {
00703         presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
00704       }
00705     } else {
00706       presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
00707     }
00708 
00709     //nassertv((dwRenderWidth == presentation_params->BackBufferWidth)&&(dwRenderHeight == presentation_params->BackBufferHeight));
00710 
00711     hr = _d3d8->CreateDevice(display._card_id, D3DDEVTYPE_HAL, _hWnd,
00712                              dwBehaviorFlags, presentation_params, &display._d3d_device);
00713 
00714     if (FAILED(hr)) {
00715       wdxdisplay8_cat.warning() << "presentation_params->BackBufferWidth : " << presentation_params->BackBufferWidth << endl;
00716       wdxdisplay8_cat.warning() << "presentation_params->BackBufferHeight : " << presentation_params->BackBufferHeight << endl;
00717       wdxdisplay8_cat.warning() << "presentation_params->BackBufferFormat : " << presentation_params->BackBufferFormat << endl;
00718       wdxdisplay8_cat.warning() << "presentation_params->BackBufferCount : " << presentation_params->BackBufferCount << endl;
00719       wdxdisplay8_cat.warning() << "D3D CreateDevice failed for device #" << display._card_id << D3DERRORSTRING(hr);
00720       goto Fallback_to_16bpp_buffers;
00721     }
00722   }  // end create windowed buffers
00723 
00724   //  ========================================================
00725 
00726   PRINT_REFCNT(wdxdisplay8, _wcontext._d3d_device);
00727 
00728   if (presentation_params->EnableAutoDepthStencil) {
00729     int depth_bits;
00730     int stencil_bits;
00731 
00732     depth_bits = 1;
00733     stencil_bits = 0;
00734     switch (presentation_params->AutoDepthStencilFormat)
00735     {
00736       case D3DFMT_D16_LOCKABLE:
00737         depth_bits = 16;
00738         break;
00739       case D3DFMT_D32:
00740         depth_bits = 32;
00741         break;
00742       case D3DFMT_D15S1:
00743         depth_bits = 15;
00744         stencil_bits = 1;
00745         break;
00746       case D3DFMT_D24S8:
00747         depth_bits = 24;
00748         stencil_bits = 8;
00749         break;
00750       case D3DFMT_D24X8:
00751         depth_bits = 24;
00752         break;
00753       case D3DFMT_D24X4S4:
00754         depth_bits = 24;
00755         stencil_bits = 4;
00756         break;
00757       case D3DFMT_D16:
00758         depth_bits = 16;
00759         break;
00760       default:
00761         wdxdisplay8_cat.error() << "unknown depth stencil format  " << presentation_params->AutoDepthStencilFormat;
00762         break;
00763     }
00764       
00765     _fb_properties.set_stencil_bits(stencil_bits);
00766     _fb_properties.set_depth_bits(depth_bits);
00767   } else {
00768     _fb_properties.set_depth_bits(0);
00769     _fb_properties.set_stencil_bits(0);
00770   }
00771 
00772   init_resized_window();
00773 
00774   return true;
00775 
00776  Fallback_to_16bpp_buffers:
00777   if ((!IS_16BPP_DISPLAY_FORMAT(presentation_params->BackBufferFormat)) &&
00778       (display._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) {
00779     // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers
00780 
00781     display._display_mode.Format = ((display._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5);
00782 
00783     if (wdxdisplay8_cat.info()) {
00784       wdxdisplay8_cat.info()
00785         << "CreateDevice failed with out-of-vidmem or invalid BackBufferFormat, retrying w/16bpp buffers on device #"
00786         << display._card_id << endl;
00787     }
00788     return create_screen_buffers_and_device(display, true);
00789     //return;
00790 
00791   } else if (!((dwRenderWidth == 640)&&(dwRenderHeight == 480))) {
00792     if (wdxdisplay8_cat.info())
00793       wdxdisplay8_cat.info() << "CreateDevice failed w/out-of-vidmem, retrying at 640x480 w/16bpp buffers on device #" << display._card_id << endl;
00794     // try final fallback to 640x480x16
00795     display._display_mode.Width = 640;
00796     display._display_mode.Height = 480;
00797     return create_screen_buffers_and_device(display, true);
00798     //return;
00799 
00800   } else {
00801     wdxdisplay8_cat.fatal()
00802       << "Can't create any screen buffers, bailing out.\n";
00803     return false;
00804   }
00805 }
00806 
00807 ////////////////////////////////////////////////////////////////////
00808 //     Function: wdxGraphicsWindow8::choose_device
00809 //       Access: Private
00810 //  Description: Looks at the list of available graphics adapters and
00811 //               chooses a suitable one for the window.
00812 //
00813 //               Returns true if successful, false on failure.
00814 ////////////////////////////////////////////////////////////////////
00815 bool wdxGraphicsWindow8::
00816 choose_device() {
00817   HRESULT hr;
00818 
00819   wdxGraphicsPipe8 *dxpipe;
00820   DCAST_INTO_R(dxpipe, _pipe, false);
00821 
00822   int num_adapters = dxpipe->__d3d8->GetAdapterCount();
00823   DXDeviceInfoVec device_infos;
00824 
00825   for (int i = 0; i < num_adapters; i++) {
00826     D3DADAPTER_IDENTIFIER8 adapter_info;
00827     ZeroMemory(&adapter_info, sizeof(D3DADAPTER_IDENTIFIER8));
00828     hr = dxpipe->__d3d8->GetAdapterIdentifier(i, D3DENUM_NO_WHQL_LEVEL, &adapter_info);
00829     if (FAILED(hr)) {
00830       wdxdisplay8_cat.fatal()
00831         << "D3D GetAdapterID(" << i << ") failed: "
00832         << D3DERRORSTRING(hr) << endl;
00833       continue;
00834     }
00835 
00836     LARGE_INTEGER *DrvVer = &adapter_info.DriverVersion;
00837 
00838     wdxdisplay8_cat.info()
00839       << "D3D8." << (dxpipe->__is_dx8_1 ?"1":"0") << " Adapter[" << i << "]: " << adapter_info.Description
00840       << ", Driver: " << adapter_info.Driver << ", DriverVersion: ("
00841       << HIWORD(DrvVer->HighPart) << "." << LOWORD(DrvVer->HighPart) << "."
00842       << HIWORD(DrvVer->LowPart) << "." << LOWORD(DrvVer->LowPart)
00843       << ")\nVendorID: 0x" << (void*) adapter_info.VendorId
00844       << " DeviceID: 0x" <<  (void*) adapter_info.DeviceId
00845       << " SubsysID: 0x" << (void*) adapter_info.SubSysId
00846       << " Revision: 0x" << (void*) adapter_info.Revision << endl;
00847 
00848     HMONITOR _monitor = dxpipe->__d3d8->GetAdapterMonitor(i);
00849     if (_monitor == NULL) {
00850       wdxdisplay8_cat.info()
00851         << "D3D8 Adapter[" << i << "]: seems to be disabled, skipping it\n";
00852       continue;
00853     }
00854 
00855     DXDeviceInfo devinfo;
00856     ZeroMemory(&devinfo, sizeof(devinfo));
00857     memcpy(&devinfo.guidDeviceIdentifier, &adapter_info.DeviceIdentifier,
00858            sizeof(GUID));
00859     strncpy(devinfo.szDescription, adapter_info.Description,
00860             MAX_DEVICE_IDENTIFIER_STRING);
00861     strncpy(devinfo.szDriver, adapter_info.Driver,
00862             MAX_DEVICE_IDENTIFIER_STRING);
00863     devinfo.VendorID = adapter_info.VendorId;
00864     devinfo.DeviceID = adapter_info.DeviceId;
00865     devinfo._monitor = _monitor;
00866     devinfo.cardID = i;
00867 
00868     device_infos.push_back(devinfo);
00869   }
00870 
00871   if (device_infos.empty()) {
00872     wdxdisplay8_cat.error()
00873       << "No available D3D8 devices found.\n";
00874     return false;
00875   }
00876 
00877   // Since some adapters may have been disabled, we should re-obtain
00878   // the number of available adapters.
00879   num_adapters = (int)device_infos.size();
00880 
00881   // Now choose a suitable adapter.
00882 
00883   int adapter_num = D3DADAPTER_DEFAULT;
00884 
00885   // Eventually, we should have some interface for specifying a device
00886   // index interactively, instead of only via Configrc.
00887   if (dx_preferred_device_id != -1) {
00888     if (dx_preferred_device_id < 0 || dx_preferred_device_id >= num_adapters) {
00889       wdxdisplay8_cat.error()
00890         << "invalid 'dx-preferred-device-id', valid values are 0-"
00891         << num_adapters - 1 << ", using default adapter instead.\n";
00892     } else {
00893       adapter_num = dx_preferred_device_id;
00894     }
00895   }
00896 
00897   UINT good_device_count = 0;
00898   for(UINT devnum = 0;devnum<device_infos.size() /*&& (good_device_count < num_windows)*/;devnum++) {
00899     if (search_for_device(dxpipe, &device_infos[devnum]))
00900       good_device_count++;
00901   }
00902 
00903   if (good_device_count == 0) {
00904     wdxdisplay8_cat.error() << "no usable display devices.\n";
00905     return false;
00906   }
00907 
00908   return true;
00909 }
00910 
00911 ////////////////////////////////////////////////////////////////////
00912 //     Function: wdxGraphicsWindow8::search_for_device
00913 //       Access: Private
00914 //  Description: Searches for a suitable hardware device for
00915 //               rendering.
00916 ////////////////////////////////////////////////////////////////////
00917 bool wdxGraphicsWindow8::
00918 search_for_device(wdxGraphicsPipe8 *dxpipe, DXDeviceInfo *device_info) {
00919 
00920   nassertr(dxpipe != NULL, false);
00921   WindowProperties properties = get_properties();
00922   DWORD dwRenderWidth = properties.get_x_size();
00923   DWORD dwRenderHeight = properties.get_y_size();
00924   HRESULT hr;
00925   LPDIRECT3D8 _d3d8 = dxpipe->__d3d8;
00926 
00927   nassertr(_dxgsg != NULL, false);
00928   _wcontext._d3d8 = _d3d8;
00929   _wcontext._is_dx8_1 = dxpipe->__is_dx8_1;
00930   _wcontext._card_id = device_info->cardID;  // could this change by end?
00931 
00932   bool bWantStencil = (_fb_properties.get_stencil_bits() > 0);
00933 
00934   hr = _d3d8->GetAdapterIdentifier(device_info->cardID, D3DENUM_NO_WHQL_LEVEL,
00935                                    &_wcontext._dx_device_id);
00936   if (FAILED(hr)) {
00937     wdxdisplay8_cat.error()
00938       << "D3D GetAdapterID failed" << D3DERRORSTRING(hr);
00939     return false;
00940   }
00941 
00942   D3DCAPS8 _d3dcaps;
00943   hr = _d3d8->GetDeviceCaps(device_info->cardID, D3DDEVTYPE_HAL, &_d3dcaps);
00944   if (FAILED(hr)) {
00945     if ((hr == D3DERR_INVALIDDEVICE)||(hr == D3DERR_NOTAVAILABLE)) {
00946       wdxdisplay8_cat.error()
00947         << "No DirectX 8 D3D-capable 3D hardware detected for device # "
00948         << device_info->cardID << " (" << device_info->szDescription
00949         << ")!\n";
00950     } else {
00951       wdxdisplay8_cat.error()
00952         << "GetDeviceCaps failed: " << D3DERRORSTRING(hr) << endl;
00953     }
00954     return false;
00955   }
00956 
00957   //search_for_valid_displaymode needs these to be set
00958   memcpy(&_wcontext._d3dcaps, &_d3dcaps, sizeof(D3DCAPS8));
00959   _wcontext._card_id = device_info->cardID;
00960 
00961   _wcontext._max_available_video_memory = UNKNOWN_VIDMEM_SIZE;
00962   _wcontext._is_low_memory_card = false;
00963 
00964   // bugbug: wouldnt we like to do GetAVailVidMem so we can do
00965   // upper-limit memory computation for dx8 cards too?  otherwise
00966   // verify_window_sizes cant do much
00967   if (_d3dcaps.MaxStreams == 0) {
00968     if (wdxdisplay8_cat.is_debug()) {
00969       wdxdisplay8_cat.debug()
00970         << "checking vidmem size\n";
00971     }
00972 
00973     UINT IDnum;
00974 
00975     // simple linear search to match DX7 card info w/DX8 card ID
00976     for (IDnum = 0; IDnum < dxpipe->_card_ids.size(); IDnum++) {
00977       if ((device_info->VendorID == dxpipe->_card_ids[IDnum].VendorID) &&
00978           (device_info->DeviceID == dxpipe->_card_ids[IDnum].DeviceID) &&
00979           (device_info->_monitor == dxpipe->_card_ids[IDnum]._monitor))
00980         break;
00981     }
00982 
00983     if (IDnum < dxpipe->_card_ids.size()) {
00984       _wcontext._max_available_video_memory = dxpipe->_card_ids[IDnum]._max_available_video_memory;
00985       _wcontext._is_low_memory_card = dxpipe->_card_ids[IDnum]._is_low_memory_card;
00986     } else {
00987       wdxdisplay8_cat.error()
00988         << "Error: couldnt find a CardID match in DX7 info, assuming card is not a lowmem card\n";
00989     }
00990   }
00991 
00992   if ((bWantStencil) && (_d3dcaps.StencilCaps == 0x0)) {
00993     wdxdisplay8_cat.fatal()
00994       << "Stencil ability requested, but device #" << device_info->cardID
00995       << " (" << _wcontext._dx_device_id.Description
00996       << "), has no stencil capability!\n";
00997     return false;
00998   }
00999 
01000   // just because TNL is true, it doesnt mean vtx shaders are
01001   // supported in HW (see GF2) for this case, you probably want MIXED
01002   // processing to use HW for fixed-fn vertex processing and SW for
01003   // vtx shaders
01004   _wcontext._is_tnl_device =
01005     ((_d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0);
01006   _wcontext._can_use_hw_vertex_shaders =
01007     (_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(1, 0));
01008   _wcontext._can_use_pixel_shaders =
01009     (_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(1, 0));
01010 
01011   bool bNeedZBuffer =
01012     ((!(_d3dcaps.RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) &&
01013      (_fb_properties.get_depth_bits() > 0));
01014 
01015   _wcontext._presentation_params.EnableAutoDepthStencil = bNeedZBuffer;
01016 
01017   D3DFORMAT pixFmt = D3DFMT_UNKNOWN;
01018 
01019   if (is_fullscreen()) {
01020     bool bCouldntFindValidZBuf;
01021     dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight,
01022                                          bNeedZBuffer, bWantStencil,
01023                                          &_wcontext._supported_screen_depths_mask,
01024                                          &bCouldntFindValidZBuf,
01025                                          &pixFmt, dx_force_16bpp_zbuffer);
01026     
01027     // note I'm not saving refresh rate, will just use adapter
01028     // default at given res for now
01029     
01030     if (pixFmt == D3DFMT_UNKNOWN) {
01031       wdxdisplay8_cat.error()
01032         << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
01033         << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _wcontext._card_id << endl;
01034       
01035       // run it again in verbose mode to get more dbg info to log
01036       dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight,
01037                                            bNeedZBuffer, bWantStencil,
01038                                            &_wcontext._supported_screen_depths_mask,
01039                                            &bCouldntFindValidZBuf,
01040                                            &pixFmt, dx_force_16bpp_zbuffer, true);
01041       
01042       // if still D3DFMT_UNKNOWN return false
01043       if (pixFmt == D3DFMT_UNKNOWN)
01044         return false;
01045     }
01046   } else {
01047     // Windowed Mode
01048 
01049     D3DDISPLAYMODE dispmode;
01050     hr = _d3d8->GetAdapterDisplayMode(device_info->cardID, &dispmode);
01051     if (FAILED(hr)) {
01052       wdxdisplay8_cat.error()
01053         << "GetAdapterDisplayMode(" << device_info->cardID
01054         << ") failed" << D3DERRORSTRING(hr);
01055       return false;
01056     }
01057     pixFmt = dispmode.Format;
01058   }
01059 
01060   _wcontext._display_mode.Width = dwRenderWidth;
01061   _wcontext._display_mode.Height = dwRenderHeight;
01062   _wcontext._display_mode.Format = pixFmt;
01063   _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT;
01064   _wcontext._monitor = device_info->_monitor;
01065 
01066   if (dwRenderWidth != properties.get_x_size() ||
01067       dwRenderHeight != properties.get_y_size()) {
01068     // This is probably not the best place to put this; I'm just
01069     // putting it here for now because the code above might have
01070     // changed the size of the window unexpectedly.  This code gets
01071     // called when make_gsg() is called, which means it is called in
01072     // the draw thread, but this method should really be called from
01073     // the window thread.  In DirectX those may always be the same
01074     // threads anyway, so we may be all right.  Still, it's a little
01075     // strange that the window may change size after it has already
01076     // been opened, at the time we create the GSG for it; it would be
01077     // better if we could find a way to do this resolution-selection
01078     // logic earlier, say at the time the window is created.
01079     system_changed_size(dwRenderWidth, dwRenderHeight);
01080     WindowProperties resized_props;
01081     resized_props.set_size(dwRenderWidth, dwRenderHeight);
01082     _properties.add_properties(resized_props);
01083   }
01084 
01085   return true;
01086 }
01087 
01088 ////////////////////////////////////////////////////////////////////
01089 //     Function: wdxGraphicsWindow8::reset_device_resize_window
01090 //       Access: Private
01091 //  Description: Called after a window (either fullscreen or windowed)
01092 //               has been resized, this recreates the D3D structures
01093 //               to match the new size.
01094 ////////////////////////////////////////////////////////////////////
01095 bool wdxGraphicsWindow8::
01096 reset_device_resize_window(UINT new_xsize, UINT new_ysize) {
01097   nassertr((new_xsize > 0) && (new_ysize > 0), false);
01098   bool retval = true;
01099 
01100   DXScreenData *screen = NULL;
01101   D3DPRESENT_PARAMETERS d3dpp;
01102   memcpy(&d3dpp, &_wcontext._presentation_params, sizeof(D3DPRESENT_PARAMETERS));
01103   _wcontext._presentation_params.BackBufferWidth = new_xsize;
01104   _wcontext._presentation_params.BackBufferHeight = new_ysize;
01105   make_current();
01106   HRESULT hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen);
01107 
01108   if (FAILED(hr)) {
01109     retval = false;
01110     wdxdisplay8_cat.error()
01111       << "reset_device_resize_window Reset() failed" << D3DERRORSTRING(hr);
01112     if (hr == D3DERR_OUTOFVIDEOMEMORY) {
01113       memcpy(&_wcontext._presentation_params, &d3dpp, sizeof(D3DPRESENT_PARAMETERS));
01114       hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen);
01115       if (FAILED(hr)) {
01116         wdxdisplay8_cat.error()
01117           << "reset_device_resize_window Reset() failed OutOfVidmem, then failed again doing Reset w/original params:" << D3DERRORSTRING(hr);
01118         throw_event("panda3d-render-error");
01119         return false;
01120 
01121       } else {
01122         if (wdxdisplay8_cat.is_info()) {
01123           wdxdisplay8_cat.info()
01124             << "reset of original size (" << _wcontext._presentation_params.BackBufferWidth
01125             << ", " << _wcontext._presentation_params.BackBufferHeight << ") succeeded\n";
01126         }
01127       }
01128     } else {
01129       wdxdisplay8_cat.fatal()
01130         << "Can't reset device, bailing out.\n";
01131       throw_event("panda3d-render-error");
01132       return false;
01133     }
01134   }
01135   // before you init_resized_window you need to copy certain changes to _wcontext
01136   if (screen) {
01137     _wcontext._swap_chain = screen->_swap_chain;
01138   }
01139   wdxdisplay8_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n";
01140   _gsg->mark_new();
01141   init_resized_window();
01142   return retval;
01143 }
01144 
01145 ////////////////////////////////////////////////////////////////////
01146 //     Function: wdxGraphicsWindow8::init_resized_window
01147 //       Access: Private
01148 //  Description: Reinitializes the window after it has been resized,
01149 //               or after it is first created.
01150 //
01151 //               Assumes CreateDevice or Device->Reset() has just been
01152 //               called, and the new size is specified in
01153 //               _wcontext._presentation_params.
01154 ////////////////////////////////////////////////////////////////////
01155 void wdxGraphicsWindow8::
01156 init_resized_window() {
01157   HRESULT hr;
01158 
01159   DWORD newWidth = _wcontext._presentation_params.BackBufferWidth;
01160   DWORD newHeight = _wcontext._presentation_params.BackBufferHeight;
01161 
01162   nassertv((newWidth != 0) && (newHeight != 0));
01163   nassertv(_wcontext._window != NULL);
01164 
01165   if (_wcontext._presentation_params.Windowed) {
01166     POINT ul, lr;
01167     RECT client_rect;
01168 
01169     // need to figure out x, y origin offset of window client area on screen
01170     // (we already know the client area size)
01171 
01172     GetClientRect(_wcontext._window, &client_rect);
01173     ul.x = client_rect.left;
01174     ul.y = client_rect.top;
01175     lr.x = client_rect.right;
01176     lr.y = client_rect.bottom;
01177     ClientToScreen(_wcontext._window, &ul);
01178     ClientToScreen(_wcontext._window, &lr);
01179     client_rect.left = ul.x;
01180     client_rect.top = ul.y;
01181     client_rect.right = lr.x;
01182     client_rect.bottom = lr.y;
01183   }
01184 
01185   // clear window to black ASAP
01186   nassertv(_wcontext._window != NULL);
01187   ClearToBlack(_wcontext._window, get_properties());
01188 
01189   // clear textures and VB's out of video&AGP mem, so cache is reset
01190   hr = _wcontext._d3d_device->ResourceManagerDiscardBytes(0);
01191   if (FAILED(hr)) {
01192     wdxdisplay8_cat.error()
01193       << "ResourceManagerDiscardBytes failed for device #"
01194       << _wcontext._card_id << D3DERRORSTRING(hr);
01195   }
01196 
01197   make_current();
01198 }
01199 
01200 ////////////////////////////////////////////////////////////////////
01201 //     Function: wdxGraphicsWindow8::D3DFMT_to_DepthBits
01202 //       Access: Private, Static
01203 //  Description: Returns the number of depth bits represented by the
01204 //               indicated D3DFORMAT value.
01205 ////////////////////////////////////////////////////////////////////
01206 int wdxGraphicsWindow8::
01207 D3DFMT_to_DepthBits(D3DFORMAT fmt) {
01208   switch(fmt) {
01209   case D3DFMT_D16:
01210     return 16;
01211 
01212   case D3DFMT_D24X8:
01213   case D3DFMT_D24X4S4:
01214   case D3DFMT_D24S8:
01215     return 24;
01216 
01217   case D3DFMT_D32:
01218     return 32;
01219 
01220   case D3DFMT_D15S1:
01221     return 15;
01222 
01223   default:
01224     wdxdisplay8_cat.debug()
01225       << "D3DFMT_DepthBits: unhandled D3DFMT!\n";
01226     return 0;
01227   }
01228 }
01229 
01230 ////////////////////////////////////////////////////////////////////
01231 //     Function: wdxGraphicsWindow8::is_badvidmem_card
01232 //       Access: Private, Static
01233 //  Description: Returns true if the indicated video adapter card is
01234 //               known to report an inaccurate figure for available
01235 //               video memory.
01236 ////////////////////////////////////////////////////////////////////
01237 bool wdxGraphicsWindow8::
01238 is_badvidmem_card(D3DADAPTER_IDENTIFIER8 *pDevID) {
01239   // don't trust Intel cards since they often use regular memory as vidmem
01240   if (pDevID->VendorId == 0x00008086) {
01241     return true;
01242   }
01243 
01244   return false;
01245 }