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"
22 #include <boost/thread.hpp>
26 #include <dali/integration-api/debug.h>
27 #include <base/interfaces/adaptor-internal-services.h>
28 #include <base/update-render-synchronization.h>
29 #include <base/environment-options.h>
42 const char* DALI_TEMP_UPDATE_FPS_FILE( "/tmp/dalifps.txt" );
43 const unsigned int MICROSECONDS_PER_MILLISECOND( 1000 );
45 #if defined(DEBUG_ENABLED)
46 Integration::Log::Filter* gUpdateLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_THREAD");
48 } // unnamed namespace
50 UpdateThread::UpdateThread( UpdateRenderSynchronization& sync,
51 AdaptorInternalServices& adaptorInterfaces,
52 const EnvironmentOptions& environmentOptions )
53 : mUpdateRenderSync( sync ),
54 mCore( adaptorInterfaces.GetCore()),
55 mFpsTrackingSeconds( environmentOptions.GetFrameRateLoggingFrequency() ),
57 mElapsedSeconds( 0u ),
58 mStatusLogInterval( environmentOptions.GetUpdateStatusLoggingFrequency() ),
59 mStatusLogCount( 0u ),
61 mEnvironmentOptions( environmentOptions )
63 if( mFpsTrackingSeconds > 0 )
65 mFpsRecord.resize( mFpsTrackingSeconds, 0.0f );
69 UpdateThread::~UpdateThread()
71 if(mFpsTrackingSeconds > 0)
78 void UpdateThread::Start()
80 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Start()\n");
83 // Create and run the update-thread
84 mThread = new boost::thread( boost::bind( &UpdateThread::Run, this ) );
88 void UpdateThread::Stop()
90 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Stop()\n");
93 // wait for the thread to finish
101 bool UpdateThread::Run()
103 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run()\n");
104 Integration::UpdateStatus status;
106 // install a function for logging
107 mEnvironmentOptions.InstallLogFunction();
109 bool running( true );
111 // Update loop, we stay inside here while the update-thread is running
114 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 1 - Sync()\n");
116 // Inform synchronization object update is ready to run, this will pause update thread if required.
117 mUpdateRenderSync.UpdateReadyToRun();
118 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 2 - Ready()\n");
120 // get the last delta and the predict when this update will be rendered
121 float lastFrameDelta( 0.0f );
122 unsigned int lastSyncTime( 0 );
123 unsigned int nextSyncTime( 0 );
124 mUpdateRenderSync.PredictNextSyncTime( lastFrameDelta, lastSyncTime, nextSyncTime );
126 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 3 - Update(delta:%f, lastSync:%u, nextSync:%u)\n", lastFrameDelta, lastSyncTime, nextSyncTime);
128 mCore.Update( lastFrameDelta, lastSyncTime, nextSyncTime, status );
130 if( mFpsTrackingSeconds > 0 )
132 FPSTracking(status.SecondsFromLastFrame());
135 bool renderNeedsUpdate;
137 // tell the synchronisation class that a buffer has been written to,
138 // and to wait until there is a free buffer to write to
139 running = mUpdateRenderSync.UpdateSyncWithRender( status.NeedsNotification(), renderNeedsUpdate );
140 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 4 - UpdateSyncWithRender complete\n");
144 unsigned int keepUpdatingStatus = status.KeepUpdating();
146 // Optional logging of update/render status
147 if ( mStatusLogInterval )
149 UpdateStatusLogging( keepUpdatingStatus, renderNeedsUpdate );
152 // 2 things can keep update running.
153 // - The status of the last update
154 // - The status of the last render
155 bool runUpdate = (Integration::KeepUpdating::NOT_REQUESTED != keepUpdatingStatus) || renderNeedsUpdate;
159 DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 5 - Nothing to update, trying to sleep\n");
161 running = mUpdateRenderSync.UpdateTryToSleep();
166 // uninstall a function for logging
167 mEnvironmentOptions.UnInstallLogFunction();
172 void UpdateThread::FPSTracking(float secondsFromLastFrame)
174 if (mElapsedSeconds < mFpsTrackingSeconds)
176 mElapsedTime += secondsFromLastFrame;
177 if( secondsFromLastFrame > 1.0 )
179 int seconds = floor(mElapsedTime);
180 mElapsedSeconds += seconds;
181 mElapsedTime -= static_cast<float>(seconds);
185 if( mElapsedTime>=1.0f )
187 mElapsedTime -= 1.0f;
188 mFpsRecord[mElapsedSeconds] += 1.0f - mElapsedTime/secondsFromLastFrame;
190 mFpsRecord[mElapsedSeconds] += mElapsedTime/secondsFromLastFrame;
194 mFpsRecord[mElapsedSeconds] += 1.0f;
202 mFpsTrackingSeconds = 0;
206 void UpdateThread::OutputFPSRecord()
208 for(unsigned int i = 0; i < mElapsedSeconds; i++)
210 DALI_LOG_FPS("fps( %d ):%f\n",i ,mFpsRecord[i]);
213 // Dumps out the DALI_FPS_TRACKING worth of frame rates.
214 // E.g. if we run: DALI_FPS_TRACKING=30 dali-demo
215 // it will dump out the first 30 seconds of FPS information to a temp file
216 FILE* outfile = fopen( DALI_TEMP_UPDATE_FPS_FILE, "w");
219 for(unsigned int i = 0; i < mElapsedSeconds; i++)
222 snprintf(fpsString,sizeof(fpsString),"%.2f \n",mFpsRecord[i]);
223 int ret = fputs( fpsString, outfile );
235 void UpdateThread::UpdateStatusLogging( unsigned int keepUpdatingStatus, bool renderNeedsUpdate )
237 DALI_ASSERT_ALWAYS( mStatusLogInterval );
241 if ( !(++mStatusLogCount % mStatusLogInterval) )
243 oss = "UpdateStatusLogging keepUpdating: " + keepUpdatingStatus ? "true":"false";
245 if ( keepUpdatingStatus )
250 if ( keepUpdatingStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING )
252 oss += "<Stage::KeepRendering() used> ";
255 if ( keepUpdatingStatus & Integration::KeepUpdating::ANIMATIONS_RUNNING )
257 oss += "<Animations running> ";
260 if ( keepUpdatingStatus & Integration::KeepUpdating::DYNAMICS_CHANGED )
262 oss += "<Dynamics running> ";
265 if ( keepUpdatingStatus & Integration::KeepUpdating::LOADING_RESOURCES )
267 oss += "<Resources loading> ";
270 if ( keepUpdatingStatus & Integration::KeepUpdating::MONITORING_PERFORMANCE )
272 oss += "<Monitoring performance> ";
275 if ( keepUpdatingStatus & Integration::KeepUpdating::RENDER_TASK_SYNC )
277 oss += "<Render task waiting for completion> ";
280 if ( renderNeedsUpdate )
282 oss += "<Render needs Update> ";
285 DALI_LOG_UPDATE_STATUS( "%s\n", oss.c_str());
289 } // namespace Adaptor
291 } // namespace Internal