Browse Source

add dx_sync_video, move WaitForVerticalBlank

David Rose 24 years ago
parent
commit
f27f662b82

+ 5 - 0
panda/src/dxgsg/config_dxgsg.cxx

@@ -35,6 +35,11 @@ bool dx_show_transforms = config_dxgsg.GetBool("dx-show-transforms", false);
 //  If false, it will just blit into a window.
 //  If false, it will just blit into a window.
 bool dx_full_screen = config_dxgsg.GetBool("dx-full-screen", false);
 bool dx_full_screen = config_dxgsg.GetBool("dx-full-screen", false);
 
 
+//  Configure this true to force the rendering to sync to the video
+//  refresh, or false to let your frame rate go as high as it can,
+//  irrespective of the video refresh.
+bool dx_sync_video = config_dxgsg.GetBool("sync-video", true);
+
 // Configure this true to perform a cull traversal over the geometry
 // Configure this true to perform a cull traversal over the geometry
 // by default, false otherwise.  The cull traversal provides support
 // by default, false otherwise.  The cull traversal provides support
 // for state-sorting, z-sorting, and binning.
 // for state-sorting, z-sorting, and binning.

+ 1 - 0
panda/src/dxgsg/config_dxgsg.h

@@ -26,6 +26,7 @@ NotifyCategoryDecl(dxgsg, EXPCL_PANDADX, EXPTP_PANDADX);
 
 
 extern bool dx_show_transforms;
 extern bool dx_show_transforms;
 extern bool dx_full_screen;
 extern bool dx_full_screen;
+extern bool dx_sync_video;
 extern bool dx_cull_traversal;
 extern bool dx_cull_traversal;
 extern bool dx_ignore_mipmaps;
 extern bool dx_ignore_mipmaps;
 extern bool dx_force_16bpp_screenbuffers;
 extern bool dx_force_16bpp_screenbuffers;

+ 69 - 35
panda/src/dxgsg/dxGraphicsStateGuardian.cxx

@@ -82,6 +82,7 @@
 #include <pStatTimer.h>
 #include <pStatTimer.h>
 #include <pStatCollector.h>
 #include <pStatCollector.h>
 
 
+
 #define DISABLE_POLYGON_OFFSET_DECALING
 #define DISABLE_POLYGON_OFFSET_DECALING
 // currently doesnt work well enough in toontown models for us to use
 // currently doesnt work well enough in toontown models for us to use
 // prob is when viewer gets close to decals, they disappear into wall poly, need to investigate
 // prob is when viewer gets close to decals, they disappear into wall poly, need to investigate
