Просмотр исходного кода

explicit sync_frame and flip_frame

David Rose 23 лет назад
Родитель
Сommit
8b9c2ae9c6

+ 6 - 0
panda/src/display/config_display.cxx

@@ -57,6 +57,12 @@ const bool pstats_unused_states = config_display.GetBool("pstats-unused-states",
 // system!
 const string threading_model = config_display.GetString("threading-model", "");
 
+// This indicates the initial setting of the auto-flip flag.  Set it
+// true (the default) to cause render_frame() to flip all the windows
+// before it returns (in single-threaded mode only), or false to wait
+// until an explicit call to flip_frame() or the next render_frame().
+const bool auto_flip = config_display.GetBool("auto-flip", true);
+
 // Use the variable load-display to specifiy the name of the default
 // graphics display library or GraphicsPipe to load.  It is the name
 // of a shared library (or * for all libraries named in aux-display),

+ 1 - 0
panda/src/display/config_display.h

@@ -34,6 +34,7 @@ extern const bool view_frustum_cull;
 extern const bool pstats_unused_states;
 
 extern const string threading_model;
+extern const bool auto_flip;
 
 extern EXPCL_PANDA void init_libdisplay();
 

+ 38 - 0
panda/src/display/graphicsEngine.I

@@ -17,6 +17,44 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::set_auto_flip
+//       Access: Published
+//  Description: Set this flag true to indicate the GraphicsEngine
+//               should automatically cause windows to sync and flip
+//               at the end of render_frame().
+//
+//               This only applies to a single-threaded rendering
+//               model.  In the presence of threading, the windows are
+//               never auto-flipped, regardless of this flag.
+//
+//               This only affects the timing of when the flip occurs.
+//               If this is true (the default), the flip occurs before
+//               render_frame() returns.  If this is false, the flip
+//               occurs whenever flip_frame() is called, or at the
+//               beginning of the next call to render_frame(), if
+//               flip_frame() is never called.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsEngine::
+set_auto_flip(bool auto_flip) {
+  // We don't bother with the mutex here.  It's just a bool, after
+  // all.
+  _auto_flip = auto_flip;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::get_auto_flip
+//       Access: Published
+//  Description: Returns the current setting for the auto-flip flag.
+//               See set_auto_flip.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsEngine::
+get_auto_flip() const {
+  // We don't bother with the mutex here.  It's just a bool, after
+  // all.
+  return _auto_flip;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::make_window
 //       Access: Published

+ 56 - 17
panda/src/display/graphicsEngine.cxx

@@ -55,7 +55,8 @@ GraphicsEngine(Pipeline *pipeline) :
     display_cat.info()
       << "Using threading model " << _threading_model << "\n";
   }
-  _needs_sync = false;
+  _auto_flip = auto_flip;
+  _flip_state = FS_flip;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -280,9 +281,8 @@ render_frame() {
   // don't do that.
   MutexHolder holder(_lock);
 
-  if (_needs_sync) {
-    // Flip the windows from the previous frame, if necessary.
-    do_sync_frame();
+  if (_flip_state != FS_flip) {
+    do_flip_frame();
   }
   
   // Grab each thread's mutex again after all windows have flipped.
@@ -310,12 +310,12 @@ render_frame() {
 
   // Some threads may still be drawing, so indicate that we have to
   // wait for those threads before we can flip.
-  _needs_sync = true;
+  _flip_state = FS_draw;
 
   // 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();
+  if (_threads.empty() && _auto_flip) {
+    do_flip_frame();
   }
 }
 
@@ -323,20 +323,35 @@ render_frame() {
 //     Function: GraphicsEngine::sync_frame
 //       Access: Published
 //  Description: Waits for all the threads that started drawing their
+//               last frame to finish drawing.  The windows are not
+//               yet flipped when this returns; see also flip_frame().
+//               It is not usually necessary to call this explicitly,
+//               unless you need to see the previous frame right away.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+sync_frame() {
+  MutexHolder holder(_lock);
+
+  if (_flip_state == FS_draw) {
+    do_sync_frame();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::flip_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.
+flip_frame() {
   MutexHolder holder(_lock);
-  if (_needs_sync) {
-    do_sync_frame();
+
+  if (_flip_state != FS_flip) {
+    do_flip_frame();
   }
 }
 
@@ -530,8 +545,32 @@ flip_windows(const GraphicsEngine::Windows &wlist) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::
 do_sync_frame() {
-  // First, wait for all the threads to finish their current frame.
-  // Grabbing the mutex should achieve that.
+  nassertv(_flip_state == FS_draw);
+
+  // Wait for all the threads to finish their current frame.  Grabbing
+  // and releasing 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();
+    thread->_cv_mutex.release();
+  }
+
+  _flip_state = FS_sync;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::do_flip_frame
+//       Access: Private
+//  Description: The implementation of flip_frame().  We assume _lock
+//               is already held before this method is called.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+do_flip_frame() {
+  nassertv(_flip_state == FS_draw || _flip_state == FS_sync);
+
+  // First, wait for all the threads to finish their current frame, if
+  // necessary.  Grabbing the mutex should achieve that.
   Threads::const_iterator ti;
   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
     RenderThread *thread = (*ti).second;
@@ -549,7 +588,7 @@ do_sync_frame() {
     thread->_cv_mutex.release();
   }
 
-  _needs_sync = false;
+  _flip_state = FS_flip;
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -56,6 +56,9 @@ PUBLISHED:
   void set_threading_model(const string &threading_model);
   string get_threading_model() const;
 
+  INLINE void set_auto_flip(bool auto_flip);
+  INLINE bool get_auto_flip() const;
+
   INLINE GraphicsWindow *make_window(GraphicsPipe *pipe);
   GraphicsWindow *make_window(GraphicsPipe *pipe,
                               const string &threading_model);
@@ -64,6 +67,7 @@ PUBLISHED:
 
   void render_frame();
   void sync_frame();
+  void flip_frame();
   
   void render_subframe(GraphicsStateGuardian *gsg, DisplayRegion *dr,
                        bool cull_sorting);
@@ -80,6 +84,7 @@ private:
   void process_events(const GraphicsEngine::Windows &wlist);
   void flip_windows(const GraphicsEngine::Windows &wlist);
   void do_sync_frame();
+  void do_flip_frame();
 
   PT(SceneSetup) setup_scene(const NodePath &camera, 
                              GraphicsStateGuardian *gsg);
@@ -143,8 +148,14 @@ private:
   typedef pmap<string, PT(RenderThread) > Threads;
   Threads _threads;
   string _threading_model;
+  bool _auto_flip;
 
-  bool _needs_sync;
+  enum FlipState {
+    FS_draw,  // Still drawing.
+    FS_sync,  // All windows are done drawing.
+    FS_flip,  // All windows are done drawing and have flipped.
+  };
+  FlipState _flip_state;
   Mutex _lock;
 
   static PStatCollector _cull_pcollector;

+ 7 - 3
panda/src/gobj/lens.I

@@ -110,8 +110,12 @@ project(const LPoint3f &point3d, LPoint3f &point2d) const {
 //       Access: Published
 //  Description: Sets the name of the event that will be generated
 //               whenever any properties of the Lens have
-//               changed.  This can be used to automatically track
-//               changes to camera fov, etc. in the simulation.
+//               changed.  If this is not set for a particular lens,
+//               no event will be generated.
+//
+//               The event is thrown with one parameter, the lens
+//               itself.  This can be used to automatically track
+//               changes to camera fov, etc. in the application.
 ////////////////////////////////////////////////////////////////////
 INLINE void Lens::
 set_change_event(const string &event) {
@@ -122,7 +126,7 @@ set_change_event(const string &event) {
 //     Function: Lens::get_change_event
 //       Access: Published
 //  Description: Returns the name of the event that will be generated
-//               whenever any properties of the Lens have
+//               whenever any properties of this particular Lens have
 //               changed.
 ////////////////////////////////////////////////////////////////////
 INLINE const string &Lens::

+ 1 - 1
panda/src/gobj/lens.cxx

@@ -998,7 +998,7 @@ throw_change_event() {
   ++_last_change;
 
   if (!_change_event.empty()) {
-    throw_event(_change_event);
+    throw_event(_change_event, this);
   }
 
   // Also update the _geom_coords, if it is in use.