{
switch( threadingMode )
{
- case ThreadingMode::SEPARATE_UPDATE_RENDER:
case ThreadingMode::COMBINED_UPDATE_RENDER:
- case ThreadingMode::SINGLE_THREADED:
{
mThreadingMode = static_cast< ThreadingMode::Type >( threadingMode );
break;
$(base_adaptor_src_dir)/performance-logging/performance-interface-factory.cpp \
$(base_adaptor_src_dir)/performance-logging/statistics/stat-context.cpp \
$(base_adaptor_src_dir)/performance-logging/statistics/stat-context-manager.cpp \
- $(base_adaptor_src_dir)/combined-update-render/combined-update-render-controller.cpp \
- $(base_adaptor_src_dir)/separate-update-render/frame-time.cpp \
- $(base_adaptor_src_dir)/separate-update-render/separate-update-render-controller.cpp \
- $(base_adaptor_src_dir)/separate-update-render/render-request.cpp \
- $(base_adaptor_src_dir)/separate-update-render/render-thread.cpp \
- $(base_adaptor_src_dir)/separate-update-render/thread-synchronization.cpp \
- $(base_adaptor_src_dir)/separate-update-render/update-thread.cpp \
- $(base_adaptor_src_dir)/separate-update-render/vsync-notifier.cpp \
- $(base_adaptor_src_dir)/single-threaded/single-thread-controller.cpp
+ $(base_adaptor_src_dir)/combined-update-render/combined-update-render-controller.cpp
base_adaptor_networking_src_files = \
$(base_adaptor_src_dir)/performance-logging/networking/network-performance-protocol.cpp \
+++ /dev/null
-/*
- * Copyright (c) 2017 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "frame-time.h"
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-#include <dali/integration-api/platform-abstraction.h>
-
-// INTERNAL INCLUDES
-#include <base/time-service.h>
-
-namespace Dali
-{
-
-using Integration::PlatformAbstraction;
-
-namespace Internal
-{
-namespace Adaptor
-{
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FRAME_TIME");
-#endif
-
-const unsigned int DEFAULT_MINIMUM_FRAME_TIME_INTERVAL( 16667u );
-
-const unsigned int MICROSECONDS_PER_MILLISECOND( 1000u );
-const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u);
-
-const float MICROSECONDS_TO_SECONDS( 0.000001f );
-
-const unsigned int HISTORY_SIZE(3);
-
-// constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
-const unsigned int TRUE = 1u;
-const unsigned int FALSE = 0u;
-} // unnamed namespace
-
-
-FrameTime::FrameTime()
-: mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
- mLastSyncTime( 0u ),
- mLastSyncTimeAtUpdate( 0u ),
- mLastSyncFrameNumber( 0u ),
- mLastUpdateFrameNumber( 0u ),
- mRunning( TRUE ),
- mFirstFrame( TRUE ),
- writePos( 0u ),
- mExtraUpdatesSinceSync( 0u )
-{
- // Clear buffer
- for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
- {
- mPreviousUpdateFrames[i] = 0;
- }
-
- SetLastSyncTime();
- mLastSyncTimeAtUpdate = mLastSyncTime;
-
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
-}
-
-FrameTime::~FrameTime()
-{
-}
-
-void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
-{
- mMinimumFrameTimeInterval = interval;
-}
-
-void FrameTime::SetSyncTime( unsigned int frameNumber )
-{
- // Only set the render time if we are running
- if ( mRunning )
- {
- SetLastSyncTime();
-
- mLastSyncFrameNumber = frameNumber;
-
- DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, static_cast<unsigned int>( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
- }
-}
-
-void FrameTime::Suspend()
-{
- mRunning = FALSE;
-
- // Reset members
- mLastSyncFrameNumber = 0;
- mLastUpdateFrameNumber = 0;
- writePos = 0;
- mExtraUpdatesSinceSync = 0;
-
- // Clear buffer
- for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
- {
- mPreviousUpdateFrames[i] = 0;
- }
-
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
-}
-
-void FrameTime::Resume()
-{
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );
-
- SetLastSyncTime(); // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
- mFirstFrame = TRUE;
-
- mRunning = TRUE;
-}
-
-void FrameTime::Sleep()
-{
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );
-
- // Mimic Suspend behaviour
- Suspend();
-}
-
-void FrameTime::WakeUp()
-{
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );
-
- SetLastSyncTime();
- mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
- mFirstFrame = TRUE;
- mRunning = TRUE;
-}
-
-void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
-{
- if ( mRunning )
- {
- const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
- const uint64_t lastSyncTime( mLastSyncTime );
- const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );
-
- float lastFrameDelta( 0.0f ); // Assume the last update frame delta is 0.
- unsigned int framesTillNextSync( 1 ); // Assume next render will be in one Sync frame time.
-
- unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
- lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;
-
- // We should only evaluate the previous frame values if this is not the first frame.
- if ( !mFirstFrame )
- {
- // Check whether we have had any Syncs since we last did an Update.
- if ( framesInLastUpdate == 0 )
- {
- // We have had another update before a Sync, increment counter.
- ++mExtraUpdatesSinceSync;
-
- // This update frame will be rendered mUpdatesSinceSync later.
- framesTillNextSync += mExtraUpdatesSinceSync;
- DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
- }
- else
- {
- mExtraUpdatesSinceSync = 0;
- }
-
- // If more than one frame elapsed since last Update, then check if this is a recurring theme so we can accurately predict when this Update is rendered.
- if ( framesInLastUpdate > 1 )
- {
- DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime framesInLastUpdate:%u\n", framesInLastUpdate);
- unsigned int average(0);
- for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
- {
- average += mPreviousUpdateFrames[i];
- }
- average /= HISTORY_SIZE;
-
- if ( average > 1 )
- {
- // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
- framesTillNextSync = average;
- }
- }
-
- // Write the number of frames the last update took to the array.
- mPreviousUpdateFrames[writePos] = framesInLastUpdate;
- writePos = ( writePos + 1 ) % HISTORY_SIZE;
- }
-
- mLastUpdateFrameNumber = lastSyncFrameNumber;
- mLastSyncTimeAtUpdate = lastSyncTime;
- mFirstFrame = FALSE;
-
- // Calculate the time till the next render
- unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync );
-
- // Set the input variables
- lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
- lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND;
- nextSyncTimeMilliseconds = ( lastSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND;
-
- DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds, lastFrameDeltaSeconds );
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, " FramesInLastUpdate: %u, FramesTillNextSync: %u\n", framesInLastUpdate, framesTillNextSync );
- }
-}
-
-inline void FrameTime::SetLastSyncTime()
-{
- uint64_t nanoseconds( 0u );
- TimeService::GetNanoseconds( nanoseconds );
-
- mLastSyncTime = nanoseconds / NANOSECONDS_PER_MICROSECOND;
-}
-
-} // namespace Adaptor
-} // namespace Internal
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__
-#define __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__
-
-/*
- * Copyright (c) 2014 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <stdint.h>
-
-namespace Dali
-{
-
-namespace Integration
-{
-class PlatformAbstraction;
-}
-
-namespace Internal
-{
-namespace Adaptor
-{
-
-/**
- * FrameTime stores the time of the last VSync. It can then be used by the update thread to predict
- * the current update will be rendered.
- */
-class FrameTime
-{
-public:
-
- // Called from Event thread
-
- /**
- * Constructor
- */
- FrameTime();
-
- /**
- * Destructor, non virtual
- */
- ~FrameTime();
-
- /**
- * Sets the expected minimum frame time interval.
- * @param[in] interval The interval in microseconds.
- */
- void SetMinimumFrameTimeInterval( unsigned int interval );
-
- /**
- * Suspends the FrameTime object when the application state changes
- */
- void Suspend();
-
- /**
- * Resumes the FrameTime object when the application state changes
- */
- void Resume();
-
- // Called from Update thread
-
- /**
- * Sets the FrameTime object to sleep, i.e. when there are no more updates required.
- */
- void Sleep();
-
- /**
- * Wakes the FrameTime object from a sleep state.
- */
- void WakeUp();
-
- /**
- * Predicts when the next render time will occur.
- *
- * @param[out] lastFrameDeltaSeconds The delta, in seconds (with float precision), between the last two renders.
- * @param[out] lastSyncTimeMilliseconds The time, in milliseconds, of the last Sync.
- * @param[out] nextSyncTimeMilliseconds The estimated time, in milliseconds, at the next Sync.
- *
- * @note Should only be called once per tick, from the update thread.
- */
- void PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastVSyncTimeMilliseconds, unsigned int& nextVSyncTimeMilliseconds );
-
- // Called from VSync thread
-
- /**
- * Tells the FrameTime object that a Sync has occurred.
- *
- * @param[in] frameNumber The frame number of the current Sync.
- *
- * @note Should only be called from the VSync thread.
- */
- void SetSyncTime( unsigned int frameNumber );
-
-private:
-
- /**
- * Sets the current time to be the last Vsync time.
- */
- inline void SetLastSyncTime();
-
-private:
-
- unsigned int mMinimumFrameTimeInterval; ///< The minimum frame time interval, set by Adaptor.
-
- uint64_t mLastSyncTime; ///< The last Sync time (in microseconds).
- uint64_t mLastSyncTimeAtUpdate; ///< The last Sync time at Update (in microseconds).
-
- unsigned int mLastSyncFrameNumber; ///< The last Sync frame number
- unsigned int mLastUpdateFrameNumber; ///< The last Sync frame number handled in Update.
-
- // NOTE cannot use bitfields or booleans as these are used from multiple threads, must use variable with machine word size for atomic read/write
- unsigned int mRunning; ///< The state of the FrameTime object.
- unsigned int mFirstFrame; ///< Whether the current update is the first frame (after initialisation, resume or wake up).
-
- unsigned int mPreviousUpdateFrames[3]; ///< Array holding the number of frames Update took in the last three iterations.
- unsigned int writePos; ///< The current write position in the array.
-
- unsigned int mExtraUpdatesSinceSync; ///< The number of extra updates since the last Sync.
-};
-
-} // namespace Adaptor
-} // namespace Internal
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "render-request.h"
-
-// EXTERNAL INCLUDES
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-namespace
-{
-}
-
-RenderRequest::RenderRequest( RenderRequest::Request type )
-: mRequestType( type )
-{
-}
-
-RenderRequest::Request RenderRequest::GetType()
-{
- return mRequestType;
-}
-
-ReplaceSurfaceRequest::ReplaceSurfaceRequest()
-: RenderRequest( RenderRequest::REPLACE_SURFACE ),
- mNewSurface( NULL ),
- mReplaceCompleted( false )
-{
-}
-
-void ReplaceSurfaceRequest::SetSurface( RenderSurface* newSurface )
-{
- mNewSurface = newSurface;
-}
-
-RenderSurface* ReplaceSurfaceRequest::GetSurface()
-{
- return mNewSurface;
-}
-
-void ReplaceSurfaceRequest::ReplaceCompleted()
-{
- mReplaceCompleted = true;
-}
-
-bool ReplaceSurfaceRequest::GetReplaceCompleted()
-{
- return mReplaceCompleted != 0u;
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_INTERNAL_RENDER_REQUEST_H__
-#define __DALI_INTERNAL_RENDER_REQUEST_H__
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-
-// INTERNAL INCLUDES
-#include <egl-interface.h>
-#include <render-surface.h> // needed for Dali::RenderSurface
-
-namespace Dali
-{
-
-class RenderSurface;
-class DisplayConnection;
-
-namespace Internal
-{
-namespace Adaptor
-{
-
-class RenderRequest
-{
-public:
- enum Request
- {
- REPLACE_SURFACE, // Request to replace surface
- };
-
- /**
- * Constructor.
- * @param[in] type The type of the request
- */
- RenderRequest( Request type );
-
- /**
- * @return the type of the request
- */
- Request GetType();
-
-private:
- Request mRequestType;
-};
-
-class ReplaceSurfaceRequest : public RenderRequest
-{
-public:
-
- /**
- * Constructor
- */
- ReplaceSurfaceRequest();
-
- /**
- * Set the new surface
- * @param[in] newSurface The new surface to use
- */
- void SetSurface(RenderSurface* newSurface);
-
- /**
- * @return the new surface
- */
- RenderSurface* GetSurface();
-
- /**
- * Called when the request has been completed to set the result.
- */
- void ReplaceCompleted();
-
- /**
- * @return true if the replace has completed.
- */
- bool GetReplaceCompleted();
-
-private:
- RenderSurface* mNewSurface; ///< The new surface to use.
- unsigned int mReplaceCompleted; ///< Set to true when the replace has completed.
-};
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_RENDER_REQUEST_H__
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "render-thread.h"
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-
-// INTERNAL INCLUDES
-#include <base/interfaces/adaptor-internal-services.h>
-#include <base/separate-update-render/thread-synchronization.h>
-#include <base/environment-options.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Integration::Log::Filter* gRenderLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_RENDER_THREAD");
-#endif
-}
-
-RenderThread::RenderThread( ThreadSynchronization& sync,
- AdaptorInternalServices& adaptorInterfaces,
- const EnvironmentOptions& environmentOptions )
-: mThreadSynchronization( sync ),
- mCore( adaptorInterfaces.GetCore() ),
- mThread( NULL ),
- mEnvironmentOptions( environmentOptions ),
- mRenderHelper( adaptorInterfaces )
-{
-}
-
-RenderThread::~RenderThread()
-{
-}
-
-void RenderThread::Start()
-{
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n");
-
- // create the render thread, initially we are rendering
- mThread = new pthread_t();
- int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
- DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in RenderThread" );
-
- mRenderHelper.Start();
-}
-
-void RenderThread::Stop()
-{
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
-
- mRenderHelper.Stop();
-
- // shutdown the render thread and destroy the opengl context
- if( mThread )
- {
- // wait for the thread to finish
- pthread_join(*mThread, NULL);
-
- delete mThread;
- mThread = NULL;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// The following methods are all executed inside render thread !!!
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool RenderThread::Run()
-{
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run\n");
-
- // Install a function for logging
- mEnvironmentOptions.InstallLogFunction();
-
- mRenderHelper.InitializeEgl();
-
- // tell core it has a context
- mCore.ContextCreated();
-
- Dali::Integration::RenderStatus renderStatus;
- RenderRequest* request = NULL;
-
- // Render loop, we stay inside here when rendering
- while( mThreadSynchronization.RenderReady( request ) )
- {
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderReady\n");
-
- // Consume any pending events to avoid memory leaks
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - ConsumeEvents\n");
- mRenderHelper.ConsumeEvents();
-
- // Check if we've got a request from the main thread (e.g. replace surface)
- if( request )
- {
- // Process the request, we should NOT render when we have a request
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Process requests\n");
- ProcessRequest( request );
- }
- else
- {
- // No request to process so we render
- if( mRenderHelper.PreRender() ) // Returns false if no surface onto which to render
- {
- // Render
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Core.Render()\n");
-
- mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::RENDER_START );
- mCore.Render( renderStatus );
- mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::RENDER_END );
-
- // Decrement the count of how far update is ahead of render
- mThreadSynchronization.RenderFinished();
-
- // Perform any post-render operations
- if( renderStatus.NeedsPostRender() )
- {
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - PostRender()\n");
- mRenderHelper.PostRender();
- }
- }
- }
-
- request = NULL; // Clear the request if it was set, no need to release memory
- }
-
- // Inform core of context destruction & shutdown EGL
- mCore.ContextDestroyed();
- mRenderHelper.ShutdownEgl();
-
- // Uninstall the logging function
- mEnvironmentOptions.UnInstallLogFunction();
-
- return true;
-}
-
-void RenderThread::ProcessRequest( RenderRequest* request )
-{
- if( request != NULL )
- {
- switch(request->GetType())
- {
- case RenderRequest::REPLACE_SURFACE:
- {
- // change the surface
- ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
- mRenderHelper.ReplaceSurface( replaceSurfaceRequest->GetSurface() );
- replaceSurfaceRequest->ReplaceCompleted();
- mThreadSynchronization.RenderInformSurfaceReplaced();
- break;
- }
- }
- }
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_INTERNAL_RENDER_THREAD_H__
-#define __DALI_INTERNAL_RENDER_THREAD_H__
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <pthread.h>
-
-// INTERNAL INCLUDES
-#include <base/render-helper.h>
-#include <base/separate-update-render/render-request.h>
-#include <egl-interface.h>
-#include <render-surface.h> // needed for Dali::RenderSurface
-
-namespace Dali
-{
-
-class RenderSurface;
-
-namespace Integration
-{
-class Core;
-}
-
-namespace Internal
-{
-namespace Adaptor
-{
-
-class AdaptorInternalServices;
-class ThreadSynchronization;
-class EnvironmentOptions;
-
-/**
- * The render-thread is responsible for calling Core::Render() after each update.
- */
-class RenderThread
-{
-public:
-
- /**
- * Create the render-thread; this will not do anything until Start() is called.
- * @param[in] sync thread synchronization object
- * @param[in] adaptorInterfaces base adaptor interface
- * @param[in] environmentOptions environment options
- */
- RenderThread( ThreadSynchronization& sync,
- AdaptorInternalServices& adaptorInterfaces,
- const EnvironmentOptions& environmentOptions );
-
- /**
- * Destructor
- */
- ~RenderThread();
-
-public:
-
- /**
- * Starts the render-thread
- */
- void Start();
-
- /**
- * Stops the render-thread
- */
- void Stop();
-
-private: // Render thread side helpers
-
- /**
- * This method is used by the Render thread for rendering the Core to the screen.
- * Called from render thread
- * @return true, if the thread finishes properly.
- */
- bool Run();
-
- /**
- * Check if main thread made any requests, e.g. ReplaceSurface
- * Called from render thread
- */
- void ProcessRequest( RenderRequest* request );
-
- /**
- * Helper for the thread calling the entry function.
- * @param[in] This A pointer to the current RenderThread object
- */
- static inline void* InternalThreadEntryFunc( void* This )
- {
- ( static_cast<RenderThread*>( This ) )->Run();
- return NULL;
- }
-
-private:
-
- // Undefined
- RenderThread( const RenderThread& renderThread );
-
- // Undefined
- RenderThread& operator=( const RenderThread& renderThread );
-
-private: // Data
-
- ThreadSynchronization& mThreadSynchronization; ///< Used to synchronize the all threads
- Dali::Integration::Core& mCore; ///< Dali core reference
- pthread_t* mThread; ///< render thread
- const EnvironmentOptions& mEnvironmentOptions; ///< Environment options
- RenderHelper mRenderHelper; ///< Helper class for EGL, pre & post rendering
-};
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_RENDER_THREAD_H__
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "separate-update-render-controller.h"
-
-// INTERNAL INCLUDES
-#include <base/separate-update-render/update-thread.h>
-#include <base/separate-update-render/render-thread.h>
-#include <base/separate-update-render/thread-synchronization.h>
-#include <base/separate-update-render/vsync-notifier.h>
-#include <base/interfaces/adaptor-internal-services.h>
-#include <base/environment-options.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-SeparateUpdateRenderController::SeparateUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
-: ThreadControllerInterface(),
- mAdaptorInterfaces( adaptorInterfaces ),
- mUpdateThread( NULL ),
- mRenderThread( NULL ),
- mVSyncNotifier( NULL ),
- mThreadSync( NULL ),
- mNumberOfVSyncsPerRender( environmentOptions.GetRenderRefreshRate() )
-{
- mThreadSync = new ThreadSynchronization( adaptorInterfaces, mNumberOfVSyncsPerRender );
-
- mUpdateThread = new UpdateThread( *mThreadSync, adaptorInterfaces, environmentOptions );
-
- mRenderThread = new RenderThread( *mThreadSync, adaptorInterfaces, environmentOptions );
-
- mVSyncNotifier = new VSyncNotifier( *mThreadSync, adaptorInterfaces, environmentOptions );
-
- // Set the thread-synchronization interface on the render-surface
- RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
- if( currentSurface )
- {
- currentSurface->SetThreadSynchronization( *mThreadSync );
- }
-}
-
-SeparateUpdateRenderController::~SeparateUpdateRenderController()
-{
- delete mVSyncNotifier;
- delete mRenderThread;
- delete mUpdateThread;
- delete mThreadSync;
-}
-
-void SeparateUpdateRenderController::Initialize()
-{
- // Notify the synchronization object before starting the threads
- mThreadSync->Initialise();
-
- // We want to the threads to be set up before they start
- mUpdateThread->Start();
- mRenderThread->Start();
- mVSyncNotifier->Start();
-}
-
-void SeparateUpdateRenderController::Start()
-{
- mThreadSync->Start();
-}
-
-void SeparateUpdateRenderController::Pause()
-{
- mThreadSync->Pause();
-}
-
-void SeparateUpdateRenderController::Resume()
-{
- mThreadSync->Resume();
-}
-
-void SeparateUpdateRenderController::Stop()
-{
- // Notify the synchronization object before stopping the threads
- mThreadSync->Stop();
-
- mVSyncNotifier->Stop();
- mUpdateThread->Stop();
- mRenderThread->Stop();
-}
-
-void SeparateUpdateRenderController::RequestUpdate()
-{
- mThreadSync->UpdateRequest();
-}
-
-void SeparateUpdateRenderController::RequestUpdateOnce()
-{
- // if we are paused, need to allow one update
- mThreadSync->UpdateOnce();
-}
-
-void SeparateUpdateRenderController::ReplaceSurface( RenderSurface* newSurface )
-{
- // Set the thread-syncronization on the new surface
- newSurface->SetThreadSynchronization( *mThreadSync );
-
- // tell render thread to start the replace. This call will block until the replace
- // has completed.
- RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
-
- // Ensure the current surface releases any locks to prevent deadlock.
- currentSurface->StopRender();
-
- mThreadSync->ReplaceSurface( newSurface );
-}
-
-void SeparateUpdateRenderController::SetRenderRefreshRate(unsigned int numberOfVSyncsPerRender )
-{
- mNumberOfVSyncsPerRender = numberOfVSyncsPerRender;
- mThreadSync->SetRenderRefreshRate(numberOfVSyncsPerRender);
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_INTERNAL_MULTI_THREAD_CONTROLLER_H__
-#define __DALI_INTERNAL_MULTI_THREAD_CONTROLLER_H__
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <base/thread-controller-interface.h>
-
-namespace Dali
-{
-
-class RenderSurface;
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-class UpdateThread;
-class RenderThread;
-class VSyncNotifier;
-class ThreadSynchronization;
-class AdaptorInternalServices;
-class EnvironmentOptions;
-
-/**
- * Class to control multiple threads:
- * - Main Event Thread
- * - VSync Thread
- * - Update Thread
- * - Render Thread
- */
-class SeparateUpdateRenderController : public ThreadControllerInterface
-{
-public:
-
- /**
- * Constructor
- */
- SeparateUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions );
-
- /**
- * Non virtual destructor. Not intended as base class.
- */
- ~SeparateUpdateRenderController();
-
- /**
- * @copydoc ThreadControllerInterface::Initialize()
- */
- void Initialize();
-
- /**
- * @copydoc ThreadControllerInterface::Start()
- */
- void Start();
-
- /**
- * @copydoc ThreadControllerInterface::Pause()
- */
- void Pause();
-
- /**
- * @copydoc ThreadControllerInterface::Resume()
- */
- void Resume();
-
- /**
- * @copydoc ThreadControllerInterface::Stop()
- */
- void Stop();
-
- /**
- * @copydoc ThreadControllerInterface::RequestUpdate()
- */
- void RequestUpdate();
-
- /**
- * @copydoc ThreadControllerInterface::RequestUpdateOnce()
- */
- void RequestUpdateOnce();
-
- /**
- * @copydoc ThreadControllerInterface::ReplaceSurface()
- */
- void ReplaceSurface( RenderSurface* surface );
-
- /**
- * @copydoc ThreadControllerInterface::SetRenderRefreshRate()
- */
- void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
-
-private:
-
- // Undefined copy constructor.
- SeparateUpdateRenderController( const SeparateUpdateRenderController& );
-
- // Undefined assignment operator.
- SeparateUpdateRenderController& operator=( const SeparateUpdateRenderController& );
-
- AdaptorInternalServices& mAdaptorInterfaces;
-
- UpdateThread* mUpdateThread; ///< The update-thread owned by SeparateUpdateRenderController
- RenderThread* mRenderThread; ///< The render-thread owned by SeparateUpdateRenderController
- VSyncNotifier* mVSyncNotifier; ///< The vsync-thread owned by SeparateUpdateRenderController
- ThreadSynchronization* mThreadSync; ///< Used to synchronize all the threads; owned by SeparateUpdateRenderController
- unsigned int mNumberOfVSyncsPerRender; ///< Frame skipping count
-};
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_MULTI_THREAD_CONTROLLER_H__
+++ /dev/null
-#ifndef __DALI_INTERNAL_THREAD_SYNCHRONIZATION_DEBUG_H__
-#define __DALI_INTERNAL_THREAD_SYNCHRONIZATION_DEBUG_H__
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-namespace
-{
-// Uncomment next line for FULL logging of the ThreadSynchronization class in release mode
-//#define RELEASE_BUILD_LOGGING
-
-#ifdef DEBUG_ENABLED
-
-#define ENABLE_LOG_IN_COLOR
-#define ENABLE_VSYNC_COUNTER_LOGGING
-#define ENABLE_UPDATE_COUNTER_LOGGING
-#define ENABLE_VSYNC_THREAD_LOGGING
-#define ENABLE_UPDATE_THREAD_LOGGING
-#define ENABLE_RENDER_THREAD_LOGGING
-#define ENABLE_EVENT_LOGGING
-
-#define DEBUG_LEVEL_COUNTER Debug::Verbose
-#define DEBUG_LEVEL_VSYNC Debug::General
-#define DEBUG_LEVEL_UPDATE Debug::General
-#define DEBUG_LEVEL_RENDER Debug::General
-#define DEBUG_LEVEL_EVENT Debug::Concise
-
-Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_THREAD_SYNC" );
-
-#define LOG_THREAD_SYNC(level, color, format, args...) \
- DALI_LOG_INFO( gLogFilter, level, "%s" format "%s\n", color, ## args, COLOR_CLEAR )
-
-#define LOG_THREAD_SYNC_TRACE(color) \
- Dali::Integration::Log::TraceObj debugTraceObj( gLogFilter, "%s%s%s", color, __FUNCTION__, COLOR_CLEAR ); \
- if( ! gLogFilter->IsTraceEnabled() ) { LOG_THREAD_SYNC( Debug::Concise, color, "%s", __FUNCTION__ ); }
-
-#define LOG_THREAD_SYNC_TRACE_FMT(color, format, args...) \
- Dali::Integration::Log::TraceObj debugTraceObj( gLogFilter, "%s%s: " format "%s", color, __FUNCTION__, ## args, COLOR_CLEAR ); \
- if( ! gLogFilter->IsTraceEnabled() ) { LOG_THREAD_SYNC( Debug::Concise, color, "%s: " format, __FUNCTION__, ## args ); }
-
-#elif defined( RELEASE_BUILD_LOGGING )
-
-#define ENABLE_LOG_IN_COLOR
-#define ENABLE_VSYNC_COUNTER_LOGGING
-#define ENABLE_UPDATE_COUNTER_LOGGING
-#define ENABLE_VSYNC_THREAD_LOGGING
-#define ENABLE_UPDATE_THREAD_LOGGING
-#define ENABLE_RENDER_THREAD_LOGGING
-#define ENABLE_EVENT_LOGGING
-
-#define DEBUG_LEVEL_COUNTER 0
-#define DEBUG_LEVEL_VSYNC 0
-#define DEBUG_LEVEL_UPDATE 0
-#define DEBUG_LEVEL_RENDER 0
-#define DEBUG_LEVEL_EVENT 0
-
-#define LOG_THREAD_SYNC(level, color, format, args...) \
- Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s" format "%s\n", color, ## args, COLOR_CLEAR )
-
-#define LOG_THREAD_SYNC_TRACE(color) \
- Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s%s%s\n", color, __FUNCTION__, COLOR_CLEAR )
-
-#define LOG_THREAD_SYNC_TRACE_FMT(color, format, args...) \
- Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s%s: " format "%s\n", color, __FUNCTION__, ## args, COLOR_CLEAR )
-
-#else
-
-#define LOG_THREAD_SYNC(level, color, format, args...)
-#define LOG_THREAD_SYNC_TRACE(color)
-#define LOG_THREAD_SYNC_TRACE_FMT(color, format, args...)
-
-#endif // DEBUG_ENABLED
-
-#ifdef ENABLE_LOG_IN_COLOR
-#define COLOR_RED "\033[31m"
-#define COLOR_YELLOW "\033[33m"
-#define COLOR_BLUE "\033[34m"
-#define COLOR_LIGHT_RED "\033[91m"
-#define COLOR_LIGHT_YELLOW "\033[93m"
-#define COLOR_LIGHT_BLUE "\033[94m"
-#define COLOR_WHITE "\033[97m"
-#define COLOR_CLEAR "\033[0m"
-#else
-#define COLOR_RED
-#define COLOR_YELLOW
-#define COLOR_BLUE
-#define COLOR_LIGHT_RED
-#define COLOR_LIGHT_YELLOW
-#define COLOR_LIGHT_BLUE
-#define COLOR_WHITE
-#define COLOR_CLEAR
-#endif
-
-#ifdef ENABLE_VSYNC_COUNTER_LOGGING
-#define LOG_VSYNC_COUNTER_VSYNC(format, args...) LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_LIGHT_RED, "%s: " format, __FUNCTION__, ## args)
-#define LOG_VSYNC_COUNTER_UPDATE(format, args...) LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_LIGHT_YELLOW, "%s: " format, __FUNCTION__, ## args)
-#else
-#define LOG_VSYNC_COUNTER_VSYNC(format, args...)
-#define LOG_VSYNC_COUNTER_UPDATE(format, args...)
-#endif
-
-#ifdef ENABLE_UPDATE_COUNTER_LOGGING
-#define LOG_UPDATE_COUNTER_UPDATE(format, args...) LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_YELLOW, "%s: " format, __FUNCTION__, ## args)
-#define LOG_UPDATE_COUNTER_RENDER(format, args...) LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_LIGHT_BLUE, "%s: " format, __FUNCTION__, ## args)
-#else
-#define LOG_UPDATE_COUNTER_UPDATE(format, args...)
-#define LOG_UPDATE_COUNTER_RENDER(format, args...)
-#endif
-
-#ifdef ENABLE_VSYNC_THREAD_LOGGING
-#define LOG_VSYNC(format, args...) LOG_THREAD_SYNC(DEBUG_LEVEL_VSYNC, COLOR_RED, "%s: " format, __FUNCTION__, ## args)
-#define LOG_VSYNC_TRACE LOG_THREAD_SYNC_TRACE(COLOR_RED)
-#define LOG_VSYNC_TRACE_FMT(format, args...) LOG_THREAD_SYNC_TRACE_FMT(COLOR_RED, format, ## args)
-#else
-#define LOG_VSYNC(format, args...)
-#define LOG_VSYNC_TRACE
-#define LOG_VSYNC_TRACE_FMT(format, args...)
-#endif
-
-#ifdef ENABLE_UPDATE_THREAD_LOGGING
-#define LOG_UPDATE(format, args...) LOG_THREAD_SYNC(DEBUG_LEVEL_UPDATE, COLOR_YELLOW, "%s: " format, __FUNCTION__, ## args)
-#define LOG_UPDATE_TRACE LOG_THREAD_SYNC_TRACE(COLOR_YELLOW)
-#define LOG_UPDATE_TRACE_FMT(format, args...) LOG_THREAD_SYNC_TRACE_FMT(COLOR_YELLOW, format, ## args)
-#else
-#define LOG_UPDATE(format, args...)
-#define LOG_UPDATE_TRACE
-#define LOG_UPDATE_TRACE_FMT(format, args...)
-#endif
-
-#ifdef ENABLE_RENDER_THREAD_LOGGING
-#define LOG_RENDER(format, args...) LOG_THREAD_SYNC(DEBUG_LEVEL_RENDER, COLOR_BLUE, "%s: " format, __FUNCTION__, ## args)
-#define LOG_RENDER_TRACE LOG_THREAD_SYNC_TRACE(COLOR_BLUE)
-#define LOG_RENDER_TRACE_FMT(format, args...) LOG_THREAD_SYNC_TRACE_FMT(COLOR_BLUE, format, ## args)
-#else
-#define LOG_RENDER(format, args...)
-#define LOG_RENDER_TRACE
-#define LOG_RENDER_TRACE_FMT(format, args...)
-#endif
-
-#ifdef ENABLE_EVENT_LOGGING
-#define LOG_EVENT(format, args...) LOG_THREAD_SYNC(DEBUG_LEVEL_EVENT, COLOR_WHITE, "%s: " format, __FUNCTION__, ## args)
-#define LOG_EVENT_TRACE LOG_THREAD_SYNC_TRACE(COLOR_WHITE)
-#define LOG_EVENT_TRACE_FMT(format, args...) LOG_THREAD_SYNC_TRACE_FMT(COLOR_WHITE, format, ## args)
-#else
-#define LOG_EVENT(format, args...)
-#define LOG_EVENT_TRACE
-#define LOG_EVENT_TRACE_FMT(format, args...)
-#endif
-} // unnamed namespace
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_THREAD_SYNCHRONIZATION_DEBUG_H__
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "thread-synchronization.h"
-
-// INTERNAL INCLUDES
-#include <base/interfaces/adaptor-internal-services.h>
-#include <base/separate-update-render/thread-synchronization-debug.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-namespace
-{
-const unsigned int TIME_PER_FRAME_IN_MICROSECONDS = 16667;
-const int TOTAL_THREAD_COUNT = 3;
-const unsigned int TRUE = 1u;
-const unsigned int FALSE = 0u;
-} // unnamed namespace
-
-ThreadSynchronization::ThreadSynchronization( AdaptorInternalServices& adaptorInterfaces, unsigned int numberOfVSyncsPerRender)
-: mFrameTime(),
- mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
- mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
- mReplaceSurfaceRequest(),
- mUpdateThreadWaitCondition(),
- mRenderThreadWaitCondition(),
- mVSyncThreadWaitCondition(),
- mEventThreadWaitCondition(),
- mMaximumUpdateCount( adaptorInterfaces.GetCore().GetMaximumUpdateCount()),
- mNumberOfVSyncsPerRender( numberOfVSyncsPerRender ),
- mTryToSleepCount( 0u ),
- mState( State::STOPPED ),
- mVSyncAheadOfUpdate( 0u ),
- mUpdateAheadOfRender( 0u ),
- mNumberOfThreadsStarted( 0u ),
- mUpdateThreadResuming( FALSE ),
- mVSyncThreadRunning( FALSE ),
- mVSyncThreadStop( FALSE ),
- mRenderThreadStop( FALSE ),
- mRenderThreadReplacingSurface( FALSE ),
- mRenderThreadPostRendering( FALSE ),
- mEventThreadSurfaceReplaced( FALSE ),
- mVSyncThreadInitialised( FALSE ),
- mRenderThreadInitialised( FALSE ),
- mRenderThreadSurfaceReplaced( FALSE )
-{
-}
-
-ThreadSynchronization::~ThreadSynchronization()
-{
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// EVENT THREAD
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ThreadSynchronization::Initialise()
-{
- LOG_EVENT_TRACE;
-
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- if( mState == State::STOPPED )
- {
- LOG_EVENT( "INITIALISING" );
- mState = State::INITIALISING;
- }
-}
-
-void ThreadSynchronization::Start()
-{
- LOG_EVENT_TRACE;
-
- bool start = false;
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- if( mState == State::INITIALISING )
- {
- start = true;
- }
- }
-
- // Not atomic, but does not matter here as we just want to ensure we only start from State::INITIALISING
- if( start )
- {
- LOG_EVENT( "STARTING" );
- mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
-
- {
- ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
- while( mNumberOfThreadsStarted < TOTAL_THREAD_COUNT )
- {
- mEventThreadWaitCondition.Wait( lock );
- }
- }
-
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- mState = State::RUNNING;
- }
- mUpdateThreadWaitCondition.Notify();
- }
-}
-
-void ThreadSynchronization::Stop()
-{
- LOG_EVENT_TRACE;
-
- bool stop = false;
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- if( mState != State::STOPPED )
- {
- stop = true;
- mState = State::STOPPED;
- }
- }
-
- // Not atomic, but does not matter here as we just want to ensure we do not stop more than once
- if( stop )
- {
- LOG_EVENT( "STOPPING" );
-
- // Notify update-thread so that it continues and sets up the other threads to stop as well
- mUpdateThreadWaitCondition.Notify();
-
- mFrameTime.Suspend();
- }
-}
-
-void ThreadSynchronization::Pause()
-{
- LOG_EVENT_TRACE;
-
- bool addPerformanceMarker = false;
- {
- // Only pause if we're RUNNING or SLEEPING
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- if( ( mState == State::RUNNING ) ||
- ( mState == State::SLEEPING ) )
- {
- LOG_EVENT( "PAUSING" );
-
- mState = State::PAUSED;
-
- mUpdateThreadResuming = FALSE;
-
- mFrameTime.Suspend();
-
- addPerformanceMarker = true;
- }
- }
-
- if( addPerformanceMarker )
- {
- // Can lock so we do not want to have a lock when calling this to avoid deadlocks
- AddPerformanceMarker( PerformanceInterface::PAUSED );
- }
-}
-
-void ThreadSynchronization::Resume()
-{
- LOG_EVENT_TRACE;
-
- // Only resume if we're PAUSED
- bool resume = false;
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- if( mState == State::PAUSED )
- {
- resume = true;
- mState = State::RUNNING;
- mUpdateThreadResuming = TRUE;
- }
- }
-
- // Not atomic, but does not matter here as we just want to ensure we only resume if we're paused
- if( resume )
- {
- LOG_EVENT( "RESUMING" );
-
- mFrameTime.Resume();
-
- // Start up Update thread again
- mUpdateThreadWaitCondition.Notify();
-
- // Can lock so we do not want to have a lock when calling this to avoid deadlocks
- AddPerformanceMarker( PerformanceInterface::RESUME);
- }
-}
-
-void ThreadSynchronization::UpdateRequest()
-{
- LOG_EVENT_TRACE;
-
- bool update = false;
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- if( mState == State::SLEEPING )
- {
- mState = State::RUNNING;
- update = true;
- }
- mTryToSleepCount = 0;
- }
-
- if( update )
- {
- LOG_EVENT( "UPDATE REQUEST" );
- mUpdateThreadWaitCondition.Notify();
- }
-}
-
-void ThreadSynchronization::UpdateOnce()
-{
- LOG_EVENT_TRACE;
- LOG_EVENT( "UPDATE ONCE" );
-
- // If we're sleeping then change state to running as this will also wake up the v-sync-thread
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- if( mState == State::SLEEPING )
- {
- mState = State::RUNNING;
- }
- }
-
- mUpdateThreadWaitCondition.Notify();
-}
-
-void ThreadSynchronization::ReplaceSurface( RenderSurface* newSurface )
-{
- LOG_EVENT_TRACE;
-
- State::Type previousState( State::STOPPED );
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- previousState = mState;
- mState = State::REPLACING_SURFACE;
- }
-
- {
- ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
- mEventThreadSurfaceReplaced = FALSE;
- }
-
- {
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- mReplaceSurfaceRequest.SetSurface( newSurface );
- mRenderThreadReplacingSurface = TRUE;
- }
-
- // Notify the RenderThread in case it's waiting
- mRenderThreadWaitCondition.Notify();
-
- {
- ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
-
- // Wait for RenderThread to replace the surface
- while( ! mEventThreadSurfaceReplaced )
- {
- LOG_EVENT( "Waiting for Surface to be Replaced" );
-
- mEventThreadWaitCondition.Wait( lock );
- }
- }
-
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- mState = previousState;
- }
- mUpdateThreadWaitCondition.Notify();
-}
-
-void ThreadSynchronization::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
-{
- LOG_EVENT_TRACE;
- LOG_EVENT( "SET RENDER REFRESH RATE" );
-
- mNumberOfVSyncsPerRender = numberOfVSyncsPerRender;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// UPDATE THREAD
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool ThreadSynchronization::UpdateReady( bool notifyEvent, bool runUpdate, float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
-{
- LOG_UPDATE_TRACE;
-
- State::Type state = State::STOPPED;
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- state = mState;
- }
-
- switch( state )
- {
- case State::STOPPED:
- {
- StopAllThreads();
- return false; // Stop update-thread
- }
-
- case State::INITIALISING:
- {
- UpdateInitialising();
- break;
- }
-
- case State::PAUSED:
- {
- LOG_UPDATE_TRACE_FMT( "PAUSED" );
-
- // Just pause the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
- PauseVSyncThread();
- }
- // No break, fall through
-
- case State::RUNNING:
- {
- LOG_UPDATE_TRACE_FMT( "RUNNING" );
-
- if( IsUpdateThreadResuming() )
- {
- LOG_UPDATE( "Restarting VSyncThread" );
-
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- mUpdateThreadResuming = FALSE;
- }
-
- // Restart the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
- RunVSyncThread();
- }
-
- if( notifyEvent )
- {
- LOG_UPDATE( "Notify Event Thread" );
-
- // Do the notifications first so the event thread can start processing them
- // Tell the event-thread to wake up (if asleep) and send a notification event to Core
- mNotificationTrigger.Trigger();
- }
-
- // Inform render thread
- {
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- ++mUpdateAheadOfRender;
- DALI_ASSERT_ALWAYS( mUpdateAheadOfRender >= 0 );
- DALI_ASSERT_ALWAYS( mUpdateAheadOfRender <= mMaximumUpdateCount );
- LOG_UPDATE_COUNTER_UPDATE( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
- }
- mRenderThreadWaitCondition.Notify();
-
- // Wait if we've reached the maximum-ahead-of-render count.
- while( MaximumUpdateAheadOfRenderReached() )
- {
- LOG_UPDATE( "Maximum Update Ahead of Render: WAIT" );
-
- mRenderThreadWaitCondition.Notify(); // Notify the render thread in case it was waiting
-
- {
- // Ensure we did not stop while we were waiting previously.
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- if( mState == State::STOPPED )
- {
- break; // Break out of while loop
- }
- mUpdateThreadWaitCondition.Wait( updateLock );
- }
- }
-
- // Ensure we have had at least 1 V-Sync before we continue
- // Ensure we didn't stop while we were previously waiting
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- if( ( mState != State::STOPPED ) &&
- ( mVSyncAheadOfUpdate == 0 ) &&
- ( !mUpdateThreadResuming ) ) // Ensure we don't wait if the update-thread is JUST resuming
- {
- LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d) WAIT", mVSyncAheadOfUpdate );
- mUpdateThreadWaitCondition.Wait( updateLock );
- }
- else
- {
- LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
- }
- mVSyncAheadOfUpdate = 0;
- }
-
- // Try to sleep if we do not require any more updates
- UpdateTryToSleep( runUpdate );
-
- break;
- }
-
- case State::SLEEPING:
- case State::REPLACING_SURFACE:
- {
- break;
- }
- }
-
- // Ensure we didn't stop while we were waiting
- if( IsUpdateThreadStopping() )
- {
- // Locks so we shouldn't have a scoped-lock when calling this
- StopAllThreads();
- return false; // Stop update-thread
- }
-
- // Just wait if we're replacing the surface as the render-thread is busy
- UpdateWaitIfReplacingSurface();
-
- mFrameTime.PredictNextSyncTime( lastFrameDeltaSeconds, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds );
-
- return true; // Keep update-thread running
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// RENDER THREAD
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool ThreadSynchronization::RenderReady( RenderRequest*& requestPtr )
-{
- LOG_RENDER_TRACE;
-
- if( ! IsRenderThreadReplacingSurface() ) // Call to this function locks so should not be called if we have a scoped-lock
- {
- if( ! mRenderThreadInitialised )
- {
- LOG_RENDER( "Initialised" );
-
- mRenderThreadInitialised = TRUE;
-
- // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
- NotifyThreadInitialised();
- }
- else
- {
- if( mRenderThreadSurfaceReplaced )
- {
- mRenderThreadSurfaceReplaced = FALSE;
- }
- }
-
- // Check if we've had an update, if we haven't then we just wait
- // Ensure we do not wait if we're supposed to stop
- {
- ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
- if( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop )
- {
- do
- {
- LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d) WAIT", mUpdateAheadOfRender );
- mRenderThreadWaitCondition.Wait( renderLock );
- } while( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop && ! mRenderThreadReplacingSurface );
- }
- else
- {
- LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
- }
- }
- }
-
- // We may have been asked to replace the surface while we were waiting so check again here
- if( IsRenderThreadReplacingSurface() )
- {
- // Replacing surface
- LOG_RENDER( "REPLACE SURFACE" );
-
- ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
- requestPtr = &mReplaceSurfaceRequest;
- mRenderThreadReplacingSurface = FALSE;
- mRenderThreadSurfaceReplaced = FALSE;
- }
-
- return IsRenderThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
-}
-
-void ThreadSynchronization::RenderFinished()
-{
- // A frame has been rendered; decrement counter
- ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
- --mUpdateAheadOfRender;
-
- LOG_RENDER( "mUpdateAheadOfRender %d\n", mUpdateAheadOfRender );
- DALI_ASSERT_ALWAYS( mUpdateAheadOfRender < mMaximumUpdateCount );
- DALI_ASSERT_ALWAYS( mUpdateAheadOfRender >= 0 );
-}
-
-void ThreadSynchronization::RenderInformSurfaceReplaced()
-{
- LOG_RENDER_TRACE;
-
- mRenderThreadSurfaceReplaced = TRUE;
- {
- ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
- mEventThreadSurfaceReplaced = TRUE;
- }
- mEventThreadWaitCondition.Notify();
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// V-SYNC THREAD
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool ThreadSynchronization::VSyncReady( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender )
-{
- LOG_VSYNC_TRACE;
-
- // Ensure we do not process an invalid v-sync
- if( validSync )
- {
- bool minimumFrameTimeIntervalChanged = false;
- {
- ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
- if( numberOfVSyncsPerRender != mNumberOfVSyncsPerRender )
- {
- numberOfVSyncsPerRender = mNumberOfVSyncsPerRender; // save it back
- minimumFrameTimeIntervalChanged = true;
- }
- }
-
- if( minimumFrameTimeIntervalChanged )
- {
- mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
- }
-
- mFrameTime.SetSyncTime( frameNumber );
-
- if( ! mVSyncThreadInitialised )
- {
- LOG_VSYNC( "Initialised" );
-
- mVSyncThreadInitialised = TRUE;
-
- // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
- NotifyThreadInitialised();
- }
- else
- {
- // Increment v-sync-ahead-of-update count and inform update-thread
- {
- ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
- ++mVSyncAheadOfUpdate;
- LOG_VSYNC_COUNTER_VSYNC( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
- }
- mUpdateThreadWaitCondition.Notify();
- }
-
- // Ensure update-thread has set us to run before continuing
- // Ensure we do not wait if we're supposed to stop
- {
- ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
- while( ! mVSyncThreadRunning && ! mVSyncThreadStop )
- {
- LOG_VSYNC( "WAIT" );
- mVSyncThreadWaitCondition.Wait( vSyncLock );
- }
- }
- }
- else
- {
- LOG_VSYNC( "INVALID SYNC" );
-
- // Later we still check if the v-sync thread is supposed to keep running so we can still stop the thread if we are supposed to
- }
-
- return IsVSyncThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////////////
-// POST RENDERING: EVENT THREAD
-/////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ThreadSynchronization::PostRenderComplete()
-{
- LOG_EVENT_TRACE;
-
- {
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- mRenderThreadPostRendering = FALSE;
- }
- mRenderThreadWaitCondition.Notify();
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// POST RENDERING: RENDER THREAD
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ThreadSynchronization::PostRenderStarted()
-{
- LOG_RENDER_TRACE;
-
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- mRenderThreadPostRendering = TRUE;
-}
-
-void ThreadSynchronization::PostRenderWaitForCompletion()
-{
- LOG_RENDER_TRACE;
-
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- while( mRenderThreadPostRendering &&
- ! mRenderThreadReplacingSurface ) // We should NOT wait if we're replacing the surface
- {
- LOG_RENDER( "WAIT" );
- mRenderThreadWaitCondition.Wait( lock );
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// ALL THREADS: Performance Marker
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ThreadSynchronization::AddPerformanceMarker( PerformanceInterface::MarkerType type )
-{
- if( mPerformanceInterface )
- {
- mPerformanceInterface->AddMarker( type );
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
-// PRIVATE METHODS
-//
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Called by ALL Threads
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ThreadSynchronization::NotifyThreadInitialised()
-{
- {
- ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
- ++mNumberOfThreadsStarted;
- }
- mEventThreadWaitCondition.Notify();
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Called by Update Thread
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ThreadSynchronization::UpdateInitialising()
-{
- LOG_UPDATE_TRACE;
-
- // Notify event thread that this thread is up and running, locks so we shouldn't have a scoped-lock when calling this
- NotifyThreadInitialised();
-
- // Wait for first thread-sync point
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
-
- while( mState == State::INITIALISING )
- {
- mUpdateThreadWaitCondition.Wait( updateLock );
- }
- }
-
- // Locks so we shouldn't have a scoped-lock when calling this
- RunVSyncThread();
-}
-
-void ThreadSynchronization::UpdateTryToSleep( bool runUpdate )
-{
- LOG_UPDATE_TRACE;
-
- if( ! runUpdate &&
- ! IsUpdateThreadResuming() ) // Locks so we shouldn't have a lock, we shouldn't try to sleep if we're JUST resuming
- {
- LOG_UPDATE( "TryToSleep" );
-
- if( ++mTryToSleepCount >= 3 )
- {
- LOG_UPDATE( "Going to sleep" );
-
- // Locks so we shouldn't have a scoped-lock when calling this
- PauseVSyncThread();
-
- // Render thread will automatically wait as it relies on update-ahead-of-render count
-
- // Change the state
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
-
- // Ensure we weren't stopped while we have been processing
- if( mState != State::STOPPED )
- {
- mState = State::SLEEPING;
- }
- }
-
- // Inform FrameTime that we're going to sleep
- mFrameTime.Sleep();
-
- // Wait while we're SLEEPING
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- while( mState == State::SLEEPING )
- {
- mUpdateThreadWaitCondition.Wait( updateLock );
- }
- }
-
- ////////////////////////
- // WAKE UP
- ////////////////////////
-
- LOG_UPDATE( "Waking Up" );
-
- // Clear V-Sync-ahead-of-update-count
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- mVSyncAheadOfUpdate = 0;
- }
-
- // Restart the v-sync-thread, locks so we shouldn't have a scoped-lock
- RunVSyncThread();
-
- // Reset try-to-sleep count
- mTryToSleepCount = 0;
-
- // Inform frame timer that we've woken up
- mFrameTime.WakeUp();
- }
- }
- else
- {
- mTryToSleepCount = 0;
- }
-}
-
-void ThreadSynchronization::UpdateWaitIfReplacingSurface()
-{
- bool replacingSurface = false;
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- replacingSurface = ( mState == State::REPLACING_SURFACE );
- }
- while( replacingSurface )
- {
- LOG_UPDATE_TRACE_FMT( "REPLACING SURFACE" );
-
- // Locks so should not be called while we have a scoped-lock
- PauseVSyncThread();
-
- // One last check before we actually wait in case the state has changed since we checked earlier
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- replacingSurface = ( mState == State::REPLACING_SURFACE );
- if( replacingSurface )
- {
- mUpdateThreadWaitCondition.Wait( updateLock );
- }
- }
-
- {
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- mVSyncAheadOfUpdate = 0;
- }
-
- // Locks so should not be called while we have a scoped-lock
- RunVSyncThread();
- }
-}
-
-bool ThreadSynchronization::IsUpdateThreadResuming()
-{
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- return mUpdateThreadResuming;
-}
-
-bool ThreadSynchronization::IsUpdateThreadStopping()
-{
- ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
- return ( mState == State::STOPPED );
-}
-
-bool ThreadSynchronization::MaximumUpdateAheadOfRenderReached()
-{
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- return mUpdateAheadOfRender >= mMaximumUpdateCount;
-}
-
-void ThreadSynchronization::StopAllThreads()
-{
- LOG_UPDATE_TRACE;
-
- // Lock so we shouldn't have a scoped-lock when calling these methods
- StopVSyncThread();
- StopRenderThread();
-}
-
-void ThreadSynchronization::RunVSyncThread()
-{
- {
- ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
- mVSyncThreadRunning = TRUE;
- }
- mVSyncThreadWaitCondition.Notify();
-}
-
-void ThreadSynchronization::PauseVSyncThread()
-{
- ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
- mVSyncThreadRunning = FALSE;
-}
-
-void ThreadSynchronization::StopVSyncThread()
-{
- {
- ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
- mVSyncThreadStop = TRUE;
- }
- mVSyncThreadWaitCondition.Notify();
-}
-
-void ThreadSynchronization::StopRenderThread()
-{
- {
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- mRenderThreadStop = TRUE;
- }
- mRenderThreadWaitCondition.Notify();
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Called by V-Sync Thread
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool ThreadSynchronization::IsVSyncThreadRunning()
-{
- ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
- return ! mVSyncThreadStop;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Called by Render Thread
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-bool ThreadSynchronization::IsRenderThreadRunning()
-{
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- return ! mRenderThreadStop;
-}
-
-bool ThreadSynchronization::IsRenderThreadReplacingSurface()
-{
- ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
- return mRenderThreadReplacingSurface;
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_INTERNAL_THREAD_SYNCHRONIZATION_H__
-#define __DALI_INTERNAL_THREAD_SYNCHRONIZATION_H__
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/threading/conditional-wait.h>
-
-// INTERNAL INCLUDES
-#include <integration-api/thread-synchronization-interface.h>
-#include <base/interfaces/performance-interface.h>
-#include <trigger-event-interface.h>
-#include <base/separate-update-render/frame-time.h>
-#include <base/separate-update-render/render-request.h>
-
-namespace Dali
-{
-
-class RenderSurface;
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-class AdaptorInternalServices;
-
-/**
- * This object is used to synchronize the update, render and vsync threads.
- * The Core::GetMaximumUpdateCount() method determines how many frames may be prepared, ahead of the rendering.
- * For example if the maximum update count is 2, then Core::Update() for frame N+1 may be processed whilst frame N is being rendered.
- * However the Core::Update() for frame N+2 may not be called, until the Core::Render() method for frame N has returned.
- *
- */
-class ThreadSynchronization : public Dali::ThreadSynchronizationInterface
-{
-public:
-
- /**
- * Create an update/render synchronization object.
- * @param[in] adaptorInterfaces base adaptor interface
- * @param[in] numberOfVSyncsPerRender The number of frames per render
- */
- ThreadSynchronization( AdaptorInternalServices& adaptorInterfaces, unsigned int numberOfVSyncsPerRender );
-
- /**
- * Non virtual destructor. Not intended as base class.
- */
- ~ThreadSynchronization();
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by the Event Thread
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Initialises the ThreadSynchronisation class. The expectation is that this function will be
- * called when all threads are about to be set up and that Start will be called when
- * the the scene is actually prepared and ready to be displayed. This way our first update
- * will have the actual scene we require.
- *
- * @note Should only be called by the Event Thread.
- */
- void Initialise();
-
- /**
- * Starts running all threads. This waits until all threads are up and running.
- *
- * @pre A call to Initialise has been made.
- *
- * @note Should only be called by the Event Thread.
- */
- void Start();
-
- /**
- * Stop the threads.
- *
- * @note Should only be called by the Event Thread.
- */
- void Stop();
-
- /**
- * Pause the controller (and threads).
- *
- * @note Should only be called by the Event Thread.
- */
- void Pause();
-
- /**
- * Resume the controller (and threads).
- *
- * @note Should only be called by the Event Thread.
- */
- void Resume();
-
- /**
- * Wake update thread if sleeping. If the update thread is not sleeping
- * this becomes a no-op.
- * Called when an update is requested by Core.
- * i.e. when a batch of messages have been queued for the next update.
- *
- * @note Should only be called by the Event Thread.
- */
- void UpdateRequest();
-
- /**
- * Update once (even if paused)
- *
- * @note Should only be called by the Event Thread.
- */
- void UpdateOnce();
-
- /**
- * Inform the render thread that there is a new surface, and that
- * it should replace the current surface.
- *
- * @param[in] newSurface The new surface for rendering.
- *
- * @note Should only be called by the Event Thread.
- */
- void ReplaceSurface( RenderSurface* newSurface );
-
- /**
- * Set the refresh rate for rendering
- *
- * @param[in] numberOfVSyncsPerRender The number of vsync frames per render
- *
- * @note Should only be called by the Event Thread.
- */
- void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by the Update Thread
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Called by Update thread when it is ready to run the update.
- *
- * @param[in] notifyEvent Whether the event thread should be woken up.
- * @param[in] runUpdate Whether to run another update. If false, then the update-thread will attempt to sleep.
- * @param[out] lastFrameDeltaSeconds The delta, in seconds (with float precision), between the last two renders.
- * @param[out] lastSyncTimeMilliseconds The time, in milliseconds, of the last Sync.
- * @param[out] nextSyncTimeMilliseconds The estimated time, in milliseconds, at the next Sync.
- * @return true if updating should continue, false if the update-thread should quit.
- *
- * @note Should only be called by the Update thread.
- */
- bool UpdateReady( bool notifyEvent, bool runUpdate, float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds );
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by the Render Thread
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Called by the Render thread when it is ready to render.
- *
- * @param[in] request Pointer to set if there are any requests. This does not need to be freed by the caller.
- *
- * @note Should only be called by the Render thread.
- * @note If there is a request, then the Render thread should NOT perform a Render and only process the request
- */
- bool RenderReady( RenderRequest*& request );
-
- /**
- * Called by the render thread after it renders a frame.
- * Used to notify the update-thread that a frame has been rendered.
- * @pre Called by render thread only.
- */
- void RenderFinished();
-
- /**
- * Called by the Render thread to inform the synchronization class that the surface has been replaced.
- *
- * @note Should only be called by the Render thread.
- */
- void RenderInformSurfaceReplaced();
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by the V-Sync Thread
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Called by the VSync notifier thread so it can sleep if Update/Render threads are sleeping/paused
- *
- * @param[in] validSync True if the sync was valid (@see VSyncMonitor::DoSync)
- * @param[in] frameNumber The current frame number
- * @param[in] seconds The current time
- * @param[in] microseconds The current time
- * @param[out] numberOfVSyncsPerRender The number of frames per render.
- * @return true if VSync monitoring/notifications should continue.
- *
- * @note Should only be called by the VSync thread.
- * @note The first call to this method should be BEFORE the actual VSync so a thread-sync point can be established (and startup time is not delayed).
- */
- bool VSyncReady( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender );
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // POST RENDERING
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- //// Called by the Event Thread if post-rendering is required
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * @copydoc ThreadSynchronizationInterface::PostRenderComplete()
- */
- void PostRenderComplete();
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- //// Called by the Render Thread if post-rendering is required
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * @copydoc ThreadSynchronizationInterface::PostRenderStarted()
- */
- void PostRenderStarted();
-
- /**
- * @copydoc ThreadSynchronizationInterface::PostRenderStarted()
- */
- void PostRenderWaitForCompletion();
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by ALL Threads
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Helper to add a performance marker to the performance server (if it's active)
- * @param type performance marker type
- */
- void AddPerformanceMarker( PerformanceInterface::MarkerType type );
-
-private:
-
- // Undefined copy constructor.
- ThreadSynchronization( const ThreadSynchronization& );
-
- // Undefined assignment operator.
- ThreadSynchronization& operator=( const ThreadSynchronization& );
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by ALL Threads
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Called by the update, render & v-sync thread when they up and running.
- * This will lock the mutex in mEventThreadWaitCondition.
- */
- inline void NotifyThreadInitialised();
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by Update Thread
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Called by the update-thread when the state is State::INITIALISING.
- * Calls methods that lock and locks itself so should NOT be called while a scoped-lock is held.
- */
- void UpdateInitialising();
-
- /**
- * Called by the update thread to attempt to sleep.
- * @param[in] runUpdate Whether to run another update. If false, then the update-thread will attempt to sleep.
- */
- void UpdateTryToSleep( bool runUpdate );
-
- /**
- * Called by the update thread to wait while the render-surface is being replaced.
- * Calls methods that lock and locks itself so should NOT be called while a scoped-lock is held.
- */
- void UpdateWaitIfReplacingSurface();
-
- /**
- * Called by the update thread to check if we're just resuming.
- * This will lock the mutex in mUpdateThreadWaitCondition.
- */
- inline bool IsUpdateThreadResuming();
-
- /**
- * Called by the update thread to check if the update thread should be running.
- * This will lock the mutex in mUpdateThreadWaitCondition.
- *
- * @return True if we're stopping, false otherwise.
- */
- inline bool IsUpdateThreadStopping();
-
- /**
- * Called by the update thread to check if we've filled all update buffers.
- * This will lock the mutex in mRenderThreadWaitCondition.
- *
- * @return True if all update buffers are full.
- */
- inline bool MaximumUpdateAheadOfRenderReached();
-
- /**
- * Called by the update thread when we are about to stop.
- * This will call other functions which lock various conditional wait mutexes.
- */
- inline void StopAllThreads();
-
- /**
- * Runs the V-Sync Thread.
- * This will lock the mutex in mVSyncThreadWaitCondition.
- */
- inline void RunVSyncThread();
-
- /**
- * Pauses the V-Sync Thread.
- * This will lock the mutex in mVSyncThreadWaitCondition.
- */
- inline void PauseVSyncThread();
-
- /**
- * Stops the V-Sync Thread.
- * This will lock the mutex in mVSyncThreadWaitCondition.
- */
- inline void StopVSyncThread();
-
- /**
- * Stops the Render Thread.
- * This will lock the mutex in mRenderThreadWaitCondition.
- */
- inline void StopRenderThread();
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by V-Sync Thread
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Checks if the V-Sync thread should be running.
- * This will lock the mutex in mVSyncThreadWaitCondition.
- *
- * @return true if running, false otherwise.
- */
- inline bool IsVSyncThreadRunning();
-
- /////////////////////////////////////////////////////////////////////////////////////////////////
- // Called by Render Thread
- /////////////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Checks if the Render thread should be running.
- * This will lock the mutex in mRenderThreadWaitCondition.
- *
- * @return true if running, false otherwise.
- */
- inline bool IsRenderThreadRunning();
-
- /**
- * Checks if the render thread should be replacing the surface
- * This will lock the mutex in mRenderThreadWaitCondition.
- *
- * @return true if the render thread should be replacing the surface, false otherwise.
- */
- inline bool IsRenderThreadReplacingSurface();
-
-private:
-
- struct State
- {
- enum Type
- {
- STOPPED,
- INITIALISING,
- RUNNING,
- PAUSED,
- SLEEPING,
- REPLACING_SURFACE
- };
- };
-
- FrameTime mFrameTime; ///< Frame timer predicts next vsync time
- TriggerEventInterface& mNotificationTrigger; ///< Reference to notification event trigger
- PerformanceInterface* mPerformanceInterface; ///< The performance logging interface
- ReplaceSurfaceRequest mReplaceSurfaceRequest; ///< Holder for a replace surface request
-
- ConditionalWait mUpdateThreadWaitCondition; ///< The wait condition for the update-thread.
- ConditionalWait mRenderThreadWaitCondition; ///< The wait condition for the render-thread.
- ConditionalWait mVSyncThreadWaitCondition; ///< The wait condition for the v-sync-thread.
- ConditionalWait mEventThreadWaitCondition; ///< The wait condition for the event-thread.
-
- const int mMaximumUpdateCount; ///< How many frames may be prepared, ahead of the rendering.
- unsigned int mNumberOfVSyncsPerRender; ///< How many frames for each update/render cycle.
-
- unsigned int mTryToSleepCount; ///< Count to ensure we don't go to sleep too early
-
- volatile State::Type mState; ///< The current state of synchronisation (set & read by both the event & update threads).
-
- volatile int mVSyncAheadOfUpdate; ///< The number of frames vsync is ahead of update (set & read by both the v-sync & update threads).
- volatile int mUpdateAheadOfRender; ///< The number of frames update is ahead of render (set & read by both the update & render threads).
- volatile int mNumberOfThreadsStarted; ///< The number of threads that are initialised and running (set by update, v-sync & render threads, read by event-thread).
-
- //
- // NOTE: cannot use booleans as these are used from multiple threads, must use variable with machine word size for atomic read/write
- //
-
- volatile unsigned int mUpdateThreadResuming; ///< Whether the update-thread is resuming.
-
- volatile unsigned int mVSyncThreadRunning; ///< Whether the V-Sync thread is running (set by the update-thread, read by v-sync-thread).
- volatile unsigned int mVSyncThreadStop; ///< Whether the V-Sync thread should be stopped (set by the update-thread, read by the v-sync-thread).
-
- volatile unsigned int mRenderThreadStop; ///< Whether the render-thread should be stopped (set by the update-thread, read by the render-thread).
- volatile unsigned int mRenderThreadReplacingSurface;///< Whether the render-thread should replace the surface (set by the event & render threads, read by the render-thread).
-
- volatile unsigned int mRenderThreadPostRendering; ///< Whether post-rendering is taking place (set by the event & render threads, read by the render-thread).
-
- volatile unsigned int mEventThreadSurfaceReplaced; ///< Checked by the event-thread & set by the render-thread when the surface has been replaced (set by the event & render threads, read by the event-thread).
-
- unsigned int mVSyncThreadInitialised; ///< Whether the V-Sync thread has been initialised (only used by v-sync-thread).
- unsigned int mRenderThreadInitialised; ///< Whether the render-thread has been initialised (only used by the render-thread).
- unsigned int mRenderThreadSurfaceReplaced; ///< Whether the render-thread has replaced the surface (only used by render-thread).
-}; // class ThreadSynchronization
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_THREAD_SYNCHRONIZATION_H__
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "update-thread.h"
-
-// EXTERNAL INCLUDES
-#include <cstdio>
-
-// INTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-#include <base/interfaces/adaptor-internal-services.h>
-#include <base/separate-update-render/thread-synchronization.h>
-#include <base/environment-options.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Integration::Log::Filter* gUpdateLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_THREAD");
-#endif
-} // unnamed namespace
-
-UpdateThread::UpdateThread( ThreadSynchronization& sync,
- AdaptorInternalServices& adaptorInterfaces,
- const EnvironmentOptions& environmentOptions )
-: mThreadSynchronization( sync ),
- mCore( adaptorInterfaces.GetCore()),
- mFpsTracker( environmentOptions ),
- mUpdateStatusLogger( environmentOptions ),
- mThread( NULL ),
- mEnvironmentOptions( environmentOptions )
-{
-}
-
-UpdateThread::~UpdateThread()
-{
- Stop();
-}
-
-void UpdateThread::Start()
-{
- DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Start()\n");
- if ( !mThread )
- {
- // Create and run the update-thread
- 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
- pthread_join(*mThread, NULL);
-
- delete mThread;
- mThread = NULL;
- }
-}
-
-bool UpdateThread::Run()
-{
- DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run()\n");
-
- // Install a function for logging
- mEnvironmentOptions.InstallLogFunction();
-
- 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
- // We also get the last delta and the predict when this update will be rendered
- while ( mThreadSynchronization.UpdateReady( status.NeedsNotification(), runUpdate, lastFrameDelta, lastSyncTime, nextSyncTime ) )
- {
- DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 1 - UpdateReady(delta:%f, lastSync:%u, nextSync:%u)\n", lastFrameDelta, lastSyncTime, nextSyncTime);
-
- DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 2 - Core.Update()\n");
-
- mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::UPDATE_START );
- mCore.Update( lastFrameDelta, lastSyncTime, nextSyncTime, status );
- mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::UPDATE_END );
-
- mFpsTracker.Track( status.SecondsFromLastFrame() );
-
- unsigned int keepUpdatingStatus = status.KeepUpdating();
-
- // Optional logging of update/render status
- mUpdateStatusLogger.Log( keepUpdatingStatus );
-
- // 2 things can keep update running.
- // - The status of the last update
- // - The status of the last render
- runUpdate = (Integration::KeepUpdating::NOT_REQUESTED != keepUpdatingStatus);
-
- DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 3 - runUpdate(%d)\n", runUpdate );
-
- // Reset time variables
- lastFrameDelta = 0.0f;
- lastSyncTime = 0;
- nextSyncTime = 0;
- }
-
- // Uninstall the logging function
- mEnvironmentOptions.UnInstallLogFunction();
-
- return true;
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_INTERNAL_UPDATE_THREAD_H__
-#define __DALI_INTERNAL_UPDATE_THREAD_H__
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <pthread.h>
-
-// INTERNAL INCLUDES
-#include <base/fps-tracker.h>
-#include <base/update-status-logger.h>
-
-namespace Dali
-{
-
-namespace Integration
-{
-class Core;
-}
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-class ThreadSynchronization;
-class AdaptorInternalServices;
-class EnvironmentOptions;
-
-/**
- * The update-thread is responsible for calling Core::Update(), and
- * for triggering the render-thread after each update.
- */
-class UpdateThread
-{
-public:
-
- /**
- * Create the update-thread; this will not do anything until Start() is called.
- * @param[in] sync An object used to synchronize update & render threads.
- * @param[in] adaptorInterfaces base adaptor interface
- * @param[in] environmentOptions environment options
- */
- UpdateThread(ThreadSynchronization& sync,
- AdaptorInternalServices& adaptorInterfaces,
- const EnvironmentOptions& environmentOptions );
-
- /**
- * Non-virtual destructor; UpdateThread is not suitable as a base class.
- */
- ~UpdateThread();
-
- /**
- * Starts the update-thread
- */
- void Start();
-
- /**
- * Stops the update-thread
- */
- void Stop();
-
-private:
-
- /**
- * This method is used by the update-thread for calling Core::Update().
- * @return true, if the thread finishes properly.
- */
- bool Run();
-
- /**
- * Helper for the thread calling the entry function
- * @param[in] This A pointer to the current UpdateThread object
- */
- static inline void* InternalThreadEntryFunc( void* This )
- {
- ( static_cast<UpdateThread*>( This ) )->Run();
- return NULL;
- }
-
-private: // Data
-
- ThreadSynchronization& mThreadSynchronization; ///< Used to synchronize all the threads
-
- Dali::Integration::Core& mCore; ///< Dali core reference
-
- FpsTracker mFpsTracker; ///< Object that tracks the FPS
- UpdateStatusLogger mUpdateStatusLogger; ///< Object that logs the update-status as required.
-
- pthread_t* mThread; ///< The actual update-thread.
- const EnvironmentOptions& mEnvironmentOptions; ///< environment options
-}; // class UpdateThread
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_UPDATE_THREAD_H__
+++ /dev/null
-/*
- * Copyright (c) 2016 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "vsync-notifier.h"
-
-// EXTERNAL INCLUDES
-#include <unistd.h>
-#include <dali/integration-api/core.h>
-#include <dali/integration-api/platform-abstraction.h>
-
-// INTERNAL INCLUDES
-#include <base/interfaces/adaptor-internal-services.h>
-#include <base/separate-update-render/thread-synchronization.h>
-#include <base/environment-options.h>
-#include <base/time-service.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-namespace
-{
-
-const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
-const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u );
-const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
-const unsigned int TIME_PER_FRAME_IN_MICROSECONDS( 16667u );
-
-#if defined(DEBUG_ENABLED)
-Integration::Log::Filter* gSyncLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_VSYNC_NOTIFIER");
-#endif
-
-} // unnamed namespace
-
-VSyncNotifier::VSyncNotifier( ThreadSynchronization& sync,
- AdaptorInternalServices& adaptorInterfaces,
- const EnvironmentOptions& environmentOptions )
-: mThreadSynchronization( sync ),
- mCore( adaptorInterfaces.GetCore() ),
- mVSyncMonitor( adaptorInterfaces.GetVSyncMonitorInterface() ),
- mThread( NULL ),
- mEnvironmentOptions( environmentOptions ),
- mNumberOfVSyncsPerRender(1)
-{
-}
-
-VSyncNotifier::~VSyncNotifier()
-{
- DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
-
- Stop();
-}
-
-void VSyncNotifier::Start()
-{
- DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
-
- if ( !mThread )
- {
- mVSyncMonitor->Initialize();
-
- mThread = new pthread_t();
- int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
- DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in VSyncNotifier" );
- }
-}
-
-void VSyncNotifier::Stop()
-{
- DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
-
- if( mThread )
- {
- // wait for the thread to finish
- pthread_join(*mThread, NULL);
-
- delete mThread;
- mThread = NULL;
- }
-
- mVSyncMonitor->Terminate();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// The following is executed inside the notifier thread !!!
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-void VSyncNotifier::Run()
-{
- // install a function for logging
- mEnvironmentOptions.InstallLogFunction();
-
- unsigned int frameNumber( 0u ); // frameCount, updated when the thread is paused
- unsigned int currentSequenceNumber( 0u ); // platform specific vsync sequence number (increments with each vsync)
- unsigned int currentSeconds( 0u ); // timestamp at latest sync
- unsigned int currentMicroseconds( 0u ); // timestamp at latest sync
- uint64_t seconds( 0u );
- uint64_t microseconds( 0u );
-
- bool validSync( true );
- while( mThreadSynchronization.VSyncReady( validSync, frameNumber++, currentSeconds, currentMicroseconds, mNumberOfVSyncsPerRender ) )
- {
- DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 1 SyncWithUpdateAndRender(frame#:%d, current Sec:%u current uSec:%u)\n", frameNumber-1, currentSeconds, currentMicroseconds);
-
- // Hardware VSyncs available?
- if( mVSyncMonitor->UseHardware() )
- {
- DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 2 Start hardware sync (%d frames) \n", mNumberOfVSyncsPerRender);
-
- for( unsigned int i=0; i<mNumberOfVSyncsPerRender; ++i )
- {
- // Yes..wait for N hardware VSync ticks
- validSync = mVSyncMonitor->DoSync( currentSequenceNumber, currentSeconds, currentMicroseconds );
- }
- }
- else
- {
- // No..use software timer
- uint64_t nanoseconds = 0;
- TimeService::GetNanoseconds( nanoseconds );
-
- seconds = nanoseconds / NANOSECONDS_PER_SECOND; // Convert to seconds
- nanoseconds -= seconds * NANOSECONDS_PER_SECOND; // Only want remainder nanoseconds
- microseconds = nanoseconds / NANOSECONDS_PER_MICROSECOND; // Convert to microseconds
-
- unsigned int timeDelta( MICROSECONDS_PER_SECOND * (seconds - currentSeconds) );
- if( microseconds < currentMicroseconds)
- {
- timeDelta += (microseconds + MICROSECONDS_PER_SECOND) - currentMicroseconds;
- }
- else
- {
- timeDelta += microseconds - currentMicroseconds;
- }
-
- currentSeconds = seconds;
- currentMicroseconds = microseconds;
-
- unsigned int sleepTimeInMicroseconds = 0;
-
- if( timeDelta < TIME_PER_FRAME_IN_MICROSECONDS )
- {
- sleepTimeInMicroseconds = TIME_PER_FRAME_IN_MICROSECONDS - timeDelta;
- }
- sleepTimeInMicroseconds += mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS;
-
- DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 2 Start software sync (%d frames, %u microseconds) \n", mNumberOfVSyncsPerRender, sleepTimeInMicroseconds);
-
- timespec sleepTime;
- sleepTime.tv_sec = 0;
- sleepTime.tv_nsec = sleepTimeInMicroseconds;
- sleepTime.tv_nsec *= NANOSECONDS_PER_MICROSECOND;
- nanosleep( &sleepTime, NULL );
- }
- mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::VSYNC );
- }
-
- // uninstall a function for logging
- mEnvironmentOptions.UnInstallLogFunction();
-
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_INTERNAL_VSYNC_NOTIFIER_H__
-#define __DALI_INTERNAL_VSYNC_NOTIFIER_H__
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <pthread.h>
-
-namespace Dali
-{
-
-namespace Integration
-{
-
-class Core;
-class PlatformAbstraction;
-
-} // namespace Integration
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-class VSyncMonitorInterface;
-class ThreadSynchronization;
-class EnvironmentOptions;
-class AdaptorInternalServices;
-
-/**
- * Implements a simple class that either monitors vertical blanks from libdrm, or manages
- * a software timer to handle syncing.
- */
-class VSyncNotifier
-{
-public:
-
- /**
- * Create the vsync notification thread; this will not start to monitor vsync and
- * send notifications until Start() is called.
- * @param[in] sync An object used to synchronize update, render and vsync threads.
- * @param[in] adaptorInterfaces base adaptor interface
- * @param[in] environmentOptions environment options
- */
- VSyncNotifier( ThreadSynchronization& sync,
- AdaptorInternalServices& adaptorInterfaces,
- const EnvironmentOptions& environmentOptions);
-
- /**
- * Non-virtual destructor; VSyncNotifier is not suitable as a base class.
- */
- ~VSyncNotifier();
-
- /**
- * Starts the thread
- */
- void Start();
-
- /**
- * Stops the thread
- */
- void Stop();
-
-private:
-
- /**
- * The main thread loop. The system thread will be destroyed on
- * exit from this function.
- */
- void Run();
-
- /**
- * Helper for the thread calling the entry function
- * @param[in] This A pointer to the current VSyncNotifier object
- */
- static inline void* InternalThreadEntryFunc( void* This )
- {
- ( static_cast<VSyncNotifier*>( This ) )->Run();
- return NULL;
- }
-
-private:
-
- ThreadSynchronization& mThreadSynchronization; ///< Used to synchronize all the threads
- Dali::Integration::Core& mCore; ///< Dali core reference
- VSyncMonitorInterface* mVSyncMonitor; ///< VSyncMonitor interface
- pthread_t* mThread; ///< The actual thread.
- const EnvironmentOptions& mEnvironmentOptions; ///< Environment options
- unsigned int mNumberOfVSyncsPerRender; ///< How many frames for each update/render cycle.
-
-}; // class VSyncNotifier
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_VSYNC_NOTIFIER_H__
+++ /dev/null
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include "single-thread-controller.h"
-
-// EXTERNAL INCLUDES
-#include <iostream>
-#include <dali/integration-api/platform-abstraction.h>
-
-// INTERNAL INCLUDES
-#include <base/interfaces/adaptor-internal-services.h>
-#include <base/environment-options.h>
-#include <base/time-service.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-namespace
-{
-const unsigned int MILLISECONDS_PER_FRAME = 17u;
-const float SECONDS_PER_FRAME = MILLISECONDS_PER_FRAME * 0.001f;
-
-const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u );
-const float NANOSECONDS_TO_SECONDS( 1e-9f );
-
-#if defined(DEBUG_ENABLED)
-Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_THREAD_SYNC");
-#endif
-
-} // unnamed namespace
-
-SingleThreadController::SingleThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
-: ConnectionTracker(),
- ThreadControllerInterface(),
- mTimer(),
- mFpsTracker( environmentOptions ),
- mUpdateStatusLogger( environmentOptions ),
- mRenderHelper( adaptorInterfaces ),
- mCore( adaptorInterfaces.GetCore()),
- mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
- mLastUpdateRenderTime( 0 ),
- mSystemTime( 0 ),
- mRefreshRate( environmentOptions.GetRenderRefreshRate() ),
- mState( State::STOPPED ),
- mUpdatingAndRendering( false ),
- mStopRequestedWhileRendering( false )
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-}
-
-SingleThreadController::~SingleThreadController()
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- Stop();
-}
-
-void SingleThreadController::Initialize()
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- mTimer = Dali::Timer::New( mRefreshRate * MILLISECONDS_PER_FRAME );
-
- // Create a tick-signal so that we can update and render every frame
- mTimer.TickSignal().Connect( this, &SingleThreadController::OnTimerTick );
-}
-
-void SingleThreadController::Start()
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- mRenderHelper.Start();
- mRenderHelper.InitializeEgl();
-
- // tell core it has a context
- mCore.ContextCreated();
-
- // Do an update/render straight away
- UpdateTimeSinceLastRender();
- UpdateRender( false );
-
- ChangeState( State::RUNNING );
-}
-
-void SingleThreadController::Pause()
-{
- if( mState == State::RUNNING )
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- ChangeState( State::PAUSED );
-
- AddPerformanceMarker( PerformanceInterface::PAUSED );
- }
-}
-
-void SingleThreadController::Resume()
-{
- if( mState == State::PAUSED )
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- // Do an update/render straight away
- UpdateTimeSinceLastRender();
- UpdateRender( false );
-
- ChangeState( State::RUNNING );
-
- AddPerformanceMarker( PerformanceInterface::RESUME );
- }
-}
-
-void SingleThreadController::Stop()
-{
- if( mState != State::STOPPED )
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- ChangeState( State::STOPPED );
-
- if( mUpdatingAndRendering )
- {
- // If we interrupted an update/render for this stop, then we should NOT terminate GL just yet
- mStopRequestedWhileRendering = true;
- }
- else
- {
- StopRendering();
- }
- }
-}
-
-void SingleThreadController::RequestUpdate()
-{
- if( mState == State::SLEEPING )
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- // Do an update/render straight away
- UpdateTimeSinceLastRender();
- UpdateRender( false );
-
- ChangeState( State::RUNNING );
- }
-}
-
-void SingleThreadController::RequestUpdateOnce()
-{
- if( mState == State::SLEEPING || mState == State::PAUSED )
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- // Just do one update and render
-
- Integration::UpdateStatus status;
- mCore.Update( 0.0f, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, status );
-
- Render();
- }
-}
-
-void SingleThreadController::ReplaceSurface( RenderSurface* newSurface )
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
- mRenderHelper.ReplaceSurface( newSurface );
-}
-
-void SingleThreadController::SetRenderRefreshRate( unsigned int refreshRate )
-{
- if ( refreshRate != mRefreshRate )
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- mRefreshRate = refreshRate;
-
- if( mTimer )
- {
- mTimer.SetInterval( mRefreshRate * MILLISECONDS_PER_FRAME );
- }
- }
-}
-
-bool SingleThreadController::OnTimerTick()
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s()\n", __FUNCTION__ );
-
- if( mState == State::RUNNING )
- {
- UpdateRender( true );
- }
- else if( mState == State::STOPPED &&
- mStopRequestedWhileRendering )
- {
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s(): STOPPING\n", __FUNCTION__ );
-
- StopRendering();
-
- mStopRequestedWhileRendering = false;
-
- return false; // Stop the timer
- }
- return true;
-}
-
-void SingleThreadController::UpdateRender( bool incrementTime )
-{
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s():START\n", __FUNCTION__ );
-
- mUpdatingAndRendering = true;
-
- float lastFrameDelta( 0.0f );
-
- if( incrementTime )
- {
- // Use our usual time per frame for smoother animations rather than the real elapsed time
-
- lastFrameDelta = mRefreshRate * SECONDS_PER_FRAME;
- mLastUpdateRenderTime += mRefreshRate * MILLISECONDS_PER_FRAME;
- }
-
- Integration::UpdateStatus updateStatus;
- AddPerformanceMarker( PerformanceInterface::UPDATE_START );
- mCore.Update( lastFrameDelta, mLastUpdateRenderTime, mLastUpdateRenderTime + mRefreshRate * MILLISECONDS_PER_FRAME, updateStatus );
- AddPerformanceMarker( PerformanceInterface::UPDATE_END );
-
- mFpsTracker.Track( UpdateTimeSinceLastRender() );
-
- unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
-
- // Optional logging of update/render status
- mUpdateStatusLogger.Log( keepUpdatingStatus );
-
- // Ensure we did not get interrupted an STOPPED
- if( mState != State::STOPPED )
- {
- mRenderHelper.ConsumeEvents();
-
- const bool needsUpdate = Render();
-
- if( !keepUpdatingStatus && !needsUpdate )
- {
- ChangeState( State::SLEEPING );
- }
- }
-
- mUpdatingAndRendering = false;
-
- DALI_LOG_INFO( gLogFilter, Debug::General, "%s():END\n", __FUNCTION__ );
-}
-
-float SingleThreadController::UpdateTimeSinceLastRender()
-{
- float timeSinceLastRender = 0.0f;
-
- // No need calculating if FPS tracking is NOT enabled
- if( mFpsTracker.Enabled() )
- {
- uint64_t currentTime = 0;
- TimeService::GetNanoseconds( currentTime );
-
- uint64_t delta = currentTime - mSystemTime;
- mSystemTime = currentTime;
-
- timeSinceLastRender = delta * NANOSECONDS_TO_SECONDS;
- }
-
- return timeSinceLastRender;
-}
-
-
-void SingleThreadController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
-{
- if( mPerformanceInterface )
- {
- mPerformanceInterface->AddMarker( type );
- }
-}
-
-void SingleThreadController::ChangeState( State::Type state )
-{
- mState = state;
-
- switch( state )
- {
- case State::RUNNING:
- {
- mTimer.Start();
- break;
- }
-
- case State::STOPPED:
- case State::PAUSED:
- case State::SLEEPING:
- {
- mTimer.Stop();
- }
- }
-}
-
-void SingleThreadController::StopRendering()
-{
- mRenderHelper.Stop();
-
- // Inform core of context destruction & shutdown EGL
- mCore.ContextDestroyed();
- mRenderHelper.ShutdownEgl();
-}
-
-bool SingleThreadController::Render()
-{
- mRenderHelper.PreRender();
-
- Integration::RenderStatus renderStatus;
- AddPerformanceMarker( PerformanceInterface::RENDER_START );
- mCore.Render( renderStatus );
- AddPerformanceMarker( PerformanceInterface::RENDER_END );
-
- if( renderStatus.NeedsPostRender() )
- {
- mRenderHelper.PostRender();
- }
-
- return renderStatus.NeedsUpdate();
-}
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
+++ /dev/null
-#ifndef __DALI_INTERNAL_SINGLE_THREAD_CONTROLLER_H__
-#define __DALI_INTERNAL_SINGLE_THREAD_CONTROLLER_H__
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <stdint.h>
-#include <dali/public-api/signals/connection-tracker.h>
-#include <dali/integration-api/core.h>
-
-// INTERNAL INCLUDES
-#include <timer.h>
-#include <base/interfaces/performance-interface.h>
-#include <base/fps-tracker.h>
-#include <base/render-helper.h>
-#include <base/thread-controller-interface.h>
-#include <base/update-status-logger.h>
-
-namespace Dali
-{
-
-class RenderSurface;
-
-namespace Internal
-{
-
-namespace Adaptor
-{
-
-class AdaptorInternalServices;
-class EnvironmentOptions;
-
-/**
- * Single Thread Controller, where events, updates & renders ALL occur on the same thread.
- */
-class SingleThreadController : public ConnectionTracker,
- public ThreadControllerInterface
-{
-public:
-
- /**
- * Constructor
- */
- SingleThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions );
-
- /**
- * Non virtual destructor. Not intended as base class.
- */
- ~SingleThreadController();
-
- /**
- * @copydoc ThreadControllerInterface::Initialize()
- */
- void Initialize();
-
- /**
- * @copydoc ThreadControllerInterface::Start()
- */
- void Start();
-
- /**
- * @copydoc ThreadControllerInterface::Pause()
- */
- void Pause();
-
- /**
- * @copydoc ThreadControllerInterface::Resume()
- */
- void Resume();
-
- /**
- * @copydoc ThreadControllerInterface::Stop()
- */
- void Stop();
-
- /**
- * @copydoc ThreadControllerInterface::RequestUpdate()
- */
- void RequestUpdate();
-
- /**
- * @copydoc ThreadControllerInterface::RequestUpdateOnce()
- */
- void RequestUpdateOnce();
-
- /**
- * @copydoc ThreadControllerInterface::ReplaceSurface()
- */
- void ReplaceSurface( RenderSurface* surface );
-
- /**
- * @copydoc ThreadControllerInterface::SetRenderRefreshRate()
- */
- void SetRenderRefreshRate( unsigned int refreshRate );
-
-private:
-
- /**
- * State Machine
- */
- struct State
- {
- enum Type
- {
- STOPPED,
- RUNNING,
- PAUSED,
- SLEEPING
- };
- };
-
- // Undefined copy constructor.
- SingleThreadController( const SingleThreadController& );
-
- // Undefined assignment operator.
- SingleThreadController& operator=( const SingleThreadController& );
-
- /**
- * Ticks whenever the timer expires
- */
- bool OnTimerTick();
-
- /**
- * Runs the update and render
- *
- * @param[in] incrementTime If true, then the animation times are incremented.
- */
- void UpdateRender( bool incrementTime );
-
- /**
- * Updates mCurrentTime and gets the time elapsed (in seconds) since last time this function was called.
- *
- * @return time elapsed (in seconds) since last call.
- */
- float UpdateTimeSinceLastRender();
-
- /**
- * Helper to add a performance marker to the performance server (if it's active)
- * @param type performance marker type
- */
- void AddPerformanceMarker( PerformanceInterface::MarkerType type );
-
- /**
- * Changes the state and performs any other state-change related functionality.
- * @param[in] state The new state
- */
- void ChangeState( State::Type state );
-
- /**
- * Performs operations to stop rendering, e.g. informing Core of context being destroyed & shutting down EGL.
- */
- void StopRendering();
-
- /**
- * Runs render (along with pre & post steps as required).
- * @return True if an update is required.
- */
- bool Render();
-
-private:
-
- Dali::Timer mTimer; ///< Ensures an update & render is run every frame.
- FpsTracker mFpsTracker; ///< Object that tracks the FPS
- UpdateStatusLogger mUpdateStatusLogger; ///< Object that logs the update-status as required.
-
- RenderHelper mRenderHelper; ///< Helper class for EGL, pre & post rendering
-
- Integration::Core& mCore; ///< DALi core reference
- PerformanceInterface* mPerformanceInterface; ///< The performance logging interface
-
- uint64_t mLastUpdateRenderTime; ///< Last time we did an update and render
- uint64_t mSystemTime; ///< The current system time for FPS calculations
- unsigned int mRefreshRate; ///< Frame skipping count
- State::Type mState; ///< The state
- bool mUpdatingAndRendering:1; ///< Set to true when we are updating and rendering.
- bool mStopRequestedWhileRendering:1; ///< Set to true if we were told to stop while we were in the middle of a render
-};
-
-} // namespace Adaptor
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_SINGLE_THREAD_CONTROLLER_H__
#include <base/environment-options.h>
#include <base/thread-controller-interface.h>
#include <base/combined-update-render/combined-update-render-controller.h>
-#include <base/separate-update-render/separate-update-render-controller.h>
-#include <base/single-threaded/single-thread-controller.h>
namespace Dali
{
{
switch( environmentOptions.GetThreadingMode() )
{
- case ThreadingMode::SEPARATE_UPDATE_RENDER:
- {
- mThreadControllerInterface = new SeparateUpdateRenderController( adaptorInterfaces, environmentOptions );
- break;
- }
-
case ThreadingMode::COMBINED_UPDATE_RENDER:
{
mThreadControllerInterface = new CombinedUpdateRenderController( adaptorInterfaces, environmentOptions );
break;
}
-
- case ThreadingMode::SINGLE_THREADED:
- {
- mThreadControllerInterface = new SingleThreadController( adaptorInterfaces, environmentOptions );
- break;
- }
}
}
{
enum Type
{
- SEPARATE_UPDATE_RENDER = 0, ///< Event, V-Sync, Update & Render on Separate threads.
- COMBINED_UPDATE_RENDER, ///< Three threads: Event, V-Sync & a Joint Update/Render thread.
- SINGLE_THREADED, ///< ALL functionality on the SAME thread.
+ COMBINED_UPDATE_RENDER = 1, ///< Three threads: Event, V-Sync & a Joint Update/Render thread.
};
};
namespace Adaptor
{
+ApplicationPtr Application::gPreInitializedApplication( NULL );
+
ApplicationPtr Application::New(
int* argc,
char **argv[],
return application;
}
+void Application::PreInitialize( int* argc, char** argv[] )
+{
+ if( !gPreInitializedApplication )
+ {
+ gPreInitializedApplication = new Application ( argc, argv, "", Dali::Application::OPAQUE, PositionSize(), Framework::NORMAL );
+
+ gPreInitializedApplication->CreateWindow(); // Only create window
+ }
+}
+
Application::Application( int* argc, char** argv[], const std::string& stylesheet,
Dali::Application::WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType )
: mInitSignal(),
mStylesheet( stylesheet ),
mEnvironmentOptions(),
mWindowPositionSize( positionSize ),
+ mLaunchpadState( Launchpad::NONE ),
mSlotDelegate( this )
{
// Get mName from environment options
void Application::DoInit()
{
- CreateWindow();
+ // If an application was pre-initialized, a window was made in advance
+ if( mLaunchpadState == Launchpad::NONE )
+ {
+ CreateWindow();
+ }
+
CreateAdaptor();
// Run the adaptor
return Internal::Adaptor::Framework::GetResourcePath();
}
+void Application::SetStyleSheet( const std::string& stylesheet )
+{
+ mStylesheet = stylesheet;
+}
+
+
+ApplicationPtr Application::GetPreInitializedApplication()
+{
+ return gPreInitializedApplication;
+}
+
} // namespace Adaptor
} // namespace Internal
namespace Adaptor
{
+
+namespace Launchpad
+{
+
+/**
+ * @brief Launchpad is used to improve application launch performance.
+ * When an application is pre-initialized, so files are preloaded, some functions are initialized and a window is made in advance.
+ */
+enum State
+{
+ NONE, ///< The default state
+ PRE_INITIALIZED ///< Application is pre-initialized.
+};
+
+} // namespace Launchpad
+
class CommandLineOptions;
class EventLoop;
class Application : public BaseObject, public Framework::Observer
{
public:
+
typedef Dali::Application::AppSignalType AppSignalType;
typedef Dali::Application::AppControlSignalType AppControlSignalType;
typedef Dali::Application::WINDOW_MODE WINDOW_MODE;
static ApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet,
WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType );
+ /**
+ * @copydoc Dali::DevelApplication::PreInitialize()
+ */
+ static void PreInitialize( int* argc, char** argv[] );
+
public:
/**
*/
static std::string GetResourcePath();
+ /**
+ * Retrieves the pre-initialized application.
+ *
+ * @return A pointer to the pre-initialized application
+ */
+ static ApplicationPtr GetPreInitializedApplication();
+
public: // Stereoscopy
/**
*/
void OnResize(Dali::Adaptor& adaptor);
+ /**
+ * Sets a user defined theme file.
+ * This should be called before initialization.
+ * @param[in] stylesheet The path to user defined theme file
+ */
+ void SetStyleSheet( const std::string& stylesheet );
+
public: // Signals
/**
std::string mStylesheet;
EnvironmentOptions mEnvironmentOptions;
PositionSize mWindowPositionSize;
+ Launchpad::State mLaunchpadState;
bool mUseRemoteSurface;
SlotDelegate< Application > mSlotDelegate;
+
+ static ApplicationPtr gPreInitializedApplication;
};
inline Application& GetImplementation(Dali::Application& application)
Dali::DevelWindow::WindowPosition GetPosition();
/**
+ * @copydoc Dali::DevelWindow::SetTransparency()
+ */
+ void SetTransparency( bool transparent );
+
+ /**
* Called from Orientation after the Change signal has been sent
*/
void RotationDone( int orientation, int width, int height );
// INTERNAL INCLUDES
#include <adaptors/devel-api/adaptor-framework/application-devel.h>
+#include <adaptors/devel-api/adaptor-framework/window-devel.h>
#include <adaptors/common/application-impl.h>
namespace Dali
Application New( int* argc, char **argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize )
{
- Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL );
- return Application( internal.Get() );
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::GetPreInitializedApplication();
+ if( internal )
+ {
+ if( argc && ( *argc > 0 ) )
+ {
+ internal->GetWindow().SetClass( (*argv)[0], "" );
+ }
+ internal->SetStyleSheet( stylesheet );
+
+ DevelWindow::SetTransparency( internal->GetWindow(), ( windowMode == Application::OPAQUE ? false : true ) );
+ DevelWindow::SetSize( internal->GetWindow(), DevelWindow::WindowSize( positionSize.width, positionSize.height ) );
+ DevelWindow::SetPosition( internal->GetWindow(), DevelWindow::WindowPosition( positionSize.x, positionSize.y ) );
+
+ return Application( internal.Get() );
+ }
+ else
+ {
+ internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL );
+ return Application( internal.Get() );
+ }
+}
+
+void PreInitialize( int* argc, char** argv[] )
+{
+ Internal::Adaptor::Application::PreInitialize( argc, argv );
}
} // namespace DevelApplication
*/
DALI_IMPORT_API Application New( int* argc, char **argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize );
+/**
+ * @brief This is used to improve application launch performance.
+ * It preloads so files, initializes some functions in advance and makes a window in advance.
+ *
+ * @param[in,out] argc A pointer to the number of arguments
+ * @param[in,out] argv A pointer to the argument list
+ */
+DALI_IMPORT_API void PreInitialize( int* argc, char** argv[] );
+
} // namespace DevelApplication
} // namespace Dali
return GetImplementation( window ).GetPosition();
}
+void SetTransparency( Window window, bool transparent )
+{
+ GetImplementation( window ).SetTransparency( transparent );
+}
+
} // namespace DevelWindow
} // namespace Dali
*/
DALI_IMPORT_API WindowPosition GetPosition( Window window );
+/**
+ * @brief Sets whether the window is transparent or not.
+ *
+ * @param[in] window The window to set transparency
+ * @param[in] transparent Whether the window is transparent
+ */
+DALI_IMPORT_API void SetTransparency( Window window, bool transparent );
+
} // namespace DevelWindow
} // namespace Dali
return Dali::DevelWindow::WindowPosition( positionSize.x, positionSize.y );
}
+void Window::SetTransparency( bool transparent )
+{
+ ECore::WindowRenderSurface* wlSurface( dynamic_cast< ECore::WindowRenderSurface * >( mSurface ) );
+ wlSurface->SetTransparency( transparent );
+}
+
} // Adaptor
} // Internal
}
}
+void WindowRenderSurface::SetTransparency( bool transparent )
+{
+ ecore_wl_window_alpha_set( mWlWindow, transparent );
+}
+
void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
{
DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
*/
void RequestRotation( Dali::Window::WindowOrientation orientation, int width, int height );
+ /**
+ * @brief Sets whether the surface is transparent or not.
+ *
+ * @param[in] transparent Whether the surface is transparent
+ */
+ void SetTransparency( bool transparent );
+
public: // from Dali::RenderSurface
/**
Application Application::New( int* argc, char **argv[] )
{
- Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, "", OPAQUE, PositionSize(),
- Internal::Adaptor::Framework::NORMAL);
- return Application(internal.Get());
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::GetPreInitializedApplication();
+ if( internal )
+ {
+ if( argc && ( *argc > 0 ) )
+ {
+ internal->GetWindow().SetClass( (*argv)[0], "" );
+ }
+
+ return Application( internal.Get() );
+ }
+ else
+ {
+ internal = Internal::Adaptor::Application::New( argc, argv, "", OPAQUE, PositionSize(),
+ Internal::Adaptor::Framework::NORMAL);
+ return Application(internal.Get());
+ }
}
Application Application::New( int* argc, char **argv[], const std::string& stylesheet )
{
- Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, OPAQUE, PositionSize(),
- Internal::Adaptor::Framework::NORMAL);
- return Application(internal.Get());
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::GetPreInitializedApplication();
+ if( internal )
+ {
+ if( argc && ( *argc > 0 ) )
+ {
+ internal->GetWindow().SetClass( (*argv)[0], "" );
+ }
+ internal->SetStyleSheet( stylesheet );
+
+ return Application( internal.Get() );
+ }
+ else
+ {
+ internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, OPAQUE, PositionSize(),
+ Internal::Adaptor::Framework::NORMAL);
+ return Application(internal.Get());
+ }
}
Application Application::New( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode )
{
- Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode, PositionSize(),
- Internal::Adaptor::Framework::NORMAL);
- return Application(internal.Get());
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::GetPreInitializedApplication();
+ if( internal )
+ {
+ if( argc && ( *argc > 0 ) )
+ {
+ internal->GetWindow().SetClass( (*argv)[0], "" );
+ }
+ internal->SetStyleSheet( stylesheet );
+
+ DevelWindow::SetTransparency( internal->GetWindow(), ( windowMode == Application::OPAQUE ? false : true ) );
+
+ return Application( internal.Get() );
+ }
+ else
+ {
+ internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode, PositionSize(),
+ Internal::Adaptor::Framework::NORMAL);
+ return Application(internal.Get());
+ }
}
Application::~Application()
const unsigned int ADAPTOR_MAJOR_VERSION = 1;
const unsigned int ADAPTOR_MINOR_VERSION = 2;
-const unsigned int ADAPTOR_MICRO_VERSION = 48;
+const unsigned int ADAPTOR_MICRO_VERSION = 49;
const char * const ADAPTOR_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
#include <unistd.h>
// INTERNAL INCLUDES
-#include <base/separate-update-render/thread-synchronization.h>
#include <gl/egl-implementation.h>
#include <trigger-event.h>
#include <base/interfaces/window-event-interface.h>
return Dali::DevelWindow::WindowPosition( positionSize.x, positionSize.y );
}
+void Window::SetTransparency( bool transparent )
+{
+}
+
} // Adaptor
} // Internal
} // Dali
return Dali::DevelWindow::WindowPosition( positionSize.x, positionSize.y );
}
+void Window::SetTransparency( bool transparent )
+{
+}
+
} // Adaptor
} // Internal
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
mLastBlendFuncSrcAlpha = 0;
mLastBlendFuncDstAlpha = 0;
mLastAutoTextureIdUsed = 0;
+ mNumGeneratedTextures = 0;
mLastShaderIdUsed = 0;
mLastProgramIdUsed = 0;
mLastUniformIdUsed = 0;
{
std::stringstream out;
out << GL_BLEND;
- bool blendEnabled = callStack.FindMethodAndParams("Enable", out.str());
+ bool blendEnabled = callStack.FindMethodAndParams( "Enable", out.str() );
return blendEnabled;
}
{
std::stringstream out;
out << GL_BLEND;
- bool blendEnabled = callStack.FindMethodAndParams("Disable", out.str());
+ bool blendEnabled = callStack.FindMethodAndParams( "Disable", out.str() );
return blendEnabled;
}
#define TEST_GL_ABSTRACTION_H
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
paramName<<"texture["<<i<<"]";
namedParams[paramName.str()] = ToString(textures[i]);
mDeletedTextureIds.push_back(textures[i]);
+ mNumGeneratedTextures--;
}
out << "]";
{
*(textures+i) = ++mLastAutoTextureIdUsed;
}
+ mNumGeneratedTextures++;
}
TraceCallStack::NamedParams namedParams;
mTextureTrace.PushCall("GenTextures", out.str(), namedParams);
}
+ inline GLuint GetLastGenTextureId()
+ {
+ return mLastAutoTextureIdUsed;
+ }
+ inline GLuint GetNumGeneratedTextures()
+ {
+ return mNumGeneratedTextures;
+ }
+
inline void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
{
}
// Data for manipulating the IDs returned by GenTextures
GLuint mLastAutoTextureIdUsed;
+ GLuint mNumGeneratedTextures;
std::vector<GLuint> mNextTextureIds;
std::vector<GLuint> mDeletedTextureIds;
std::vector<GLuint> mBoundTextures;
DALI_TEST_EQUALS( buffer[3], 0x00u, TEST_LOCATION );
DALI_TEST_EQUALS( buffer[7], 0x00u, TEST_LOCATION );
- // Test that an odd pixel in the second quadrant has full alpha value
- DALI_TEST_EQUALS( buffer[23], 0xffu, TEST_LOCATION );
+ // Test that an odd pixel in the fourth quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[(6*10+7)*4+3], 0xffu, TEST_LOCATION );
- // Test that an even pixel in the second quadrant has full alpha value
- DALI_TEST_EQUALS( buffer[27], 0xffu, TEST_LOCATION );
+ // Test that an even pixel in the fourth quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[(6*10+8)*4+3], 0xffu, TEST_LOCATION );
END_TEST;
}
unsigned int width = 20u;
unsigned int height = 20u;
- Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::L8 );
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ Mask1stQuadrant(maskData);
+
+ width = 10u;
+ height = 10u;
+ Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+ FillCheckerboard(imageData);
+
+ imageData.ApplyMask( maskData );
+
+ // Test that the pixel format has been promoted to RGBA8888
+ DALI_TEST_EQUALS( imageData.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
+
+ // Test that a pixel in the first quadrant has no alpha value
+ unsigned char* buffer = imageData.GetBuffer();
+ DALI_TEST_EQUALS( buffer[3], 0x00u, TEST_LOCATION );
+ DALI_TEST_EQUALS( buffer[7], 0x00u, TEST_LOCATION );
+
+ // Test that an odd pixel in the second quadrant has full alpha value
+ DALI_TEST_EQUALS( buffer[39], 0xffu, TEST_LOCATION );
+
+ // Test that an even pixel in the second quadrant has no alpha value
+ DALI_TEST_EQUALS( buffer[27], 0x00u, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliPixelBufferMask06(void)
+{
+ TestApplication application;
+ tet_infoline("Test application of alpha mask to same size RGBA8888 image");
+
+ unsigned int width = 10u;
+ unsigned int height = 10u;
+ Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
Mask1stQuadrant(maskData);
width = 10u;
DALI_TEST_EQUALS( buffer[7], 0x00u, TEST_LOCATION );
// Test that an odd pixel in the second quadrant has full alpha value
- DALI_TEST_EQUALS( buffer[23], 0xffu, TEST_LOCATION );
+ DALI_TEST_EQUALS( buffer[39], 0xffu, TEST_LOCATION );
// Test that an even pixel in the second quadrant has no alpha value
DALI_TEST_EQUALS( buffer[27], 0x00u, TEST_LOCATION );
Name: dali-adaptor
Summary: The DALi Tizen Adaptor
-Version: 1.2.48
+Version: 1.2.49
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT
#include "pixel-manipulation.h"
#include "alpha-mask.h"
#include "pixel-buffer-impl.h"
+#include <dali/public-api/images/image-operations.h> // For ImageDimensions
+#include <platform-abstractions/portable/image-operations.h>
namespace Dali
{
namespace Adaptor
{
-
-void ApplyMaskToAlphaChannel( PixelBuffer& buffer, const PixelBuffer& mask )
+PixelBufferPtr ResizeMask( const PixelBuffer& inMask, ImageDimensions outDimensions )
{
- const float rowFactor = float(mask.GetHeight()) / (1.0f * buffer.GetHeight());
- const float colFactor = float(mask.GetWidth()) / (1.0f * buffer.GetWidth()) ;
+ PixelBufferPtr mask;
+
+ if( inMask.GetWidth() != outDimensions.GetWidth() || inMask.GetHeight() != outDimensions.GetHeight() )
+ {
+ mask = PixelBuffer::New( outDimensions.GetWidth(), outDimensions.GetHeight(), inMask.GetPixelFormat() );
+ ImageDimensions inDimensions( inMask.GetWidth(), inMask.GetHeight() );
- int numSamples = 1;
- if( mask.GetHeight() > buffer.GetHeight() || mask.GetWidth() > buffer.GetWidth() )
+ if( Pixel::GetBytesPerPixel( inMask.GetPixelFormat() ) == 4 )
+ {
+ Dali::Internal::Platform::LanczosSample4BPP( inMask.GetBuffer(), inDimensions,
+ mask->GetBuffer(), outDimensions );
+ }
+ else if( inMask.GetPixelFormat() == Pixel::L8 )
+ {
+ Dali::Internal::Platform::LanczosSample1BPP( inMask.GetBuffer(), inDimensions,
+ mask->GetBuffer(), outDimensions );
+ }
+ }
+ else
{
- numSamples = 4;
+ mask = const_cast<PixelBuffer*>(&inMask);
}
+ return mask;
+}
+void ApplyMaskToAlphaChannel( PixelBuffer& buffer, const PixelBuffer& inMask )
+{
int srcAlphaByteOffset=0;
int srcAlphaMask=0;
- Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
+ Dali::Pixel::Format srcPixelFormat = inMask.GetPixelFormat();
+
+ PixelBufferPtr mask = ResizeMask( inMask, ImageDimensions( buffer.GetWidth(), buffer.GetHeight() ) );
- Channel alphaChannel = ALPHA;
if( Pixel::HasAlpha(srcPixelFormat) )
{
Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
else if( srcPixelFormat == Pixel::L8 )
{
srcAlphaMask=0xFF;
- alphaChannel = LUMINANCE;
}
int destAlphaByteOffset=0;
Dali::Pixel::GetAlphaOffsetAndMask( buffer.GetPixelFormat(), destAlphaByteOffset, destAlphaMask );
unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
- int srcStride = mask.GetWidth() * srcBytesPerPixel;
- unsigned char* srcBuffer = mask.GetBuffer();
+ unsigned char* srcBuffer = mask->GetBuffer();
unsigned char* destBuffer = buffer.GetBuffer();
unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( buffer.GetPixelFormat() );
{
for( unsigned int col = 0; col < buffer.GetWidth(); ++col )
{
- if( numSamples == 1 )
- {
- srcOffset = floorf(row * rowFactor) * srcStride + floorf(col * colFactor) * srcBytesPerPixel;
- unsigned char alpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
- srcAlphaValue = float(alpha)/255.0f;
- }
- else
- {
- srcAlphaValue = ReadWeightedSample( srcBuffer, srcPixelFormat, srcStride, col*colFactor, row*rowFactor, mask.GetWidth(), mask.GetHeight(), alphaChannel );
- }
+ unsigned char alpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
+ srcAlphaValue = float(alpha)/255.0f;
unsigned char destAlpha = destBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
destBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
+ srcOffset += srcBytesPerPixel;
destOffset += destBytesPerPixel;
}
}
}
-PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& mask )
+PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& inMask )
{
- const float rowFactor = float(mask.GetHeight()) / (1.0f * buffer.GetHeight());
- const float colFactor = float(mask.GetWidth()) / (1.0f * buffer.GetWidth()) ;
-
- int numSamples = 1;
- if( mask.GetHeight() > buffer.GetHeight() || mask.GetWidth() > buffer.GetWidth() )
- {
- numSamples = 4;
- }
-
// Set up source alpha offsets
int srcAlphaByteOffset=0;
int srcAlphaMask=0;
- Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
- Channel alphaChannel = ALPHA;
+ Dali::Pixel::Format srcPixelFormat = inMask.GetPixelFormat();
+
+ PixelBufferPtr mask = ResizeMask( inMask, ImageDimensions( buffer.GetWidth(), buffer.GetHeight() ) );
if( Pixel::HasAlpha(srcPixelFormat) )
{
Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
else if( srcPixelFormat == Pixel::L8 )
{
srcAlphaMask=0xFF;
- alphaChannel = LUMINANCE;
}
unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
- int srcStride = mask.GetWidth() * srcBytesPerPixel;
- unsigned char* srcBuffer = mask.GetBuffer();
+ unsigned char* srcBuffer = mask->GetBuffer();
// Set up source color offsets
Dali::Pixel::Format srcColorPixelFormat = buffer.GetPixelFormat();
PixelBufferPtr newPixelBuffer = PixelBuffer::New( buffer.GetWidth(), buffer.GetHeight(),
destPixelFormat );
unsigned char* destBuffer = newPixelBuffer->GetBuffer();
-
unsigned char* oldBuffer = buffer.GetBuffer();
int srcAlphaOffset=0;
{
for( unsigned int col = 0; col < buffer.GetWidth(); ++col )
{
- if( numSamples == 1 )
- {
- srcAlphaOffset = floorf(row * rowFactor) * srcStride + floorf(col * colFactor) * srcBytesPerPixel;
- unsigned char alpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
- srcAlphaValue = float(alpha)/255.0f;
- }
- else
- {
- srcAlphaValue = ReadWeightedSample( srcBuffer, srcPixelFormat, srcStride, col*colFactor, row*rowFactor, mask.GetWidth(), mask.GetHeight(), alphaChannel );
- }
+ unsigned char alpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
+ srcAlphaValue = float(alpha)/255.0f;
ConvertColorChannelsToRGBA8888(oldBuffer, srcColorOffset, srcColorPixelFormat, destBuffer, destOffset );
destBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
srcColorOffset += srcColorBytesPerPixel;
+ srcAlphaOffset += srcBytesPerPixel;
destOffset += destBytesPerPixel;
}
}
return newPixelBuffer;
}
-
-float ReadWeightedSample( unsigned char* buffer, Pixel::Format pixelFormat, int stride, float x, float y, int width, int height, Channel alphaChannel )
-{
- int srcRow = floorf( y );
- int srcCol = floorf( x );
-
- int bytesPerPixel = Dali::Pixel::GetBytesPerPixel( pixelFormat );
- int srcOffset = srcRow * stride + srcCol * bytesPerPixel;
- float samples[4];
-
- samples[0] = ReadChannel( buffer + srcOffset, pixelFormat, alphaChannel );
-
- if( srcCol < width-1 )
- {
- samples[1] = ReadChannel( buffer + srcOffset+bytesPerPixel, pixelFormat, alphaChannel );
- }
- else
- {
- samples[1] = samples[0];
- }
-
- if( srcRow < height-1 )
- {
- samples[2] = ReadChannel( buffer + stride + srcOffset, pixelFormat, alphaChannel );
- }
- else
- {
- samples[2] = samples[0];
- }
-
- if( srcRow < height-1 && srcCol < width-1 )
- {
- samples[3] = ReadChannel( buffer + stride + srcOffset + bytesPerPixel, pixelFormat, alphaChannel );
- }
- else
- {
- samples[3] = samples[2];
- }
-
- // Bilinear interpolation:
- float weight[4];
- weight[0] = float(srcRow+1.0f) - y;
- weight[1] = y - float(srcRow);
- weight[2] = float(srcCol+1.0f) - x;
- weight[3] = x - float(srcCol);
-
- return ( weight[2] * (samples[0] * weight[0] + samples[1] * weight[1]) +
- weight[3] * (samples[2] * weight[0] + samples[3] * weight[1]) ) / 255.0f;
-}
-
} //namespace Adaptor
}// namespace Internal
LinearSampleGeneric<Pixel4Bytes, BilinearFilter4Bytes, true>( inPixels, inputDimensions, outPixels, desiredDimensions );
}
-void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
- ImageDimensions inputDimensions,
- unsigned char * __restrict__ outPixels,
- ImageDimensions desiredDimensions )
+void LanczosSample( const unsigned char * __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned char * __restrict__ outPixels,
+ ImageDimensions desiredDimensions,
+ int numChannels, bool hasAlpha )
{
// Got from the test.cpp of the ImageResampler lib.
const float ONE_DIV_255 = 1.0f / 255.0f;
const int MAX_UNSIGNED_CHAR = std::numeric_limits<uint8_t>::max();
const int LINEAR_TO_SRGB_TABLE_SIZE = 4096;
- const int ALPHA_CHANNEL = 3;
- const int NUMBER_OF_CHANNELS = 4;
-
- float srgbToLinear[MAX_UNSIGNED_CHAR + 1];
- for( int i = 0; i <= MAX_UNSIGNED_CHAR; ++i )
- {
- srgbToLinear[i] = pow( static_cast<float>( i ) * ONE_DIV_255, DEFAULT_SOURCE_GAMMA );
- }
+ const int ALPHA_CHANNEL = hasAlpha ? (numChannels-1) : 0;
- unsigned char linearToSrgb[LINEAR_TO_SRGB_TABLE_SIZE];
+ static bool loadColorSpaces = true;
+ static float srgbToLinear[MAX_UNSIGNED_CHAR + 1];
+ static unsigned char linearToSrgb[LINEAR_TO_SRGB_TABLE_SIZE];
- const float invLinearToSrgbTableSize = 1.0f / static_cast<float>( LINEAR_TO_SRGB_TABLE_SIZE );
- const float invSourceGamma = 1.0f / DEFAULT_SOURCE_GAMMA;
-
- for( int i = 0; i < LINEAR_TO_SRGB_TABLE_SIZE; ++i )
+ if( loadColorSpaces ) // Only create the color space conversions on the first execution
{
- int k = static_cast<int>( 255.0f * pow( static_cast<float>( i ) * invLinearToSrgbTableSize, invSourceGamma ) + 0.5f );
- if( k < 0 )
+ loadColorSpaces = false;
+
+ for( int i = 0; i <= MAX_UNSIGNED_CHAR; ++i )
{
- k = 0;
+ srgbToLinear[i] = pow( static_cast<float>( i ) * ONE_DIV_255, DEFAULT_SOURCE_GAMMA );
}
- else if( k > MAX_UNSIGNED_CHAR )
+
+ const float invLinearToSrgbTableSize = 1.0f / static_cast<float>( LINEAR_TO_SRGB_TABLE_SIZE );
+ const float invSourceGamma = 1.0f / DEFAULT_SOURCE_GAMMA;
+
+ for( int i = 0; i < LINEAR_TO_SRGB_TABLE_SIZE; ++i )
{
- k = MAX_UNSIGNED_CHAR;
+ int k = static_cast<int>( 255.0f * pow( static_cast<float>( i ) * invLinearToSrgbTableSize, invSourceGamma ) + 0.5f );
+ if( k < 0 )
+ {
+ k = 0;
+ }
+ else if( k > MAX_UNSIGNED_CHAR )
+ {
+ k = MAX_UNSIGNED_CHAR;
+ }
+ linearToSrgb[i] = static_cast<unsigned char>( k );
}
- linearToSrgb[i] = static_cast<unsigned char>( k );
}
- Resampler* resamplers[NUMBER_OF_CHANNELS] = { 0 };
- Vector<float> samples[NUMBER_OF_CHANNELS];
+ Resampler* resamplers[numChannels];
+ Vector<float> samples[numChannels];
const int srcWidth = inputDimensions.GetWidth();
const int srcHeight = inputDimensions.GetHeight();
FILTER_SCALE, // src_x_ofs,
FILTER_SCALE ); // src_y_ofs. Offset input image by specified amount (fractional values okay).
samples[0].Resize( srcWidth );
- for( int i = 1; i < NUMBER_OF_CHANNELS; ++i )
+ for( int i = 1; i < numChannels; ++i )
{
resamplers[i] = new Resampler( srcWidth,
srcHeight,
samples[i].Resize( srcWidth );
}
- const int srcPitch = srcWidth * NUMBER_OF_CHANNELS;
- const int dstPitch = dstWidth * NUMBER_OF_CHANNELS;
+ const int srcPitch = srcWidth * numChannels;
+ const int dstPitch = dstWidth * numChannels;
int dstY = 0;
for( int srcY = 0; srcY < srcHeight; ++srcY )
for( int x = 0; x < srcWidth; ++x )
{
- for( int c = 0; c < NUMBER_OF_CHANNELS; ++c )
+ for( int c = 0; c < numChannels; ++c )
{
- if( c == ALPHA_CHANNEL )
+ if( c == ALPHA_CHANNEL && hasAlpha )
{
samples[c][x] = *pSrc++ * ONE_DIV_255;
}
}
}
- for( int c = 0; c < NUMBER_OF_CHANNELS; ++c )
+ for( int c = 0; c < numChannels; ++c )
{
if( !resamplers[c]->put_line( &samples[c][0] ) )
{
for(;;)
{
int compIndex;
- for( compIndex = 0; compIndex < NUMBER_OF_CHANNELS; ++compIndex )
+ for( compIndex = 0; compIndex < numChannels; ++compIndex )
{
const float* pOutputSamples = resamplers[compIndex]->get_line();
if( !pOutputSamples )
break;
}
- const bool isAlphaChannel = ( compIndex == ALPHA_CHANNEL );
+ const bool isAlphaChannel = ( compIndex == ALPHA_CHANNEL && hasAlpha );
DALI_ASSERT_DEBUG( dstY < dstHeight );
unsigned char* pDst = &outPixels[dstY * dstPitch + compIndex];
*pDst = linearToSrgb[j];
}
- pDst += NUMBER_OF_CHANNELS;
+ pDst += numChannels;
}
}
- if( compIndex < NUMBER_OF_CHANNELS )
+ if( compIndex < numChannels )
{
break;
}
}
// Delete the resamplers.
- for( int i = 0; i < NUMBER_OF_CHANNELS; ++i )
+ for( int i = 0; i < numChannels; ++i )
{
delete resamplers[i];
}
}
+void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned char * __restrict__ outPixels,
+ ImageDimensions desiredDimensions )
+{
+ LanczosSample( inPixels, inputDimensions, outPixels, desiredDimensions, 4, true );
+}
+
+void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned char * __restrict__ outPixels,
+ ImageDimensions desiredDimensions )
+{
+ // For L8 images
+ LanczosSample( inPixels, inputDimensions, outPixels, desiredDimensions, 1, false );
+}
+
// Dispatch to a format-appropriate linear sampling function:
void LinearSample( const unsigned char * __restrict__ inPixels,
ImageDimensions inDimensions,
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
* @brief Resamples the input image with the Lanczos algorithm.
*
* @pre @p inPixels must not alias @p outPixels. The input image should be a totally
- * separate buffer from the input one.
+ * separate buffer from the output buffer.
*
* @param[in] inPixels Pointer to the input image buffer.
* @param[in] inputDimensions The input dimensions of the image.
ImageDimensions inputDimensions,
unsigned char * __restrict__ outPixels,
ImageDimensions desiredDimensions );
+
+/**
+ * @brief Resamples the input image with the Lanczos algorithm.
+ *
+ * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @param[in] inPixels Pointer to the input image buffer.
+ * @param[in] inputDimensions The input dimensions of the image.
+ * @param[out] outPixels Pointer to the output image buffer.
+ * @param[in] desiredDimensions The output dimensions of the image.
+ */
+void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
+ ImageDimensions inputDimensions,
+ unsigned char * __restrict__ outPixels,
+ ImageDimensions desiredDimensions );
+
/**@}*/
/**