Use separated semaphore in CombinedUpdateRenderController
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / combined-update-render-controller.cpp
index 4b794ce..eb28975 100644 (file)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <errno.h>
 #include <dali/integration-api/platform-abstraction.h>
+#include <unistd.h>
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
@@ -32,6 +33,7 @@
 #include <dali/internal/graphics/common/graphics-interface.h>
 #include <dali/internal/system/common/environment-options.h>
 #include <dali/internal/system/common/time-service.h>
+#include <dali/internal/window-system/common/window-impl.h>
 
 namespace Dali
 {
@@ -87,11 +89,12 @@ const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
 // EVENT THREAD
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
+CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions, ThreadMode threadMode )
 : mFpsTracker( environmentOptions ),
   mUpdateStatusLogger( environmentOptions ),
   mEventThreadSemaphore(),
   mGraphicsInitializeSemaphore(),
+  mSurfaceSemaphore(),
   mUpdateRenderThreadWaitCondition(),
   mAdaptorInterfaces( adaptorInterfaces ),
   mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
@@ -107,6 +110,7 @@ CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalS
   mDefaultHalfFrameNanoseconds( 0u ),
   mUpdateRequestCount( 0u ),
   mRunning( FALSE ),
+  mThreadMode( threadMode ),
   mUpdateRenderRunCount( 0 ),
   mDestroyUpdateRenderThread( FALSE ),
   mUpdateRenderThreadCanSleep( FALSE ),
@@ -132,12 +136,12 @@ CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalS
     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 );
 
   // 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 );
+  sem_init( &mSurfaceSemaphore, 0, 0 );
 }
 
 CombinedUpdateRenderController::~CombinedUpdateRenderController()
@@ -178,7 +182,7 @@ void CombinedUpdateRenderController::Start()
     sem_wait( &mEventThreadSemaphore );
   }
 
-  Integration::RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+  Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
   if( currentSurface )
   {
     currentSurface->StartRender();
@@ -235,7 +239,7 @@ void CombinedUpdateRenderController::Stop()
   LOG_EVENT_TRACE;
 
   // Stop Rendering and the Update/Render Thread
-  Integration::RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+  Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
   if( currentSurface )
   {
     currentSurface->StopRender();
@@ -288,7 +292,7 @@ void CombinedUpdateRenderController::RequestUpdateOnce( UpdateMode updateMode )
     ++mUpdateRequestCount;
   }
 
-  if( IsUpdateRenderThreadPaused() )
+  if( IsUpdateRenderThreadPaused() || updateMode == UpdateMode::FORCE_RENDER )
   {
     LOG_EVENT_TRACE;
 
@@ -317,7 +321,7 @@ void CombinedUpdateRenderController::ReplaceSurface( Dali::RenderSurfaceInterfac
     }
 
     // Wait until the surface has been replaced
-    sem_wait( &mEventThreadSemaphore );
+    sem_wait( &mSurfaceSemaphore );
 
     LOG_EVENT( "Surface replaced, event-thread continuing" );
   }
@@ -340,7 +344,7 @@ void CombinedUpdateRenderController::DeleteSurface( Dali::RenderSurfaceInterface
     }
 
     // Wait until the surface has been deleted
-    sem_wait( &mEventThreadSemaphore );
+    sem_wait( &mSurfaceSemaphore );
 
     LOG_EVENT( "Surface deleted, event-thread continuing" );
   }
