Panda3D

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