2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "single-thread-controller.h"
23 #include <dali/integration-api/platform-abstraction.h>
26 #include <base/interfaces/adaptor-internal-services.h>
27 #include <base/environment-options.h>
40 const unsigned int MILLISECONDS_PER_FRAME = 17u;
41 const float SECONDS_PER_FRAME = MILLISECONDS_PER_FRAME * 0.001f;
43 const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u );
44 const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
45 const float MICROSECONDS_TO_SECONDS( 0.000001f );
47 #if defined(DEBUG_ENABLED)
48 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_THREAD_SYNC");
51 } // unnamed namespace
53 SingleThreadController::SingleThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
54 : ConnectionTracker(),
55 ThreadControllerInterface(),
57 mFpsTracker( environmentOptions ),
58 mUpdateStatusLogger( environmentOptions ),
59 mRenderHelper( adaptorInterfaces ),
60 mCore( adaptorInterfaces.GetCore()),
61 mPlatformAbstraction( adaptorInterfaces.GetPlatformAbstractionInterface() ),
62 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
63 mLastUpdateRenderTime( 0 ),
66 mState( State::STOPPED ),
67 mUpdatingAndRendering( false ),
68 mStopRequestedWhileRendering( false )
70 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
73 SingleThreadController::~SingleThreadController()
75 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
80 void SingleThreadController::Initialize()
82 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
84 mTimer = Dali::Timer::New( mRefreshRate * MILLISECONDS_PER_FRAME );
86 // Create a tick-signal so that we can update and render every frame
87 mTimer.TickSignal().Connect( this, &SingleThreadController::OnTimerTick );
90 void SingleThreadController::Start()
92 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
94 mRenderHelper.Start();
95 mRenderHelper.InitializeEgl();
97 // tell core it has a context
98 mCore.ContextCreated();
100 // Do an update/render straight away
101 UpdateTimeSinceLastRender();
102 UpdateRender( false );
104 ChangeState( State::RUNNING );
107 void SingleThreadController::Pause()
109 if( mState == State::RUNNING )
111 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
113 ChangeState( State::PAUSED );
115 AddPerformanceMarker( PerformanceInterface::PAUSED );
119 void SingleThreadController::Resume()
121 if( mState == State::PAUSED )
123 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
125 // Do an update/render straight away
126 UpdateTimeSinceLastRender();
127 UpdateRender( false );
129 ChangeState( State::RUNNING );
131 AddPerformanceMarker( PerformanceInterface::RESUME );
135 void SingleThreadController::Stop()
137 if( mState != State::STOPPED )
139 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
141 ChangeState( State::STOPPED );
143 if( mUpdatingAndRendering )
145 // If we interrupted an update/render for this stop, then we should NOT terminate GL just yet
146 mStopRequestedWhileRendering = true;
155 void SingleThreadController::RequestUpdate()
157 if( mState == State::SLEEPING )
159 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
161 // Do an update/render straight away
162 UpdateTimeSinceLastRender();
163 UpdateRender( false );
165 ChangeState( State::RUNNING );
169 void SingleThreadController::RequestUpdateOnce()
171 if( mState == State::SLEEPING || mState == State::PAUSED )
173 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
175 // Just do one update and render
177 Integration::UpdateStatus status;
178 mCore.Update( 0.0f, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, status );
180 Integration::RenderStatus renderStatus;
181 mRenderHelper.PreRender();
182 mCore.Render( renderStatus );
183 if( renderStatus.HasRendered() )
185 mRenderHelper.PostRender();
190 void SingleThreadController::ReplaceSurface( RenderSurface* newSurface )
192 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
193 mRenderHelper.ReplaceSurface( newSurface );
196 void SingleThreadController::SetRenderRefreshRate( unsigned int refreshRate )
198 if ( refreshRate != mRefreshRate )
200 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
202 mRefreshRate = refreshRate;
206 mTimer.SetInterval( mRefreshRate * MILLISECONDS_PER_FRAME );
211 bool SingleThreadController::OnTimerTick()
213 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
215 if( mState == State::RUNNING )
217 UpdateRender( true );
219 else if( mState == State::STOPPED &&
220 mStopRequestedWhileRendering )
222 DALI_LOG_INFO( gLogFilter, Debug::General, "%s(): STOPPING\n", __FUNCTION__ );
226 mStopRequestedWhileRendering = false;
228 return false; // Stop the timer
233 void SingleThreadController::UpdateRender( bool incrementTime )
235 DALI_LOG_INFO( gLogFilter, Debug::General, "%s():START\n", __FUNCTION__ );
237 mUpdatingAndRendering = true;
239 float lastFrameDelta( 0.0f );
243 // Use our usual time per frame for smoother animations rather than the real elapsed time
245 lastFrameDelta = mRefreshRate * SECONDS_PER_FRAME;
246 mLastUpdateRenderTime += mRefreshRate * MILLISECONDS_PER_FRAME;
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 );
254 mFpsTracker.Track( UpdateTimeSinceLastRender() );
256 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
258 // Optional logging of update/render status
259 mUpdateStatusLogger.Log( keepUpdatingStatus );
261 // Ensure we did not get interrupted an STOPPED
262 if( mState != State::STOPPED )
264 mRenderHelper.ConsumeEvents();
265 mRenderHelper.PreRender();
267 Integration::RenderStatus renderStatus;
268 AddPerformanceMarker( PerformanceInterface::RENDER_START );
269 mCore.Render( renderStatus );
270 AddPerformanceMarker( PerformanceInterface::RENDER_END );
272 if( renderStatus.HasRendered() )
274 mRenderHelper.PostRender();
277 if( ! keepUpdatingStatus &&
278 ! renderStatus.NeedsUpdate() )
280 ChangeState( State::SLEEPING );
284 mUpdatingAndRendering = false;
286 DALI_LOG_INFO( gLogFilter, Debug::General, "%s():END\n", __FUNCTION__ );
289 float SingleThreadController::UpdateTimeSinceLastRender()
291 float timeSinceLastRender = 0.0f;
293 // No need calculating if FPS tracking is NOT enabled
294 if( mFpsTracker.Enabled() )
296 uint64_t seconds = 0;
297 uint64_t microSeconds = 0;
299 mPlatformAbstraction.GetTimeNanoseconds( seconds, microSeconds );
300 microSeconds /= NANOSECONDS_PER_MICROSECOND;
302 uint64_t currentTime = ( seconds * MICROSECONDS_PER_SECOND ) + microSeconds;
304 uint64_t delta = currentTime - mSystemTime;
305 mSystemTime = currentTime;
307 timeSinceLastRender = delta * MICROSECONDS_TO_SECONDS;
310 return timeSinceLastRender;
314 void SingleThreadController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
316 if( mPerformanceInterface )
318 mPerformanceInterface->AddMarker( type );
322 void SingleThreadController::ChangeState( State::Type state )
336 case State::SLEEPING:
343 void SingleThreadController::StopRendering()
345 mRenderHelper.Stop();
347 // Inform core of context destruction & shutdown EGL
348 mCore.ContextDestroyed();
349 mRenderHelper.ShutdownEgl();
352 } // namespace Adaptor
354 } // namespace Internal