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 );
183 void SingleThreadController::ReplaceSurface( RenderSurface* newSurface )
185 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
186 mRenderHelper.ReplaceSurface( newSurface );
189 void SingleThreadController::SetRenderRefreshRate( unsigned int refreshRate )
191 if ( refreshRate != mRefreshRate )
193 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
195 mRefreshRate = refreshRate;
199 mTimer.SetInterval( mRefreshRate * MILLISECONDS_PER_FRAME );
204 bool SingleThreadController::OnTimerTick()
206 DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
208 if( mState == State::RUNNING )
210 UpdateRender( true );
212 else if( mState == State::STOPPED &&
213 mStopRequestedWhileRendering )
215 DALI_LOG_INFO( gLogFilter, Debug::General, "%s(): STOPPING\n", __FUNCTION__ );
219 mStopRequestedWhileRendering = false;
221 return false; // Stop the timer
226 void SingleThreadController::UpdateRender( bool incrementTime )
228 DALI_LOG_INFO( gLogFilter, Debug::General, "%s():START\n", __FUNCTION__ );
230 mUpdatingAndRendering = true;
232 float lastFrameDelta( 0.0f );
236 // Use our usual time per frame for smoother animations rather than the real elapsed time
238 lastFrameDelta = mRefreshRate * SECONDS_PER_FRAME;
239 mLastUpdateRenderTime += mRefreshRate * MILLISECONDS_PER_FRAME;
242 Integration::UpdateStatus updateStatus;
243 AddPerformanceMarker( PerformanceInterface::UPDATE_START );
244 mCore.Update( lastFrameDelta, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, updateStatus );
245 AddPerformanceMarker( PerformanceInterface::UPDATE_END );
247 mFpsTracker.Track( UpdateTimeSinceLastRender() );
249 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
251 // Optional logging of update/render status
252 mUpdateStatusLogger.Log( keepUpdatingStatus );
254 // Ensure we did not get interrupted an STOPPED
255 if( mState != State::STOPPED )
257 mRenderHelper.ConsumeEvents();
259 const bool needsUpdate = Render();
261 if( !keepUpdatingStatus && !needsUpdate )
263 ChangeState( State::SLEEPING );
267 mUpdatingAndRendering = false;
269 DALI_LOG_INFO( gLogFilter, Debug::General, "%s():END\n", __FUNCTION__ );
272 float SingleThreadController::UpdateTimeSinceLastRender()
274 float timeSinceLastRender = 0.0f;
276 // No need calculating if FPS tracking is NOT enabled
277 if( mFpsTracker.Enabled() )
279 uint64_t currentTime = 0;
280 TimeService::GetNanoseconds( currentTime );
282 uint64_t delta = currentTime - mSystemTime;
283 mSystemTime = currentTime;
285 timeSinceLastRender = delta * NANOSECONDS_TO_SECONDS;
288 return timeSinceLastRender;
292 void SingleThreadController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
294 if( mPerformanceInterface )
296 mPerformanceInterface->AddMarker( type );
300 void SingleThreadController::ChangeState( State::Type state )
314 case State::SLEEPING:
321 void SingleThreadController::StopRendering()
323 mRenderHelper.Stop();
325 // Inform core of context destruction & shutdown EGL
326 mCore.ContextDestroyed();
327 mRenderHelper.ShutdownEgl();
330 bool SingleThreadController::Render()
332 mRenderHelper.PreRender();
334 Integration::RenderStatus renderStatus;
335 AddPerformanceMarker( PerformanceInterface::RENDER_START );
336 mCore.Render( renderStatus );
337 AddPerformanceMarker( PerformanceInterface::RENDER_END );
339 if( renderStatus.NeedsPostRender() )
341 mRenderHelper.PostRender();
344 return renderStatus.NeedsUpdate();
347 } // namespace Adaptor
349 } // namespace Internal