/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "update-thread.h"
// EXTERNAL INCLUDES
-#include <cstdlib>
-#include <fstream>
-#include <sstream>
-#include <boost/thread.hpp>
+#include <cstdio>
// INTERNAL INCLUDES
#include <dali/integration-api/debug.h>
#include <base/interfaces/adaptor-internal-services.h>
-#include <base/update-render-synchronization.h>
+#include <base/thread-synchronization.h>
#include <base/environment-options.h>
namespace Dali
namespace
{
-
-const unsigned int MICROSECONDS_PER_MILLISECOND( 1000 );
-
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gUpdateLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_THREAD");
+#endif
} // unnamed namespace
-UpdateThread::UpdateThread( UpdateRenderSynchronization& sync,
+UpdateThread::UpdateThread( ThreadSynchronization& sync,
AdaptorInternalServices& adaptorInterfaces,
const EnvironmentOptions& environmentOptions )
-: mUpdateRenderSync( sync ),
+: mThreadSynchronization( sync ),
mCore( adaptorInterfaces.GetCore()),
- mFpsTrackingSeconds( environmentOptions.GetFrameRateLoggingFrequency() ),
- mElapsedTime( 0.0f ),
- mElapsedSeconds( 0u ),
- mStatusLogInterval( environmentOptions.GetUpdateStatusLoggingFrequency() ),
- mStatusLogCount( 0u ),
- mNotificationTrigger( adaptorInterfaces.GetTriggerEventInterface() ),
+ mFpsTracker( environmentOptions ),
+ mUpdateStatusLogger( environmentOptions ),
mThread( NULL ),
mEnvironmentOptions( environmentOptions )
{
- if( mFpsTrackingSeconds > 0 )
- {
- mFpsRecord.resize( mFpsTrackingSeconds, 0.0f );
- }
}
UpdateThread::~UpdateThread()
{
- if(mFpsTrackingSeconds > 0)
- {
- OutputFPSRecord();
- }
Stop();
}
void UpdateThread::Start()
{
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Start()\n");
if ( !mThread )
{
// Create and run the update-thread
- mThread = new boost::thread( boost::bind( &UpdateThread::Run, this ) );
+ mThread = new pthread_t();
+ int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
+ DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in UpdateThread" );
}
}
void UpdateThread::Stop()
{
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Stop()\n");
if( mThread )
{
// wait for the thread to finish
- mThread->join();
+ pthread_join(*mThread, NULL);
delete mThread;
mThread = NULL;
bool UpdateThread::Run()
{
- Integration::UpdateStatus status;
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run()\n");
- // install a function for logging
+ // Install a function for logging
mEnvironmentOptions.InstallLogFunction();
- bool running( true );
+ Integration::UpdateStatus status;
+ bool runUpdate = true;
+ float lastFrameDelta( 0.0f );
+ unsigned int lastSyncTime( 0 );
+ unsigned int nextSyncTime( 0 );
// Update loop, we stay inside here while the update-thread is running
- while ( running )
+ // We also get the last delta and the predict when this update will be rendered
+ while ( mThreadSynchronization.UpdateReady( status.NeedsNotification(), runUpdate, lastFrameDelta, lastSyncTime, nextSyncTime ) )
{
- // Inform synchronization object update is ready to run, this will pause update thread if required.
- mUpdateRenderSync.UpdateReadyToRun();
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 1 - UpdateReady(delta:%f, lastSync:%u, nextSync:%u)\n", lastFrameDelta, lastSyncTime, nextSyncTime);
- // Do the update
- mCore.Update( status );
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 2 - Core.Update()\n");
- if( mFpsTrackingSeconds > 0 )
- {
- FPSTracking(status.SecondsFromLastFrame());
- }
+ mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::UPDATE_START );
+ mCore.Update( lastFrameDelta, lastSyncTime, nextSyncTime, status );
+ mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::UPDATE_END );
- // Do the notifications first so the actor-thread can start processing them
- if( status.NeedsNotification() )
- {
- // Tell the event-thread to wake up (if asleep) and send a notification event to Core
- mNotificationTrigger.Trigger();
- }
+ mFpsTracker.Track( status.SecondsFromLastFrame() );
- bool renderNeedsUpdate;
+ unsigned int keepUpdatingStatus = status.KeepUpdating();
- // tell the synchronisation class that a buffer has been written to,
- // and to wait until there is a free buffer to write to
- running = mUpdateRenderSync.UpdateSyncWithRender( renderNeedsUpdate );
+ // Optional logging of update/render status
+ mUpdateStatusLogger.Log( keepUpdatingStatus );
- if( running )
- {
- unsigned int keepUpdatingStatus = status.KeepUpdating();
+ // 2 things can keep update running.
+ // - The status of the last update
+ // - The status of the last render
+ runUpdate = (Integration::KeepUpdating::NOT_REQUESTED != keepUpdatingStatus);
- // Optional logging of update/render status
- if ( mStatusLogInterval )
- {
- UpdateStatusLogging( keepUpdatingStatus, renderNeedsUpdate );
- }
+ DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 3 - runUpdate(%d)\n", runUpdate );
- // 2 things can keep update running.
- // - The status of the last update
- // - The status of the last render
- bool runUpdate = (Integration::KeepUpdating::NOT_REQUESTED != keepUpdatingStatus) || renderNeedsUpdate;
-
- if( !runUpdate )
- {
- running = mUpdateRenderSync.UpdateTryToSleep();
- }
- }
+ // Reset time variables
+ lastFrameDelta = 0.0f;
+ lastSyncTime = 0;
+ nextSyncTime = 0;
}
- // uninstall a function for logging
+ // Uninstall the logging function
mEnvironmentOptions.UnInstallLogFunction();
return true;
}
-void UpdateThread::FPSTracking(float secondsFromLastFrame)
-{
- if (mElapsedSeconds < mFpsTrackingSeconds)
- {
- mElapsedTime += secondsFromLastFrame;
- if( secondsFromLastFrame > 1.0 )
- {
- int seconds = floor(mElapsedTime);
- mElapsedSeconds += seconds;
- mElapsedTime -= static_cast<float>(seconds);
- }
- else
- {
- if( mElapsedTime>=1.0f )
- {
- mElapsedTime -= 1.0f;
- mFpsRecord[mElapsedSeconds] += 1.0f - mElapsedTime/secondsFromLastFrame;
- mElapsedSeconds++;
- mFpsRecord[mElapsedSeconds] += mElapsedTime/secondsFromLastFrame;
- }
- else
- {
- mFpsRecord[mElapsedSeconds] += 1.0f;
- }
- }
- }
- else
- {
- OutputFPSRecord();
- mFpsRecord.clear();
- mFpsTrackingSeconds = 0;
- }
-}
-
-void UpdateThread::OutputFPSRecord()
-{
- for(unsigned int i = 0; i < mElapsedSeconds; i++)
- {
- DALI_LOG_FPS("fps( %d ):%f\n",i ,mFpsRecord[i]);
- }
- std::ofstream outFile("/tmp/dalifps.txt");
- if(outFile.is_open())
- {
- for(unsigned int i = 0; i < mElapsedSeconds; i++)
- {
- outFile << mFpsRecord[i]<<std::endl;
- }
- outFile.close();
- }
-}
-
-void UpdateThread::UpdateStatusLogging( unsigned int keepUpdatingStatus, bool renderNeedsUpdate )
-{
- DALI_ASSERT_ALWAYS( mStatusLogInterval );
-
- std::ostringstream oss;
-
- if ( !(++mStatusLogCount % mStatusLogInterval) )
- {
- oss << "UpdateStatusLogging keepUpdating: " << (bool)keepUpdatingStatus << " ";
-
- if ( keepUpdatingStatus )
- {
- oss << "because: ";
- }
-
- if ( keepUpdatingStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING )
- {
- oss << "<Stage::KeepRendering() used> ";
- }
-
- if ( keepUpdatingStatus & Integration::KeepUpdating::INCOMING_MESSAGES )
- {
- oss << "<Messages sent to Update> ";
- }
-
- if ( keepUpdatingStatus & Integration::KeepUpdating::ANIMATIONS_RUNNING )
- {
- oss << "<Animations running> ";
- }
-
- if ( keepUpdatingStatus & Integration::KeepUpdating::DYNAMICS_CHANGED )
- {
- oss << "<Dynamics running> ";
- }
-
- if ( keepUpdatingStatus & Integration::KeepUpdating::LOADING_RESOURCES )
- {
- oss << "<Resources loading> ";
- }
-
- if ( keepUpdatingStatus & Integration::KeepUpdating::NOTIFICATIONS_PENDING )
- {
- oss << "<Notifications pending> ";
- }
-
- if ( renderNeedsUpdate )
- {
- oss << "<Render needs Update> ";
- }
-
- DALI_LOG_UPDATE_STATUS( "%s\n", oss.str().c_str() );
- }
-}
-
} // namespace Adaptor
} // namespace Internal