Performance Improvements: Remove unnecessary SwapBuffer calls
[platform/core/uifw/dali-adaptor.git] / adaptors / base / single-threaded / single-thread-controller.cpp
1 /*
2  * Copyright (c) 2015 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 "single-thread-controller.h"
20
21 // EXTERNAL INCLUDES
22 #include <iostream>
23 #include <dali/integration-api/platform-abstraction.h>
24
25 // INTERNAL INCLUDES
26 #include <base/interfaces/adaptor-internal-services.h>
27 #include <base/environment-options.h>
28 #include <base/time-service.h>
29
30 namespace Dali
31 {
32
33 namespace Internal
34 {
35
36 namespace Adaptor
37 {
38
39 namespace
40 {
41 const unsigned int MILLISECONDS_PER_FRAME = 17u;
42 const float SECONDS_PER_FRAME = MILLISECONDS_PER_FRAME * 0.001f;
43
44 const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u );
45 const float        NANOSECONDS_TO_SECONDS( 1e-9f );
46
47 #if defined(DEBUG_ENABLED)
48 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_THREAD_SYNC");
49 #endif
50
51 } // unnamed namespace
52
53 SingleThreadController::SingleThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
54 : ConnectionTracker(),
55   ThreadControllerInterface(),
56   mTimer(),
57   mFpsTracker( environmentOptions ),
58   mUpdateStatusLogger( environmentOptions ),
59   mRenderHelper( adaptorInterfaces ),
60   mCore( adaptorInterfaces.GetCore()),
61   mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
62   mLastUpdateRenderTime( 0 ),
63   mSystemTime( 0 ),
64   mRefreshRate( environmentOptions.GetRenderRefreshRate() ),
65   mState( State::STOPPED ),
66   mUpdatingAndRendering( false ),
67   mStopRequestedWhileRendering( false )
68 {
69   DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
70 }
71
72 SingleThreadController::~SingleThreadController()
73 {
74   DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
75
76   Stop();
77 }
78
79 void SingleThreadController::Initialize()
80 {
81   DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
82
83   mTimer = Dali::Timer::New( mRefreshRate * MILLISECONDS_PER_FRAME );
84
85   // Create a tick-signal so that we can update and render every frame
86   mTimer.TickSignal().Connect( this, &SingleThreadController::OnTimerTick );
87 }
88
89 void SingleThreadController::Start()
90 {
91   DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
92
93   mRenderHelper.Start();
94   mRenderHelper.InitializeEgl();
95
96   // tell core it has a context
97   mCore.ContextCreated();
98
99   // Do an update/render straight away
100   UpdateTimeSinceLastRender();
101   UpdateRender( false );
102
103   ChangeState( State::RUNNING );
104 }
105
106 void SingleThreadController::Pause()
107 {
108   if( mState == State::RUNNING )
109   {
110     DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
111
112     ChangeState( State::PAUSED );
113
114     AddPerformanceMarker( PerformanceInterface::PAUSED );
115   }
116 }
117
118 void SingleThreadController::Resume()
119 {
120   if( mState == State::PAUSED )
121   {
122     DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
123
124     // Do an update/render straight away
125     UpdateTimeSinceLastRender();
126     UpdateRender( false );
127
128     ChangeState( State::RUNNING );
129
130     AddPerformanceMarker( PerformanceInterface::RESUME );
131   }
132 }
133
134 void SingleThreadController::Stop()
135 {
136   if( mState != State::STOPPED )
137   {
138     DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
139
140     ChangeState( State::STOPPED );
141
142     if( mUpdatingAndRendering )
143     {
144       // If we interrupted an update/render for this stop, then we should NOT terminate GL just yet
145       mStopRequestedWhileRendering = true;
146     }
147     else
148     {
149       StopRendering();
150     }
151   }
152 }
153
154 void SingleThreadController::RequestUpdate()
155 {
156   if( mState == State::SLEEPING )
157   {
158     DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
159
160     // Do an update/render straight away
161     UpdateTimeSinceLastRender();
162     UpdateRender( false );
163
164     ChangeState( State::RUNNING );
165   }
166 }
167
168 void SingleThreadController::RequestUpdateOnce()
169 {
170   if( mState == State::SLEEPING || mState == State::PAUSED )
171   {
172     DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
173
174     // Just do one update and render
175
176     Integration::UpdateStatus status;
177     mCore.Update( 0.0f, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, status );
178
179     Render();
180   }
181 }
182
183 void SingleThreadController::ReplaceSurface( RenderSurface* newSurface )
184 {
185   DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
186   mRenderHelper.ReplaceSurface( newSurface );
187 }
188
189 void SingleThreadController::SetRenderRefreshRate( unsigned int refreshRate )
190 {
191   if ( refreshRate != mRefreshRate )
192   {
193     DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
194
195     mRefreshRate = refreshRate;
196
197     if( mTimer )
198     {
199       mTimer.SetInterval( mRefreshRate * MILLISECONDS_PER_FRAME );
200     }
201   }
202 }
203
204 bool SingleThreadController::OnTimerTick()
205 {
206   DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
207
208   if( mState == State::RUNNING )
209   {
210     UpdateRender( true );
211   }
212   else if( mState == State::STOPPED &&
213            mStopRequestedWhileRendering )
214   {
215     DALI_LOG_INFO( gLogFilter, Debug::General, "%s(): STOPPING\n", __FUNCTION__ );
216
217     StopRendering();
218
219     mStopRequestedWhileRendering = false;
220
221     return false; // Stop the timer
222   }
223   return true;
224 }
225
226 void SingleThreadController::UpdateRender( bool incrementTime )
227 {
228   DALI_LOG_INFO( gLogFilter, Debug::General, "%s():START\n", __FUNCTION__ );
229
230   mUpdatingAndRendering = true;
231
232   float lastFrameDelta( 0.0f );
233
234   if( incrementTime )
235   {
236     // Use our usual time per frame for smoother animations rather than the real elapsed time
237
238     lastFrameDelta = mRefreshRate * SECONDS_PER_FRAME;
239     mLastUpdateRenderTime += mRefreshRate * MILLISECONDS_PER_FRAME;
240   }
241
242   Integration::UpdateStatus updateStatus;
243   AddPerformanceMarker( PerformanceInterface::UPDATE_START );
244   mCore.Update( lastFrameDelta, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, updateStatus );
245   AddPerformanceMarker( PerformanceInterface::UPDATE_END );
246
247   mFpsTracker.Track( UpdateTimeSinceLastRender() );
248
249   unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
250
251   // Optional logging of update/render status
252   mUpdateStatusLogger.Log( keepUpdatingStatus );
253
254   // Ensure we did not get interrupted an STOPPED
255   if( mState != State::STOPPED )
256   {
257     mRenderHelper.ConsumeEvents();
258
259     const bool needsUpdate = Render();
260
261     if( !keepUpdatingStatus && !needsUpdate )
262     {
263       ChangeState( State::SLEEPING );
264     }
265   }
266
267   mUpdatingAndRendering = false;
268
269   DALI_LOG_INFO( gLogFilter, Debug::General, "%s():END\n", __FUNCTION__ );
270 }
271
272 float SingleThreadController::UpdateTimeSinceLastRender()
273 {
274   float timeSinceLastRender = 0.0f;
275
276   // No need calculating if FPS tracking is NOT enabled
277   if( mFpsTracker.Enabled() )
278   {
279     uint64_t currentTime = 0;
280     TimeService::GetNanoseconds( currentTime );
281
282     uint64_t delta = currentTime - mSystemTime;
283     mSystemTime = currentTime;
284
285     timeSinceLastRender = delta * NANOSECONDS_TO_SECONDS;
286   }
287
288   return timeSinceLastRender;
289 }
290
291
292 void SingleThreadController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
293 {
294   if( mPerformanceInterface )
295   {
296     mPerformanceInterface->AddMarker( type );
297   }
298 }
299
300 void SingleThreadController::ChangeState( State::Type state )
301 {
302   mState = state;
303
304   switch( state )
305   {
306     case State::RUNNING:
307     {
308       mTimer.Start();
309       break;
310     }
311
312     case State::STOPPED:
313     case State::PAUSED:
314     case State::SLEEPING:
315     {
316       mTimer.Stop();
317     }
318   }
319 }
320
321 void SingleThreadController::StopRendering()
322 {
323   mRenderHelper.Stop();
324
325   // Inform core of context destruction & shutdown EGL
326   mCore.ContextDestroyed();
327   mRenderHelper.ShutdownEgl();
328 }
329
330 bool SingleThreadController::Render()
331 {
332   mRenderHelper.PreRender();
333
334   Integration::RenderStatus renderStatus;
335   AddPerformanceMarker( PerformanceInterface::RENDER_START );
336   mCore.Render( renderStatus );
337   AddPerformanceMarker( PerformanceInterface::RENDER_END );
338
339   if( renderStatus.NeedsPostRender() )
340   {
341     mRenderHelper.PostRender();
342   }
343
344   return renderStatus.NeedsUpdate();
345 }
346
347 } // namespace Adaptor
348
349 } // namespace Internal
350
351 } // namespace Dali