explicit sync_frame and flip_frame

This commit is contained in:
David Rose 2003-01-22 19:54:56 +00:00
parent 8c6e59f6a9
commit 8b9c2ae9c6
7 changed files with 121 additions and 22 deletions

View File

@ -57,6 +57,12 @@ const bool pstats_unused_states = config_display.GetBool("pstats-unused-states",
// system! // system!
const string threading_model = config_display.GetString("threading-model", ""); 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 // Use the variable load-display to specifiy the name of the default
// graphics display library or GraphicsPipe to load. It is the name // graphics display library or GraphicsPipe to load. It is the name
// of a shared library (or * for all libraries named in aux-display), // of a shared library (or * for all libraries named in aux-display),

View File

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

View File

@ -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 // Function: GraphicsEngine::make_window
// Access: Published // Access: Published

View File

@ -55,7 +55,8 @@ GraphicsEngine(Pipeline *pipeline) :
display_cat.info() display_cat.info()
<< "Using threading model " << _threading_model << "\n"; << "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. // don't do that.
MutexHolder holder(_lock); MutexHolder holder(_lock);
if (_needs_sync) { if (_flip_state != FS_flip) {
// Flip the windows from the previous frame, if necessary. do_flip_frame();
do_sync_frame();
} }
// Grab each thread's mutex again after all windows have flipped. // 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 // Some threads may still be drawing, so indicate that we have to
// wait for those threads before we can flip. // 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 // But if we don't have any threads, go ahead and flip the frame
// now. No point in waiting if we're single-threaded. // now. No point in waiting if we're single-threaded.
if (_threads.empty()) { if (_threads.empty() && _auto_flip) {
do_sync_frame(); do_flip_frame();
} }
} }
@ -323,20 +323,35 @@ render_frame() {
// Function: GraphicsEngine::sync_frame // Function: GraphicsEngine::sync_frame
// Access: Published // Access: Published
// Description: Waits for all the threads that started drawing their // 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 // last frame to finish drawing, and then flips all the
// windows. It is not usually necessary to call this // windows. It is not usually necessary to call this
// explicitly, unless you need to see the previous frame // explicitly, unless you need to see the previous frame
// right away. // right away.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void GraphicsEngine:: void GraphicsEngine::
sync_frame() { flip_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); 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:: void GraphicsEngine::
do_sync_frame() { do_sync_frame() {
// First, wait for all the threads to finish their current frame. nassertv(_flip_state == FS_draw);
// Grabbing the mutex should achieve that.
// 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; Threads::const_iterator ti;
for (ti = _threads.begin(); ti != _threads.end(); ++ti) { for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
RenderThread *thread = (*ti).second; RenderThread *thread = (*ti).second;
@ -549,7 +588,7 @@ do_sync_frame() {
thread->_cv_mutex.release(); thread->_cv_mutex.release();
} }
_needs_sync = false; _flip_state = FS_flip;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -56,6 +56,9 @@ PUBLISHED:
void set_threading_model(const string &threading_model); void set_threading_model(const string &threading_model);
string get_threading_model() const; 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); INLINE GraphicsWindow *make_window(GraphicsPipe *pipe);
GraphicsWindow *make_window(GraphicsPipe *pipe, GraphicsWindow *make_window(GraphicsPipe *pipe,
const string &threading_model); const string &threading_model);
@ -64,6 +67,7 @@ PUBLISHED:
void render_frame(); void render_frame();
void sync_frame(); void sync_frame();
void flip_frame();
void render_subframe(GraphicsStateGuardian *gsg, DisplayRegion *dr, void render_subframe(GraphicsStateGuardian *gsg, DisplayRegion *dr,
bool cull_sorting); bool cull_sorting);
@ -80,6 +84,7 @@ private:
void process_events(const GraphicsEngine::Windows &wlist); void process_events(const GraphicsEngine::Windows &wlist);
void flip_windows(const GraphicsEngine::Windows &wlist); void flip_windows(const GraphicsEngine::Windows &wlist);
void do_sync_frame(); void do_sync_frame();
void do_flip_frame();
PT(SceneSetup) setup_scene(const NodePath &camera, PT(SceneSetup) setup_scene(const NodePath &camera,
GraphicsStateGuardian *gsg); GraphicsStateGuardian *gsg);
@ -143,8 +148,14 @@ private:
typedef pmap<string, PT(RenderThread) > Threads; typedef pmap<string, PT(RenderThread) > Threads;
Threads _threads; Threads _threads;
string _threading_model; 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; Mutex _lock;
static PStatCollector _cull_pcollector; static PStatCollector _cull_pcollector;

View File

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

View File

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