mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 19:08:55 -04:00
add ClockObject::M_integer and M_integer_limited; pstats clock wait
This commit is contained in:
parent
463cc7be4f
commit
70f9db5ec4
@ -30,11 +30,14 @@
|
|||||||
#include "config_pstats.h"
|
#include "config_pstats.h"
|
||||||
#include "pStatProperties.h"
|
#include "pStatProperties.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "clockObject.h"
|
||||||
|
|
||||||
PStatCollector PStatClient::_total_size_pcollector("Memory usage");
|
PStatCollector PStatClient::_total_size_pcollector("Memory usage");
|
||||||
PStatCollector PStatClient::_cpp_size_pcollector("Memory usage:C++");
|
PStatCollector PStatClient::_cpp_size_pcollector("Memory usage:C++");
|
||||||
PStatCollector PStatClient::_interpreter_size_pcollector("Memory usage:Interpreter");
|
PStatCollector PStatClient::_interpreter_size_pcollector("Memory usage:Interpreter");
|
||||||
PStatCollector PStatClient::_pstats_pcollector("*:PStats");
|
PStatCollector PStatClient::_pstats_pcollector("*:PStats");
|
||||||
|
PStatCollector PStatClient::_clock_wait_pcollector("Wait:Clock Wait:Sleep");
|
||||||
|
PStatCollector PStatClient::_clock_busy_wait_pcollector("Wait:Clock Wait:Spin");
|
||||||
|
|
||||||
PStatClient *PStatClient::_global_pstats = NULL;
|
PStatClient *PStatClient::_global_pstats = NULL;
|
||||||
|
|
||||||
@ -317,6 +320,10 @@ PStatClient *PStatClient::
|
|||||||
get_global_pstats() {
|
get_global_pstats() {
|
||||||
if (_global_pstats == (PStatClient *)NULL) {
|
if (_global_pstats == (PStatClient *)NULL) {
|
||||||
_global_pstats = new PStatClient;
|
_global_pstats = new PStatClient;
|
||||||
|
|
||||||
|
ClockObject::_start_clock_wait = start_clock_wait;
|
||||||
|
ClockObject::_start_clock_busy_wait = start_clock_busy_wait;
|
||||||
|
ClockObject::_stop_clock_wait = stop_clock_wait;
|
||||||
}
|
}
|
||||||
return _global_pstats;
|
return _global_pstats;
|
||||||
}
|
}
|
||||||
@ -796,6 +803,58 @@ get_level(int collector_index, int thread_index) const {
|
|||||||
return collector->_per_thread[thread_index]._level / factor;
|
return collector->_per_thread[thread_index]._level / factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PStatClient::start_clock_wait
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: This function is added as a hook into ClockObject, so
|
||||||
|
// that we may time the delay for
|
||||||
|
// ClockObject::wait_until(), used for certain special
|
||||||
|
// clock modes.
|
||||||
|
//
|
||||||
|
// This callback is a hack around the fact that we can't
|
||||||
|
// let the ClockObject directly create a PStatCollector,
|
||||||
|
// because the pstatclient module depends on putil.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PStatClient::
|
||||||
|
start_clock_wait() {
|
||||||
|
_clock_wait_pcollector.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PStatClient::start_clock_busy_wait
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: This function is added as a hook into ClockObject, so
|
||||||
|
// that we may time the delay for
|
||||||
|
// ClockObject::wait_until(), used for certain special
|
||||||
|
// clock modes.
|
||||||
|
//
|
||||||
|
// This callback is a hack around the fact that we can't
|
||||||
|
// let the ClockObject directly create a PStatCollector,
|
||||||
|
// because the pstatclient module depends on putil.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PStatClient::
|
||||||
|
start_clock_busy_wait() {
|
||||||
|
_clock_wait_pcollector.stop();
|
||||||
|
_clock_busy_wait_pcollector.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PStatClient::stop_clock_wait
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: This function is added as a hook into ClockObject, so
|
||||||
|
// that we may time the delay for
|
||||||
|
// ClockObject::wait_until(), used for certain special
|
||||||
|
// clock modes.
|
||||||
|
//
|
||||||
|
// This callback is a hack around the fact that we can't
|
||||||
|
// let the ClockObject directly create a PStatCollector,
|
||||||
|
// because the pstatclient module depends on putil.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PStatClient::
|
||||||
|
stop_clock_wait() {
|
||||||
|
_clock_busy_wait_pcollector.stop();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PStatClient::add_collector
|
// Function: PStatClient::add_collector
|
||||||
// Access: Private
|
// Access: Private
|
||||||
|
@ -128,6 +128,10 @@ private:
|
|||||||
void add_level(int collector_index, int thread_index, float increment);
|
void add_level(int collector_index, int thread_index, float increment);
|
||||||
float get_level(int collector_index, int thread_index) const;
|
float get_level(int collector_index, int thread_index) const;
|
||||||
|
|
||||||
|
static void start_clock_wait();
|
||||||
|
static void start_clock_busy_wait();
|
||||||
|
static void stop_clock_wait();
|
||||||
|
|
||||||
class Collector;
|
class Collector;
|
||||||
class InternalThread;
|
class InternalThread;
|
||||||
void add_collector(Collector *collector);
|
void add_collector(Collector *collector);
|
||||||
@ -220,6 +224,8 @@ private:
|
|||||||
static PStatCollector _cpp_size_pcollector;
|
static PStatCollector _cpp_size_pcollector;
|
||||||
static PStatCollector _interpreter_size_pcollector;
|
static PStatCollector _interpreter_size_pcollector;
|
||||||
static PStatCollector _pstats_pcollector;
|
static PStatCollector _pstats_pcollector;
|
||||||
|
static PStatCollector _clock_wait_pcollector;
|
||||||
|
static PStatCollector _clock_busy_wait_pcollector;
|
||||||
|
|
||||||
static PStatClient *_global_pstats;
|
static PStatClient *_global_pstats;
|
||||||
|
|
||||||
|
@ -111,6 +111,10 @@ static TimeCollectorProperties time_properties[] = {
|
|||||||
{ 1, "Wait", { 0.6, 0.6, 0.6 } },
|
{ 1, "Wait", { 0.6, 0.6, 0.6 } },
|
||||||
{ 0, "Wait:Mutex block", { 0.5, 0.0, 1.0 } },
|
{ 0, "Wait:Mutex block", { 0.5, 0.0, 1.0 } },
|
||||||
{ 1, "Wait:Thread sync", { 0.0, 1.0, 0.5 } },
|
{ 1, "Wait:Thread sync", { 0.0, 1.0, 0.5 } },
|
||||||
|
{ 1, "Wait:Clock Wait", { 0.2, 0.8, 0.2 } },
|
||||||
|
{ 1, "Wait:Clock Wait:Sleep", { 0.9, 0.4, 0.8 } },
|
||||||
|
{ 1, "Wait:Clock Wait:Spin", { 0.2, 0.8, 1.0 } },
|
||||||
|
{ 0, "Wait:Mutex block", { 0.5, 0.0, 1.0 } },
|
||||||
{ 1, "App", { 0.0, 0.4, 0.8 }, 1.0 / 30.0 },
|
{ 1, "App", { 0.0, 0.4, 0.8 }, 1.0 / 30.0 },
|
||||||
{ 1, "App:Collisions", { 1.0, 0.5, 0.0 } },
|
{ 1, "App:Collisions", { 1.0, 0.5, 0.0 } },
|
||||||
{ 1, "App:Collisions:Reset", { 0.0, 0.0, 0.5 } },
|
{ 1, "App:Collisions:Reset", { 0.0, 0.0, 0.5 } },
|
||||||
|
@ -25,50 +25,6 @@ INLINE ClockObject::
|
|||||||
~ClockObject() {
|
~ClockObject() {
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: ClockObject::set_mode
|
|
||||||
// Access: Published
|
|
||||||
// Description: Changes the mode of the clock. Normally, the clock
|
|
||||||
// is in mode M_normal. In this mode, each call to
|
|
||||||
// tick() will set the value returned by
|
|
||||||
// get_frame_time() to the current real time; thus, the
|
|
||||||
// clock simply reports time advancing.
|
|
||||||
//
|
|
||||||
// Other possible modes:
|
|
||||||
//
|
|
||||||
// M_non_real_time - the clock ignores real time
|
|
||||||
// completely; at each call to tick(), it pretends that
|
|
||||||
// exactly dt seconds have elapsed since the last call
|
|
||||||
// to tick(). You may set the value of dt with
|
|
||||||
// set_dt().
|
|
||||||
//
|
|
||||||
// M_limited - the clock will run as fast as it can, as
|
|
||||||
// in M_normal, but will not run faster than the rate
|
|
||||||
// specified by set_dt(). If the application would run
|
|
||||||
// faster than this rate, the clock will slow down the
|
|
||||||
// application.
|
|
||||||
//
|
|
||||||
// M_forced - the clock forces the application to run at
|
|
||||||
// the rate specified by set_dt(). If the application
|
|
||||||
// would run faster than this rate, the clock will slow
|
|
||||||
// down the application; if the application would run
|
|
||||||
// slower than this rate, the clock slows down time so
|
|
||||||
// that the application believes it is running at the
|
|
||||||
// given rate.
|
|
||||||
//
|
|
||||||
// M_degrade - the clock runs at real time, but the
|
|
||||||
// application is slowed down by a set factor of its
|
|
||||||
// frame rate, specified by set_degrade_factor().
|
|
||||||
//
|
|
||||||
// M_slave - the clock does not advance, but relies on
|
|
||||||
// the user to call set_frame_time() and/or
|
|
||||||
// set_frame_count() each frame.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE void ClockObject::
|
|
||||||
set_mode(ClockObject::Mode mode) {
|
|
||||||
_mode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: ClockObject::get_mode
|
// Function: ClockObject::get_mode
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -200,14 +156,15 @@ get_dt(Thread *current_thread) const {
|
|||||||
// Description: In non-real-time mode, sets the number of seconds
|
// Description: In non-real-time mode, sets the number of seconds
|
||||||
// that should appear to elapse between frames. In
|
// that should appear to elapse between frames. In
|
||||||
// forced mode or limited mode, sets our target dt. In
|
// forced mode or limited mode, sets our target dt. In
|
||||||
// normal mode, this has no effect.
|
// normal mode, this has no effect.
|
||||||
|
//
|
||||||
|
// Also see set_frame_rate(), which is a different way
|
||||||
|
// to specify the same quantity.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE void ClockObject::
|
INLINE void ClockObject::
|
||||||
set_dt(double dt, Thread *current_thread) {
|
set_dt(double dt) {
|
||||||
nassertv(current_thread->get_pipeline_stage() == 0);
|
nassertv(dt != 0.0);
|
||||||
_set_dt = dt;
|
set_frame_rate(1.0 / dt);
|
||||||
CDWriter cdata(_cycler, current_thread);
|
|
||||||
cdata->_dt = dt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -306,25 +263,6 @@ get_average_frame_rate_interval() const {
|
|||||||
return _average_frame_rate_interval;
|
return _average_frame_rate_interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: ClockObject::get_average_frame_rate
|
|
||||||
// Access: Published
|
|
||||||
// Description: Returns the average frame rate in number of frames
|
|
||||||
// per second over the last
|
|
||||||
// get_average_frame_rate_interval() seconds. This
|
|
||||||
// measures the virtual frame rate if the clock is in
|
|
||||||
// M_non_real_time mode.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE double ClockObject::
|
|
||||||
get_average_frame_rate(Thread *current_thread) const {
|
|
||||||
CDStageReader cdata(_cycler, 0, current_thread);
|
|
||||||
if (_ticks.size() <= 1) {
|
|
||||||
return 0.0;
|
|
||||||
} else {
|
|
||||||
return _ticks.size() / (cdata->_reported_frame_time - _ticks.front());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: ClockObject::check_errors
|
// Function: ClockObject::check_errors
|
||||||
// Access: Published
|
// Access: Published
|
||||||
|
@ -19,8 +19,13 @@
|
|||||||
#include "clockObject.h"
|
#include "clockObject.h"
|
||||||
#include "config_util.h"
|
#include "config_util.h"
|
||||||
#include "configVariableEnum.h"
|
#include "configVariableEnum.h"
|
||||||
|
#include "string_utils.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
|
void (*ClockObject::_start_clock_wait)() = ClockObject::dummy_clock_wait;
|
||||||
|
void (*ClockObject::_start_clock_busy_wait)() = ClockObject::dummy_clock_wait;
|
||||||
|
void (*ClockObject::_stop_clock_wait)() = ClockObject::dummy_clock_wait;
|
||||||
|
|
||||||
ClockObject *ClockObject::_global_clock = (ClockObject *)NULL;
|
ClockObject *ClockObject::_global_clock = (ClockObject *)NULL;
|
||||||
TypeHandle ClockObject::_type_handle;
|
TypeHandle ClockObject::_type_handle;
|
||||||
|
|
||||||
@ -42,13 +47,83 @@ ClockObject() {
|
|||||||
_start_long_time = _true_clock->get_long_time();
|
_start_long_time = _true_clock->get_long_time();
|
||||||
_actual_frame_time = 0.0;
|
_actual_frame_time = 0.0;
|
||||||
_max_dt = max_dt;
|
_max_dt = max_dt;
|
||||||
|
_user_frame_rate = clock_frame_rate;
|
||||||
_degrade_factor = clock_degrade_factor;
|
_degrade_factor = clock_degrade_factor;
|
||||||
_average_frame_rate_interval = average_frame_rate_interval;
|
_average_frame_rate_interval = average_frame_rate_interval;
|
||||||
|
|
||||||
_error_count = _true_clock->get_error_count();
|
_error_count = _true_clock->get_error_count();
|
||||||
|
}
|
||||||
|
|
||||||
CDReader cdata(_cycler);
|
////////////////////////////////////////////////////////////////////
|
||||||
_set_dt = cdata->_dt;
|
// Function: ClockObject::set_mode
|
||||||
|
// Access: Published
|
||||||
|
// Description: Changes the mode of the clock. Normally, the clock
|
||||||
|
// is in mode M_normal. In this mode, each call to
|
||||||
|
// tick() will set the value returned by
|
||||||
|
// get_frame_time() to the current real time; thus, the
|
||||||
|
// clock simply reports time advancing.
|
||||||
|
//
|
||||||
|
// Other possible modes:
|
||||||
|
//
|
||||||
|
// M_non_real_time - the clock ignores real time
|
||||||
|
// completely; at each call to tick(), it pretends that
|
||||||
|
// exactly dt seconds have elapsed since the last call
|
||||||
|
// to tick(). You may set the value of dt with
|
||||||
|
// set_dt() or set_frame_rate().
|
||||||
|
//
|
||||||
|
// M_limited - the clock will run as fast as it can, as
|
||||||
|
// in M_normal, but will not run faster than the rate
|
||||||
|
// specified by set_frame_rate(). If the application
|
||||||
|
// would run faster than this rate, the clock will slow
|
||||||
|
// down the application.
|
||||||
|
//
|
||||||
|
// M_integer - the clock will run as fast as it can, but
|
||||||
|
// the rate will be constrained to be an integer
|
||||||
|
// multiple or divisor of the rate specified by
|
||||||
|
// set_frame_rate(). The clock will slow down the
|
||||||
|
// application a bit to guarantee this.
|
||||||
|
//
|
||||||
|
// M_integer_limited - a combination of M_limited and
|
||||||
|
// M_integer; the clock will not run faster than
|
||||||
|
// set_frame_rate(), and if it runs slower, it will run
|
||||||
|
// at a integer divisor of that rate.
|
||||||
|
//
|
||||||
|
// M_forced - the clock forces the application to run at
|
||||||
|
// the rate specified by set_frame_rate(). If the
|
||||||
|
// application would run faster than this rate, the
|
||||||
|
// clock will slow down the application; if the
|
||||||
|
// application would run slower than this rate, the
|
||||||
|
// clock slows down time so that the application
|
||||||
|
// believes it is running at the given rate.
|
||||||
|
//
|
||||||
|
// M_degrade - the clock runs at real time, but the
|
||||||
|
// application is slowed down by a set factor of its
|
||||||
|
// frame rate, specified by set_degrade_factor().
|
||||||
|
//
|
||||||
|
// M_slave - the clock does not advance, but relies on
|
||||||
|
// the user to call set_frame_time() and/or
|
||||||
|
// set_frame_count() each frame.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void ClockObject::
|
||||||
|
set_mode(ClockObject::Mode mode) {
|
||||||
|
Thread *current_thread = Thread::get_current_thread();
|
||||||
|
nassertv(current_thread->get_pipeline_stage() == 0);
|
||||||
|
CDWriter cdata(_cycler, current_thread);
|
||||||
|
|
||||||
|
_mode = mode;
|
||||||
|
|
||||||
|
// In case we have set the clock to one of the modes that uses
|
||||||
|
// _reported_frame_time_epoch, recompute the epoch.
|
||||||
|
switch (_mode) {
|
||||||
|
case M_non_real_time:
|
||||||
|
case M_forced:
|
||||||
|
cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
|
||||||
|
cdata->_frame_count / _user_frame_rate;
|
||||||
|
cdata->_dt = 1.0 / _user_frame_rate;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -95,6 +170,10 @@ set_frame_time(double time, Thread *current_thread) {
|
|||||||
CDWriter cdata(_cycler, current_thread);
|
CDWriter cdata(_cycler, current_thread);
|
||||||
_actual_frame_time = time;
|
_actual_frame_time = time;
|
||||||
cdata->_reported_frame_time = time;
|
cdata->_reported_frame_time = time;
|
||||||
|
|
||||||
|
// Recompute the epoch in case we are in a mode that relies on this.
|
||||||
|
cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
|
||||||
|
cdata->_frame_count / _user_frame_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -116,6 +195,62 @@ set_frame_count(int frame_count, Thread *current_thread) {
|
|||||||
#endif // NOTIFY_DEBUG
|
#endif // NOTIFY_DEBUG
|
||||||
CDWriter cdata(_cycler, current_thread);
|
CDWriter cdata(_cycler, current_thread);
|
||||||
cdata->_frame_count = frame_count;
|
cdata->_frame_count = frame_count;
|
||||||
|
|
||||||
|
// Recompute the epoch in case we are in a mode that relies on this.
|
||||||
|
cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
|
||||||
|
cdata->_frame_count / _user_frame_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ClockObject::set_frame_rate
|
||||||
|
// Access: Published
|
||||||
|
// Description: In non-real-time mode, sets the number of frames per
|
||||||
|
// second that we should appear to be running. In forced
|
||||||
|
// mode or limited mode, sets our target frame rate. In
|
||||||
|
// normal mode, this has no effect.
|
||||||
|
//
|
||||||
|
// Also see set_dt(), which is a different way to
|
||||||
|
// specify the same quantity.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void ClockObject::
|
||||||
|
set_frame_rate(double frame_rate) {
|
||||||
|
nassertv(frame_rate != 0.0);
|
||||||
|
|
||||||
|
Thread *current_thread = Thread::get_current_thread();
|
||||||
|
nassertv(current_thread->get_pipeline_stage() == 0);
|
||||||
|
|
||||||
|
CDWriter cdata(_cycler, current_thread);
|
||||||
|
_user_frame_rate = frame_rate;
|
||||||
|
|
||||||
|
switch (_mode) {
|
||||||
|
case M_non_real_time:
|
||||||
|
case M_forced:
|
||||||
|
cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
|
||||||
|
cdata->_frame_count / _user_frame_rate;
|
||||||
|
cdata->_dt = 1.0 / _user_frame_rate;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ClockObject::get_average_frame_rate
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the average frame rate in number of frames
|
||||||
|
// per second over the last
|
||||||
|
// get_average_frame_rate_interval() seconds. This
|
||||||
|
// measures the virtual frame rate if the clock is in
|
||||||
|
// M_non_real_time mode.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
double ClockObject::
|
||||||
|
get_average_frame_rate(Thread *current_thread) const {
|
||||||
|
CDStageReader cdata(_cycler, 0, current_thread);
|
||||||
|
if (_ticks.size() <= 1) {
|
||||||
|
return 0.0;
|
||||||
|
} else {
|
||||||
|
return _ticks.size() / (cdata->_reported_frame_time - _ticks.front());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -137,6 +272,14 @@ tick(Thread *current_thread) {
|
|||||||
if (_mode != M_slave) {
|
if (_mode != M_slave) {
|
||||||
double old_time = _actual_frame_time;
|
double old_time = _actual_frame_time;
|
||||||
_actual_frame_time = get_real_time();
|
_actual_frame_time = get_real_time();
|
||||||
|
|
||||||
|
// In case someone munged the clock last frame and sent us
|
||||||
|
// backward in time, clamp the previous time to the current time
|
||||||
|
// to make sure we don't report anything strange (or wait
|
||||||
|
// interminably).
|
||||||
|
old_time = min(old_time, _actual_frame_time);
|
||||||
|
|
||||||
|
++cdata->_frame_count;
|
||||||
|
|
||||||
switch (_mode) {
|
switch (_mode) {
|
||||||
case M_normal:
|
case M_normal:
|
||||||
@ -148,22 +291,67 @@ tick(Thread *current_thread) {
|
|||||||
case M_non_real_time:
|
case M_non_real_time:
|
||||||
// Ignore real time. We always report the same interval having
|
// Ignore real time. We always report the same interval having
|
||||||
// elapsed each frame.
|
// elapsed each frame.
|
||||||
cdata->_reported_frame_time += _set_dt;
|
cdata->_reported_frame_time = cdata->_reported_frame_time_epoch +
|
||||||
|
cdata->_frame_count / _user_frame_rate;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_limited:
|
case M_limited:
|
||||||
// If we are running faster than the desired interval, slow down.
|
// If we are running faster than the desired interval, slow down.
|
||||||
wait_until(old_time + _set_dt);
|
{
|
||||||
cdata->_dt = _actual_frame_time - old_time;
|
double wait_until_time = old_time + 1.0 / _user_frame_rate;
|
||||||
cdata->_reported_frame_time = _actual_frame_time;
|
wait_until(wait_until_time);
|
||||||
|
cdata->_dt = _actual_frame_time - old_time;
|
||||||
|
cdata->_reported_frame_time = max(_actual_frame_time, wait_until_time);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_integer:
|
||||||
|
{
|
||||||
|
double dt = _actual_frame_time - old_time;
|
||||||
|
double target_dt = 1.0 / _user_frame_rate;
|
||||||
|
if (dt < target_dt) {
|
||||||
|
// We're running faster than the desired interval, so slow
|
||||||
|
// down to the next integer multiple of the frame rate.
|
||||||
|
target_dt = target_dt / floor(target_dt / dt);
|
||||||
|
} else {
|
||||||
|
// We're running slower than the desired interval, so slow
|
||||||
|
// down to the next integer divisor of the frame rate.
|
||||||
|
target_dt = target_dt * ceil(dt / target_dt);
|
||||||
|
}
|
||||||
|
double wait_until_time = old_time + target_dt;
|
||||||
|
wait_until(wait_until_time);
|
||||||
|
cdata->_dt = target_dt;
|
||||||
|
cdata->_reported_frame_time = wait_until_time;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_integer_limited:
|
||||||
|
{
|
||||||
|
double dt = _actual_frame_time - old_time;
|
||||||
|
double target_dt = 1.0 / _user_frame_rate;
|
||||||
|
if (dt < target_dt) {
|
||||||
|
// We're running faster than the desired interval, so slow
|
||||||
|
// down to the target frame rate.
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// We're running slower than the desired interval, so slow
|
||||||
|
// down to the next integer divisor of the frame rate.
|
||||||
|
target_dt = target_dt * ceil(dt / target_dt);
|
||||||
|
}
|
||||||
|
double wait_until_time = old_time + target_dt;
|
||||||
|
wait_until(wait_until_time);
|
||||||
|
cdata->_dt = target_dt;
|
||||||
|
cdata->_reported_frame_time = wait_until_time;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_forced:
|
case M_forced:
|
||||||
// If we are running faster than the desired interval, slow down.
|
// If we are running faster than the desired interval, slow down.
|
||||||
// If we are running slower than the desired interval, ignore that
|
// If we are running slower than the desired interval, ignore that
|
||||||
// and pretend we're running at the specified rate.
|
// and pretend we're running at the specified rate.
|
||||||
wait_until(old_time + _set_dt);
|
wait_until(old_time + 1.0 / _user_frame_rate);
|
||||||
cdata->_reported_frame_time += _set_dt;
|
cdata->_reported_frame_time = cdata->_reported_frame_time_epoch +
|
||||||
|
cdata->_frame_count / _user_frame_rate;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_degrade:
|
case M_degrade:
|
||||||
@ -189,13 +377,11 @@ tick(Thread *current_thread) {
|
|||||||
// Handled above.
|
// Handled above.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cdata->_frame_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_average_frame_rate_interval > 0.0) {
|
if (_average_frame_rate_interval > 0.0) {
|
||||||
_ticks.push_back(old_reported_time);
|
_ticks.push_back(old_reported_time);
|
||||||
while (!_ticks.empty() &&
|
while (_ticks.size() > 2 &&
|
||||||
cdata->_reported_frame_time - _ticks.front() > _average_frame_rate_interval) {
|
cdata->_reported_frame_time - _ticks.front() > _average_frame_rate_interval) {
|
||||||
_ticks.pop_front();
|
_ticks.pop_front();
|
||||||
}
|
}
|
||||||
@ -233,16 +419,32 @@ sync_frame_time(Thread *current_thread) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void ClockObject::
|
void ClockObject::
|
||||||
wait_until(double want_time) {
|
wait_until(double want_time) {
|
||||||
|
if (want_time <= _actual_frame_time) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DO_PSTATS
|
||||||
|
(*_start_clock_wait)();
|
||||||
|
#endif
|
||||||
|
|
||||||
double wait_interval = (want_time - _actual_frame_time) - sleep_precision;
|
double wait_interval = (want_time - _actual_frame_time) - sleep_precision;
|
||||||
|
|
||||||
if (wait_interval > 0.0) {
|
if (wait_interval > 0.0) {
|
||||||
Thread::sleep(wait_interval);
|
Thread::sleep(wait_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DO_PSTATS
|
||||||
|
(*_start_clock_busy_wait)();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Now busy-wait until the actual time elapses.
|
// Now busy-wait until the actual time elapses.
|
||||||
while (_actual_frame_time < want_time) {
|
while (_actual_frame_time < want_time) {
|
||||||
_actual_frame_time = get_real_time();
|
_actual_frame_time = get_real_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DO_PSTATS
|
||||||
|
(*_stop_clock_wait)();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -266,6 +468,17 @@ make_global_clock() {
|
|||||||
_global_clock->set_mode(clock_mode);
|
_global_clock->set_mode(clock_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ClockObject::dummy_clock_wait
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: This no-op function is assigned as the initial
|
||||||
|
// pointer for _start_clock_wait and _stop_clock_wait,
|
||||||
|
// until the PStatClient comes along and replaces it.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void ClockObject::
|
||||||
|
dummy_clock_wait() {
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: ClockObject::CData::Constructor
|
// Function: ClockObject::CData::Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -275,7 +488,8 @@ ClockObject::CData::
|
|||||||
CData() {
|
CData() {
|
||||||
_frame_count = 0;
|
_frame_count = 0;
|
||||||
_reported_frame_time = 0.0;
|
_reported_frame_time = 0.0;
|
||||||
_dt = 1.0 / clock_frame_rate;
|
_reported_frame_time_epoch = 0.0;
|
||||||
|
_dt = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -304,6 +518,12 @@ operator << (ostream &out, ClockObject::Mode mode) {
|
|||||||
case ClockObject::M_limited:
|
case ClockObject::M_limited:
|
||||||
return out << "limited";
|
return out << "limited";
|
||||||
|
|
||||||
|
case ClockObject::M_integer:
|
||||||
|
return out << "integer";
|
||||||
|
|
||||||
|
case ClockObject::M_integer_limited:
|
||||||
|
return out << "integer_limited";
|
||||||
|
|
||||||
case ClockObject::M_forced:
|
case ClockObject::M_forced:
|
||||||
return out << "forced";
|
return out << "forced";
|
||||||
|
|
||||||
@ -326,17 +546,21 @@ operator >> (istream &in, ClockObject::Mode &mode) {
|
|||||||
string word;
|
string word;
|
||||||
in >> word;
|
in >> word;
|
||||||
|
|
||||||
if (word == "normal") {
|
if (cmp_nocase_uh(word, "normal") == 0) {
|
||||||
mode = ClockObject::M_normal;
|
mode = ClockObject::M_normal;
|
||||||
} else if (word == "non-real-time") {
|
} else if (cmp_nocase_uh(word, "non-real-time") == 0) {
|
||||||
mode = ClockObject::M_non_real_time;
|
mode = ClockObject::M_non_real_time;
|
||||||
} else if (word == "limited") {
|
} else if (cmp_nocase_uh(word, "limited") == 0) {
|
||||||
mode = ClockObject::M_limited;
|
mode = ClockObject::M_limited;
|
||||||
} else if (word == "forced") {
|
} else if (cmp_nocase_uh(word, "integer") == 0) {
|
||||||
|
mode = ClockObject::M_integer;
|
||||||
|
} else if (cmp_nocase_uh(word, "integer_limited") == 0) {
|
||||||
|
mode = ClockObject::M_integer_limited;
|
||||||
|
} else if (cmp_nocase_uh(word, "forced") == 0) {
|
||||||
mode = ClockObject::M_forced;
|
mode = ClockObject::M_forced;
|
||||||
} else if (word == "degrade") {
|
} else if (cmp_nocase_uh(word, "degrade") == 0) {
|
||||||
mode = ClockObject::M_degrade;
|
mode = ClockObject::M_degrade;
|
||||||
} else if (word == "slave") {
|
} else if (cmp_nocase_uh(word, "slave") == 0) {
|
||||||
mode = ClockObject::M_slave;
|
mode = ClockObject::M_slave;
|
||||||
} else {
|
} else {
|
||||||
util_cat.error()
|
util_cat.error()
|
||||||
|
@ -72,12 +72,14 @@ PUBLISHED:
|
|||||||
M_degrade,
|
M_degrade,
|
||||||
M_slave,
|
M_slave,
|
||||||
M_limited,
|
M_limited,
|
||||||
|
M_integer,
|
||||||
|
M_integer_limited,
|
||||||
};
|
};
|
||||||
|
|
||||||
ClockObject();
|
ClockObject();
|
||||||
INLINE ~ClockObject();
|
INLINE ~ClockObject();
|
||||||
|
|
||||||
INLINE void set_mode(Mode mode);
|
void set_mode(Mode mode);
|
||||||
INLINE Mode get_mode() const;
|
INLINE Mode get_mode() const;
|
||||||
|
|
||||||
INLINE double get_frame_time(Thread *current_thread = Thread::get_current_thread()) const;
|
INLINE double get_frame_time(Thread *current_thread = Thread::get_current_thread()) const;
|
||||||
@ -93,7 +95,8 @@ PUBLISHED:
|
|||||||
INLINE double get_net_frame_rate(Thread *current_thread = Thread::get_current_thread()) const;
|
INLINE double get_net_frame_rate(Thread *current_thread = Thread::get_current_thread()) const;
|
||||||
|
|
||||||
INLINE double get_dt(Thread *current_thread = Thread::get_current_thread()) const;
|
INLINE double get_dt(Thread *current_thread = Thread::get_current_thread()) const;
|
||||||
INLINE void set_dt(double dt, Thread *current_thread = Thread::get_current_thread());
|
INLINE void set_dt(double dt);
|
||||||
|
void set_frame_rate(double frame_rate);
|
||||||
|
|
||||||
INLINE double get_max_dt() const;
|
INLINE double get_max_dt() const;
|
||||||
INLINE void set_max_dt(double max_dt);
|
INLINE void set_max_dt(double max_dt);
|
||||||
@ -103,7 +106,7 @@ PUBLISHED:
|
|||||||
|
|
||||||
INLINE void set_average_frame_rate_interval(double time);
|
INLINE void set_average_frame_rate_interval(double time);
|
||||||
INLINE double get_average_frame_rate_interval() const;
|
INLINE double get_average_frame_rate_interval() const;
|
||||||
INLINE double get_average_frame_rate(Thread *current_thread = Thread::get_current_thread()) const;
|
double get_average_frame_rate(Thread *current_thread = Thread::get_current_thread()) const;
|
||||||
|
|
||||||
void tick(Thread *current_thread = Thread::get_current_thread());
|
void tick(Thread *current_thread = Thread::get_current_thread());
|
||||||
void sync_frame_time(Thread *current_thread = Thread::get_current_thread());
|
void sync_frame_time(Thread *current_thread = Thread::get_current_thread());
|
||||||
@ -112,9 +115,15 @@ PUBLISHED:
|
|||||||
|
|
||||||
INLINE static ClockObject *get_global_clock();
|
INLINE static ClockObject *get_global_clock();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void (*_start_clock_wait)();
|
||||||
|
static void (*_start_clock_busy_wait)();
|
||||||
|
static void (*_stop_clock_wait)();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void wait_until(double want_time);
|
void wait_until(double want_time);
|
||||||
static void make_global_clock();
|
static void make_global_clock();
|
||||||
|
static void dummy_clock_wait();
|
||||||
|
|
||||||
TrueClock *_true_clock;
|
TrueClock *_true_clock;
|
||||||
Mode _mode;
|
Mode _mode;
|
||||||
@ -122,7 +131,7 @@ private:
|
|||||||
double _start_long_time;
|
double _start_long_time;
|
||||||
double _actual_frame_time;
|
double _actual_frame_time;
|
||||||
double _max_dt;
|
double _max_dt;
|
||||||
double _set_dt;
|
double _user_frame_rate;
|
||||||
double _degrade_factor;
|
double _degrade_factor;
|
||||||
int _error_count;
|
int _error_count;
|
||||||
|
|
||||||
@ -145,6 +154,7 @@ private:
|
|||||||
|
|
||||||
int _frame_count;
|
int _frame_count;
|
||||||
double _reported_frame_time;
|
double _reported_frame_time;
|
||||||
|
double _reported_frame_time_epoch;
|
||||||
double _dt;
|
double _dt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user