@@ -399,6 +403,17 @@ void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callbac
   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
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -406,9 +421,31 @@ void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callbac
 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode )
 {
   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
-  mUpdateRenderRunCount = numberOfCycles;
+
+  switch( mThreadMode )
+  {
+    case ThreadMode::NORMAL:
+    {
+      mUpdateRenderRunCount = numberOfCycles;
+      mUseElapsedTimeAfterWait = ( animationProgression == AnimationProgression::USE_ELAPSED_TIME );
+      break;
+    }
+    case ThreadMode::RUN_IF_REQUESTED:
+    {
+      if( updateMode != UpdateMode::FORCE_RENDER )
+      {
+        // Render only if the update mode is FORCE_RENDER which means the application requests it.
+        // We don't want to awake the update thread.
+        return;
+      }
+
+      mUpdateRenderRunCount++;          // Increase the update request count
+      mUseElapsedTimeAfterWait = TRUE;  // The elapsed time should be used. We want animations to proceed.
+      break;
+    }
+  }
+
   mUpdateRenderThreadCanSleep = FALSE;
-  mUseElapsedTimeAfterWait = ( animationProgression == AnimationProgression::USE_ELAPSED_TIME );
   mUploadWithoutRendering = ( updateMode == UpdateMode::SKIP_RENDER );
   LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
   mUpdateRenderThreadWaitCondition.Notify( lock );
@@ -430,6 +467,12 @@ void CombinedUpdateRenderController::StopUpdateRenderThread()
 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
 {
   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+
+  if( mThreadMode == ThreadMode::RUN_IF_REQUESTED )
+  {
+    return !mRunning || mUpdateRenderThreadCanSleep;
+  }
+
   return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
          mUpdateRenderThreadCanSleep;               // Report paused if sleeping
 }
@@ -550,7 +593,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     uint64_t currentFrameStartTime = 0;
     TimeService::GetNanoseconds( currentFrameStartTime );
 
-    const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
+    uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
 
     // Optional FPS Tracking when continuously rendering
     if( useElapsedTime && mFpsTracker.Enabled() )
@@ -565,7 +608,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     // REPLACE SURFACE
     //////////////////////////////
 
-    Integration::RenderSurface* newSurface = ShouldSurfaceBeReplaced();
+    Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
     if( DALI_UNLIKELY( newSurface ) )
     {
       LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
@@ -597,6 +640,16 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     float frameDelta = 0.0f;
     if( useElapsedTime )
     {
+      if( mThreadMode == ThreadMode::RUN_IF_REQUESTED )
+      {
+        extraFramesDropped = 0;
+        while( timeSinceLastFrame >= mDefaultFrameDurationNanoseconds )
+        {
+           timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
+           extraFramesDropped++;
+        }
+      }
+
       // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
       noOfFramesSinceLastUpdate += extraFramesDropped;
 
@@ -625,6 +678,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     }
 
     // Check resize
+    bool surfaceResized = false;
     bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
     if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
     {
@@ -632,6 +686,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       {
         LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
         SurfaceResized();
+        surfaceResized = true;
       }
     }
 
@@ -671,18 +726,69 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     Integration::RenderStatus renderStatus;
 
     AddPerformanceMarker( PerformanceInterface::RENDER_START );
-    mCore.Render( renderStatus, mForceClear, mUploadWithoutRendering );
+
+    // Upload shared resources
+    mCore.PreRender( renderStatus, mForceClear, mUploadWithoutRendering );
+
+    if ( !mUploadWithoutRendering )
+    {
+      // Go through each window
+      WindowContainer windows;
+      mAdaptorInterfaces.GetWindowContainerInterface( windows );
+
+      for( auto&& window : windows )
+      {
+        Dali::Integration::Scene scene = window->GetScene();
+        Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
+
+        if ( scene && windowSurface )
+        {
+          Integration::RenderStatus windowRenderStatus;
+
+          windowSurface->InitializeGraphics();
+
+          // clear previous frame damaged render items rects, buffer history is tracked on surface level
+          mDamagedRects.clear();
+
+          // Collect damage rects
+          mCore.PreRender( scene, mDamagedRects );
+
+          // Render off-screen frame buffers first if any
+          mCore.RenderScene( windowRenderStatus, scene, true );
+
+          Rect<int> clippingRect; // Empty for fbo rendering
+
+          // Switch to the EGL context of the surface, merge damaged areas for previous frames
+          windowSurface->PreRender( surfaceResized, mDamagedRects, clippingRect ); // Switch GL context
+
+          if (clippingRect.IsEmpty())
+          {
+            mDamagedRects.clear();
+          }
+
+          // Render the surface
+          mCore.RenderScene( windowRenderStatus, scene, false, clippingRect );
+
+          if( windowRenderStatus.NeedsPostRender() )
+          {
+            windowSurface->PostRender( false, false, surfaceResized, mDamagedRects ); // Swap Buffer with damage
+          }
+        }
+      }
+    }
+
+    mCore.PostRender( mUploadWithoutRendering );
 
     //////////////////////////////
     // DELETE SURFACE
     //////////////////////////////
 
-    Integration::RenderSurface* deletedSurface = ShouldSurfaceBeDeleted();
+    Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
     if( DALI_UNLIKELY( deletedSurface ) )
     {
       LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
 
-      mCore.SurfaceDeleted( deletedSurface );
+      deletedSurface->DestroySurface();
 
       SurfaceDeleted();
     }
@@ -747,15 +853,22 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     }
   }
 
-  // Inform core of context destruction & shutdown EGL
+  // Inform core of context destruction
   mCore.ContextDestroyed();
-  currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
-  if( currentSurface )
+
+  WindowContainer windows;
+  mAdaptorInterfaces.GetWindowContainerInterface( windows );
+
+  // Destroy surfaces
+  for( auto&& window : windows )
   {
-    currentSurface->DestroySurface();
-    currentSurface = nullptr;
+    Dali::RenderSurfaceInterface* surface = window->GetSurface();
+    surface->DestroySurface();
   }
 
+  // Shutdown EGL
+  eglInterface->TerminateGles();
+
   LOG_UPDATE_RENDER( "THREAD DESTROYED" );
 
   // Uninstall the logging function
@@ -816,11 +929,11 @@ bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bo
   return ! mDestroyUpdateRenderThread;
 }
 
-Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
+Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
 {
   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
 
-  Integration::RenderSurface* newSurface = mNewSurface;
+  Dali::RenderSurfaceInterface* newSurface = mNewSurface;
   mNewSurface = NULL;
 
   return newSurface;
@@ -829,14 +942,14 @@ Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeRepla
 void CombinedUpdateRenderController::SurfaceReplaced()
 {
   // Just increment the semaphore
-  sem_post( &mEventThreadSemaphore );
+  sem_post( &mSurfaceSemaphore );
 }
 
-Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
+Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
 {
   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
 
-  Integration::RenderSurface* deletedSurface = mDeletedSurface;
+  Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
   mDeletedSurface = NULL;
 
   return deletedSurface;
@@ -845,7 +958,7 @@ Integration::RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeDelet
 void CombinedUpdateRenderController::SurfaceDeleted()
 {
   // Just increment the semaphore
-  sem_post( &mEventThreadSemaphore );
+  sem_post( &mSurfaceSemaphore );
 }
 
 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()