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