#include <dali/integration-api/platform-abstraction.h>
// INTERNAL INCLUDES
-#include <dali/integration-api/trigger-event-factory.h>
-#include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
-#include <dali/internal/system/common/environment-options.h>
-#include <dali/internal/system/common/time-service.h>
-#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
#include <dali/internal/graphics/gles/egl-graphics.h>
#include <dali/internal/graphics/gles/egl-implementation.h>
#include <dali/internal/graphics/common/graphics-interface.h>
+#include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/system/common/time-service.h>
namespace Dali
{
mPendingRequestUpdate( FALSE ),
mUseElapsedTimeAfterWait( FALSE ),
mNewSurface( NULL ),
+ mDeletedSurface( nullptr ),
mPostRendering( FALSE ),
mSurfaceResized( FALSE ),
- mForceClear( FALSE )
+ mForceClear( FALSE ),
+ mUploadWithoutRendering( FALSE ),
+ mFirstFrameAfterResume( FALSE )
{
LOG_EVENT_TRACE;
LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
- RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
+ RunUpdateRenderThread( CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL );
DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Start\n" );
}
{
LOG_EVENT( "Resuming" );
- RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
+ RunUpdateRenderThread( CONTINUOUS, AnimationProgression::USE_ELAPSED_TIME, UpdateMode::NORMAL );
AddPerformanceMarker( PerformanceInterface::RESUME );
mRunning = TRUE;
mForceClear = TRUE;
- }
+ mFirstFrameAfterResume = TRUE;
- DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume\n" );
+ DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume\n" );
+ }
+ else
+ {
+ DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep );
+ }
}
void CombinedUpdateRenderController::Stop()
{
LOG_EVENT( "Processing" );
- RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
+ RunUpdateRenderThread( CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL );
}
ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
mPendingRequestUpdate = TRUE;
}
-void CombinedUpdateRenderController::RequestUpdateOnce()
+void CombinedUpdateRenderController::RequestUpdateOnce( UpdateMode updateMode )
{
// Increment the update-request count to the maximum
if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
LOG_EVENT_TRACE;
// Run Update/Render once
- RunUpdateRenderThread( ONCE, false /* No animation progression */ );
+ RunUpdateRenderThread( ONCE, AnimationProgression::NONE, updateMode );
}
}
{
LOG_EVENT_TRACE;
- // Set the ThreadSyncronizationInterface on the new surface
- newSurface->SetThreadSynchronization( *this );
+ if( mUpdateRenderThread )
+ {
+ // Set the ThreadSyncronizationInterface on the new surface
+ newSurface->SetThreadSynchronization( *this );
- LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
+ LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
- // Start replacing the surface.
- {
- ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
- mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
- mNewSurface = newSurface;
- mUpdateRenderThreadWaitCondition.Notify( lock );
+ // Start replacing the surface.
+ {
+ ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+ mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
+ mNewSurface = newSurface;
+ mUpdateRenderThreadWaitCondition.Notify( lock );
+ }
+
+ // Wait until the surface has been replaced
+ sem_wait( &mEventThreadSemaphore );
+
+ LOG_EVENT( "Surface replaced, event-thread continuing" );
}
+}
+
+void CombinedUpdateRenderController::DeleteSurface( Dali::RenderSurfaceInterface* surface )
+{
+ LOG_EVENT_TRACE;
+
+ if( mUpdateRenderThread )
+ {
+ LOG_EVENT( "Starting to delete the surface, event-thread blocked" );
- // Wait until the surface has been replaced
- sem_wait( &mEventThreadSemaphore );
+ // Start replacing the surface.
+ {
+ ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+ mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will delete the surface now
+ mDeletedSurface = surface;
+ mUpdateRenderThreadWaitCondition.Notify( lock );
+ }
+
+ // Wait until the surface has been deleted
+ sem_wait( &mEventThreadSemaphore );
- LOG_EVENT( "Surface replaced, event-thread continuing" );
+ LOG_EVENT( "Surface deleted, event-thread continuing" );
+ }
}
void CombinedUpdateRenderController::ResizeSurface()
// EVENT THREAD
///////////////////////////////////////////////////////////////////////////////////////////////////
-void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
+void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode )
{
ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
mUpdateRenderRunCount = numberOfCycles;
mUpdateRenderThreadCanSleep = FALSE;
- mUseElapsedTimeAfterWait = useElapsedTime;
+ mUseElapsedTimeAfterWait = ( animationProgression == AnimationProgression::USE_ELAPSED_TIME );
+ mUploadWithoutRendering = ( updateMode == UpdateMode::SKIP_RENDER );
LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
mUpdateRenderThreadWaitCondition.Notify( lock );
}
EglInterface* eglInterface = &eglGraphics->GetEglInterface();
Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( *eglInterface );
+
// Try to use OpenGL es 3.0
// ChooseConfig returns false here when the device only support gles 2.0.
// Because eglChooseConfig with gles 3.0 setting fails when the device only support gles 2.0 and Our default setting is gles 3.0.
- if( eglImpl.ChooseConfig( true, COLOR_DEPTH_32 ) )
+ if( !eglImpl.ChooseConfig( true, COLOR_DEPTH_32 ) )
+ {
+ // Retry to use OpenGL es 2.0
+ eglGraphics->SetGlesVersion( 20 );
+ eglImpl.ChooseConfig( true, COLOR_DEPTH_32 );
+ }
+
+ // Check whether surfaceless context is supported
+ bool isSurfacelessContextSupported = eglImpl.IsSurfacelessContextSupported();
+ eglGraphics->SetIsSurfacelessContextSupported( isSurfacelessContextSupported );
+
+ if ( isSurfacelessContextSupported )
{
// Create a surfaceless OpenGL context for shared resources
eglImpl.CreateContext();
eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
}
- else // Retry to use OpenGL es 2.0
+ else
{
- eglGraphics->SetGlesVersion( 20 );
currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
if( currentSurface )
{
}
}
+ eglGraphics->GetGlesInterface().ContextCreated();
+
// Tell core it has a context
mCore.ContextCreated();
}
}
- if( eglImpl.GetGlesVersion() >= 30 )
+ if( eglImpl.IsSurfacelessContextSupported() )
{
// Make the shared surfaceless context as current before rendering
eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
}
+ if( mFirstFrameAfterResume )
+ {
+ // mFirstFrameAfterResume is set to true when the thread is resumed
+ // Let eglImplementation know the first frame after thread initialized or resumed.
+ eglImpl.SetFirstFrameAfterResume();
+ mFirstFrameAfterResume = FALSE;
+ }
+
Integration::RenderStatus renderStatus;
AddPerformanceMarker( PerformanceInterface::RENDER_START );
- mCore.Render( renderStatus, mForceClear );
+ mCore.Render( renderStatus, mForceClear, mUploadWithoutRendering );
+
+ //////////////////////////////
+ // DELETE SURFACE
+ //////////////////////////////
+
+ Integration::RenderSurface* deletedSurface = ShouldSurfaceBeDeleted();
+ if( DALI_UNLIKELY( deletedSurface ) )
+ {
+ LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
+
+ mCore.SurfaceDeleted( deletedSurface );
+
+ SurfaceDeleted();
+ }
+
AddPerformanceMarker( PerformanceInterface::RENDER_END );
mForceClear = false;
( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
! mNewSurface && // Ensure we don't wait if we need to replace the surface
+ ! mDeletedSurface && // Ensure we don't wait if we need to delete the surface
! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
{
LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
+ LOG_UPDATE_RENDER( " mDeletedSurface: %d", mDeletedSurface );
LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
// Reset the time when the thread is waiting, so the sleep-until time for
LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
+ LOG_COUNTER_UPDATE_RENDER( "mDeletedSurface: %d", mDeletedSurface );
LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
mUseElapsedTimeAfterWait = FALSE;
sem_post( &mEventThreadSemaphore );
}
+Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
+{
+ ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+
+ Integration::RenderSurface* deletedSurface = mDeletedSurface;
+ mDeletedSurface = NULL;
+
+ return deletedSurface;
+}
+
+void CombinedUpdateRenderController::SurfaceDeleted()
+{
+ // Just increment the semaphore
+ sem_post( &mEventThreadSemaphore );
+}
+
bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
{
ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
while( mPostRendering &&
! mNewSurface && // We should NOT wait if we're replacing the surface
+ ! mDeletedSurface && // We should NOT wait if we're deleting the surface
! mSurfaceResized && // We should NOT wait if we're resizing the surface
! mDestroyUpdateRenderThread )
{