2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "frame-time.h"
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/platform-abstraction.h>
26 #include <base/time-service.h>
31 using Integration::PlatformAbstraction;
40 #if defined(DEBUG_ENABLED)
41 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FRAME_TIME");
44 const unsigned int DEFAULT_MINIMUM_FRAME_TIME_INTERVAL( 16667u );
46 const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
47 const unsigned int MICROSECONDS_PER_MILLISECOND( 1000u );
48 const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u);
50 const float MICROSECONDS_TO_SECONDS( 0.000001f );
52 const unsigned int HISTORY_SIZE(3);
54 // constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
55 const unsigned int TRUE = 1u;
56 const unsigned int FALSE = 0u;
57 } // unnamed namespace
60 FrameTime::FrameTime()
61 : mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
63 mLastSyncTimeAtUpdate( 0u ),
64 mLastSyncFrameNumber( 0u ),
65 mLastUpdateFrameNumber( 0u ),
69 mExtraUpdatesSinceSync( 0u )
72 for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
74 mPreviousUpdateFrames[i] = 0;
78 mLastSyncTimeAtUpdate = mLastSyncTime;
80 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
83 FrameTime::~FrameTime()
87 void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
89 mMinimumFrameTimeInterval = interval;
92 void FrameTime::SetSyncTime( unsigned int frameNumber )
94 // Only set the render time if we are running
99 mLastSyncFrameNumber = frameNumber;
101 DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, (unsigned int) ( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
105 void FrameTime::Suspend()
110 mLastSyncFrameNumber = 0;
111 mLastUpdateFrameNumber = 0;
113 mExtraUpdatesSinceSync = 0;
116 for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
118 mPreviousUpdateFrames[i] = 0;
121 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
124 void FrameTime::Resume()
126 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );
128 SetLastSyncTime(); // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
134 void FrameTime::Sleep()
136 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );
138 // Mimic Suspend behaviour
142 void FrameTime::WakeUp()
144 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );
147 mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
152 void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
156 const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
157 const uint64_t lastSyncTime( mLastSyncTime );
158 const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );
160 float lastFrameDelta( 0.0f ); // Assume the last update frame delta is 0.
161 unsigned int framesTillNextSync( 1 ); // Assume next render will be in one Sync frame time.
163 unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
164 lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;
166 // We should only evaluate the previous frame values if this is not the first frame.
169 // Check whether we have had any Syncs since we last did an Update.
170 if ( framesInLastUpdate == 0 )
172 // We have had another update before a Sync, increment counter.
173 ++mExtraUpdatesSinceSync;
175 // This update frame will be rendered mUpdatesSinceSync later.
176 framesTillNextSync += mExtraUpdatesSinceSync;
177 DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
181 mExtraUpdatesSinceSync = 0;
184 // If more than one frame elapsed since last Update, then check if this is a recurring theme so we can accurately predict when this Update is rendered.
185 if ( framesInLastUpdate > 1 )
187 DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime framesInLastUpdate:%u\n", framesInLastUpdate);
188 unsigned int average(0);
189 for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
191 average += mPreviousUpdateFrames[i];
193 average /= HISTORY_SIZE;
197 // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
198 framesTillNextSync = average;
202 // Write the number of frames the last update took to the array.
203 mPreviousUpdateFrames[writePos] = framesInLastUpdate;
204 writePos = ( writePos + 1 ) % HISTORY_SIZE;
207 mLastUpdateFrameNumber = lastSyncFrameNumber;
208 mLastSyncTimeAtUpdate = lastSyncTime;
211 // Calculate the time till the next render
212 unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync );
214 // Set the input variables
215 lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
216 lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND;
217 nextSyncTimeMilliseconds = ( lastSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND;
219 DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds, lastFrameDeltaSeconds );
220 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " FramesInLastUpdate: %u, FramesTillNextSync: %u\n", framesInLastUpdate, framesTillNextSync );
224 inline void FrameTime::SetLastSyncTime()
226 uint64_t nanoseconds( 0u );
227 TimeService::GetNanoseconds( nanoseconds );
229 mLastSyncTime = nanoseconds / NANOSECONDS_PER_MICROSECOND;
232 } // namespace Adaptor
233 } // namespace Internal