@@ -5560,12 +5561,12 @@ HRESULT DXGraphicsStateGuardian::RestoreAllVideoSurfaces(void) {
 //       Description:   Repaint primary buffer from back buffer
 //       Description:   Repaint primary buffer from back buffer
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::show_frame(void) {
 void DXGraphicsStateGuardian::show_frame(void) {
-  PStatTimer timer(_win->_swap_pcollector);  // this times just the flip, so it must go here in dxgsg, instead of wdxdisplay, which would time the whole frame
+  if(_pri==NULL)
+    return;
 
 
-    if(_pri==NULL)
-        return;
+  PStatTimer timer(_win->_swap_pcollector);  // this times just the flip, so it must go here in dxgsg, instead of wdxdisplay, which would time the whole frame
 
 
-    if(dx_full_screen) {
+  if(dx_full_screen) {
     show_full_screen_frame();
     show_full_screen_frame();
   } else {
   } else {
     show_windowed_frame();
     show_windowed_frame();
@@ -5578,7 +5579,22 @@ void DXGraphicsStateGuardian::show_frame(void) {
 //       Description:   Repaint primary buffer from back buffer
 //       Description:   Repaint primary buffer from back buffer
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::show_full_screen_frame(void) {
 void DXGraphicsStateGuardian::show_full_screen_frame(void) {
-  HRESULT hr = _pri->Flip( NULL, DDFLIP_WAIT );  // bugbug:  dont we want triple buffering instead of wasting time waiting for vsync?
+  HRESULT hr;
+  
+  // Flip the front and back buffers, to make what we just rendered
+  // visible.
+  if (dx_sync_video) {
+    // bugbug: dont we want triple buffering instead of wasting time
+    // waiting for vsync?
+    hr = _pri->Flip( NULL, DDFLIP_WAIT );
+  } else {
+    // If the user indicated via Config that we shouldn't wait for
+    // video sync, then don't wait (if the hardware supports this).
+    // This will introduce visible artifacts like tearing, and may
+    // cause the frame rate to grow excessively (and pointlessly)
+    // high, starving out other processes.
+    hr = _pri->Flip( NULL, DDFLIP_WAIT | DDFLIP_NOVSYNC );
+  }
 
 
   if(hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY) {
   if(hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY) {
     //full screen app has been switched away
     //full screen app has been switched away
@@ -5634,52 +5650,80 @@ void DXGraphicsStateGuardian::show_full_screen_frame(void) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: show_windowed_frame
 //     Function: show_windowed_frame
-//       Access:
-//       Description:   Repaint primary buffer from back buffer  (windowed mode only)
+//       Access: Public
+//  Description: Repaint primary buffer from back buffer (windowed
+//               mode only)
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::show_windowed_frame(void) {
 void DXGraphicsStateGuardian::show_windowed_frame(void) {
-  DX_DECLARE_CLEAN(DDBLTFX, bltfx);
+  HRESULT hr;
+
+  if (dx_sync_video) {
+    // Wait for the video refresh *before* we blt the rendered image
+    // onto the window.  This will (a) prevent the "tearing" of the
+    // image that would occur if only part of the image happened to be
+    // copied into the window before the video refresh occurred, and
+    // (b) prevent our frame rate from going excessively (and
+    // pointlessly) higher than our video refresh rate, starving out
+    // other processes.
+
+    // Unfortunately, when the system is even lightly loaded, this
+    // wait call sometimes appears to wait through multiple frames
+    // before returning, causing our frame rate to be unreasonably low
+    // and erratic.  There doesn't appear to be any way to prevent
+    // this behavior; thus, we allow the user to avoid this wait,
+    // based on the Config settings.
+
+    hr = _pDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
+    if(hr != DD_OK) {
+      dxgsg_cat.error() << "DXGraphicsStateGuardian::WaitForVerticalBlank() failed : " << ConvD3DErrorToString(hr) << endl;
+      exit(1);
+    }
+  }
 
 
+  DX_DECLARE_CLEAN(DDBLTFX, bltfx);
+  
   bltfx.dwDDFX |= DDBLTFX_NOTEARING;
   bltfx.dwDDFX |= DDBLTFX_NOTEARING;
-  HRESULT hr = _pri->Blt( &_view_rect, _back,  NULL, DDBLT_DDFX | DDBLT_WAIT, &bltfx );
+  hr = _pri->Blt( &_view_rect, _back,  NULL, DDBLT_DDFX | DDBLT_WAIT, &bltfx );
 
 
   if(FAILED(hr)) {
   if(FAILED(hr)) {
     if(hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY) {
     if(hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY) {
 
 
       HRESULT hr;
       HRESULT hr;
 
 
-            // TestCooperativeLevel returns DD_OK: If the current mode is same as the one which the App set.
-            // The following two errors are returned to NORMALMODE (windowed)apps only.
-            //
-            // DDERR_WRONGMODE: If the App is a windowed app and the current mode is
-            //                  not the same as the one in which the app was created.
-            // DDERR_EXCLUSIVEMODEALREADYSET: If another app took exclusivemode access
+      // TestCooperativeLevel returns DD_OK: If the current mode is
+      // same as the one which the App set.  The following two errors
+      // are returned to NORMALMODE (windowed)apps only.
+      //
+      // DDERR_WRONGMODE: If the App is a windowed app and the current mode is
+      //                  not the same as the one in which the app was created.
+      // DDERR_EXCLUSIVEMODEALREADYSET: If another app took exclusivemode access
       hr = _pDD->TestCooperativeLevel();
       hr = _pDD->TestCooperativeLevel();
       while(hr == DDERR_EXCLUSIVEMODEALREADYSET) {
       while(hr == DDERR_EXCLUSIVEMODEALREADYSET) {
-                // This means that mode changes had taken place, surfaces
-                // were lost but still we are in the original mode, so we
-                // simply restore all surfaces and keep going.
-
+        // This means that mode changes had taken place, surfaces
+        // were lost but still we are in the original mode, so we
+        // simply restore all surfaces and keep going.
+        
         _dx_ready = FALSE;
         _dx_ready = FALSE;
-
+        
 #ifdef _DEBUG
 #ifdef _DEBUG
         dxgsg_cat.spam() << "DXGraphicsStateGuardian:: another app has exclusive mode, waiting...\n";
         dxgsg_cat.spam() << "DXGraphicsStateGuardian:: another app has exclusive mode, waiting...\n";
 #endif
 #endif
 
 
         Sleep( 500 );   // Dont consume CPU.
         Sleep( 500 );   // Dont consume CPU.
         throw_event("PandaPaused");   // throw panda event to invoke network-only processing
         throw_event("PandaPaused");   // throw panda event to invoke network-only processing
-
+        
         hr = _pDD->TestCooperativeLevel();
         hr = _pDD->TestCooperativeLevel();
       }
       }
-
+      
       if(hr==DDERR_WRONGMODE) {
       if(hr==DDERR_WRONGMODE) {
-                // This means that the desktop mode has changed
-                // need to destroy all of dx stuff and recreate everything back again, which is a big hit
+        // This means that the desktop mode has changed
+        // need to destroy all of dx stuff and recreate everything
+        // back again, which is a big hit
         dxgsg_cat.error() << "DXGraphicsStateGuardian:: detected display mode change in TestCoopLevel, must recreate all DDraw surfaces, D3D devices, this is not handled yet.  " << ConvD3DErrorToString(hr) << endl;
         dxgsg_cat.error() << "DXGraphicsStateGuardian:: detected display mode change in TestCoopLevel, must recreate all DDraw surfaces, D3D devices, this is not handled yet.  " << ConvD3DErrorToString(hr) << endl;
         exit(1);
         exit(1);
         return;
         return;
       }
       }
-
+      
       if(FAILED(hr)) {
       if(FAILED(hr)) {
         dxgsg_cat.error() << "DXGraphicsStateGuardian::unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl;
         dxgsg_cat.error() << "DXGraphicsStateGuardian::unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl;
         return;
         return;
@@ -5700,16 +5744,6 @@ void DXGraphicsStateGuardian::show_windowed_frame(void) {
       exit(1);
       exit(1);
     }
     }
   }
   }
-
-  // right now, we force sync to v-blank (time from now up to vblank
-  // is wasted) this keeps calling processes from trying to render
-  // more frames than the refresh rate since (as implemented right
-  // now) they expect this call to block
-  hr =  _pDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
-  if(hr != DD_OK) {
-    dxgsg_cat.error() << "DXGraphicsStateGuardian::WaitForVerticalBlank() failed : " << ConvD3DErrorToString(hr) << endl;
-    exit(1);
-  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////