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