Browse Source

add sync_frame

David Rose 23 years ago
parent
commit
f277976827
2 changed files with 74 additions and 20 deletions
  1. 69 19
      panda/src/display/graphicsEngine.cxx
  2. 5 1
      panda/src/display/graphicsEngine.h

+ 69 - 19
panda/src/display/graphicsEngine.cxx

@@ -55,6 +55,7 @@ GraphicsEngine(Pipeline *pipeline) :
     display_cat.info()
       << "Using threading model " << _threading_model << "\n";
   }
+  _needs_sync = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -278,27 +279,14 @@ render_frame() {
   // threads tries to call any methods on the GraphicsEngine.  So
   // don't do that.
   MutexHolder holder(_lock);
-  
-  // First, wait for all the threads to finish their current frame.
-  // Grabbing the mutex should achieve that.
-  Threads::const_iterator ti;
-  for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
-    RenderThread *thread = (*ti).second;
-    thread->_cv_mutex.lock();
-  }
-  
-  // Now signal all of our threads to flip the windows.
-  _app.do_flip(this);
-  for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
-    RenderThread *thread = (*ti).second;
-    if (thread->_thread_state == TS_wait) {
-      thread->_thread_state = TS_do_flip;
-      thread->_cv.signal();
-    }
-    thread->_cv_mutex.release();
+
+  if (_needs_sync) {
+    // Flip the windows from the previous frame, if necessary.
+    do_sync_frame();
   }
   
-  // Grab the mutex again after all windows have flipped.
+  // Grab each thread's mutex again after all windows have flipped.
+  Threads::const_iterator ti;
   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
     RenderThread *thread = (*ti).second;
     thread->_cv_mutex.lock();
@@ -319,8 +307,40 @@ render_frame() {
     }
     thread->_cv_mutex.release();
   }
+
+  // Some threads may still be drawing, so indicate that we have to
+  // wait for those threads before we can flip.
+  _needs_sync = true;
+
+  // But if we don't have any threads, go ahead and flip the frame
+  // now.  No point in waiting if we're single-threaded.
+  if (_threads.empty()) {
+    do_sync_frame();
+  }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::sync_frame
+//       Access: Published
+//  Description: Waits for all the threads that started drawing their
+//               last frame to finish drawing, and then flips all the
+//               windows.  It is not usually necessary to call this
+//               explicitly, unless you need to see the previous frame
+//               right away.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+sync_frame() {
+  // We hold the GraphicsEngine mutex while we wait for all of the
+  // threads.  Doing this puts us at risk for deadlock if any of the
+  // threads tries to call any methods on the GraphicsEngine.  So
+  // don't do that.
+  MutexHolder holder(_lock);
+  if (_needs_sync) {
+    do_sync_frame();
+  }
+}
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::render_subframe
 //       Access: Published
@@ -502,6 +522,36 @@ flip_windows(const GraphicsEngine::Windows &wlist) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::do_sync_frame
+//       Access: Private
+//  Description: The implementation of sync_frame().  We assume _lock
+//               is already held before this method is called.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+do_sync_frame() {
+  // First, wait for all the threads to finish their current frame.
+  // Grabbing the mutex should achieve that.
+  Threads::const_iterator ti;
+  for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
+    RenderThread *thread = (*ti).second;
+    thread->_cv_mutex.lock();
+  }
+  
+  // Now signal all of our threads to flip the windows.
+  _app.do_flip(this);
+  for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
+    RenderThread *thread = (*ti).second;
+    if (thread->_thread_state == TS_wait) {
+      thread->_thread_state = TS_do_flip;
+      thread->_cv.signal();
+    }
+    thread->_cv_mutex.release();
+  }
+
+  _needs_sync = false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::setup_scene
 //       Access: Private

+ 5 - 1
panda/src/display/graphicsEngine.h

@@ -63,9 +63,11 @@ PUBLISHED:
   void remove_all_windows();
 
   void render_frame();
+  void sync_frame();
+  
   void render_subframe(GraphicsStateGuardian *gsg, DisplayRegion *dr,
                        bool cull_sorting);
-  
+
 private:
   typedef pset< PT(GraphicsWindow) > Windows;
 
@@ -77,6 +79,7 @@ private:
 
   void process_events(const GraphicsEngine::Windows &wlist);
   void flip_windows(const GraphicsEngine::Windows &wlist);
+  void do_sync_frame();
 
   PT(SceneSetup) setup_scene(const NodePath &camera, 
                              GraphicsStateGuardian *gsg);
@@ -141,6 +144,7 @@ private:
   Threads _threads;
   string _threading_model;
 
+  bool _needs_sync;
   Mutex _lock;
 
   static PStatCollector _cull_pcollector;