2 * Copyright (c) 2014 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 "update-thread.h"
25 #include <boost/thread.hpp>
28 #include <dali/integration-api/debug.h>
29 #include <base/interfaces/adaptor-internal-services.h>
30 #include <base/update-render-synchronization.h>
31 #include <base/environment-options.h>
44 const unsigned int MICROSECONDS_PER_MILLISECOND( 1000 );
46 #if defined(DEBUG_ENABLED)
47 Integration::Log::Filter* gUpdateLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_THREAD");
49 } // unnamed namespace
51 UpdateThread::UpdateThread( UpdateRenderSynchronization& sync,
52 AdaptorInternalServices& adaptorInterfaces,
53 const EnvironmentOptions& environmentOptions )
54 : mUpdateRenderSync( sync ),
55 mCore( adaptorInterfaces.GetCore()),
56 mFpsTrackingSeconds( environmentOptions.GetFrameRateLoggingFrequency() ),
58 mElapsedSeconds( 0u ),
59 mStatusLogInterval( environmentOptions.GetUpdateStatusLoggingFrequency() ),
60 mStatusLogCount( 0u ),
61 mNotificationTrigger( adaptorInterfaces.GetTriggerEventInterface() ),
63 mEnvironmentOptions( environmentOptions )
65 if( mFpsTrackingSeconds > 0 )
67 mFpsRecord.resize( mFpsTrackingSeconds, 0.0f );
71 UpdateThread::~UpdateThread()
73 if(mFpsTrackingSeconds > 0)
80 void UpdateThread::Start()
82 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Start()\n");
85 // Create and run the update-thread
86 mThread = new boost::thread( boost::bind( &UpdateThread::Run, this ) );
90 void UpdateThread::Stop()
92 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Stop()\n");
95 // wait for the thread to finish
103 bool UpdateThread::Run()
105 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run()\n");
106 Integration::UpdateStatus status;
108 // install a function for logging
109 mEnvironmentOptions.InstallLogFunction();
111 bool running( true );
113 // Update loop, we stay inside here while the update-thread is running
116 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 1 - Sync()\n");
118 // Inform synchronization object update is ready to run, this will pause update thread if required.
119 mUpdateRenderSync.UpdateReadyToRun();
120 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 2 - Ready()\n");
122 // get the last delta and the predict when this update will be rendered
123 float lastFrameDelta( 0.0f );
124 unsigned int lastSyncTime( 0 );
125 unsigned int nextSyncTime( 0 );
126 mUpdateRenderSync.PredictNextSyncTime( lastFrameDelta, lastSyncTime, nextSyncTime );
128 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 3 - Update(delta:%f, lastSync:%u, nextSync:%u)\n", lastFrameDelta, lastSyncTime, nextSyncTime);
130 mCore.Update( lastFrameDelta, lastSyncTime, nextSyncTime, status );
132 if( mFpsTrackingSeconds > 0 )
134 FPSTracking(status.SecondsFromLastFrame());
137 // Do the notifications first so the actor-thread can start processing them
138 if( status.NeedsNotification() )
140 // Tell the event-thread to wake up (if asleep) and send a notification event to Core
141 mNotificationTrigger.Trigger();
144 bool renderNeedsUpdate;
146 // tell the synchronisation class that a buffer has been written to,
147 // and to wait until there is a free buffer to write to
148 running = mUpdateRenderSync.UpdateSyncWithRender( renderNeedsUpdate );
149 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 4 - UpdateSyncWithRender complete\n");
153 unsigned int keepUpdatingStatus = status.KeepUpdating();
155 // Optional logging of update/render status
156 if ( mStatusLogInterval )
158 UpdateStatusLogging( keepUpdatingStatus, renderNeedsUpdate );
161 // 2 things can keep update running.
162 // - The status of the last update
163 // - The status of the last render
164 bool runUpdate = (Integration::KeepUpdating::NOT_REQUESTED != keepUpdatingStatus) || renderNeedsUpdate;
168 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 5 - Nothing to update, trying to sleep\n");
170 running = mUpdateRenderSync.UpdateTryToSleep();
175 // uninstall a function for logging
176 mEnvironmentOptions.UnInstallLogFunction();
181 void UpdateThread::FPSTracking(float secondsFromLastFrame)
183 if (mElapsedSeconds < mFpsTrackingSeconds)
185 mElapsedTime += secondsFromLastFrame;
186 if( secondsFromLastFrame > 1.0 )
188 int seconds = floor(mElapsedTime);
189 mElapsedSeconds += seconds;
190 mElapsedTime -= static_cast<float>(seconds);
194 if( mElapsedTime>=1.0f )
196 mElapsedTime -= 1.0f;
197 mFpsRecord[mElapsedSeconds] += 1.0f - mElapsedTime/secondsFromLastFrame;
199 mFpsRecord[mElapsedSeconds] += mElapsedTime/secondsFromLastFrame;
203 mFpsRecord[mElapsedSeconds] += 1.0f;
211 mFpsTrackingSeconds = 0;
215 void UpdateThread::OutputFPSRecord()
217 for(unsigned int i = 0; i < mElapsedSeconds; i++)
219 DALI_LOG_FPS("fps( %d ):%f\n",i ,mFpsRecord[i]);
221 std::ofstream outFile("/tmp/dalifps.txt");
222 if(outFile.is_open())
224 for(unsigned int i = 0; i < mElapsedSeconds; i++)
226 outFile << mFpsRecord[i]<<std::endl;
232 void UpdateThread::UpdateStatusLogging( unsigned int keepUpdatingStatus, bool renderNeedsUpdate )
234 DALI_ASSERT_ALWAYS( mStatusLogInterval );
236 std::ostringstream oss;
238 if ( !(++mStatusLogCount % mStatusLogInterval) )
240 oss << "UpdateStatusLogging keepUpdating: " << keepUpdatingStatus << " ";
242 if ( keepUpdatingStatus )
247 if ( keepUpdatingStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING )
249 oss << "<Stage::KeepRendering() used> ";
252 if ( keepUpdatingStatus & Integration::KeepUpdating::INCOMING_MESSAGES )
254 oss << "<Messages sent to Update> ";
257 if ( keepUpdatingStatus & Integration::KeepUpdating::ANIMATIONS_RUNNING )
259 oss << "<Animations running> ";
262 if ( keepUpdatingStatus & Integration::KeepUpdating::DYNAMICS_CHANGED )
264 oss << "<Dynamics running> ";
267 if ( keepUpdatingStatus & Integration::KeepUpdating::LOADING_RESOURCES )
269 oss << "<Resources loading> ";
272 if ( keepUpdatingStatus & Integration::KeepUpdating::NOTIFICATIONS_PENDING )
274 oss << "<Notifications pending> ";
277 if ( keepUpdatingStatus & Integration::KeepUpdating::MONITORING_PERFORMANCE )
279 oss << "<Monitoring performance> ";
282 if ( keepUpdatingStatus & Integration::KeepUpdating::RENDER_TASK_SYNC )
284 oss << "<Render task waiting for completion> ";
287 if ( renderNeedsUpdate )
289 oss << "<Render needs Update> ";
292 DALI_LOG_UPDATE_STATUS( "%s\n", oss.str().c_str() );
296 } // namespace Adaptor
298 } // namespace Internal