Panda3D

wdxGraphicsWindow9.cxx

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