From ea31a192b0575e67dce1083b7690a9ef42aab4c1 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 5 Dec 2009 19:04:39 +0000 Subject: [PATCH] add frame_sync flag --- panda/src/event/asyncTaskChain.cxx | 58 +++++++++++++++++++++++++++--- panda/src/event/asyncTaskChain.h | 5 +++ 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/panda/src/event/asyncTaskChain.cxx b/panda/src/event/asyncTaskChain.cxx index 1657f27f6d..1fa853db1d 100644 --- a/panda/src/event/asyncTaskChain.cxx +++ b/panda/src/event/asyncTaskChain.cxx @@ -43,6 +43,7 @@ AsyncTaskChain(AsyncTaskManager *manager, const string &name) : _num_threads(0), _thread_priority(TP_normal), _frame_budget(-1.0), + _frame_sync(false), _num_busy_threads(0), _num_tasks(0), _state(S_initial), @@ -50,7 +51,8 @@ AsyncTaskChain(AsyncTaskManager *manager, const string &name) : _pickup_mode(false), _needs_cleanup(false), _current_frame(0), - _time_in_frame(0.0) + _time_in_frame(0.0), + _block_till_next_frame(false) { } @@ -216,6 +218,43 @@ get_frame_budget() const { return _frame_budget; } +//////////////////////////////////////////////////////////////////// +// Function: AsyncTaskChain::set_frame_sync +// Access: Published +// Description: Sets the frame_sync flag. When this flag is true, +// this task chain will be forced to sync with the +// TaskManager's clock. It will run no faster than one +// epoch per clock frame. +// +// When this flag is false, the default, the task chain +// will finish all of its tasks and then immediately +// start from the first task again, regardless of the +// clock frame. When it is true, the task chain will +// finish all of its tasks and then wait for the clock +// to tick to the next frame before resuming the first +// task. +// +// This only makes sense for threaded task chains. +// Non-threaded task chains are automatically +// synchronous. +//////////////////////////////////////////////////////////////////// +void AsyncTaskChain:: +set_frame_sync(bool frame_sync) { + MutexHolder holder(_manager->_lock); + _frame_sync = frame_sync; +} + +//////////////////////////////////////////////////////////////////// +// Function: AsyncTaskChain::get_frame_sync +// Access: Published +// Description: Returns the frame_sync flag. See set_frame_sync(). +//////////////////////////////////////////////////////////////////// +bool AsyncTaskChain:: +get_frame_sync() const { + MutexHolder holder(_manager->_lock); + return _frame_sync; +} + //////////////////////////////////////////////////////////////////// // Function: AsyncTaskChain::set_timeslice_priority // Access: Published @@ -924,6 +963,11 @@ finish_sort_group() { } _manager->_clock->tick(); _manager->_frame_cvar.notify_all(); + + } else if (_frame_sync) { + // If we're a synced chain, we have to wait at the end of the + // epoch for someone else to tick the clock. + _block_till_next_frame = true; } // Check for any sleeping tasks that need to be woken. @@ -1239,8 +1283,10 @@ do_poll() { if (_current_frame != frame) { _current_frame = frame; _time_in_frame = 0.0; + _block_till_next_frame = false; } - if (_frame_budget >= 0.0 && _time_in_frame >= _frame_budget) { + if (_block_till_next_frame || + (_frame_budget >= 0.0 && _time_in_frame >= _frame_budget)) { // If we've exceeded our budget, stop here. We'll resume from // this point at the next call to poll(). cleanup_pickup_mode(); @@ -1479,12 +1525,15 @@ thread_main() { if (_chain->_current_frame != frame) { _chain->_current_frame = frame; _chain->_time_in_frame = 0.0; + _chain->_block_till_next_frame = false; } // If we've exceeded our frame budget, sleep until the next // frame. - if (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget) { - while (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget && + if (_chain->_block_till_next_frame || + (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget)) { + while ((_chain->_block_till_next_frame || + (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget)) && _chain->_state != S_shutdown && _chain->_state != S_interrupted) { _chain->cleanup_pickup_mode(); _chain->_manager->_frame_cvar.wait(); @@ -1492,6 +1541,7 @@ thread_main() { if (_chain->_current_frame != frame) { _chain->_current_frame = frame; _chain->_time_in_frame = 0.0; + _chain->_block_till_next_frame = false; } } // Now that it's the next frame, go back to the top of the loop. diff --git a/panda/src/event/asyncTaskChain.h b/panda/src/event/asyncTaskChain.h index 50d84e0862..d0768516ea 100644 --- a/panda/src/event/asyncTaskChain.h +++ b/panda/src/event/asyncTaskChain.h @@ -73,6 +73,9 @@ PUBLISHED: void set_frame_budget(double frame_budget); double get_frame_budget() const; + void set_frame_sync(bool frame_sync); + bool get_frame_sync() const; + void set_timeslice_priority(bool timeslice_priority); bool get_timeslice_priority() const; @@ -173,6 +176,7 @@ protected: ThreadPriority _thread_priority; Threads _threads; double _frame_budget; + bool _frame_sync; int _num_busy_threads; int _num_tasks; TaskHeap _active; @@ -186,6 +190,7 @@ protected: int _current_frame; double _time_in_frame; + bool _block_till_next_frame; static PStatCollector _task_pcollector; static PStatCollector _wait_pcollector;