Dali 3D User Interface Engine
frame-time.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17 
18 // CLASS HEADER
19 #include "frame-time.h"
20 
21 // EXTERNAL INCLUDES
24 
25 // INTERNAL INCLUDES
26 #include <base/time-service.h>
27 
28 namespace Dali
29 {
30 
31 using Integration::PlatformAbstraction;
32 
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37 
38 namespace
39 {
40 #if defined(DEBUG_ENABLED)
41 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FRAME_TIME");
42 #endif
43 
44 const unsigned int DEFAULT_MINIMUM_FRAME_TIME_INTERVAL( 16667u );
45 
46 const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
47 const unsigned int MICROSECONDS_PER_MILLISECOND( 1000u );
48 const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u);
49 
50 const float MICROSECONDS_TO_SECONDS( 0.000001f );
51 
52 const unsigned int HISTORY_SIZE(3);
53 
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
58 
59 
61 : mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
62  mLastSyncTime( 0u ),
63  mLastSyncTimeAtUpdate( 0u ),
64  mLastSyncFrameNumber( 0u ),
65  mLastUpdateFrameNumber( 0u ),
66  mRunning( TRUE ),
67  mFirstFrame( TRUE ),
68  writePos( 0u ),
69  mExtraUpdatesSinceSync( 0u )
70 {
71  // Clear buffer
72  for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
73  {
74  mPreviousUpdateFrames[i] = 0;
75  }
76 
79 
80  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
81 }
82 
84 {
85 }
86 
87 void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
88 {
89  mMinimumFrameTimeInterval = interval;
90 }
91 
92 void FrameTime::SetSyncTime( unsigned int frameNumber )
93 {
94  // Only set the render time if we are running
95  if ( mRunning )
96  {
98 
99  mLastSyncFrameNumber = frameNumber;
100 
101  DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, (unsigned int) ( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
102  }
103 }
104 
106 {
107  mRunning = FALSE;
108 
109  // Reset members
112  writePos = 0;
114 
115  // Clear buffer
116  for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
117  {
118  mPreviousUpdateFrames[i] = 0;
119  }
120 
121  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
122 }
123 
125 {
126  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );
127 
128  SetLastSyncTime(); // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
129  mFirstFrame = TRUE;
130 
131  mRunning = TRUE;
132 }
133 
135 {
136  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );
137 
138  // Mimic Suspend behaviour
139  Suspend();
140 }
141 
143 {
144  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );
145 
146  SetLastSyncTime();
147  mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
148  mFirstFrame = TRUE;
149  mRunning = TRUE;
150 }
151 
152 void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
153 {
154  if ( mRunning )
155  {
156  const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
157  const uint64_t lastSyncTime( mLastSyncTime );
158  const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );
159 
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.
162 
163  unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
164  lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;
165 
166  // We should only evaluate the previous frame values if this is not the first frame.
167  if ( !mFirstFrame )
168  {
169  // Check whether we have had any Syncs since we last did an Update.
170  if ( framesInLastUpdate == 0 )
171  {
172  // We have had another update before a Sync, increment counter.
174 
175  // This update frame will be rendered mUpdatesSinceSync later.
176  framesTillNextSync += mExtraUpdatesSinceSync;
177  DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
178  }
179  else
180  {
182  }
183 
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 )
186  {
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 )
190  {
191  average += mPreviousUpdateFrames[i];
192  }
193  average /= HISTORY_SIZE;
194 
195  if ( average > 1 )
196  {
197  // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
198  framesTillNextSync = average;
199  }
200  }
201 
202  // Write the number of frames the last update took to the array.
203  mPreviousUpdateFrames[writePos] = framesInLastUpdate;
204  writePos = ( writePos + 1 ) % HISTORY_SIZE;
205  }
206 
207  mLastUpdateFrameNumber = lastSyncFrameNumber;
208  mLastSyncTimeAtUpdate = lastSyncTime;
209  mFirstFrame = FALSE;
210 
211  // Calculate the time till the next render
212  unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync );
213 
214  // Set the input variables
215  lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
216  lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND;
217  nextSyncTimeMilliseconds = ( lastSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND;
218 
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 );
221  }
222 }
223 
225 {
226  uint64_t nanoseconds( 0u );
227  TimeService::GetNanoseconds( nanoseconds );
228 
230 }
231 
232 } // namespace Adaptor
233 } // namespace Internal
234 } // namespace Dali
Dali Docs Home
Read more about Dali