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!
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),

View File

@ -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();

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
// Access: Published

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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::

View File

@ -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.