2 * Copyright (c) 2017 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_MILLISECOND( 1000u );
47 const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u);
49 const float MICROSECONDS_TO_SECONDS( 0.000001f );
51 const unsigned int HISTORY_SIZE(3);
53 // constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
54 const unsigned int TRUE = 1u;
55 const unsigned int FALSE = 0u;
56 } // unnamed namespace
59 FrameTime::FrameTime()
60 : mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
62 mLastSyncTimeAtUpdate( 0u ),
63 mLastSyncFrameNumber( 0u ),
64 mLastUpdateFrameNumber( 0u ),
68 mExtraUpdatesSinceSync( 0u )
71 for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
73 mPreviousUpdateFrames[i] = 0;
77 mLastSyncTimeAtUpdate = mLastSyncTime;
79 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
82 FrameTime::~FrameTime()
86 void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
88 mMinimumFrameTimeInterval = interval;
91 void FrameTime::SetSyncTime( unsigned int frameNumber )
93 // Only set the render time if we are running
98 mLastSyncFrameNumber = frameNumber;
100 DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, static_cast<unsigned int>( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
104 void FrameTime::Suspend()
109 mLastSyncFrameNumber = 0;
110 mLastUpdateFrameNumber = 0;
112 mExtraUpdatesSinceSync = 0;
115 for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
117 mPreviousUpdateFrames[i] = 0;
120 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
123 void FrameTime::Resume()
125 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );
127 SetLastSyncTime(); // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
133 void FrameTime::Sleep()
135 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );
137 // Mimic Suspend behaviour
141 void FrameTime::WakeUp()
143 DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );
146 mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
151 void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
155 const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
156 const uint64_t lastSyncTime( mLastSyncTime );
157 const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );
159 float lastFrameDelta( 0.0f ); // Assume the last update frame delta is 0.
160 unsigned int framesTillNextSync( 1 ); // Assume next render will be in one Sync frame time.
162 unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
163 lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;
165 // We should only evaluate the previous frame values if this is not the first frame.
168 // Check whether we have had any Syncs since we last did an Update.
169 if ( framesInLastUpdate == 0 )
171 // We have had another update before a Sync, increment counter.
172 ++mExtraUpdatesSinceSync;
174 // This update frame will be rendered mUpdatesSinceSync later.
175 framesTillNextSync += mExtraUpdatesSinceSync;
176 DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
180 mExtraUpdatesSinceSync = 0;
183 // 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.
184 if ( framesInLastUpdate > 1 )
186 DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime framesInLastUpdate:%u\n", framesInLastUpdate);
187 unsigned int average(0);
188 for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
190 average += mPreviousUpdateFrames[i];
192 average /= HISTORY_SIZE;
196 // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
197 framesTillNextSync = average;
201 // Write the number of frames the last update took to the array.
202 mPreviousUpdateFrames[writePos] = framesInLastUpdate;
203 writePos = ( writePos + 1 ) % HISTORY_SIZE;
206 mLastUpdateFrameNumber = lastSyncFrameNumber;
207 mLastSyncTimeAtUpdate = lastSyncTime;
210 // Calculate the time till the next render
211 unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync );
213 // Set the input variables
214 lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
215 lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND;
216 nextSyncTimeMilliseconds = ( lastSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND;
218 DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds, lastFrameDeltaSeconds );
219 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " FramesInLastUpdate: %u, FramesTillNextSync: %u\n", framesInLastUpdate, framesTillNextSync );
223 inline void FrameTime::SetLastSyncTime()
225 uint64_t nanoseconds( 0u );
226 TimeService::GetNanoseconds( nanoseconds );
228 mLastSyncTime = nanoseconds / NANOSECONDS_PER_MICROSECOND;
231 } // namespace Adaptor
232 } // namespace Internal