From 8b9c2ae9c61b41cd707f29c6b68adfee67642a88 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 22 Jan 2003 19:54:56 +0000 Subject: [PATCH] explicit sync_frame and flip_frame --- panda/src/display/config_display.cxx | 6 +++ panda/src/display/config_display.h | 1 + panda/src/display/graphicsEngine.I | 38 +++++++++++++++ panda/src/display/graphicsEngine.cxx | 73 +++++++++++++++++++++------- panda/src/display/graphicsEngine.h | 13 ++++- panda/src/gobj/lens.I | 10 ++-- panda/src/gobj/lens.cxx | 2 +- 7 files changed, 121 insertions(+), 22 deletions(-) diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index cab222aad3..e1ab9e8966 100644 --- a/panda/src/display/config_display.cxx +++ b/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), diff --git a/panda/src/display/config_display.h b/panda/src/display/config_display.h index 6d7bfe346d..a1b0acc336 100644 --- a/panda/src/display/config_display.h +++ b/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(); diff --git a/panda/src/display/graphicsEngine.I b/panda/src/display/graphicsEngine.I index f314a4d9c3..ecc6405a4f 100644 --- a/panda/src/display/graphicsEngine.I +++ b/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 diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 696db02bef..6ff0fd1a7d 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/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; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index 3f7acb7230..2e778dd595 100644 --- a/panda/src/display/graphicsEngine.h +++ b/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 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; diff --git a/panda/src/gobj/lens.I b/panda/src/gobj/lens.I index 6270800bc5..4fede366bf 100644 --- a/panda/src/gobj/lens.I +++ b/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:: diff --git a/panda/src/gobj/lens.cxx b/panda/src/gobj/lens.cxx index 2e77c84b05..e35ee5ace2 100644 --- a/panda/src/gobj/lens.cxx +++ b/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.