Quellcode durchsuchen

fullscrn resize support, part2

cxgeorge vor 24 Jahren
Ursprung
Commit
2b717435cd

+ 7 - 7
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -751,7 +751,7 @@ dx_init(HCURSOR hMouseCursor) {
     scrn.pD3DDevice->SetRenderState(D3DRS_LIGHTING, _lighting_enabled);
 
     // turn on dithering if the rendertarget is < 8bits/color channel
-    _dither_enabled = ((!dx_no_dithering) && IS_16BPP_FORMAT(scrn.PresParams.BackBufferFormat)
+    _dither_enabled = ((!dx_no_dithering) && IS_16BPP_DISPLAY_FORMAT(scrn.PresParams.BackBufferFormat)
                         && (scrn.d3dcaps.RasterCaps & D3DPRASTERCAPS_DITHER));
     scrn.pD3DDevice->SetRenderState(D3DRS_DITHERENABLE, _dither_enabled);
 
@@ -957,7 +957,7 @@ dx_init(HCURSOR hMouseCursor) {
 
         // Create a new surface for the texture
         if(FAILED( hr = scrn.pD3DDevice->CreateSurface( &ddsd, &_fpsmeter_font_surf, NULL ) )) {
-            dxgsg_cat.error() << "CreateSurface() failed for fpsmeter font!  hr = " << D3DERRORSTRING(hr);
+            dxgsg_cat.error() << "CreateSurface() failed for fpsmeter font!" << D3DERRORSTRING(hr);
             _bShowFPSMeter = false;
             return;
         }
@@ -1069,7 +1069,7 @@ enable_light(int light_id, bool val) {
 #endif
 
         if (FAILED(hr)) {
-            dxgsg_cat.error() << "LightEnable(" << light_id << "=" << val << ") failed, hr=" << D3DERRORSTRING(hr);
+            dxgsg_cat.error() << "LightEnable(" << light_id << "=" << val << ") failed, " <<D3DERRORSTRING(hr);
             return false;
         }
     }
@@ -3972,7 +3972,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
        hr=scrn.pD3DDevice->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pD3DSurf);
 
        if(FAILED(hr)) {
-           dxgsg_cat.error() << "GetBackBuffer failed, hr = " << D3DERRORSTRING(hr);
+           dxgsg_cat.error() << "GetBackBuffer failed" << D3DERRORSTRING(hr);
            exit(1);
        }
 
@@ -4016,7 +4016,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
         
         hr=scrn.pD3DDevice->CreateImageSurface(TmpSurfXsize,TmpSurfYsize,D3DFMT_A8R8G8B8,&pD3DSurf);
         if(FAILED(hr)) {
-           dxgsg_cat.error() << "CreateImageSurface failed in copy_pixel_buffer(), hr = " << D3DERRORSTRING(hr);
+           dxgsg_cat.error() << "CreateImageSurface failed in copy_pixel_buffer()" << D3DERRORSTRING(hr);
            exit(1);
         }
         
@@ -5733,7 +5733,7 @@ dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled) {
           if(dxgsg_cat.is_spam())
                 dxgsg_cat.spam() << "dx_cleanup -  Restoring original desktop DisplayMode\n";
           if(FAILED(hr)) {
-                dxgsg_cat.error() << "dx_cleanup -  RestoreDisplayMode failed, hr = " << D3DERRORSTRING(hr);
+                dxgsg_cat.error() << "dx_cleanup -  RestoreDisplayMode failed" << D3DERRORSTRING(hr);
           }
         }
 
@@ -5866,7 +5866,7 @@ void DXGraphicsStateGuardian::show_frame(void) {
     if(hr == D3DERR_DEVICELOST) {
         CheckCooperativeLevel();
     } else {
-      dxgsg_cat.error() << "show_frame() - Present() failed, hr = " << D3DERRORSTRING(hr);
+      dxgsg_cat.error() << "show_frame() - Present() failed" << D3DERRORSTRING(hr);
       exit(1);
     }
   }

+ 5 - 5
panda/src/dxgsg8/dxTextureContext8.cxx

@@ -752,7 +752,7 @@ HRESULT ConvertD3DSurftoPixBuf(RECT &SrcRect,IDirect3DSurface8 *pD3DSurf8,PixelB
 
     hr = pD3DSurf8->LockRect(&LockedRect,(CONST RECT*)NULL,(D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE /* | D3DLOCK_NOSYSLOCK */));
     if(FAILED(hr)) {
-        dxgsg_cat.error() << "ConvertDDSurftoPixBuf LockRect() failed! hr = " << D3DERRORSTRING(hr);
+        dxgsg_cat.error() << "ConvertDDSurftoPixBuf LockRect() failed!" << D3DERRORSTRING(hr);
         return hr;
     }
 
@@ -1409,7 +1409,7 @@ IDirect3DTexture8 *DXTextureContext::CreateTexture(DXScreenData &scrn) {
     
     if(FAILED( hr = scrn.pD3DDevice->CreateTexture(TargetWidth,TargetHeight,cMipLevelCount,0x0,
                                                    TargetPixFmt,D3DPOOL_MANAGED,&_pD3DTexture8) )) {
-        dxgsg_cat.error() << "pD3DDevice->CreateTexture() failed!  hr = " << D3DERRORSTRING(hr);
+        dxgsg_cat.error() << "pD3DDevice->CreateTexture() failed!" << D3DERRORSTRING(hr);
         goto error_exit;
     }
 
@@ -1459,7 +1459,7 @@ FillDDSurfTexturePixels(void) {
     IDirect3DSurface8 *pMipLevel0;
     hr=_pD3DTexture8->GetSurfaceLevel(0,&pMipLevel0);
     if(FAILED(hr)) {
-       dxgsg_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", GetSurfaceLevel returns hr = " << D3DERRORSTRING(hr);
+       dxgsg_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
        return E_FAIL;
     }
 
@@ -1477,7 +1477,7 @@ FillDDSurfTexturePixels(void) {
     hr=D3DXLoadSurfaceFromMemory(pMipLevel0,(PALETTEENTRY*)NULL,(RECT*)NULL,(LPCVOID) pbuf->_image.p(),_PixBufD3DFmt,
                                  OrigWidth*cNumColorChannels,(PALETTEENTRY*)NULL,&SrcSize,Lev0Filter,(D3DCOLOR)0x0);
     if(FAILED(hr)) {
-       dxgsg_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXLoadSurfFromMem returns hr = " << D3DERRORSTRING(hr);
+       dxgsg_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
        goto exit_FillDDSurf;
     }
 
@@ -1490,7 +1490,7 @@ FillDDSurfTexturePixels(void) {
 
         hr=D3DXFilterTexture(_pD3DTexture8,(PALETTEENTRY*)NULL,0,MipFilterFlags);
         if(FAILED(hr)) {
-            dxgsg_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXFilterTex returns hr = " << D3DERRORSTRING(hr);
+            dxgsg_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXFilterTex failed" << D3DERRORSTRING(hr);
             goto exit_FillDDSurf;
         }
     }

+ 10 - 1
panda/src/dxgsg8/dxgsg8base.h

@@ -54,8 +54,12 @@
 #endif
 
 #ifndef D3DERRORSTRING
+#ifdef NDEBUG
+#define D3DERRORSTRING(HRESULT) " at (" << __FILE__ << ":" << __LINE__ << "), hr=" <<  DXGetErrorString8(HRESULT) << endl  // leave out descriptions to shrink release build
+#else
 #define D3DERRORSTRING(HRESULT) " at (" << __FILE__ << ":" << __LINE__ << "), hr=" <<  DXGetErrorString8(HRESULT) << ": " << DXGetErrorDescription8(HRESULT) << endl
 #endif
+#endif
 
 #define ISPOW2(X) (((X) & ((X)-1))==0)
 #define IS_VALID_PTR(PTR)  (!IsBadWritePtr(PTR,sizeof(void*)))
@@ -152,7 +156,12 @@ typedef enum {
     DXT5_FLAG =         FLG(31)
 } D3DFORMAT_FLAG;
 
-#define IS_16BPP_FORMAT(FMT) (((FMT)>=D3DFMT_R5G6B5)&&((FMT)<=D3DFMT_A1R5G5B5))
+// this is only used in conjunction w/rendertgt fmts, so just make it something that can never be a rtgt
+#define DISPLAY_32BPP_REQUIRES_16BPP_ZBUFFER_FLAG DXT1_FLAG
+#define DISPLAY_16BPP_REQUIRES_16BPP_ZBUFFER_FLAG DXT2_FLAG
+
+#define IS_16BPP_DISPLAY_FORMAT(FMT) (((FMT)==D3DFMT_R5G6B5)||((FMT)==D3DFMT_X1R5G5B5)||((FMT)==D3DFMT_A1R5G5B5))
+#define IS_16BPP_ZBUFFER(FMT) ((FMT==D3DFMT_D16)||(FMT==D3DFMT_D15S1))
 #define IS_STENCIL_FORMAT(FMT) (((FMT)==D3DFMT_D24S8) || ((FMT)==D3DFMT_D15S1) || ((FMT)==D3DFMT_D24X4S4))
 #define RECT_XSIZE(REC) (REC.right-REC.left)
 #define RECT_YSIZE(REC) (REC.bottom-REC.top)

+ 1 - 1
panda/src/wdxdisplay8/config_wdxdisplay8.cxx

@@ -32,7 +32,7 @@ ConfigureFn(config_wdxdisplay) {
 bool dx_force_16bpp_zbuffer = config_wdxdisplay.GetBool("dx-force-16bpp-zbuffer", false);
 bool bResponsive_minimized_fullscreen_window = config_wdxdisplay.GetBool("responsive-minimized-fullscreen-window",false);
 bool dx_preserve_fpu_state = config_wdxdisplay.GetBool("dx-preserve-fpu-state", false);
-int dx_preferred_deviceID = config_wdxdisplay.GetInt("dx-preferred-deviceID", -1);
+int dx_preferred_deviceID = config_wdxdisplay.GetInt("dx-preferred-device-id", -1);
 
 extern void AtExitFn(void);
 

+ 141 - 85
panda/src/wdxdisplay8/wdxGraphicsWindow8.cxx

@@ -212,7 +212,7 @@ void DestroyAllWindows(bool bAtExitFnCalled) {
    while(!hwnd_pandawin_map.empty()) {
      // cant use a for loop cause DestroyMe erases things out from under us, so iterator is invalid
      HWND_PANDAWIN_MAP::iterator pwin = hwnd_pandawin_map.begin();
-     if((*pwin).second != NULL) 
+     if((*pwin).second != NULL)
          (*pwin).second->DestroyMe(bAtExitFnCalled);
    }
 }
@@ -1281,75 +1281,41 @@ void wdxGraphicsWindow::resize(unsigned int xsize,unsigned int ysize) {
     _dxgsg->SetDXReady(true);
 }
 
-unsigned int wdxGraphicsWindow::
-verify_window_sizes(unsigned int numsizes,unsigned int *dimen) {
+UINT wdxGraphicsWindow::
+verify_window_sizes(UINT numsizes,UINT *dimen) {
+   // unfortunately this only works AFTER you make the window initially,
+   // so its really mostly useful for resizes only
+   assert(IS_VALID_PTR(_dxgsg));  
 
-    wdxdisplay_cat.error() << "verify_window_sizes not implemented for dx8 yet!\n";
-    return numsizes;
-    
-#if 0
-   DWORD num_valid_modes=0;
-   HRESULT hr;
+   UINT num_valid_modes=0;
 
    // not requesting same refresh rate since changing res might not support same refresh rate at new size
 
-   DDSURFACEDESC2 DDSD_Arr[MAX_DISPLAY_MODES];
-   DisplayModeInfo DMI;
-   DWORD i,*pCurDim=(DWORD *)dimen;
-
-   for(i=0;i<numsizes;i++,pCurDim+=2) {
-      DWORD xsize=pCurDim[0];
-      DWORD ysize=pCurDim[1];
-
-       DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_search);
-       ddsd_search.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; //| DDSD_PIXELFORMAT;
-       ddsd_search.dwWidth=xsize; ddsd_search.dwHeight=ysize;
-    
-       ZeroMemory(&DDSD_Arr,sizeof(DDSD_Arr));
-       ZeroMemory(&DMI,sizeof(DMI));
-       DMI.maxWidth=xsize;  DMI.maxHeight=ysize;
-       DMI.pDDSD_Arr=DDSD_Arr;
-    
-       if(FAILED(hr = _dxgsg->scrn.pDD->EnumDisplayModes(DDEDM_REFRESHRATES,&ddsd_search,&DMI,EnumDisplayModesCallBack))) {
-           wdxdisplay_cat.fatal() << "resize() - EnumDisplayModes failed, hr = " << ConvD3DErrorToString(hr) << endl;
-           return 0;
-       }
-    
-       // get rid of bpp's we cant render at
-       DMI.supportedBitDepths &= _dxgsg->scrn.D3DDevDesc.dwDeviceRenderBitDepth;
-
-       bool bIsGoodMode=false;
-
-       if(_dxgsg->scrn.bIsLowVidMemCard) 
-           bIsGoodMode=(((float)xsize*(float)ysize)<=(float)(640*480));
-         else if(DMI.supportedBitDepths & (DDBD_16 | DDBD_24 | DDBD_32)) {
-             // assume user is testing fullscreen, not windowed, so use the dwTotal value
-             // see if 3 scrnbufs (front/back/z)at 16bpp at xsize*ysize will fit with a few 
-             // extra megs for texmem
+   UINT *pCurDim=(UINT *)dimen;
 
-             // 8MB Rage Pro says it has 6.8 megs Total free and will run at 1024x768, so
-             // formula makes it so that is OK
+   for(UINT i=0;i<numsizes;i++,pCurDim+=2) {
+      UINT xsize=pCurDim[0];
+      UINT ysize=pCurDim[1];
 
-             #define REQD_TEXMEM 1800000.0f  
+      bool bIsGoodMode=false;
+      bool CouldntFindAnyValidZBuf;
+      D3DFORMAT newPixFmt;
 
-             if(_dxgsg->scrn.MaxAvailVidMem==0) {
-                 //assume buggy drivers return bad val of 0 and everything will be OK
-                 bIsGoodMode=true;
-             } else {
-                 bIsGoodMode = ((((float)xsize*(float)ysize)*6+REQD_TEXMEM) < (float)_dxgsg->scrn.MaxAvailVidMem);
-             }
-         }
+      search_for_valid_displaymode(xsize,ysize,_dxgsg->scrn.PresParams.EnableAutoDepthStencil!=false,
+                                    IS_STENCIL_FORMAT(_dxgsg->scrn.PresParams.AutoDepthStencilFormat),
+                                    &_dxgsg->scrn.SupportedScreenDepthsMask,&CouldntFindAnyValidZBuf,
+                                    &newPixFmt);
 
-       if(bIsGoodMode)
+      if(newPixFmt!=D3DFMT_UNKNOWN)
          num_valid_modes++;
-        else {
+       else {
+            // tell caller the mode is invalid
             pCurDim[0] = 0;
             pCurDim[1] = 0;
-        }
+       }
    }
 
    return num_valid_modes;
- #endif
 }
 
 BOOL WINAPI DX7_DriverEnumCallback( GUID* pGUID, TCHAR* strDesc,TCHAR* strName,VOID *argptr, HMONITOR hm) {
@@ -1468,15 +1434,27 @@ find_all_card_memavails(void) {
     
         pDD->Release();  // release DD obj, since this is all we needed it for
         
+        if(dwVidMemTotal==0)   // unreliable driver
+            dwVidMemTotal=0xFFFFFFFF;
+         else {
+             // assume they wont return a proper max value, so
+             // round up to next pow of 2
+             UINT count=0;
+             while((dwVidMemTotal >> count)!=0)
+                count++;
+             dwVidMemTotal = (1 << count);
+         }
+        
         // after SetDisplayMode, GetAvailVidMem totalmem seems to go down by 1.2 meg (contradicting above
         // comment and what I think would be correct behavior (shouldnt FS mode release the desktop vidmem?),
         // so this is the true value
         (*g_pCardIDVec)[i].MaxAvailVidMem = dwVidMemTotal;
-        
+
+
         #define LOWVIDMEMTHRESHOLD 3500000
         #define CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 1000000
         
-        // assume buggy drivers (this means you, FireGL2) may return zero for dwVidMemTotal, so ignore value if its < CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD
+        // assume buggy drivers (this means you, FireGL2) may return zero (or small amts) for dwVidMemTotal, so ignore value if its < CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD
         (*g_pCardIDVec)[i].bIsLowVidMemCard = ((dwVidMemTotal>CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD) && (dwVidMemTotal< LOWVIDMEMTHRESHOLD));
     }
 
@@ -1559,7 +1537,7 @@ int D3DFMT_to_DepthBits(D3DFORMAT fmt) {
     }
 }
 
-bool wdxGraphicsWindow::FindBestDepthFormat(DXScreenData &Display,D3DDISPLAYMODE &TestDisplayMode,D3DFORMAT *pBestFmt,bool bWantStencil) const {
+bool wdxGraphicsWindow::FindBestDepthFormat(DXScreenData &Display,D3DDISPLAYMODE &TestDisplayMode,D3DFORMAT *pBestFmt,bool bWantStencil,bool bForce16bpp) const {
     // list fmts in order of preference
     #define NUM_TEST_ZFMTS 3
     static D3DFORMAT NoStencilPrefList[NUM_TEST_ZFMTS]={D3DFMT_D32,D3DFMT_D24X8,D3DFMT_D16};
@@ -1574,18 +1552,17 @@ bool wdxGraphicsWindow::FindBestDepthFormat(DXScreenData &Display,D3DDISPLAYMODE
     HRESULT hr;
 
     // nvidia likes zbuf depth to match rendertarget depth
-    bool bOnlySelect16bpp= (dx_force_16bpp_zbuffer ||
-        (IS_NVIDIA(Display.DXDeviceID) && ((TestDisplayMode.Format==D3DFMT_X1R5G5B5) ||
-                                           (TestDisplayMode.Format==D3DFMT_R5G6B5))));
+    bool bOnlySelect16bpp= (dx_force_16bpp_zbuffer || bForce16bpp ||
+        (IS_NVIDIA(Display.DXDeviceID) && IS_16BPP_DISPLAY_FORMAT(TestDisplayMode.Format)));
     
     for(int i=0;i<NUM_TEST_ZFMTS;i++) {
         D3DFORMAT TestDepthFmt = (bWantStencil ? StencilPrefList[i] : NoStencilPrefList[i]);
 
-        if(bOnlySelect16bpp && (TestDepthFmt!=D3DFMT_D16) && (TestDepthFmt!=D3DFMT_D15S1))
+        if(bOnlySelect16bpp && !IS_16BPP_ZBUFFER(TestDepthFmt))
             continue;
 
         hr = Display.pD3D8->CheckDeviceFormat(Display.CardIDNum,D3DDEVTYPE_HAL,TestDisplayMode.Format,
-                                  D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,TestDepthFmt);
+                                              D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,TestDepthFmt);
 
         if(FAILED(hr)) {
           if(hr==D3DERR_NOTAVAILABLE)
@@ -1639,13 +1616,16 @@ void wdxGraphicsWindow::search_for_valid_displaymode(UINT RequestedXsize,UINT Re
             exit(1); 
         }
 
+        if((dispmode.Width!=RequestedXsize) || (dispmode.Height!=RequestedYsize))
+            continue;
+
         if((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) {
             // dont want refresh rates under 60Hz, but 0 or 1 might indicate a default refresh rate, which is usually >=60
             continue;
         }
 
-        if((dispmode.Width!=RequestedXsize) || (dispmode.Height!=RequestedYsize))
-            continue;
+        // Note no attempt is made to verify if format will work at requested size, so even if this call
+        // succeeds, could still get an out-of-video-mem error
 
         hr = _dxgsg->scrn.pD3D8->CheckDeviceFormat(_dxgsg->scrn.CardIDNum,D3DDEVTYPE_HAL,dispmode.Format,
                                                    D3DUSAGE_RENDERTARGET,D3DRTYPE_SURFACE,dispmode.Format);
@@ -1653,17 +1633,73 @@ void wdxGraphicsWindow::search_for_valid_displaymode(UINT RequestedXsize,UINT Re
            if(hr==D3DERR_NOTAVAILABLE)
                continue;
              else {
-                 wdxdisplay_cat.error() << "CheckDeviceFormat failed for device #"<<_dxgsg->scrn.CardIDNum << D3DERRORSTRING(hr);
+                 wdxdisplay_cat.error() << "CheckDeviceFormat failed for device #" <<_dxgsg->scrn.CardIDNum << D3DERRORSTRING(hr);
                  exit(1); 
              }
         }
 
+        bool bIs16bppRenderTgt = IS_16BPP_DISPLAY_FORMAT(dispmode.Format);
+        float RendTgtMinMemReqmt;
+
+        // if we have a valid memavail value, try to determine if we have enough space
+        if(_dxgsg->scrn.MaxAvailVidMem!=0xFFFFFFFF) {
+            // assume user is testing fullscreen, not windowed, so use the dwTotal value
+            // see if 3 scrnbufs (front/back/z)at 16bpp at xsize*ysize will fit with a few 
+            // extra megs for texmem
+
+            // 8MB Rage Pro says it has 6.8 megs Total free and will run at 1024x768, so
+            // formula makes it so that is OK
+
+             #define REQD_TEXMEM 1800000
+             
+             float bytes_per_pixel = (bIs16bppRenderTgt ? 2 : 4);
+             assert(_props._mask & W_DOUBLE);
+
+             // *2 for double buffer
+
+             RendTgtMinMemReqmt = ((float)RequestedXsize)*((float)RequestedYsize)*bytes_per_pixel*2+REQD_TEXMEM;
+
+             if(RendTgtMinMemReqmt>_dxgsg->scrn.MaxAvailVidMem) {
+                 if(wdxdisplay_cat.is_debug())
+                     wdxdisplay_cat.debug() << "not enough VidMem for render tgt, skipping display fmt " << D3DFormatStr(dispmode.Format) 
+                                            << " (" << (int)RendTgtMinMemReqmt << " > " << _dxgsg->scrn.MaxAvailVidMem << ")\n";
+                 continue;
+             }
+        }
+
         if(bWantZBuffer) {
-            D3DFORMAT junk;
-            if(!FindBestDepthFormat(_dxgsg->scrn,dispmode,&junk,bWantStencil)) {
+            D3DFORMAT zformat;
+            if(!FindBestDepthFormat(_dxgsg->scrn,dispmode,&zformat,bWantStencil,false)) {
                 *pCouldntFindAnyValidZBuf=true;
                 continue;
             }
+
+            if(_dxgsg->scrn.MaxAvailVidMem!=0xFFFFFFFF) {
+                // test memory
+                float zbytes_per_pixel = (IS_16BPP_ZBUFFER(zformat) ? 2 : 4);
+                float MinMemReqmt = RendTgtMinMemReqmt + ((float)RequestedXsize)*((float)RequestedYsize)*zbytes_per_pixel;
+
+                if(MinMemReqmt>_dxgsg->scrn.MaxAvailVidMem) {
+                    if(!IS_16BPP_ZBUFFER(zformat)) {
+                        // see if things fit with a 16bpp zbuffer
+
+                        if(!FindBestDepthFormat(_dxgsg->scrn,dispmode,&zformat,bWantStencil,true)) {
+                            *pCouldntFindAnyValidZBuf=true;
+                            continue;
+                        }
+
+                        float MinMemReqmt = RendTgtMinMemReqmt + ((float)RequestedXsize)*((float)RequestedYsize)*zbytes_per_pixel;
+                        if(MinMemReqmt>_dxgsg->scrn.MaxAvailVidMem) {
+                            if(wdxdisplay_cat.is_debug())
+                                wdxdisplay_cat.debug() << "not enough VidMem for RendTgt+zbuf, skipping display fmt " << D3DFormatStr(dispmode.Format)
+                                                       << " (" << (int)MinMemReqmt << " > " << _dxgsg->scrn.MaxAvailVidMem << ")\n";
+                            continue;
+                        }
+                        // right now I'm not going to use these flags, just let the create fail out-of-mem and retry at 16bpp
+                        *pSupportedScreenDepthsMask |= (IS_16BPP_DISPLAY_FORMAT(dispmode.Format) ? DISPLAY_16BPP_REQUIRES_16BPP_ZBUFFER_FLAG : DISPLAY_32BPP_REQUIRES_16BPP_ZBUFFER_FLAG);
+                    }
+                }
+            }
         }
 
         switch(dispmode.Format) {
@@ -1775,21 +1811,33 @@ bool wdxGraphicsWindow::search_for_device(LPDIRECT3D8 pD3D8,DXDeviceInfo *pDevIn
         _props._xorg = _props._yorg = 0;
         
         bool bCouldntFindValidZBuf;
-        search_for_valid_displaymode(dwRenderWidth,dwRenderHeight,bNeedZBuffer,bWantStencil,
+        if(!_dxgsg->scrn.bIsLowVidMemCard) {
+            search_for_valid_displaymode(dwRenderWidth,dwRenderHeight,bNeedZBuffer,bWantStencil,
                                      &_dxgsg->scrn.SupportedScreenDepthsMask,
                                      &bCouldntFindValidZBuf,
                                      &pixFmt);
+    
+            // note I'm not saving refresh rate, will just use adapter default at given res for now
+    
+            if(pixFmt==D3DFMT_UNKNOWN) {
+                wdxdisplay_cat.fatal() 
+                    << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
+                    << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _dxgsg->scrn.CardIDNum <<endl;
+               return false;
+            }
+        } else {
+            // Low Memory card
+               dwRenderWidth=640;
+               dwRenderHeight=480;
+               dx_force_16bpptextures = true;
 
-        // note I'm not saving refresh rate, will just use adapter default at given res for now
+               // force 16bpp zbuf? or let user get extra bits if they have the mem?
+
+               search_for_valid_displaymode(dwRenderWidth,dwRenderHeight,bNeedZBuffer,bWantStencil,
+                                     &_dxgsg->scrn.SupportedScreenDepthsMask,
+                                     &bCouldntFindValidZBuf,
+                                     &pixFmt);
 
-        if(pixFmt==D3DFMT_UNKNOWN) {
-            wdxdisplay_cat.fatal() 
-                << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
-                << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _dxgsg->scrn.CardIDNum <<endl;
-           return false;
-        }
-        
-        if(_dxgsg->scrn.bIsLowVidMemCard) {
                // hack: figuring out exactly what res to use is tricky, instead I will
                // just use 640x480 if we have < 3 meg avail
     
@@ -1802,14 +1850,13 @@ bool wdxGraphicsWindow::search_for_device(LPDIRECT3D8 pD3D8,DXDeviceInfo *pDevIn
                    << " for device #" << pDevInfo->cardID << " (" <<  _dxgsg->scrn.DXDeviceID.Description <<"), skipping device...\n";
                    return false;
                }
-               dwRenderWidth=640;
-               dwRenderHeight=480;
-               dx_force_16bpptextures = true;
         
                if(wdxdisplay_cat.is_info())
                    wdxdisplay_cat.info() << "Available VidMem (" << _dxgsg->scrn.MaxAvailVidMem << ") is under " << LOWVIDMEMTHRESHOLD <<", using 640x480 16bpp rendertargets to save tex vidmem.\n";
         }
     } else {
+        // Windowed Mode
+
         D3DDISPLAYMODE dispmode;
         hr=pD3D8->GetAdapterDisplayMode(pDevInfo->cardID,&dispmode);
         if(FAILED(hr)) {
@@ -1952,7 +1999,7 @@ CreateScreenBuffersAndDevice(DXScreenData &Display) {
     }
     
     if(Display.PresParams.EnableAutoDepthStencil) {
-        if(!FindBestDepthFormat(Display,Display.DisplayMode,&Display.PresParams.AutoDepthStencilFormat,bWantStencil)) {
+        if(!FindBestDepthFormat(Display,Display.DisplayMode,&Display.PresParams.AutoDepthStencilFormat,bWantStencil,false)) {
             wdxdisplay_cat.error() << "FindBestDepthFormat failed in CreateScreenBuffers for device #"<<Display.CardIDNum<< endl;
             goto Fallback_to_16bpp_buffers;
         }
@@ -2104,7 +2151,7 @@ CreateScreenBuffersAndDevice(DXScreenData &Display) {
 
 Fallback_to_16bpp_buffers:
 
-    if(!IS_16BPP_FORMAT(pPresParams->BackBufferFormat) &&
+    if(!IS_16BPP_DISPLAY_FORMAT(pPresParams->BackBufferFormat) &&
        (Display.SupportedScreenDepthsMask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) {
             // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers
 
@@ -2114,9 +2161,18 @@ Fallback_to_16bpp_buffers:
 
             dx_force_16bpp_zbuffer=true;
             if(wdxdisplay_cat.info())
-               wdxdisplay_cat.info() << "CreateDevice failed, retrying w/16bpp buffers on device #"<< Display.CardIDNum << D3DERRORSTRING(hr);
+               wdxdisplay_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #"<< Display.CardIDNum << endl;
             CreateScreenBuffersAndDevice(Display);
             return;
+    } else if(!((dwRenderWidth==640)&&(dwRenderWidth==480))) {
+        if(wdxdisplay_cat.info())
+           wdxdisplay_cat.info() << "CreateDevice failed w/out-of-vidmem, retrying at 640x480 w/16bpp buffers on device #"<< Display.CardIDNum << endl;
+        // try final fallback to 640x480x16
+        dx_force_16bpp_zbuffer=true;
+        Display.DisplayMode.Width=640;
+        Display.DisplayMode.Height=480;
+        CreateScreenBuffersAndDevice(Display);
+        return;
     } else {
         exit(1);
     }

+ 1 - 1
panda/src/wdxdisplay8/wdxGraphicsWindow8.h

@@ -94,7 +94,7 @@ protected:
   void search_for_valid_displaymode(UINT RequestedXsize,UINT RequestedYsize,bool bWantZBuffer,bool bWantStencil,
                                     UINT *pSupportedScreenDepthsMask,bool *pCouldntFindAnyValidZBuf,
                                     D3DFORMAT *pSuggestedPixFmt);
-  bool FindBestDepthFormat(DXScreenData &Display,D3DDISPLAYMODE &TestDisplayMode,D3DFORMAT *pBestFmt,bool bWantStencil) const;
+  bool FindBestDepthFormat(DXScreenData &Display,D3DDISPLAYMODE &TestDisplayMode,D3DFORMAT *pBestFmt,bool bWantStencil,bool bForce16bpp) const;
   void init_resized_window(void);
   bool reset_device_resize_window(RECT &viewrect);
   void setup_colormap(void);