Merge branch 'devel/master (1.1.16)' into tizen
[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     Integration::RenderStatus renderStatus;
180     mRenderHelper.PreRender();
181     mCore.Render( renderStatus );
182     if( renderStatus.HasRendered() )
183     {
184       mRenderHelper.PostRender();
185     }
186   }
187 }
188
189 void SingleThreadController::ReplaceSurface( RenderSurface* newSurface )
190 {
191   DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
192   mRenderHelper.ReplaceSurface( newSurface );
193 }
194
195 void SingleThreadController::SetRenderRefreshRate( unsigned int refreshRate )
196 {
197   if ( refreshRate != mRefreshRate )
198   {
199     DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
200
201     mRefreshRate = refreshRate;
202
203     if( mTimer )
204     {
205       mTimer.SetInterval( mRefreshRate * MILLISECONDS_PER_FRAME );
206     }
207   }
208 }
209
210 bool SingleThreadController::OnTimerTick()
211 {
212   DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
213
214   if( mState == State::RUNNING )
215   {
216     UpdateRender( true );
217   }
218   else if( mState == State::STOPPED &&
219            mStopRequestedWhileRendering )
220   {
221     DALI_LOG_INFO( gLogFilter, Debug::General, "%s(): STOPPING\n", __FUNCTION__ );
222
223     StopRendering();
224
225     mStopRequestedWhileRendering = false;
226
227     return false; // Stop the timer
228   }
229   return true;
230 }
231
232 void SingleThreadController::UpdateRender( bool incrementTime )
233 {
234   DALI_LOG_INFO( gLogFilter, Debug::General, "%s():START\n", __FUNCTION__ );
235
236   mUpdatingAndRendering = true;
237
238   float lastFrameDelta( 0.0f );
239
240   if( incrementTime )
241   {
242     // Use our usual time per frame for smoother animations rather than the real elapsed time
243
244     lastFrameDelta = mRefreshRate * SECONDS_PER_FRAME;
245     mLastUpdateRenderTime += mRefreshRate * MILLISECONDS_PER_FRAME;
246   }
247
248   Integration::UpdateStatus updateStatus;
249   AddPerformanceMarker( PerformanceInterface::UPDATE_START );
250   mCore.Update( lastFrameDelta, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, updateStatus );
251   AddPerformanceMarker( PerformanceInterface::UPDATE_END );
252
253   mFpsTracker.Track( UpdateTimeSinceLastRender() );
254
255   unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
256
257   // Optional logging of update/render status
258   mUpdateStatusLogger.Log( keepUpdatingStatus );
259
260   // Ensure we did not get interrupted an STOPPED
261   if( mState != State::STOPPED )
262   {
263     mRenderHelper.ConsumeEvents();
264     mRenderHelper.PreRender();
265
266     Integration::RenderStatus renderStatus;
267     AddPerformanceMarker( PerformanceInterface::RENDER_START );
268     mCore.Render( renderStatus );
269     AddPerformanceMarker( PerformanceInterface::RENDER_END );
270
271     if( renderStatus.HasRendered() )
272     {
273       mRenderHelper.PostRender();
274     }
275
276     if( ! keepUpdatingStatus &&
277         ! renderStatus.NeedsUpdate() )
278     {
279       ChangeState( State::SLEEPING );
280     }
281   }
282
283   mUpdatingAndRendering = false;
284
285   DALI_LOG_INFO( gLogFilter, Debug::General, "%s():END\n", __FUNCTION__ );
286 }
287
288 float SingleThreadController::UpdateTimeSinceLastRender()
289 {
290   float timeSinceLastRender = 0.0f;
291
292   // No need calculating if FPS tracking is NOT enabled
293   if( mFpsTracker.Enabled() )
294   {
295     uint64_t currentTime = 0;
296     TimeService::GetNanoseconds( currentTime );
297
298     uint64_t delta = currentTime - mSystemTime;
299     mSystemTime = currentTime;
300
301     timeSinceLastRender = delta * NANOSECONDS_TO_SECONDS;
302   }
303
304   return timeSinceLastRender;
305 }
306
307
308 void SingleThreadController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
309 {
310   if( mPerformanceInterface )
311   {
312     mPerformanceInterface->AddMarker( type );
313   }
314 }
315
316 void SingleThreadController::ChangeState( State::Type state )
317 {
318   mState = state;
319
320   switch( state )
321   {
322     case State::RUNNING:
323     {
324       mTimer.Start();
325       break;
326     }
327
328     case State::STOPPED:
329     case State::PAUSED:
330     case State::SLEEPING:
331     {
332       mTimer.Stop();
333     }
334   }
335 }
336
337 void SingleThreadController::StopRendering()
338 {
339   mRenderHelper.Stop();
340
341   // Inform core of context destruction & shutdown EGL
342   mCore.ContextDestroyed();
343   mRenderHelper.ShutdownEgl();
344 }
345
346 } // namespace Adaptor
347
348 } // namespace Internal
349
350 } // namespace Dali