X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fadaptor%2Fcommon%2Fcombined-update-render-controller.cpp;h=80bc0a3de178576cc9df959914d9340601d6876a;hb=aecc2d4c642e0cdf360e56accd3e5b96622a707f;hp=72aa9da0b5c846ffedd82dde016fee5fa6fe6147;hpb=3f68e6293fd8ae60250897c5cbf5aa466cafa631;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/adaptor/common/combined-update-render-controller.cpp b/dali/internal/adaptor/common/combined-update-render-controller.cpp index 72aa9da..80bc0a3 100644 --- a/dali/internal/adaptor/common/combined-update-render-controller.cpp +++ b/dali/internal/adaptor/common/combined-update-render-controller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -21,14 +21,19 @@ // EXTERNAL INCLUDES #include #include +#include // INTERNAL INCLUDES -#include +#include +#include +#include #include +#include +#include +#include #include #include -#include -#include +#include namespace Dali { @@ -87,8 +92,8 @@ const unsigned int MAXIMUM_UPDATE_REQUESTS = 2; CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions ) : mFpsTracker( environmentOptions ), mUpdateStatusLogger( environmentOptions ), - mRenderHelper( adaptorInterfaces ), mEventThreadSemaphore(), + mGraphicsInitializeSemaphore(), mUpdateRenderThreadWaitCondition(), mAdaptorInterfaces( adaptorInterfaces ), mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ), @@ -96,6 +101,7 @@ CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalS mEnvironmentOptions( environmentOptions ), mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ), mSleepTrigger( NULL ), + mPreRenderCallback( NULL ), mUpdateRenderThread( NULL ), mDefaultFrameDelta( 0.0f ), mDefaultFrameDurationMilliseconds( 0u ), @@ -111,7 +117,10 @@ CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalS mNewSurface( NULL ), mPostRendering( FALSE ), mSurfaceResized( FALSE ), - mForceClear( FALSE ) + mForceClear( FALSE ), + mUploadWithoutRendering( FALSE ), + mFirstFrameAfterResume( FALSE ), + mIsRenderingWindows( false ) { LOG_EVENT_TRACE; @@ -119,16 +128,17 @@ CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalS SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() ); // Set the thread-synchronization interface on the render-surface - RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface(); + Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface(); if( currentSurface ) { currentSurface->SetThreadSynchronization( *this ); } - TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface(); - mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ); + mSleepTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ); - sem_init( &mEventThreadSemaphore, 0, 0 ); // Initialize to 0 so that it just waits if sem_post has not been called + // Initialize to 0 so that it just waits if sem_post has not been called + sem_init( &mEventThreadSemaphore, 0, 0 ); + sem_init( &mGraphicsInitializeSemaphore, 0, 0 ); } CombinedUpdateRenderController::~CombinedUpdateRenderController() @@ -137,6 +147,7 @@ CombinedUpdateRenderController::~CombinedUpdateRenderController() Stop(); + delete mPreRenderCallback; delete mSleepTrigger; } @@ -152,7 +163,7 @@ void CombinedUpdateRenderController::Initialize() int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this ); DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" ); - // The Update/Render thread will now run and initialise EGL etc. and will then wait for Start to be called + // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called // When this function returns, the application initialisation on the event thread should occur } @@ -168,13 +179,19 @@ void CombinedUpdateRenderController::Start() sem_wait( &mEventThreadSemaphore ); } - mRenderHelper.Start(); + Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface(); + if( currentSurface ) + { + currentSurface->StartRender(); + } mRunning = TRUE; 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" ); } void CombinedUpdateRenderController::Pause() @@ -186,6 +203,8 @@ void CombinedUpdateRenderController::Pause() PauseUpdateRenderThread(); AddPerformanceMarker( PerformanceInterface::PAUSED ); + + DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Pause\n" ); } void CombinedUpdateRenderController::Resume() @@ -196,12 +215,19 @@ void CombinedUpdateRenderController::Resume() { 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" ); + } + else + { + DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep ); } } @@ -210,7 +236,11 @@ void CombinedUpdateRenderController::Stop() LOG_EVENT_TRACE; // Stop Rendering and the Update/Render Thread - mRenderHelper.Stop(); + Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface(); + if( currentSurface ) + { + currentSurface->StopRender(); + } StopUpdateRenderThread(); @@ -226,6 +256,8 @@ void CombinedUpdateRenderController::Stop() } mRunning = FALSE; + + DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Stop\n" ); } void CombinedUpdateRenderController::RequestUpdate() @@ -242,14 +274,14 @@ void CombinedUpdateRenderController::RequestUpdate() { 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 ) @@ -262,31 +294,49 @@ void CombinedUpdateRenderController::RequestUpdateOnce() LOG_EVENT_TRACE; // Run Update/Render once - RunUpdateRenderThread( ONCE, false /* No animation progression */ ); + RunUpdateRenderThread( ONCE, AnimationProgression::NONE, updateMode ); } } -void CombinedUpdateRenderController::ReplaceSurface( RenderSurface* newSurface ) +void CombinedUpdateRenderController::ReplaceSurface( Dali::RenderSurfaceInterface* newSurface ) { 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" ); } +} - // Wait until the surface has been replaced - sem_wait( &mEventThreadSemaphore ); +void CombinedUpdateRenderController::WaitForGraphicsInitialization() +{ + LOG_EVENT_TRACE; + + if( mUpdateRenderThread ) + { + LOG_EVENT( "Waiting for graphics initialisation, event-thread blocked" ); - LOG_EVENT( "Surface replaced, event-thread continuing" ); + // Wait until the graphics has been initialised + sem_wait( &mGraphicsInitializeSemaphore ); + + LOG_EVENT( "graphics initialised, event-thread continuing" ); + } } void CombinedUpdateRenderController::ResizeSurface() @@ -314,16 +364,41 @@ void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOf LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds ); } +void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback ) +{ + LOG_EVENT_TRACE; + LOG_EVENT( "Set PreRender Callback" ); + + ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition ); + if( mPreRenderCallback ) + { + delete mPreRenderCallback; + } + mPreRenderCallback = callback; +} + +void CombinedUpdateRenderController::AddSurface( Dali::RenderSurfaceInterface* surface ) +{ + LOG_EVENT_TRACE; + LOG_EVENT( "Surface is added" ); + if( mUpdateRenderThread ) + { + // Set the ThreadSyncronizationInterface on the added surface + surface->SetThreadSynchronization( *this ); + } +} + /////////////////////////////////////////////////////////////////////////////////////////////////// // 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 ); } @@ -385,9 +460,56 @@ void CombinedUpdateRenderController::UpdateRenderThread() LOG_UPDATE_RENDER( "THREAD CREATED" ); - mRenderHelper.InitializeEgl(); + // Initialize EGL & OpenGL + Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface(); + displayConnection.Initialize(); + + // EGL has been initialised at this point + NotifyGraphicsInitialised(); - // tell core it has a context + RenderSurfaceInterface* currentSurface = nullptr; + + GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface(); + EglGraphics* eglGraphics = static_cast(&graphics); + + // This will only be created once + EglInterface* eglInterface = &eglGraphics->GetEglInterface(); + + Internal::Adaptor::EglImplementation& eglImpl = static_cast( *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 ) ) + { + // 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 + { + currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface(); + if( currentSurface ) + { + currentSurface->InitializeGraphics(); + currentSurface->MakeContextCurrent(); + } + } + + eglGraphics->GetGlesInterface().ContextCreated(); + + // Tell core it has a context mCore.ContextCreated(); NotifyThreadInitialised(); @@ -432,11 +554,21 @@ void CombinedUpdateRenderController::UpdateRenderThread() // REPLACE SURFACE ////////////////////////////// - RenderSurface* newSurface = ShouldSurfaceBeReplaced(); + Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced(); if( DALI_UNLIKELY( newSurface ) ) { LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" ); - mRenderHelper.ReplaceSurface( newSurface ); + // This is designed for replacing pixmap surfaces, but should work for window as well + // we need to delete the surface and renderable (pixmap / window) + // Then create a new pixmap/window and new surface + // If the new surface has a different display connection, then the context will be lost + mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize(); + newSurface->InitializeGraphics(); + newSurface->MakeContextCurrent(); + // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics() + // already creates new surface window, the surface and the context. + // We probably don't need ReplaceGraphicsSurface at all. + // newSurface->ReplaceGraphicsSurface(); SurfaceReplaced(); } @@ -482,15 +614,15 @@ void CombinedUpdateRenderController::UpdateRenderThread() } // Check resize - bool surfaceResized = ShouldSurfaceBeResized(); - if( DALI_UNLIKELY( surfaceResized ) ) + bool surfaceResized = false; + bool shouldSurfaceBeResized = ShouldSurfaceBeResized(); + if( DALI_UNLIKELY( shouldSurfaceBeResized ) ) { - // RenderHelper::ResizeSurface() should be called right after a viewport is changed. if( updateStatus.SurfaceRectChanged() ) { LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" ); - mRenderHelper.ResizeSurface(); SurfaceResized(); + surfaceResized = true; } } @@ -501,25 +633,83 @@ void CombinedUpdateRenderController::UpdateRenderThread() // RENDER ////////////////////////////// - mRenderHelper.ConsumeEvents(); - mRenderHelper.PreRender(); + mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents(); + + if( mPreRenderCallback != NULL ) + { + bool keepCallback = CallbackBase::ExecuteReturn(*mPreRenderCallback); + if( ! keepCallback ) + { + delete mPreRenderCallback; + mPreRenderCallback = NULL; + } + } + + 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 ); - AddPerformanceMarker( PerformanceInterface::RENDER_END ); - mForceClear = false; + mIsRenderingWindows = true; - if( renderStatus.NeedsPostRender() ) + // Upload shared resources + mCore.PreRender( renderStatus, mForceClear, mUploadWithoutRendering ); + + if ( !mUploadWithoutRendering ) { - mRenderHelper.PostRender( isRenderingToFbo ); + // Go through each window + WindowContainer windows; + mAdaptorInterfaces.GetWindowContainerInterface( windows ); + + for( auto&& window : windows ) + { + if ( window && !window->IsBeingDeleted() ) + { + Dali::Integration::Scene scene = window->GetScene(); + Dali::RenderSurfaceInterface* windowSurface = window->GetSurface(); + + if ( scene && windowSurface ) + { + windowSurface->InitializeGraphics(); + + // Render off-screen frame buffers first if any + mCore.RenderScene( scene, true ); + + // Switch to the EGL context of the surface + windowSurface->PreRender( surfaceResized ); // Switch GL context + + // Render the surface + mCore.RenderScene( scene, false ); + + windowSurface->PostRender( false, false, surfaceResized ); // Swap Buffer + } + } + } } + mCore.PostRender( mUploadWithoutRendering ); + + mIsRenderingWindows = false; + + AddPerformanceMarker( PerformanceInterface::RENDER_END ); + + mForceClear = false; + // Trigger event thread to request Update/Render thread to sleep if update not required - if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && - ! renderStatus.NeedsUpdate() ) + if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() ) { mSleepTrigger->Trigger(); updateRequired = false; @@ -576,7 +766,12 @@ void CombinedUpdateRenderController::UpdateRenderThread() // Inform core of context destruction & shutdown EGL mCore.ContextDestroyed(); - mRenderHelper.ShutdownEgl(); + currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface(); + if( currentSurface ) + { + currentSurface->DestroySurface(); + currentSurface = nullptr; + } LOG_UPDATE_RENDER( "THREAD DESTROYED" ); @@ -635,11 +830,11 @@ bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bo return ! mDestroyUpdateRenderThread; } -RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced() +Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced() { ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition ); - RenderSurface* newSurface = mNewSurface; + Dali::RenderSurfaceInterface* newSurface = mNewSurface; mNewSurface = NULL; return newSurface; @@ -673,6 +868,11 @@ void CombinedUpdateRenderController::NotifyThreadInitialised() sem_post( &mEventThreadSemaphore ); } +void CombinedUpdateRenderController::NotifyGraphicsInitialised() +{ + sem_post( &mGraphicsInitializeSemaphore ); +} + void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type ) { if( mPerformanceInterface ) @@ -707,7 +907,6 @@ void CombinedUpdateRenderController::PostRenderWaitForCompletion() ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition ); while( mPostRendering && ! mNewSurface && // We should NOT wait if we're replacing the surface - ! mSurfaceResized && // We should NOT wait if we're resizing the surface ! mDestroyUpdateRenderThread ) { mUpdateRenderThreadWaitCondition.Wait( lock );