Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/dxgsg7/wdxGraphicsWindow7.cxx

Go to the documentation of this file.
00001 // Filename: wdxGraphicsWindow7.cxx
00002 // Created by:  drose (20Dec02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "wdxGraphicsWindow7.h"
00020 #include "config_dxgsg7.h"
00021 #include "config_windisplay.h"
00022 #include "wdxGraphicsPipe7.h"
00023 #include "dxGraphicsStateGuardian7.h"
00024 
00025 #include <wingdi.h>
00026 
00027 static DWORD
00028 BitDepth_2_DDBDMask(DWORD iBitDepth) {
00029   switch (iBitDepth) {
00030   case 16: return DDBD_16;
00031   case 32: return DDBD_32;
00032   case 24: return DDBD_24;
00033   case 8: return DDBD_8;
00034   case 1: return DDBD_1;
00035   case 2: return DDBD_2;
00036   case 4: return DDBD_4;
00037   }
00038   return 0x0;
00039 }
00040 
00041 #define MAX_DX_ZBUF_FMTS 20
00042 static int cNumZBufFmts;
00043 
00044 HRESULT CALLBACK
00045 EnumZBufFmtsCallback(LPDDPIXELFORMAT pddpf, VOID *param)  {
00046   DDPIXELFORMAT *ZBufFmtsArr = (DDPIXELFORMAT *) param;
00047   assert(cNumZBufFmts < MAX_DX_ZBUF_FMTS);
00048   memcpy(&(ZBufFmtsArr[cNumZBufFmts]), pddpf, sizeof(DDPIXELFORMAT));
00049   cNumZBufFmts++;
00050   return DDENUMRET_OK;
00051 }
00052 
00053 HRESULT CALLBACK
00054 EnumDevicesCallback(LPSTR pDeviceDescription, LPSTR pDeviceName,
00055                     LPD3DDEVICEDESC7 pD3DDeviceDesc,LPVOID pContext) {
00056   D3DDEVICEDESC7 *pd3ddevs = (D3DDEVICEDESC7 *)pContext;
00057 #ifdef _DEBUG
00058   wdxdisplay7_cat.spam()
00059     << "Enumerating Device " << pDeviceName << " : " 
00060     << pDeviceDescription << endl;
00061 #endif
00062 
00063 #define REGHALIDX 0
00064 #define TNLHALIDX 1
00065 #define SWRASTIDX 2
00066   
00067   if (IsEqualGUID(pD3DDeviceDesc->deviceGUID, IID_IDirect3DHALDevice)) {
00068     CopyMemory(&pd3ddevs[REGHALIDX], pD3DDeviceDesc, sizeof(D3DDEVICEDESC7));
00069   } else if (IsEqualGUID(pD3DDeviceDesc->deviceGUID, IID_IDirect3DTnLHalDevice)) {
00070     CopyMemory(&pd3ddevs[TNLHALIDX], pD3DDeviceDesc, sizeof(D3DDEVICEDESC7));
00071   } else if(IsEqualGUID(pD3DDeviceDesc->deviceGUID, IID_IDirect3DRGBDevice)) {
00072     CopyMemory(&pd3ddevs[SWRASTIDX], pD3DDeviceDesc, sizeof(D3DDEVICEDESC7));
00073   }
00074   return DDENUMRET_OK;
00075 }
00076 
00077 #define MAX_DISPLAY_MODES 100  // probably dont need this much, since i already screen for width&hgt
00078 typedef struct {
00079   DWORD maxWidth,maxHeight;
00080   DWORD supportedBitDepths;    // uses DDBD_* flags
00081   LPDDSURFACEDESC2 pDDSD_Arr;
00082   DWORD cNumSurfDescs;
00083 } DisplayModeInfo;
00084 
00085 HRESULT WINAPI
00086 EnumDisplayModesCallBack(LPDDSURFACEDESC2 lpDDSurfaceDesc,LPVOID lpContext) {
00087   DisplayModeInfo *pDMI = (DisplayModeInfo *) lpContext;
00088   
00089   // ddsd_search should assure this is true
00090   assert((lpDDSurfaceDesc->dwWidth == pDMI->maxWidth) && (lpDDSurfaceDesc->dwHeight == pDMI->maxHeight));
00091   
00092   // ignore refresh rates under 60Hz (and special values of 0 & 1)
00093   if ((lpDDSurfaceDesc->dwRefreshRate > 1) && 
00094       (lpDDSurfaceDesc->dwRefreshRate < 60)) {
00095     return DDENUMRET_OK;
00096   }
00097   
00098   assert(pDMI->cNumSurfDescs < MAX_DISPLAY_MODES);
00099   memcpy(&(pDMI->pDDSD_Arr[pDMI->cNumSurfDescs]), lpDDSurfaceDesc, sizeof(DDSURFACEDESC2));
00100   pDMI->cNumSurfDescs++;
00101   pDMI->supportedBitDepths |= BitDepth_2_DDBDMask(lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount);
00102   
00103   return DDENUMRET_OK;
00104 }
00105 
00106 // imperfect method to ID NVid? could also scan desc str, but that isnt fullproof either
00107 #define IS_NVIDIA(DDDEVICEID) ((DDDEVICEID.dwVendorId==0x10DE) || (DDDEVICEID.dwVendorId==0x12D2))
00108 #define IS_ATI(DDDEVICEID) (DDDEVICEID.dwVendorId==0x1002) 
00109 #define IS_MATROX(DDDEVICEID) (DDDEVICEID.dwVendorId==0x102B)
00110 
00111 TypeHandle wdxGraphicsWindow7::_type_handle;
00112 
00113 ////////////////////////////////////////////////////////////////////
00114 //     Function: wdxGraphicsWindow7::Constructor
00115 //       Access: Public
00116 //  Description:
00117 ////////////////////////////////////////////////////////////////////
00118 wdxGraphicsWindow7::
00119 wdxGraphicsWindow7(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) :
00120   WinGraphicsWindow(pipe, gsg) 
00121 {
00122   _dxgsg = DCAST(DXGraphicsStateGuardian7, gsg);
00123   ZeroMemory(&_wcontext,sizeof(_wcontext));
00124 }
00125 
00126 ////////////////////////////////////////////////////////////////////
00127 //     Function: wdxGraphicsWindow7::Destructor
00128 //       Access: Public, Virtual
00129 //  Description:
00130 ////////////////////////////////////////////////////////////////////
00131 wdxGraphicsWindow7::
00132 ~wdxGraphicsWindow7() {
00133 }
00134 
00135 void wdxGraphicsWindow7::
00136 make_current(void) {
00137   DXGraphicsStateGuardian7 *dxgsg;
00138   DCAST_INTO_V(dxgsg, _gsg);
00139   //wglMakeCurrent(_hdc, wdxgsg->_context);
00140   dxgsg->set_context(&_wcontext);
00141 
00142   // Now that we have made the context current to a window, we can
00143   // reset the GSG state if this is the first time it has been used.
00144   // (We can't just call reset() when we construct the GSG, because
00145   // reset() requires having a current context.)
00146   dxgsg->reset_if_new();
00147 }
00148 
00149 ////////////////////////////////////////////////////////////////////
00150 //     Function: wdxGraphicsWindow7::open_window
00151 //       Access: Protected, Virtual
00152 //  Description: Opens the window right now.  Called from the window
00153 //               thread.  Returns true if the window is successfully
00154 //               opened, or false if there was a problem.
00155 ////////////////////////////////////////////////////////////////////
00156 bool wdxGraphicsWindow7::
00157 open_window(void) {
00158   
00159   if (!choose_device(0, NULL)) {
00160     wdxdisplay7_cat.error() << "Unable to find suitable rendering device.\n";
00161     return false;
00162   }
00163 
00164   if (!WinGraphicsWindow::open_window()) {
00165     return false;
00166   }
00167 
00168   _wcontext.hWnd = _hWnd;
00169   set_coop_levels_and_display_modes();
00170   create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer);
00171 
00172   return true;
00173 }
00174 
00175 /*
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: wdxGraphicsWindow7::make_gsg
00178 //       Access: Public, Virtual
00179 //  Description: Creates a new GSG for the window and stores it in the
00180 //               _gsg pointer.  This should only be called from within
00181 //               the draw thread.
00182 ////////////////////////////////////////////////////////////////////
00183 void wdxGraphicsWindow7::
00184 make_gsg() {
00185   nassertv(_gsg == (GraphicsStateGuardian *)NULL);
00186   _dxgsg = new DXGraphicsStateGuardian7(this);
00187   _gsg = _dxgsg;
00188   // Tell the associated dxGSG about the window handle.
00189   _wcontext.hWnd = _hWnd;
00190 
00191   if (!choose_device(0, NULL)) {
00192     wdxdisplay7_cat.error()
00193       << "Unable to find suitable rendering device.\n";
00194     release_gsg();
00195     return;
00196   }
00197 
00198   set_coop_levels_and_display_modes();
00199   create_screen_buffers_and_device(_dxgsg->scrn, dx_force_16bpp_zbuffer);
00200 }
00201 */
00202 
00203 ////////////////////////////////////////////////////////////////////
00204 //     Function: wdxGraphicsWindow7::end_flip
00205 //       Access: Public, Virtual
00206 //  Description: This function will be called within the draw thread
00207 //               after begin_flip() has been called on all windows, to
00208 //               finish the exchange of the front and back buffers.
00209 //
00210 //               This should cause the window to wait for the flip, if
00211 //               necessary.
00212 ////////////////////////////////////////////////////////////////////
00213 void wdxGraphicsWindow7::
00214 end_flip() {
00215   if (_dxgsg != (DXGraphicsStateGuardian7 *)NULL && is_active()) {
00216     _dxgsg->show_frame();
00217   }
00218 }
00219 
00220 ////////////////////////////////////////////////////////////////////
00221 //     Function: wdxGraphicsWindow7::fullscreen_restored
00222 //       Access: Protected, Virtual
00223 //  Description: This is a hook for derived classes to do something
00224 //               special, if necessary, when a fullscreen window has
00225 //               been restored after being minimized.  The given
00226 //               WindowProperties struct will be applied to this
00227 //               window's properties after this function returns.
00228 ////////////////////////////////////////////////////////////////////
00229 void wdxGraphicsWindow7::
00230 fullscreen_restored(WindowProperties &properties) {
00231   // For some reason, this message comes in twice, once while the
00232   // fullscreen window is still minimized, and once again when it has
00233   // been restored.
00234 
00235   // In DX7, it seems to be necessary to render one frame between the
00236   // two cases, so we must set the minimized property to false even in
00237   // the first case.
00238   properties.set_minimized(false);
00239 }
00240 
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: wdxGraphicsWindow7::handle_reshape
00243 //       Access: Protected, Virtual
00244 //  Description: Called in the window thread when the window size or
00245 //               location is changed, this updates the properties
00246 //               structure accordingly.
00247 ////////////////////////////////////////////////////////////////////
00248 void wdxGraphicsWindow7::
00249 handle_reshape() {
00250   GdiFlush();
00251   WinGraphicsWindow::handle_reshape();
00252 
00253   if (_dxgsg!=NULL) {
00254     HRESULT hr;
00255 
00256     if (_wcontext.pddsBack == NULL) {
00257       // assume this is initial creation reshape and ignore this call
00258       return;
00259     }
00260 
00261     // Clear the back/primary surface to black using ddraw
00262     DX_DECLARE_CLEAN(DDBLTFX, bltfx);
00263     bltfx.dwDDFX |= DDBLTFX_NOTEARING;
00264     hr = _wcontext.pddsPrimary->Blt
00265       (NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx);
00266     if (FAILED(hr)) {
00267       wdxdisplay7_cat.fatal()
00268         << "Blt to Black of Primary Surf failed! : result = "
00269         << ConvD3DErrorToString(hr) << endl;
00270       exit(1);
00271     }
00272 
00273     hr = _wcontext.pDD->TestCooperativeLevel();
00274     if (FAILED(hr)) {
00275       wdxdisplay7_cat.error()
00276         << "TestCooperativeLevel failed : result = "
00277         << ConvD3DErrorToString(hr) << endl;
00278       return;
00279     }
00280 
00281     _dxgsg->RestoreAllVideoSurfaces();
00282 
00283     set_to_temp_rendertarget();
00284 
00285     // create the new resized rendertargets
00286     //RECT view_rect;
00287     //get_client_rect_screen(hWnd, &view_rect);
00288     //_dxgsg->dx_setup_after_resize(view_rect, &_wcontext);
00289 
00290     RECT view_rect;
00291     get_client_rect_screen(_wcontext.hWnd, &view_rect);
00292     _dxgsg->dx_setup_after_resize(&view_rect);
00293   }
00294 }
00295 
00296 ////////////////////////////////////////////////////////////////////
00297 //     Function: wdxGraphicsWindow7::do_fullscreen_resize
00298 //       Access: Protected, Virtual
00299 //  Description: Called in the window thread to resize a fullscreen
00300 //               window.
00301 ////////////////////////////////////////////////////////////////////
00302 bool wdxGraphicsWindow7::
00303 do_fullscreen_resize(int x_size, int y_size) {
00304   _dxgsg->SetDXReady(false);
00305 
00306   HRESULT hr;
00307 
00308   DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_curmode);
00309 
00310   hr = _wcontext.pDD->GetDisplayMode(&ddsd_curmode);
00311   if (FAILED(hr)) {
00312     wdxdisplay7_cat.fatal() 
00313       << "resize() - GetDisplayMode failed, result = "
00314       << ConvD3DErrorToString(hr) << endl;
00315     exit(1);
00316   }
00317 
00318   DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd_search);
00319 
00320   ddsd_search.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
00321   ddsd_search.dwWidth=x_size;  
00322   ddsd_search.dwHeight=y_size;
00323 
00324   // not requesting same refresh rate since changing res might not
00325   // support same refresh rate
00326 
00327   DDSURFACEDESC2 DDSD_Arr[MAX_DISPLAY_MODES];
00328   DisplayModeInfo DMI;
00329   ZeroMemory(&DDSD_Arr,sizeof(DDSD_Arr));
00330   ZeroMemory(&DMI,sizeof(DMI));
00331   DMI.maxWidth = x_size;  
00332   DMI.maxHeight = y_size;
00333   DMI.pDDSD_Arr = DDSD_Arr;
00334 
00335   hr = _wcontext.pDD->EnumDisplayModes(DDEDM_REFRESHRATES, &ddsd_search,
00336                                           &DMI, EnumDisplayModesCallBack);
00337   if (FAILED(hr)) {
00338     wdxdisplay7_cat.fatal()
00339       << "resize() - EnumDisplayModes failed, result = "
00340       << ConvD3DErrorToString(hr) << endl;
00341     return false;
00342   }
00343 
00344   DMI.supportedBitDepths &= _wcontext.D3DDevDesc.dwDeviceRenderBitDepth;
00345 
00346   DWORD dwFullScreenBitDepth;
00347   DWORD requested_bpp = ddsd_curmode.ddpfPixelFormat.dwRGBBitCount;
00348 
00349   // would like to match current bpp first.  if that is not possible,
00350   // try 16bpp, then 32
00351   DWORD requested_bpp_DDBD = BitDepth_2_DDBDMask(requested_bpp);
00352 
00353   if (DMI.supportedBitDepths & requested_bpp_DDBD) {
00354     dwFullScreenBitDepth = requested_bpp;
00355   } else if (DMI.supportedBitDepths & DDBD_16) {
00356     dwFullScreenBitDepth = 16;
00357   } else if (DMI.supportedBitDepths & DDBD_32) {
00358     dwFullScreenBitDepth = 32;
00359   } else {
00360     wdxdisplay7_cat.error()
00361       << "resize failed, no fullScreen resolutions at " << x_size
00362       << "x" << y_size << endl;
00363     return false;
00364   }
00365 
00366   hr = _wcontext.pDD->TestCooperativeLevel();
00367   if (FAILED(hr)) {
00368     wdxdisplay7_cat.error()
00369       << "TestCooperativeLevel failed : result = " 
00370       << ConvD3DErrorToString(hr) << endl;
00371     wdxdisplay7_cat.error()
00372       << "Full screen app failed to get exclusive mode on resize, exiting..\n";
00373     return false;
00374   }
00375 
00376   _dxgsg->free_dxgsg_objects();
00377 
00378    // let driver choose default refresh rate (hopefully its >=60Hz)   
00379   hr = _wcontext.pDD->SetDisplayMode(x_size, y_size, dwFullScreenBitDepth,
00380                                         0L, 0L);
00381   if (FAILED(hr)) {
00382     wdxdisplay7_cat.error()
00383       << "resize failed to reset display mode to (" 
00384       << x_size << "x" << y_size << "x" 
00385       << dwFullScreenBitDepth << "): result = " 
00386       << ConvD3DErrorToString(hr) << endl;
00387   }
00388 
00389   if (wdxdisplay7_cat.is_debug()) {
00390     DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd34); 
00391     _wcontext.pDD->GetDisplayMode(&ddsd34);
00392     wdxdisplay7_cat.debug()
00393       << "set displaymode to " << ddsd34.dwWidth << "x" << ddsd34.dwHeight
00394       << " at "<< ddsd34.ddpfPixelFormat.dwRGBBitCount << "bpp, "
00395       << ddsd34.dwRefreshRate << "Hz\n";
00396   }
00397 
00398   _wcontext.dwRenderWidth = x_size;
00399   _wcontext.dwRenderHeight = y_size;
00400 
00401   create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer);
00402   _dxgsg->RecreateAllVideoSurfaces();
00403   _dxgsg->SetDXReady(true);
00404   return true;
00405 }
00406 
00407 ////////////////////////////////////////////////////////////////////
00408 //     Function: wdxGraphicsWindow7::set_to_temp_rendertarget
00409 //       Access: Private
00410 //  Description: Constructs a temporary tiny render target for the d3d
00411 //               device (and sets the d3d device to use it).  This is
00412 //               called by handle_reshape() just before the full-sized
00413 //               rendertargets are constructed, in order to save video
00414 //               memory and thereby allow resizing of the window to
00415 //               work on 4MB cards.
00416 ////////////////////////////////////////////////////////////////////
00417 bool wdxGraphicsWindow7::
00418 set_to_temp_rendertarget() {
00419   LPDIRECTDRAWSURFACE7 pddsDummy = NULL, pddsDummyZ = NULL;
00420   ULONG refcnt;
00421   HRESULT hr;
00422     
00423   DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd);
00424 
00425   _wcontext.pddsBack->GetSurfaceDesc(&ddsd);
00426   LPDIRECTDRAW7 pDD = _wcontext.pDD;
00427     
00428   ddsd.dwFlags &= ~DDSD_PITCH;
00429   ddsd.dwWidth = 1; 
00430   ddsd.dwHeight = 1;
00431   ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER);
00432   
00433   PRINTVIDMEM(pDD, &ddsd.ddsCaps, "dummy backbuf");
00434   
00435   hr = pDD->CreateSurface(&ddsd, &pddsDummy, NULL);    
00436   if (FAILED(hr)) {
00437     wdxdisplay7_cat.error()
00438       << "Resize CreateSurface for temp backbuf failed : result = "
00439       << ConvD3DErrorToString(hr) << endl;
00440     return false;
00441   }
00442   
00443   if (_wcontext.pddsZBuf != NULL) {
00444     DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsdZ);
00445     _wcontext.pddsZBuf->GetSurfaceDesc(&ddsdZ);
00446     ddsdZ.dwFlags &= ~DDSD_PITCH;
00447     ddsdZ.dwWidth = 1;
00448     ddsdZ.dwHeight = 1;
00449     
00450     PRINTVIDMEM(pDD,&ddsdZ.ddsCaps,"dummy zbuf");
00451     
00452     hr = pDD->CreateSurface(&ddsdZ, &pddsDummyZ, NULL);
00453     if (FAILED(hr)) {
00454       wdxdisplay7_cat.error()
00455         << "Resize CreateSurface for temp zbuf failed : result = "
00456         << ConvD3DErrorToString(hr) << endl;
00457       return false;
00458     }
00459 
00460     hr = pddsDummy->AddAttachedSurface(pddsDummyZ);        
00461     if (FAILED(hr)) {
00462       wdxdisplay7_cat.error()
00463         << "Resize AddAttachedSurf for temp zbuf failed : result = "
00464         << ConvD3DErrorToString(hr) << endl;
00465       return false;
00466     }
00467   }
00468 
00469   hr = _wcontext.pD3DDevice->SetRenderTarget(pddsDummy, 0x0);
00470   if (FAILED(hr)) {
00471     wdxdisplay7_cat.error()
00472       << "Resize failed to set render target to temporary surface, result = " 
00473       << ConvD3DErrorToString(hr) << endl;
00474     return false;
00475   }
00476   
00477   RELEASE(pddsDummyZ, wdxdisplay7, "dummy resize zbuffer", false);
00478   RELEASE(pddsDummy, wdxdisplay7, "dummy resize rendertarget buffer", false);
00479 
00480   return true;
00481 }
00482 
00483 ////////////////////////////////////////////////////////////////////
00484 //     Function: wdxGraphicsWindow7::create_screen_buffers_and_device
00485 //       Access: Private
00486 //  Description: Called whenever the window is resized, this recreates
00487 //               the necessary buffers for rendering.
00488 ////////////////////////////////////////////////////////////////////
00489 void wdxGraphicsWindow7::
00490 create_screen_buffers_and_device(DXScreenData &Display, bool force_16bpp_zbuffer) {
00491   DWORD dwRenderWidth=Display.dwRenderWidth;
00492   DWORD dwRenderHeight=Display.dwRenderHeight;
00493   LPDIRECT3D7 pD3DI=Display.pD3D;
00494   LPDIRECTDRAW7 pDD=Display.pDD;
00495   D3DDEVICEDESC7 *pD3DDevDesc=&Display.D3DDevDesc;
00496 
00497   LPDIRECTDRAWSURFACE7 pPrimaryDDSurf,pBackDDSurf,pZDDSurf;
00498   LPDIRECT3DDEVICE7 pD3DDevice;
00499   RECT view_rect;
00500   int i;
00501   HRESULT hr;
00502   DX_DECLARE_CLEAN(DDSURFACEDESC2, SurfaceDesc);
00503 
00504   assert(pDD!=NULL);
00505   assert(pD3DI!=NULL);
00506 
00507   DX_DECLARE_CLEAN(DDCAPS, DDCaps);
00508   pDD->GetCaps(&DDCaps, NULL);
00509 
00510   // if window is not foreground in exclusive mode, ddraw thinks you
00511   // are 'not active', so it changes your WM_ACTIVATEAPP from true to
00512   // false, causing us to go into a 'wait-for WM_ACTIVATEAPP true'
00513   // loop, and the event never comes so we hang in fullscreen wait.
00514   SetForegroundWindow(Display.hWnd);
00515 
00516   if (is_fullscreen()) {
00517     // Setup to create the primary surface w/backbuffer
00518     DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd);
00519     ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
00520     ddsd.ddsCaps.dwCaps = 
00521       DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE |
00522       DDSCAPS_FLIP | DDSCAPS_COMPLEX;
00523     ddsd.dwBackBufferCount = 1;
00524     Display.bIsFullScreen=true;
00525 
00526     if (dx_full_screen_antialiasing) {
00527       // cant check that d3ddevice has this capability yet, so got to
00528       // set it anyway.  hope this is OK.
00529       ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_HINTANTIALIASING; 
00530     }
00531 
00532     PRINTVIDMEM(pDD, &ddsd.ddsCaps, "initial primary & backbuf");
00533 
00534     // Create the primary surface for the fullscreen window
00535     hr = pDD->CreateSurface(&ddsd, &pPrimaryDDSurf, NULL);
00536     if (FAILED(hr)) {
00537       wdxdisplay7_cat.fatal()
00538         << "CreateSurface failed for primary surface: result = " 
00539         << ConvD3DErrorToString(hr) << endl;
00540 
00541       if (((hr == DDERR_OUTOFVIDEOMEMORY)||(hr == DDERR_OUTOFMEMORY)) &&
00542           (Display.dwFullScreenBitDepth > 16)) {
00543         // emergency fallback to 16bpp (shouldnt have to do this
00544         // unless GetAvailVidMem lied) will this work for multimon?
00545         // what if surfs are already created on 1st mon?
00546         Display.dwFullScreenBitDepth=16;
00547 
00548         wdxdisplay7_cat.info()
00549           << "GetAvailVidMem lied, not enough VidMem for 32bpp, so trying 16bpp on device #"
00550           << Display.CardIDNum << endl;
00551 
00552         hr = pDD->SetDisplayMode(Display.dwRenderWidth, 
00553                                  Display.dwRenderHeight,
00554                                  Display.dwFullScreenBitDepth, 0, 0);
00555         if (FAILED(hr)) {
00556           wdxdisplay7_cat.fatal()
00557             << "SetDisplayMode failed to set ("
00558             << Display.dwRenderWidth << "x" << Display.dwRenderHeight
00559             << "x" << Display.dwFullScreenBitDepth << ") on device #"
00560             << Display.CardIDNum << ": result = "
00561             << ConvD3DErrorToString(hr) << endl;
00562           exit(1);
00563         }
00564         create_screen_buffers_and_device(Display, true);
00565         return;
00566       } else {
00567         exit(1);
00568       }
00569     }
00570 
00571     // Clear the primary surface to black
00572     DX_DECLARE_CLEAN(DDBLTFX, bltfx);
00573     bltfx.dwDDFX |= DDBLTFX_NOTEARING;
00574     hr = pPrimaryDDSurf->Blt(NULL, NULL, NULL, 
00575                              DDBLT_COLORFILL | DDBLT_WAIT, &bltfx);
00576 
00577     if (FAILED(hr)) {
00578       wdxdisplay7_cat.fatal()
00579         << "Blt to Black of Primary Surf failed! : result = " 
00580         << ConvD3DErrorToString(hr) << endl;
00581       exit(1);
00582     }
00583 
00584     // Get the backbuffer, which was created along with the primary.
00585     DDSCAPS2 ddscaps = { 
00586       DDSCAPS_BACKBUFFER, 0, 0, 0
00587     };
00588     hr = pPrimaryDDSurf->GetAttachedSurface(&ddscaps, &pBackDDSurf);
00589     if (FAILED(hr)) {
00590       wdxdisplay7_cat.fatal() 
00591         << "Can't get the backbuffer: result = " 
00592         << ConvD3DErrorToString(hr) << endl;
00593       exit(1);
00594     }
00595 
00596     hr = pBackDDSurf->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&bltfx);
00597     if (FAILED(hr)) {
00598       wdxdisplay7_cat.fatal() 
00599         << "Blt to Black of Back Surf failed! : result = "
00600         << ConvD3DErrorToString(hr) << endl;
00601       exit(1);
00602     }
00603 
00604     SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight);
00605     // end create full screen buffers
00606 
00607   } else {          // CREATE WINDOWED BUFFERS
00608     if (!(DDCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED)) {
00609       wdxdisplay7_cat.fatal()
00610         << "the 3D HW cannot render windowed, exiting..." << endl;
00611       exit(1);
00612     }
00613 
00614     hr = pDD->GetDisplayMode(&SurfaceDesc);
00615     if (FAILED(hr)) {
00616       wdxdisplay7_cat.fatal() 
00617         << "GetDisplayMode failed result = " 
00618         << ConvD3DErrorToString(hr) << endl;
00619       exit(1);
00620     }
00621     if (SurfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8) {
00622       wdxdisplay7_cat.fatal()
00623         << "Can't run windowed in an 8-bit or less display mode" << endl;
00624       exit(1);
00625     }
00626 
00627     if (!(BitDepth_2_DDBDMask(SurfaceDesc.ddpfPixelFormat.dwRGBBitCount) & pD3DDevDesc->dwDeviceRenderBitDepth)) {
00628       wdxdisplay7_cat.fatal() 
00629         << "3D Device doesnt support rendering at " 
00630         << SurfaceDesc.ddpfPixelFormat.dwRGBBitCount 
00631         << "bpp (current desktop bitdepth)" << endl;
00632       exit(1);
00633     }
00634 
00635     // Get the dimensions of the viewport and screen bounds
00636     get_client_rect_screen(Display.hWnd, &view_rect);
00637 
00638     dwRenderWidth = view_rect.right - view_rect.left;
00639     dwRenderHeight = view_rect.bottom - view_rect.top;
00640 
00641     // _properties should reflect view rectangle
00642     WindowProperties properties;
00643     properties.set_origin(view_rect.left, view_rect.top);
00644     properties.set_size(dwRenderWidth, dwRenderHeight);
00645     system_changed_properties(properties);
00646 
00647     // Initialize the description of the primary surface
00648     ZeroMemory(&SurfaceDesc, sizeof(DDSURFACEDESC2));
00649     SurfaceDesc.dwSize = sizeof(DDSURFACEDESC2);
00650     SurfaceDesc.dwFlags = DDSD_CAPS ;
00651     SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
00652 
00653     PRINTVIDMEM(pDD, &SurfaceDesc.ddsCaps, "initial primary surface");
00654 
00655     // Create the primary surface for windowed mode.  This includes
00656     // all of the visible window, so no need to specify height/width.
00657     hr = pDD->CreateSurface(&SurfaceDesc, &pPrimaryDDSurf, NULL);
00658     if (FAILED(hr)) {
00659       wdxdisplay7_cat.fatal()
00660         << "CreateSurface failed for primary surface: result = "
00661         << ConvD3DErrorToString(hr) << endl;
00662       exit(1);
00663     }
00664 
00665     // Create a clipper object which handles all our clipping for
00666     // cases when our window is partially obscured by other windows.
00667     LPDIRECTDRAWCLIPPER Clipper;
00668     hr = pDD->CreateClipper(0, &Clipper, NULL);
00669     if (FAILED(hr)) {
00670       wdxdisplay7_cat.fatal()
00671         << "CreateClipper failed : result = "
00672         << ConvD3DErrorToString(hr) << endl;
00673       exit(1);
00674     }
00675 
00676     // Associate the clipper with our window.  Note that, afterwards,
00677     // the clipper is internally referenced by the primary surface, so
00678     // it is safe to release our local reference to it.
00679     Clipper->SetHWnd(0, Display.hWnd);
00680     pPrimaryDDSurf->SetClipper(Clipper);
00681     Clipper->Release();
00682    
00683     // Clear the primary surface to black
00684     DX_DECLARE_CLEAN(DDBLTFX, bltfx);
00685 
00686     hr = pPrimaryDDSurf->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&bltfx);
00687     if (FAILED(hr)) {
00688       wdxdisplay7_cat.fatal()
00689         << "Blt to Black of Primary Surf failed! : result = " << ConvD3DErrorToString(hr) << endl;
00690       exit(1);
00691     }
00692 
00693     // Set up a surface description to create a backbuffer.
00694     SurfaceDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
00695     SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY;
00696     SurfaceDesc.dwWidth = dwRenderWidth;
00697     SurfaceDesc.dwHeight = dwRenderHeight;
00698 
00699     if (dx_full_screen_antialiasing) {
00700       // cant check that d3ddevice has this capability yet, so got to
00701       // set it anyway.  hope this is OK.
00702       SurfaceDesc.ddsCaps.dwCaps2 |= DDSCAPS2_HINTANTIALIASING; 
00703     }
00704 
00705     PRINTVIDMEM(pDD, &SurfaceDesc.ddsCaps, "initial backbuf");
00706 
00707     // Create the backbuffer. (might want to handle failure due to
00708     // running out of video memory)
00709     hr = pDD->CreateSurface(&SurfaceDesc, &pBackDDSurf, NULL);
00710     if (FAILED(hr)) {
00711       wdxdisplay7_cat.fatal()
00712         << "CreateSurface failed for backbuffer : result = "
00713         << ConvD3DErrorToString(hr) << endl;
00714       exit(1);
00715     }
00716 
00717     hr = pBackDDSurf->Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&bltfx);
00718     if (FAILED(hr)) {
00719       wdxdisplay7_cat.fatal()
00720         << "Blt to Black of Back Surf failed! : result = "
00721         << ConvD3DErrorToString(hr) << endl;
00722       exit(1);
00723     }
00724   }  // end create windowed buffers
00725 
00726   //  ========================================================
00727 
00728   //  resized(dwRenderWidth, dwRenderHeight);  // update panda channel/display rgn info
00729 
00730   int frame_buffer_mode = _gsg->get_properties().get_frame_buffer_mode();
00731 
00732 #ifndef NDEBUG
00733   if ((frame_buffer_mode & FrameBufferProperties::FM_depth) == 0) {
00734     wdxdisplay7_cat.info()
00735       << "no zbuffer requested, skipping zbuffer creation\n";
00736   }
00737 #endif
00738 
00739   // Check if the device supports z-bufferless hidden surface
00740   // removal. If so, we don't really need a z-buffer
00741   if ((!(pD3DDevDesc->dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) &&
00742       ((frame_buffer_mode & FrameBufferProperties::FM_depth) != 0)) {
00743 
00744     // Get z-buffer dimensions from the render target
00745     DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd);
00746     pBackDDSurf->GetSurfaceDesc( &ddsd );
00747 
00748     // Setup the surface desc for the z-buffer.
00749     ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
00750     ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | ((_wcontext.bIsSWRast) ?  DDSCAPS_SYSTEMMEMORY : DDSCAPS_VIDEOMEMORY);
00751 
00752     DDPIXELFORMAT ZBufPixFmts[MAX_DX_ZBUF_FMTS];
00753     cNumZBufFmts=0;
00754 
00755     // Get an appropiate pixel format from enumeration of the
00756     // formats. On the first pass, we look for a zbuffer dpeth which
00757     // is equal to the frame buffer depth (as some cards unfornately
00758     // require this).
00759     hr = pD3DI->EnumZBufferFormats((Display.bIsTNLDevice ? IID_IDirect3DHALDevice : IID_IDirect3DTnLHalDevice),
00760                                    EnumZBufFmtsCallback,
00761                                    (VOID*)&ZBufPixFmts);
00762     if (FAILED(hr)) {
00763       wdxdisplay7_cat.fatal() << "EnumZBufferFormats failed" << endl;
00764       exit(1);
00765     }
00766 
00767 #ifdef _DEBUG
00768     {
00769       static BOOL bPrinted=FALSE;
00770       if (!bPrinted) {
00771         for (i = 0; i < cNumZBufFmts; i++) {
00772           DebugPrintPixFmt(&ZBufPixFmts[i]);
00773         }
00774         bPrinted=TRUE;
00775       }
00776     }
00777 #endif
00778 
00779     // should we pay attn to these at some point?  
00780     //int want_depth_bits = _props._want_depth_bits; 
00781     //int want_color_bits = _props._want_color_bits;
00782     bool bWantStencil = ((frame_buffer_mode & FrameBufferProperties::FM_stencil) != 0);
00783 
00784     LPDDPIXELFORMAT pCurPixFmt, pz16 = NULL, pz24 = NULL, pz32 = NULL;
00785     for (i = 0, pCurPixFmt = ZBufPixFmts; 
00786          i < cNumZBufFmts; 
00787          i++, pCurPixFmt++) {
00788       if (bWantStencil == ((pCurPixFmt->dwFlags & DDPF_STENCILBUFFER)!=0)) {
00789         switch (pCurPixFmt->dwRGBBitCount) {
00790         case 16:
00791           pz16 = pCurPixFmt;
00792           break;
00793         case 24:
00794           pz24 = pCurPixFmt;
00795           break;
00796         case 32:
00797           pz32 = pCurPixFmt;
00798           break;
00799         }
00800       }
00801     }
00802 
00803     if ((pz16 == NULL) && (pz24 == NULL) && (pz32 == NULL)) {
00804       if (bWantStencil) {
00805         wdxdisplay7_cat.fatal()
00806           << "stencil buffer requested, device has no stencil capability\n";
00807       } else {
00808         wdxdisplay7_cat.fatal()
00809           << "failed to find adequate zbuffer capability\n";
00810       }
00811       exit(1);
00812     }
00813 
00814 #define SET_ZBUF_DEPTH(DEPTH) { assert(pz##DEPTH != NULL); Display.depth_buffer_bitdepth=DEPTH; ddsd.ddpfPixelFormat = *pz##DEPTH;}
00815         
00816     if (_wcontext.bIsSWRast) {
00817       SET_ZBUF_DEPTH(16);    // need this for fast path rasterizers
00818     } else {
00819       if (IS_NVIDIA(Display.DXDeviceID)) {
00820         DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_pri);
00821         pPrimaryDDSurf->GetSurfaceDesc(&ddsd_pri);
00822 
00823         // must pick zbuf depth to match primary surface depth for nvidia
00824         if (ddsd_pri.ddpfPixelFormat.dwRGBBitCount==16) {
00825           SET_ZBUF_DEPTH(16);
00826         } else {
00827           if (force_16bpp_zbuffer) {
00828             wdxdisplay7_cat.fatal()
00829               << "'dx-force-16bpp-zbuffer #t' requires a 16bpp desktop on nvidia cards\n";
00830             exit(1);
00831           }
00832           // take the smaller of 24 or 32.  (already assured to match stencil capability)
00833           if(pz24 != NULL) {
00834             SET_ZBUF_DEPTH(24);
00835           } else {
00836             SET_ZBUF_DEPTH(32);
00837           }
00838         }
00839       } else {
00840         if (force_16bpp_zbuffer) {
00841           if (pz16 == NULL) {
00842             wdxdisplay7_cat.fatal()
00843               << "'dx-force-16bpp-zbuffer #t', but no 16bpp zbuf fmts available on this card\n";
00844             exit(1);
00845           }
00846 
00847           if(wdxdisplay7_cat.is_debug()) {
00848             wdxdisplay7_cat.debug() << "forcing use of 16bpp Z-Buffer\n";
00849           }
00850           SET_ZBUF_DEPTH(16);
00851           ddsd.ddpfPixelFormat = *pz16;
00852 
00853         } else {
00854           // pick the highest res zbuffer format avail.  Note: this is
00855           // choosing to waste vid-memory and possibly perf for more
00856           // accuracy, less z-fighting at long distance (std 16bpp
00857           // would be smaller, maybe faster) order of preference 24:
00858           // (should be enough), 32: probably means 24 of Z, then 16
00859 
00860           if (bWantStencil && (pz32!=NULL)) {
00861             // dont want to select 16/8 z/stencil over 24/8 z/stenc
00862             SET_ZBUF_DEPTH(32);
00863           } else {
00864             if (pz24!=NULL) {
00865               SET_ZBUF_DEPTH(24);
00866             } else if (pz32!=NULL) {
00867               SET_ZBUF_DEPTH(32);
00868             } else {
00869               SET_ZBUF_DEPTH(16);
00870             }
00871           }
00872         }
00873       }
00874     }
00875 
00876     PRINTVIDMEM(pDD, &ddsd.ddsCaps, "initial zbuf");
00877 
00878 #ifdef _DEBUG
00879     wdxdisplay7_cat.info()
00880       << "Creating " << ddsd.ddpfPixelFormat.dwRGBBitCount << "bpp zbuffer\n";
00881 #endif
00882 
00883     // Create and attach a z-buffer
00884     hr = pDD->CreateSurface(&ddsd, &pZDDSurf, NULL);
00885     if (FAILED(hr)) {
00886       wdxdisplay7_cat.fatal()
00887         << "CreateSurface failed for Z buffer: result = "
00888         <<  ConvD3DErrorToString(hr) << endl;
00889 
00890       if (((hr==DDERR_OUTOFVIDEOMEMORY)||(hr==DDERR_OUTOFMEMORY)) &&
00891           ((Display.dwFullScreenBitDepth>16)||(ddsd.ddpfPixelFormat.dwRGBBitCount>16))) {
00892         Display.dwFullScreenBitDepth=16;
00893         // emergency fallback to 16bpp (shouldnt have to do this
00894         // unless GetAvailVidMem lied) will this work for multimon?
00895         // what if surfs are already created on 1st mon?
00896 
00897         wdxdisplay7_cat.info()
00898           << "GetAvailVidMem lied, not enough VidMem for 32bpp, so trying 16bpp on device #"
00899           << Display.CardIDNum << endl;
00900         
00901         ULONG refcnt;
00902 
00903         // free pri and back (maybe should just free pri since created
00904         // as complex chain?)
00905         RELEASE(pBackDDSurf, wdxdisplay7, "backbuffer", false);
00906         RELEASE(pPrimaryDDSurf, wdxdisplay7, "primary surface", false);
00907 
00908         hr = pDD->SetDisplayMode(Display.dwRenderWidth,
00909                                  Display.dwRenderHeight,
00910                                  Display.dwFullScreenBitDepth, 
00911                                  0, 0);
00912         if (FAILED(hr)) {
00913           wdxdisplay7_cat.fatal()
00914             << "SetDisplayMode failed to set (" 
00915             << Display.dwRenderWidth << "x" << Display.dwRenderHeight 
00916             << "x" << Display.dwFullScreenBitDepth << ") on device #"
00917             << Display.CardIDNum << ": result = " 
00918             << ConvD3DErrorToString(hr) << endl;
00919           exit(1);
00920         }
00921         create_screen_buffers_and_device(Display, true);
00922         return;
00923 
00924       } else {
00925         exit(1);
00926       }
00927     }
00928 
00929     hr = pBackDDSurf->AddAttachedSurface(pZDDSurf);
00930     if (FAILED(hr)) {
00931       wdxdisplay7_cat.fatal()
00932         << "AddAttachedSurface failed : result = " 
00933         << ConvD3DErrorToString(hr) << endl;
00934       exit(1);
00935     }
00936   }
00937 
00938   // Create the device. The device is created off of our back buffer,
00939   // which becomes the render target for the newly created device.
00940   hr = pD3DI->CreateDevice(pD3DDevDesc->deviceGUID, pBackDDSurf, &pD3DDevice);
00941   if (hr != DD_OK) {
00942     wdxdisplay7_cat.fatal() 
00943       << "CreateDevice failed : result = " 
00944       << ConvD3DErrorToString(hr) << endl;
00945     exit(1);
00946   }
00947 
00948   // No reason to create a viewport at this point.
00949   /*
00950   // Create the viewport
00951   WindowProperties properties = get_properties();
00952   D3DVIEWPORT7 vp = { 
00953     0, 0,
00954     properties.get_x_size(), properties.get_y_size(),
00955     0.0f, 1.0f
00956   };
00957   hr = pD3DDevice->SetViewport(&vp);
00958   if (hr != DD_OK) {
00959     wdxdisplay7_cat.fatal()
00960       << "SetViewport failed : result = " << ConvD3DErrorToString(hr) << endl;
00961     exit(1);
00962   }
00963   */
00964 
00965   Display.pD3DDevice = pD3DDevice;
00966   Display.pddsPrimary = pPrimaryDDSurf;
00967   Display.pddsBack = pBackDDSurf;
00968   Display.pddsZBuf = pZDDSurf;
00969   Display.view_rect = view_rect;
00970 
00971   _dxgsg->set_context(&Display);
00972   //pDD, pPrimaryDDSurf, pBackDDSurf, pZDDSurf, pD3DI, pD3DDevice, view_rect);
00973   _dxgsg->dx_init();
00974 
00975   // do not SetDXReady() yet since caller may want to do more work
00976   // before letting rendering proceed
00977 
00978   // Oh, go ahead and call it.
00979   _dxgsg->SetDXReady(true);
00980 }
00981 
00982 ////////////////////////////////////////////////////////////////////
00983 //     Function: wdxGraphicsWindow7::choose_device
00984 //       Access: Private
00985 //  Description: Searches for a suitable hardware device for
00986 //               rendering.
00987 ////////////////////////////////////////////////////////////////////
00988 bool wdxGraphicsWindow7::
00989 choose_device(int devnum, DXDeviceInfo *pDevinfo) {
00990   wdxGraphicsPipe7 *dxpipe;
00991   DCAST_INTO_R(dxpipe, _pipe, false);
00992 
00993   DWORD dwRenderWidth = get_properties().get_x_size();
00994   DWORD dwRenderHeight = get_properties().get_y_size();
00995   LPDIRECTDRAW7 pDD=NULL;
00996   HRESULT hr;
00997 
00998   assert(_dxgsg != NULL);
00999 
01000   GUID *pDDDeviceGUID;
01001   if (pDevinfo == NULL) {
01002     pDDDeviceGUID = NULL;
01003   } else {
01004     pDDDeviceGUID = &pDevinfo->guidDeviceIdentifier;
01005   }
01006 
01007   assert(dxpipe->_DirectDrawCreateEx != NULL);
01008 
01009   // Create the Direct Draw Objects
01010   hr = (*dxpipe->_DirectDrawCreateEx)(pDDDeviceGUID, (void **)&pDD, 
01011                                       IID_IDirectDraw7, NULL);
01012   if ((hr != DD_OK) || (pDD == NULL)) {
01013     wdxdisplay7_cat.fatal()
01014       << "DirectDrawCreateEx failed for monitor(" << devnum
01015       << "): result = " << ConvD3DErrorToString(hr) << endl;
01016     return false;
01017   }
01018 
01019   _wcontext.pDD = pDD;
01020 
01021   // GetDeviceID bug writes an extra 4 bytes, so need xtra space
01022   BYTE id_arr[sizeof(DDDEVICEIDENTIFIER2) + 4];
01023   pDD->GetDeviceIdentifier((DDDEVICEIDENTIFIER2 *)&id_arr, 0x0);
01024 
01025   memcpy(&_wcontext.DXDeviceID, id_arr, sizeof(DDDEVICEIDENTIFIER2));
01026 
01027   if (wdxdisplay7_cat.is_info()) {
01028     DDDEVICEIDENTIFIER2 *pDevID = &_wcontext.DXDeviceID;
01029     wdxdisplay7_cat.info() 
01030       << "GfxCard: " << pDevID->szDescription <<  "; DriverFile: '" 
01031       << pDevID->szDriver  
01032       << "'; VendorID: 0x" <<  (void*)pDevID->dwVendorId 
01033       << "; DeviceID: 0x" <<  (void*)pDevID->dwDeviceId 
01034       << "; DriverVer: " 
01035       << HIWORD(pDevID->liDriverVersion.HighPart) << "." 
01036       << LOWORD(pDevID->liDriverVersion.HighPart) << "."
01037       << HIWORD(pDevID->liDriverVersion.LowPart) << "." 
01038       << LOWORD(pDevID->liDriverVersion.LowPart) << endl;
01039   }
01040 
01041   // Query DirectDraw for access to Direct3D
01042   hr = pDD->QueryInterface(IID_IDirect3D7, (VOID**)&_wcontext.pD3D);
01043   if(hr != DD_OK) {
01044     wdxdisplay7_cat.fatal()
01045       << "QI for D3D failed : result = " << ConvD3DErrorToString(hr) << endl;
01046     goto error_exit;
01047   }
01048 
01049   D3DDEVICEDESC7 d3ddevs[3];  // put HAL in 0, TnLHAL in 1, SW rast in 2
01050 
01051   // just look for HAL and TnL devices right now.  I dont think
01052   // we have any interest in the sw rasts at this point
01053 
01054   ZeroMemory(d3ddevs,3*sizeof(D3DDEVICEDESC7));
01055 
01056   hr = _wcontext.pD3D->EnumDevices(EnumDevicesCallback, d3ddevs);
01057   if(hr != DD_OK) {
01058     wdxdisplay7_cat.fatal()
01059       << "EnumDevices failed : result = " << ConvD3DErrorToString(hr) << endl;
01060     goto error_exit;
01061   }
01062     
01063   WORD DeviceIdx;
01064 
01065   // select TNL if present
01066   if (d3ddevs[TNLHALIDX].dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) {
01067     DeviceIdx = TNLHALIDX;
01068   } else if (d3ddevs[REGHALIDX].dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) {
01069     DeviceIdx = REGHALIDX;
01070   } else if (dx_allow_software_renderer || dx_force_software_renderer) {
01071     DeviceIdx = SWRASTIDX;      
01072   } else {
01073     wdxdisplay7_cat.error()
01074       << "No 3D HW present on device #" << devnum << ", skipping it... ("
01075       << _wcontext.DXDeviceID.szDescription<<")\n";
01076     goto error_exit;
01077   }
01078 
01079   if (dx_force_software_renderer) {
01080     DeviceIdx = SWRASTIDX; 
01081   }
01082     
01083   memcpy(&_wcontext.D3DDevDesc, &d3ddevs[DeviceIdx], 
01084          sizeof(D3DDEVICEDESC7));
01085 
01086   _wcontext.bIsTNLDevice = (DeviceIdx == TNLHALIDX);
01087 
01088   // Get Current VidMem avail.  Note this is only an estimate, when we
01089   // switch to fullscreen mode from desktop, more vidmem will be
01090   // available (typically 1.2 meg).  I dont want to switch to
01091   // fullscreen more than once due to the annoying monitor flicker, so
01092   // try to figure out optimal mode using this estimate
01093   DDSCAPS2 ddsGAVMCaps;
01094   DWORD dwVidMemTotal, dwVidMemFree;
01095   dwVidMemTotal = dwVidMemFree = 0;
01096   ZeroMemory(&ddsGAVMCaps, sizeof(DDSCAPS2));
01097   ddsGAVMCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;  // dont count AGP mem!
01098   hr = pDD->GetAvailableVidMem(&ddsGAVMCaps,&dwVidMemTotal,&dwVidMemFree);
01099   if (FAILED(hr)) {
01100     wdxdisplay7_cat.error()
01101       << "GetAvailableVidMem failed for device #" << devnum
01102       << ": result = " << ConvD3DErrorToString(hr) << endl;
01103     // goto skip_device;
01104     exit(1);  // probably want to exit, since it may be my fault
01105   }
01106     
01107   // after SetDisplayMode, GetAvailVidMem totalmem seems to go down by
01108   // 1.2 meg (contradicting above comment and what I think would be
01109   // correct behavior (shouldnt FS mode release the desktop vidmem?),
01110   // so this is the true value
01111   _wcontext.MaxAvailVidMem = dwVidMemTotal;
01112     
01113 #define LOWVIDMEMTHRESHOLD 5500000
01114 #define CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 1000000     // every vidcard we deal with should have at least 1MB
01115     
01116   // assume buggy drivers (this means you, FireGL2) may return zero for dwVidMemTotal, so ignore value if its < CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD
01117   _wcontext.bIsLowVidMemCard = 
01118     ((dwVidMemTotal>CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD) && 
01119      (dwVidMemTotal< LOWVIDMEMTHRESHOLD));   
01120 
01121   if (!dx_do_vidmemsize_check) {
01122     _wcontext.MaxAvailVidMem = 0xFFFFFFFF;
01123     _wcontext.bIsLowVidMemCard = false; 
01124   }
01125 
01126   if (DeviceIdx == SWRASTIDX) {
01127     // this will force 640x480x16, is this what we want for all sw rast?
01128     _wcontext.bIsLowVidMemCard = true; 
01129     _wcontext.bIsSWRast = true; 
01130     dx_force_16bpp_zbuffer = true;
01131   }
01132 
01133   if (is_fullscreen()) {
01134     DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_search);
01135     ddsd_search.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
01136     ddsd_search.dwWidth = dwRenderWidth;
01137     ddsd_search.dwHeight = dwRenderHeight;
01138     
01139     DDSURFACEDESC2 DDSD_Arr[MAX_DISPLAY_MODES];
01140     DisplayModeInfo DMI;
01141     ZeroMemory(&DDSD_Arr, sizeof(DDSD_Arr));
01142     ZeroMemory(&DMI, sizeof(DMI));
01143     DMI.maxWidth = dwRenderWidth;
01144     DMI.maxHeight = dwRenderHeight;
01145     DMI.pDDSD_Arr = DDSD_Arr;
01146 
01147     hr= pDD->EnumDisplayModes(DDEDM_REFRESHRATES, &ddsd_search,
01148                               &DMI, EnumDisplayModesCallBack);        
01149     if (FAILED(hr)) {
01150       wdxdisplay7_cat.fatal()
01151         << "EnumDisplayModes failed for device #" << devnum 
01152         << " (" << _wcontext.DXDeviceID.szDescription
01153         << "), result = " << ConvD3DErrorToString(hr) << endl;
01154       // goto skip_device;
01155       exit(1);  // probably want to exit, since it may be my fault
01156     }
01157         
01158     if (wdxdisplay7_cat.is_info()) {
01159       wdxdisplay7_cat.info()
01160         << "Before fullscreen switch: GetAvailableVidMem for device #"
01161         << devnum << " returns Total: " << dwVidMemTotal/1000000.0
01162         << "  Free: " << dwVidMemFree/1000000.0 << endl;
01163     }
01164         
01165     // Now we try to figure out if we can use requested screen
01166     // resolution and best rendertarget bpp and still have at least 2
01167     // meg of texture vidmem
01168         
01169     DMI.supportedBitDepths &= _wcontext.D3DDevDesc.dwDeviceRenderBitDepth;
01170 
01171     DWORD dwFullScreenBitDepth;
01172 
01173     // note: this chooses 32bpp, which may not be preferred over 16
01174     // for memory & speed reasons
01175     if (DMI.supportedBitDepths & DDBD_32) {
01176       dwFullScreenBitDepth = 32;              // go for 32bpp if its avail
01177     } else if (DMI.supportedBitDepths & DDBD_24) {
01178       dwFullScreenBitDepth = 24;              // go for 24bpp if its avail
01179     } else if (DMI.supportedBitDepths & DDBD_16) {
01180       dwFullScreenBitDepth = 16;              // do 16bpp
01181     } else {
01182       wdxdisplay7_cat.fatal() 
01183         << "No Supported FullScreen resolutions at " << dwRenderWidth
01184         << "x" << dwRenderHeight << " for device #" << devnum 
01185         << " (" << _wcontext.DXDeviceID.szDescription
01186         << "), skipping device...\n";
01187       goto error_exit;
01188     }
01189         
01190     if (_wcontext.bIsLowVidMemCard) {
01191       {
01192         // hack: figuring out exactly what res to use is tricky,
01193         // instead I will just use 640x480 if we have < 3 meg avail
01194     
01195         dwFullScreenBitDepth = 16; 
01196         dwRenderWidth = 640;
01197         dwRenderHeight = 480;
01198         dx_force_16bpptextures = true;
01199         
01200         if (wdxdisplay7_cat.is_info())
01201           wdxdisplay7_cat.info() 
01202             << "Available VidMem (" << dwVidMemFree << ") is under "
01203             << LOWVIDMEMTHRESHOLD 
01204             << ", using 640x480 16bpp rendertargets to save tex vidmem.\n";
01205       }
01206     }
01207 
01208     _wcontext.dwFullScreenBitDepth = dwFullScreenBitDepth;
01209   }
01210     
01211   _wcontext.dwRenderWidth = dwRenderWidth;
01212   _wcontext.dwRenderHeight = dwRenderHeight;
01213   if (pDevinfo) {
01214     _wcontext.hMon = pDevinfo->hMon;
01215   }
01216   _wcontext.CardIDNum = devnum;  // add ID tag for dbgprint purposes
01217 
01218   return true;
01219     
01220   // handle errors within this for device loop
01221     
01222  error_exit:
01223   if (_wcontext.pD3D != NULL)
01224     _wcontext.pD3D->Release();
01225   if (_wcontext.pDD != NULL)
01226     _wcontext.pDD->Release();
01227 
01228   _wcontext.pDD = NULL;
01229   _wcontext.pD3D = NULL;
01230   return false;
01231 }
01232 
01233 ////////////////////////////////////////////////////////////////////
01234 //     Function: wdxGraphicsWindow7::set_coop_levels_and_display_modes
01235 //       Access: Private
01236 //  Description: 
01237 ////////////////////////////////////////////////////////////////////
01238 void wdxGraphicsWindow7::
01239 set_coop_levels_and_display_modes() {
01240   HRESULT hr;
01241   DWORD SCL_FPUFlag;
01242 
01243   if (dx_preserve_fpu_state) {
01244     // tell d3d to preserve the fpu state across calls.  this hurts
01245     // perf, but is good for dbgging
01246     SCL_FPUFlag = DDSCL_FPUPRESERVE;
01247   } else {
01248     SCL_FPUFlag = DDSCL_FPUSETUP;
01249   }
01250 
01251   //  DXScreenData *pScrn = &_dxgsg->scrn;
01252 
01253   if (!is_fullscreen()) {
01254     hr = _wcontext.pDD->SetCooperativeLevel(_hWnd, 
01255                                             SCL_FPUFlag | DDSCL_NORMAL);
01256     if (FAILED(hr)) {
01257       wdxdisplay7_cat.fatal()
01258         << "SetCooperativeLevel failed : result = "
01259         << ConvD3DErrorToString(hr) << endl;
01260       exit(1);
01261     }
01262     return; 
01263   }
01264     
01265   DWORD SCL_FLAGS = SCL_FPUFlag | DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT;
01266 
01267   // The following code would be done per window if were supporting
01268   // multiple fullscreen windows on different graphics cards.  TODO:
01269   // restore that functionality.
01270   DWORD devnum = 0;
01271   {
01272     // DXScreenData *pScrn = &_dxgsg->scrn;
01273 
01274     // need to set focus/device windows for multimon
01275     // focus window is primary monitor that will receive keybd input
01276     // all ddraw objs need to have same focus window
01277     /*
01278     if(_windows.size()>1) {    
01279       if(FAILED(hr = pScrn->pDD->SetCooperativeLevel(_hParentWindow, DDSCL_SETFOCUSWINDOW))) {
01280         wdxdisplay7_cat.fatal() << "SetCooperativeLevel SetFocusWindow failed on device 0: result = " << ConvD3DErrorToString(hr) << endl;
01281         exit(1);
01282       }
01283     }
01284     */
01285 
01286     // s3 savage2000 on w95 seems to set EXCLUSIVE_MODE only if you call
01287     // SetCoopLevel twice.  so we do it, it really shouldnt be necessary
01288     // if drivers werent buggy
01289     for (int jj=0; jj<2; jj++) {
01290       hr = _wcontext.pDD->SetCooperativeLevel(_wcontext.hWnd, SCL_FLAGS);
01291       if (FAILED(hr)) {
01292         wdxdisplay7_cat.fatal() 
01293           << "SetCooperativeLevel failed for device #" << devnum 
01294           << ": result = " << ConvD3DErrorToString(hr) << endl;
01295         exit(1);
01296       }
01297     }
01298     
01299     hr = _wcontext.pDD->TestCooperativeLevel();
01300     if (FAILED(hr)) {
01301       wdxdisplay7_cat.fatal()
01302         << "TestCooperativeLevel failed: result = " << ConvD3DErrorToString(hr)
01303         << endl;
01304       wdxdisplay7_cat.fatal()
01305         << "Full screen app failed to get exclusive mode on init, exiting..\n";
01306       exit(1);
01307     }
01308 
01309     // note: its important we call SetDisplayMode on all cards before
01310     // creating surfaces on any of them to let driver choose default
01311     // refresh rate (hopefully its >=60Hz)
01312     hr = _wcontext.pDD->SetDisplayMode(_wcontext.dwRenderWidth, 
01313                                     _wcontext.dwRenderHeight,
01314                                     _wcontext.dwFullScreenBitDepth, 0, 0);
01315     if (FAILED(hr)) {
01316       wdxdisplay7_cat.fatal()
01317         << "SetDisplayMode failed to set (" << _wcontext.dwRenderWidth
01318         << "x" <<_wcontext.dwRenderHeight << "x" << _wcontext.dwFullScreenBitDepth
01319         << ") on device #" << _wcontext.CardIDNum << ": result = " 
01320         << ConvD3DErrorToString(hr) << endl;
01321       exit(1);
01322     }
01323     
01324     if(wdxdisplay7_cat.is_debug()) {
01325       DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_temp); 
01326       _wcontext.pDD->GetDisplayMode(&ddsd_temp);
01327       wdxdisplay7_cat.debug()
01328         << "set displaymode to " << ddsd_temp.dwWidth << "x" << ddsd_temp.dwHeight
01329         << " at " << ddsd_temp.ddpfPixelFormat.dwRGBBitCount << "bpp, " 
01330         << ddsd_temp.dwRefreshRate<< "Hz\n";
01331     }
01332   }
01333 }
01334 
01335 #if 0
01336 
01337 // probably need this here similar to dx8
01338 ////////////////////////////////////////////////////////////////////
01339 //     Function: wdxGraphicsWindow8::begin_frame
01340 //       Access: Public, Virtual
01341 //  Description: This function will be called within the draw thread
01342 //               before beginning rendering for a given frame.  It
01343 //               should do whatever setup is required, and return true
01344 //               if the frame should be rendered, or false if it
01345 //               should be skipped.
01346 ////////////////////////////////////////////////////////////////////
01347 bool wdxGraphicsWindow7::
01348 begin_frame() {
01349   if (_awaiting_restore) {
01350     // The fullscreen window was recently restored; we can't continue
01351     // until the GSG says we can.
01352     if (!_dxgsg->CheckCooperativeLevel()) {
01353       // Keep waiting.
01354       return false;
01355     }
01356     _awaiting_restore = false;
01357 
01358     init_resized_window();
01359   }
01360 
01361   return WinGraphicsWindow::begin_frame();
01362 }
01363 #endif

Generated on Fri May 2 00:37:07 2003 for Panda by doxygen1.3