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