Improve ThreadSynchronization Logging (enable release logging if required)
[platform/core/uifw/dali-adaptor.git] / adaptors / base / frame-time.cpp
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
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/platform-abstraction.h>
24
25 namespace Dali
26 {
27
28 using Integration::PlatformAbstraction;
29
30 namespace Internal
31 {
32 namespace Adaptor
33 {
34
35 namespace
36 {
37 #if defined(DEBUG_ENABLED)
38 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FRAME_TIME");
39 #endif
40
41 const unsigned int DEFAULT_MINIMUM_FRAME_TIME_INTERVAL( 16667u );
42
43 const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
44 const unsigned int MICROSECONDS_PER_MILLISECOND( 1000u );
45
46 const float        MICROSECONDS_TO_SECONDS( 0.000001f );
47
48 const unsigned int HISTORY_SIZE(3);
49
50 // constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
51 const unsigned int TRUE = 1u;
52 const unsigned int FALSE = 0u;
53 } // unnamed namespace
54
55
56 FrameTime::FrameTime( PlatformAbstraction& platform )
57 : mPlatform( platform ),
58   mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
59   mLastSyncTime( 0u ),
60   mLastSyncTimeAtUpdate( 0u ),
61   mLastSyncFrameNumber( 0u ),
62   mLastUpdateFrameNumber( 0u ),
63   mRunning( TRUE ),
64   mFirstFrame( TRUE ),
65   writePos( 0u ),
66   mExtraUpdatesSinceSync( 0u )
67 {
68   // Clear buffer
69   for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
70   {
71     mPreviousUpdateFrames[i] = 0;
72   }
73
74   SetLastSyncTime();
75   mLastSyncTimeAtUpdate = mLastSyncTime;
76
77   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
78 }
79
80 FrameTime::~FrameTime()
81 {
82 }
83
84 void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
85 {
86   mMinimumFrameTimeInterval = interval;
87 }
88
89 void FrameTime::SetSyncTime( unsigned int frameNumber )
90 {
91   // Only set the render time if we are running
92   if ( mRunning )
93   {
94     SetLastSyncTime();
95
96     mLastSyncFrameNumber = frameNumber;
97
98     DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, (unsigned int) ( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
99   }
100 }
101
102 void FrameTime::Suspend()
103 {
104   mRunning = FALSE;
105
106   // Reset members
107   mLastSyncFrameNumber = 0;
108   mLastUpdateFrameNumber = 0;
109   writePos = 0;
110   mExtraUpdatesSinceSync = 0;
111
112   // Clear buffer
113   for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
114   {
115     mPreviousUpdateFrames[i] = 0;
116   }
117
118   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
119 }
120
121 void FrameTime::Resume()
122 {
123   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );
124
125   SetLastSyncTime();   // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
126   mFirstFrame = TRUE;
127
128   mRunning = TRUE;
129 }
130
131 void FrameTime::Sleep()
132 {
133   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );
134
135   // Mimic Suspend behaviour
136   Suspend();
137 }
138
139 void FrameTime::WakeUp()
140 {
141   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );
142
143   SetLastSyncTime();
144   mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
145   mFirstFrame = TRUE;
146   mRunning = TRUE;
147 }
148
149 void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
150 {
151   if ( mRunning )
152   {
153     const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
154     const uint64_t lastSyncTime( mLastSyncTime );
155     const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );
156
157     float lastFrameDelta( 0.0f ); // Assume the last update frame delta is 0.
158     unsigned int framesTillNextSync( 1 ); // Assume next render will be in one Sync frame time.
159
160     unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
161     lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;
162
163     // We should only evaluate the previous frame values if this is not the first frame.
164     if ( !mFirstFrame )
165     {
166       // Check whether we have had any Syncs since we last did an Update.
167       if ( framesInLastUpdate == 0 )
168       {
169         // We have had another update before a Sync, increment counter.
170         ++mExtraUpdatesSinceSync;
171
172         // This update frame will be rendered mUpdatesSinceSync later.
173         framesTillNextSync += mExtraUpdatesSinceSync;
174         DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
175       }
176       else
177       {
178         mExtraUpdatesSinceSync = 0;
179       }
180
181       // 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.
182       if ( framesInLastUpdate > 1 )
183       {
184         DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime framesInLastUpdate:%u\n", framesInLastUpdate);
185         unsigned int average(0);
186         for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
187         {
188           average += mPreviousUpdateFrames[i];
189         }
190         average /= HISTORY_SIZE;
191
192         if ( average > 1 )
193         {
194           // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
195           framesTillNextSync = average;
196         }
197       }
198
199       // Write the number of frames the last update took to the array.
200       mPreviousUpdateFrames[writePos] = framesInLastUpdate;
201       writePos = ( writePos + 1 ) % HISTORY_SIZE;
202     }
203
204     mLastUpdateFrameNumber = lastSyncFrameNumber;
205     mLastSyncTimeAtUpdate = lastSyncTime;
206     mFirstFrame = FALSE;
207
208     // Calculate the time till the next render
209     unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync );
210
211     // Set the input variables
212     lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
213     lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND;
214     nextSyncTimeMilliseconds = ( lastSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND;
215
216     DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds, lastFrameDeltaSeconds );
217     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                      FramesInLastUpdate: %u, FramesTillNextSync: %u\n", framesInLastUpdate, framesTillNextSync );
218   }
219 }
220
221 inline void FrameTime::SetLastSyncTime()
222 {
223   unsigned int seconds( 0u );
224   unsigned int microseconds( 0u );
225
226   mPlatform.GetTimeMicroseconds( seconds, microseconds );
227
228   mLastSyncTime = seconds; // Promote from 32 bit to 64 bit value
229   mLastSyncTime = ( mLastSyncTime * MICROSECONDS_PER_SECOND ) + microseconds;
230 }
231
232 } // namespace Adaptor
233 } // namespace Internal
234 } // namespace Dali