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>
28 #include <base/time-service.h>
41 const unsigned int MILLISECONDS_PER_FRAME = 17u;
42 const float SECONDS_PER_FRAME = MILLISECONDS_PER_FRAME * 0.001f;
44 const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u );
45 const float NANOSECONDS_TO_SECONDS( 1e-9f );
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 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
62 mLastUpdateRenderTime( 0 ),
64 mRefreshRate( environmentOptions.GetRenderRefreshRate() ),
65 mState( State::STOPPED ),
66 mUpdatingAndRendering( false ),
67 mStopRequestedWhileRendering( false )
69 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
72 SingleThreadController::~SingleThreadController()
74 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
79 void SingleThreadController::Initialize()
81 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
83 mTimer = Dali::Timer::New( mRefreshRate * MILLISECONDS_PER_FRAME );
85 // Create a tick-signal so that we can update and render every frame
86 mTimer.TickSignal().Connect( this, &SingleThreadController::OnTimerTick );
89 void SingleThreadController::Start()
91 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
93 mRenderHelper.Start();
94 mRenderHelper.InitializeEgl();
96 // tell core it has a context
97 mCore.ContextCreated();
99 // Do an update/render straight away
100 UpdateTimeSinceLastRender();
101 UpdateRender( false );
103 ChangeState( State::RUNNING );
106 void SingleThreadController::Pause()
108 if( mState == State::RUNNING )
110 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
112 ChangeState( State::PAUSED );
114 AddPerformanceMarker( PerformanceInterface::PAUSED );
118 void SingleThreadController::Resume()
120 if( mState == State::PAUSED )
122 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
124 // Do an update/render straight away
125 UpdateTimeSinceLastRender();
126 UpdateRender( false );
128 ChangeState( State::RUNNING );
130 AddPerformanceMarker( PerformanceInterface::RESUME );
134 void SingleThreadController::Stop()
136 if( mState != State::STOPPED )
138 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
140 ChangeState( State::STOPPED );
142 if( mUpdatingAndRendering )
144 // If we interrupted an update/render for this stop, then we should NOT terminate GL just yet
145 mStopRequestedWhileRendering = true;
154 void SingleThreadController::RequestUpdate()
156 if( mState == State::SLEEPING )
158 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
160 // Do an update/render straight away
161 UpdateTimeSinceLastRender();
162 UpdateRender( false );
164 ChangeState( State::RUNNING );
168 void SingleThreadController::RequestUpdateOnce()
170 if( mState == State::SLEEPING || mState == State::PAUSED )
172 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
174 // Just do one update and render
176 Integration::UpdateStatus status;
177 mCore.Update( 0.0f, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, status );
179 Integration::RenderStatus renderStatus;
180 mRenderHelper.PreRender();
181 mCore.Render( renderStatus );
182 mRenderHelper.PostRender();
186 void SingleThreadController::ReplaceSurface( RenderSurface* newSurface )
188 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
189 mRenderHelper.ReplaceSurface( newSurface );
192 void SingleThreadController::SetRenderRefreshRate( unsigned int refreshRate )
194 if ( refreshRate != mRefreshRate )
196 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
198 mRefreshRate = refreshRate;
202 mTimer.SetInterval( mRefreshRate * MILLISECONDS_PER_FRAME );
207 bool SingleThreadController::OnTimerTick()
209 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
211 if( mState == State::RUNNING )
213 UpdateRender( true );
215 else if( mState == State::STOPPED &&
216 mStopRequestedWhileRendering )
218 DALI_LOG_INFO( gLogFilter, Debug::General, "%s(): STOPPING\n", __FUNCTION__ );
222 mStopRequestedWhileRendering = false;
224 return false; // Stop the timer
229 void SingleThreadController::UpdateRender( bool incrementTime )
231 DALI_LOG_INFO( gLogFilter, Debug::General, "%s():START\n", __FUNCTION__ );
233 mUpdatingAndRendering = true;
235 float lastFrameDelta( 0.0f );
239 // Use our usual time per frame for smoother animations rather than the real elapsed time
241 lastFrameDelta = mRefreshRate * SECONDS_PER_FRAME;
242 mLastUpdateRenderTime += mRefreshRate * MILLISECONDS_PER_FRAME;
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 );
250 mFpsTracker.Track( UpdateTimeSinceLastRender() );
252 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
254 // Optional logging of update/render status
255 mUpdateStatusLogger.Log( keepUpdatingStatus );
257 // Ensure we did not get interrupted an STOPPED
258 if( mState != State::STOPPED )
260 mRenderHelper.ConsumeEvents();
261 mRenderHelper.PreRender();
263 Integration::RenderStatus renderStatus;
264 AddPerformanceMarker( PerformanceInterface::RENDER_START );
265 mCore.Render( renderStatus );
266 AddPerformanceMarker( PerformanceInterface::RENDER_END );
268 mRenderHelper.PostRender();
270 if( ! keepUpdatingStatus &&
271 ! renderStatus.NeedsUpdate() )
273 ChangeState( State::SLEEPING );
277 mUpdatingAndRendering = false;
279 DALI_LOG_INFO( gLogFilter, Debug::General, "%s():END\n", __FUNCTION__ );
282 float SingleThreadController::UpdateTimeSinceLastRender()
284 float timeSinceLastRender = 0.0f;
286 // No need calculating if FPS tracking is NOT enabled
287 if( mFpsTracker.Enabled() )
289 uint64_t currentTime = 0;
290 TimeService::GetNanoseconds( currentTime );
292 uint64_t delta = currentTime - mSystemTime;
293 mSystemTime = currentTime;
295 timeSinceLastRender = delta * NANOSECONDS_TO_SECONDS;
298 return timeSinceLastRender;
302 void SingleThreadController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
304 if( mPerformanceInterface )
306 mPerformanceInterface->AddMarker( type );
310 void SingleThreadController::ChangeState( State::Type state )
324 case State::SLEEPING:
331 void SingleThreadController::StopRendering()
333 mRenderHelper.Stop();
335 // Inform core of context destruction & shutdown EGL
336 mCore.ContextDestroyed();
337 mRenderHelper.ShutdownEgl();
340 } // namespace Adaptor
342 } // namespace Internal