Added APIs to support Launchpad and set window transparency
[platform/core/uifw/dali-adaptor.git] / adaptors / base / separate-update-render / frame-time.cpp
1 /*
2  * Copyright (c) 2017 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 // 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_MILLISECOND( 1000u );
47 const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u);
48
49 const float        MICROSECONDS_TO_SECONDS( 0.000001f );
50
51 const unsigned int HISTORY_SIZE(3);
52
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
57
58
59 FrameTime::FrameTime()
60 : mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
61   mLastSyncTime( 0u ),
62   mLastSyncTimeAtUpdate( 0u ),
63   mLastSyncFrameNumber( 0u ),
64   mLastUpdateFrameNumber( 0u ),
65   mRunning( TRUE ),
66   mFirstFrame( TRUE ),
67   writePos( 0u ),
68   mExtraUpdatesSinceSync( 0u )
69 {
70   // Clear buffer
71   for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
72   {
73     mPreviousUpdateFrames[i] = 0;
74   }
75
76   SetLastSyncTime();
77   mLastSyncTimeAtUpdate = mLastSyncTime;
78
79   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
80 }
81
82 FrameTime::~FrameTime()
83 {
84 }
85
86 void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
87 {
88   mMinimumFrameTimeInterval = interval;
89 }
90
91 void FrameTime::SetSyncTime( unsigned int frameNumber )
92 {
93   // Only set the render time if we are running
94   if ( mRunning )
95   {
96     SetLastSyncTime();
97
98     mLastSyncFrameNumber = frameNumber;
99
100     DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, static_cast<unsigned int>( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
101   }
102 }
103
104 void FrameTime::Suspend()
105 {
106   mRunning = FALSE;
107
108   // Reset members
109   mLastSyncFrameNumber = 0;
110   mLastUpdateFrameNumber = 0;
111   writePos = 0;
112   mExtraUpdatesSinceSync = 0;
113
114   // Clear buffer
115   for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
116   {
117     mPreviousUpdateFrames[i] = 0;
118   }
119
120   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
121 }
122
123 void FrameTime::Resume()
124 {
125   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );
126
127   SetLastSyncTime();   // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
128   mFirstFrame = TRUE;
129
130   mRunning = TRUE;
131 }
132
133 void FrameTime::Sleep()
134 {
135   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );
136
137   // Mimic Suspend behaviour
138   Suspend();
139 }
140
141 void FrameTime::WakeUp()
142 {
143   DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );
144
145   SetLastSyncTime();
146   mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
147   mFirstFrame = TRUE;
148   mRunning = TRUE;
149 }
150
151 void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
152 {
153   if ( mRunning )
154   {
155     const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
156     const uint64_t lastSyncTime( mLastSyncTime );
157     const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );
158
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.
161
162     unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
163     lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;
164
165     // We should only evaluate the previous frame values if this is not the first frame.
166     if ( !mFirstFrame )
167     {
168       // Check whether we have had any Syncs since we last did an Update.
169       if ( framesInLastUpdate == 0 )
170       {
171         // We have had another update before a Sync, increment counter.
172         ++mExtraUpdatesSinceSync;
173
174         // This update frame will be rendered mUpdatesSinceSync later.
175         framesTillNextSync += mExtraUpdatesSinceSync;
176         DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
177       }
178       else
179       {
180         mExtraUpdatesSinceSync = 0;
181       }
182
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 )
185       {
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 )
189         {
190           average += mPreviousUpdateFrames[i];
191         }
192         average /= HISTORY_SIZE;
193
194         if ( average > 1 )
195         {
196           // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
197           framesTillNextSync = average;
198         }
199       }
200
201       // Write the number of frames the last update took to the array.
202       mPreviousUpdateFrames[writePos] = framesInLastUpdate;
203       writePos = ( writePos + 1 ) % HISTORY_SIZE;
204     }
205
206     mLastUpdateFrameNumber = lastSyncFrameNumber;
207     mLastSyncTimeAtUpdate = lastSyncTime;
208     mFirstFrame = FALSE;
209
210     // Calculate the time till the next render
211     unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync );
212
213     // Set the input variables
214     lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
215     lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND;
216     nextSyncTimeMilliseconds = ( lastSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND;
217
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 );
220   }
221 }
222
223 inline void FrameTime::SetLastSyncTime()
224 {
225   uint64_t nanoseconds( 0u );
226   TimeService::GetNanoseconds( nanoseconds );
227
228   mLastSyncTime = nanoseconds / NANOSECONDS_PER_MICROSECOND;
229 }
230
231 } // namespace Adaptor
232 } // namespace Internal
233 } // namespace Dali