framerateEqualizer.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "framerateEqualizer.h"
00019
00020 #include "../compound.h"
00021 #include "../compoundVisitor.h"
00022 #include "../config.h"
00023 #include "../log.h"
00024
00025 #include <eq/base/debug.h>
00026
00027 #define USE_AVERAGE
00028 #define VSYNC_CAP 60.f
00029 #define SLOWDOWN 1.05f
00030
00031 namespace eq
00032 {
00033 namespace server
00034 {
00035
00036 namespace
00037 {
00038 class LoadSubscriber : public CompoundVisitor
00039 {
00040 public:
00041 LoadSubscriber( ChannelListener* listener ) : _listener( listener ) {}
00042
00043 virtual VisitorResult visit( Compound* compound )
00044 {
00045 Channel* channel = compound->getChannel();
00046 EQASSERT( channel );
00047 channel->addListener( _listener );
00048
00049 return TRAVERSE_CONTINUE;
00050 }
00051
00052 private:
00053 ChannelListener* const _listener;
00054 };
00055
00056 class LoadUnsubscriber : public CompoundVisitor
00057 {
00058 public:
00059 LoadUnsubscriber( ChannelListener* listener ) : _listener( listener ) {}
00060
00061 virtual VisitorResult visit( Compound* compound )
00062 {
00063 Channel* channel = compound->getChannel();
00064 EQASSERT( channel );
00065 channel->removeListener( _listener );
00066
00067 return TRAVERSE_CONTINUE;
00068 }
00069
00070 private:
00071 ChannelListener* const _listener;
00072 };
00073
00074 }
00075
00076
00077
00078
00079 FramerateEqualizer::FramerateEqualizer()
00080 : _nSamples( 0 )
00081 {
00082 EQINFO << "New FramerateEqualizer @" << (void*)this << std::endl;
00083 }
00084
00085 FramerateEqualizer::FramerateEqualizer( const FramerateEqualizer& from )
00086 : Equalizer( from )
00087 , _nSamples( 0 )
00088 {
00089 }
00090
00091 FramerateEqualizer::~FramerateEqualizer()
00092 {
00093 attach( 0 );
00094 }
00095
00096 void FramerateEqualizer::attach( Compound* compound )
00097 {
00098 _exit();
00099 Equalizer::attach( compound );
00100 }
00101
00102
00103 void FramerateEqualizer::_init()
00104 {
00105 const Compound* compound = getCompound();
00106
00107 if( _nSamples > 0 || !compound )
00108 return;
00109
00110 _nSamples = 1;
00111
00112
00113 const CompoundVector& children = compound->getChildren();
00114
00115 EQASSERT( _loadListeners.empty( ));
00116 _loadListeners.resize( children.size( ));
00117
00118 for( size_t i = 0; i < children.size(); ++i )
00119 {
00120 Compound* child = children[i];
00121 const uint32_t period = child->getInheritPeriod();
00122 LoadListener& loadListener = _loadListeners[i];
00123
00124 loadListener.parent = this;
00125 loadListener.period = period;
00126
00127 LoadSubscriber subscriber( &loadListener );
00128 child->accept( subscriber );
00129
00130 _nSamples = EQ_MAX( _nSamples, period );
00131 }
00132
00133 _nSamples = EQ_MIN( _nSamples, 100 );
00134 }
00135
00136 void FramerateEqualizer::_exit()
00137 {
00138 const Compound* compound = getCompound();
00139 if( !compound || _nSamples == 0 )
00140 return;
00141
00142 const CompoundVector& children = compound->getChildren();
00143
00144 EQASSERT( _loadListeners.size() == children.size( ));
00145 for( size_t i = 0; i < children.size(); ++i )
00146 {
00147 Compound* child = children[i];
00148 LoadListener& loadListener = _loadListeners[i];
00149
00150 LoadUnsubscriber unsubscriber( &loadListener );
00151 child->accept( unsubscriber );
00152 }
00153
00154 _loadListeners.clear();
00155 _times.clear();
00156 _nSamples = 0;
00157 }
00158
00159
00160 void FramerateEqualizer::notifyUpdatePre( Compound* compound,
00161 const uint32_t frameNumber )
00162 {
00163 _init();
00164
00165
00166 const ssize_t size = static_cast< ssize_t >( _times.size( ));
00167 ssize_t from = 0;
00168 if( size > 0 )
00169 {
00170 for( ssize_t i = size-1; i >= 0; --i )
00171 {
00172 if( _times[i].second != 0.f )
00173 continue;
00174
00175 from = i;
00176 break;
00177 }
00178 }
00179
00180
00181 size_t nSamples = 0;
00182 #ifdef USE_AVERAGE
00183 float sumTime = 0.f;
00184 #else
00185 float maxTime = 0.f;
00186 #endif
00187
00188 for( ++from; from < size && nSamples < _nSamples; ++from )
00189 {
00190 const FrameTime& time = _times[from];
00191 EQASSERT( time.first > 0 );
00192 EQASSERT( time.second != 0.f );
00193
00194 ++nSamples;
00195 #ifdef USE_AVERAGE
00196 sumTime += time.second;
00197 #else
00198 maxTime = EQ_MAX( maxTime, time.second );
00199 #endif
00200 EQLOG( LOG_LB2 ) << "Using " << time.first << ", " << time.second << "ms"
00201 << std::endl;
00202 }
00203
00204 if( nSamples == _nSamples )
00205 while( from < static_cast< ssize_t >( _times.size( )))
00206 _times.pop_back();
00207
00208 if( isFrozen() || !compound->isActive( ))
00209 {
00210
00211 compound->setMaxFPS( std::numeric_limits< float >::max( ));
00212 return;
00213 }
00214
00215 if( nSamples > 0 )
00216 {
00217
00218 #ifdef USE_AVERAGE
00219 const float time = (sumTime / nSamples) * SLOWDOWN;
00220 #else
00221 const float time = maxTime * SLOWDOWN;
00222 #endif
00223
00224 const float fps = 1000.f / time;
00225 #ifdef VSYNC_CAP
00226 if( fps > VSYNC_CAP )
00227 compound->setMaxFPS( std::numeric_limits< float >::max( ));
00228 else
00229 #endif
00230 compound->setMaxFPS( fps );
00231
00232 EQLOG( LOG_LB2 ) << fps << " Hz from " << nSamples << "/"
00233 << _times.size() << " samples, " << time << "ms"
00234 << std::endl;
00235 }
00236
00237 _times.push_front( FrameTime( frameNumber, 0.f ));
00238 EQASSERT( _times.size() < 210 );
00239 }
00240
00241 void FramerateEqualizer::LoadListener::notifyLoadData(
00242 Channel* channel,
00243 const uint32_t frameNumber,
00244 const uint32_t nStatistics,
00245 const eq::Statistic* statistics )
00246 {
00247
00248 float startTime = std::numeric_limits< float >::max();
00249 float endTime = 0.0f;
00250 for( uint32_t i = 0; i < nStatistics; ++i )
00251 {
00252 const eq::Statistic& data = statistics[i];
00253 switch( data.type )
00254 {
00255 case eq::Statistic::CHANNEL_CLEAR:
00256 case eq::Statistic::CHANNEL_DRAW:
00257 case eq::Statistic::CHANNEL_ASSEMBLE:
00258 case eq::Statistic::CHANNEL_READBACK:
00259 startTime = EQ_MIN( startTime, data.startTime );
00260 endTime = EQ_MAX( endTime, data.endTime );
00261 break;
00262
00263 default:
00264 break;
00265 }
00266 }
00267
00268 if( startTime == std::numeric_limits< float >::max( ))
00269 return;
00270
00271 for( std::deque< FrameTime >::iterator i = parent->_times.begin();
00272 i != parent->_times.end(); ++i )
00273 {
00274 FrameTime& frameTime = *i;
00275 if( frameTime.first != frameNumber )
00276 continue;
00277
00278 const float time = (endTime - startTime) / period;
00279 frameTime.second = EQ_MAX( frameTime.second, time );
00280 EQLOG( LOG_LB2 ) << "Frame " << frameNumber << " channel "
00281 << channel->getName() << " time " << time
00282 << " period " << period << std::endl;
00283 }
00284 }
00285
00286 std::ostream& operator << ( std::ostream& os, const FramerateEqualizer* lb )
00287 {
00288 if( lb )
00289 os << "framerate_equalizer {}" << std::endl;
00290 return os;
00291 }
00292
00293 }
00294 }