Remove EGL surface in the update thread 45/233245/2
authorHeeyong Song <heeyong.song@samsung.com>
Wed, 13 May 2020 07:30:29 +0000 (16:30 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Wed, 13 May 2020 08:04:48 +0000 (17:04 +0900)
Change-Id: I251f2b89e02e883839964c80c2b80704a95ebf8d

dali/integration-api/adaptor-framework/scene-holder-impl.cpp
dali/internal/adaptor/common/adaptor-impl.cpp
dali/internal/adaptor/common/adaptor-impl.h
dali/internal/adaptor/common/combined-update-render-controller.cpp
dali/internal/adaptor/common/combined-update-render-controller.h
dali/internal/adaptor/common/thread-controller-interface.h
dali/internal/system/common/thread-controller.cpp
dali/internal/system/common/thread-controller.h
dali/internal/window-system/common/window-impl.cpp
dali/internal/window-system/common/window-render-surface.cpp

index 2440b35..7162a1c 100644 (file)
@@ -133,6 +133,8 @@ SceneHolder::~SceneHolder()
     mAdaptor->RemoveObserver( *mLifeCycleObserver.get() );
     mAdaptor->RemoveWindow( this );
 
+    mAdaptor->DeleteSurface( *mSurface.get() );
+
     mAdaptor = nullptr;
   }
 
index 2ecb543..188c64e 100755 (executable)
@@ -557,6 +557,16 @@ void Adaptor::ReplaceSurface( Dali::Integration::SceneHolder window, Dali::Rende
   }
 }
 
+void Adaptor::DeleteSurface( Dali::RenderSurfaceInterface& surface )
+{
+  // Flush the event queue to give the update-render thread chance
+  // to start processing messages for new camera setup etc as soon as possible
+  ProcessCoreEvents();
+
+  // This method blocks until the render thread has finished rendering the current surface.
+  mThreadController->DeleteSurface( &surface );
+}
+
 Dali::RenderSurfaceInterface& Adaptor::GetSurface() const
 {
   return *mWindows.front()->GetSurface();
@@ -1041,11 +1051,6 @@ bool Adaptor::IsMultipleWindowSupported() const
   return mConfigurationManager->IsMultipleWindowSupported();
 }
 
-bool Adaptor::IsRenderingWindows() const
-{
-  return ( mThreadController && mThreadController->IsRenderingWindows() );
-}
-
 void Adaptor::RequestUpdateOnce()
 {
   if( mThreadController )
index c2a9ad4..d0d2379 100755 (executable)
@@ -292,6 +292,12 @@ public: // AdaptorInternalServices implementation
   bool RemoveWindow( Dali::Internal::Adaptor::SceneHolder* childWindow );
 
   /**
+   * @brief Deletes the rendering surface
+   * @param[in] surface to delete
+   */
+  void DeleteSurface( Dali::RenderSurfaceInterface& surface );
+
+  /**
    * @brief Retrieve the window that the given actor is added to.
    *
    * @param[in] actor The actor
@@ -443,13 +449,6 @@ public:
    */
   bool IsMultipleWindowSupported() const;
 
-  /**
-   * @brief Checks whether the windows are being rendered in the render thread.
-   *
-   * @return true if the windows are being rendered in the render thread, or false if not.
-   */
-  bool IsRenderingWindows() const;
-
 public:  //AdaptorInternalServices
 
   /**
index 80bc0a3..7343b43 100644 (file)
@@ -115,12 +115,12 @@ CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalS
   mPendingRequestUpdate( FALSE ),
   mUseElapsedTimeAfterWait( FALSE ),
   mNewSurface( NULL ),
+  mDeletedSurface( nullptr ),
   mPostRendering( FALSE ),
   mSurfaceResized( FALSE ),
   mForceClear( FALSE ),
   mUploadWithoutRendering( FALSE ),
-  mFirstFrameAfterResume( FALSE ),
-  mIsRenderingWindows( false )
+  mFirstFrameAfterResume( FALSE )
 {
   LOG_EVENT_TRACE;
 
@@ -324,6 +324,29 @@ void CombinedUpdateRenderController::ReplaceSurface( Dali::RenderSurfaceInterfac
   }
 }
 
+void CombinedUpdateRenderController::DeleteSurface( Dali::RenderSurfaceInterface* surface )
+{
+  LOG_EVENT_TRACE;
+
+  if( mUpdateRenderThread )
+  {
+    LOG_EVENT( "Starting to delete 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 delete the surface now
+      mDeletedSurface = surface;
+      mUpdateRenderThreadWaitCondition.Notify( lock );
+    }
+
+    // Wait until the surface has been deleted
+    sem_wait( &mEventThreadSemaphore );
+
+    LOG_EVENT( "Surface deleted, event-thread continuing" );
+  }
+}
+
 void CombinedUpdateRenderController::WaitForGraphicsInitialization()
 {
   LOG_EVENT_TRACE;
@@ -663,8 +686,6 @@ void CombinedUpdateRenderController::UpdateRenderThread()
 
     AddPerformanceMarker( PerformanceInterface::RENDER_START );
 
-    mIsRenderingWindows = true;
-
     // Upload shared resources
     mCore.PreRender( renderStatus, mForceClear, mUploadWithoutRendering );
 
@@ -676,33 +697,42 @@ void CombinedUpdateRenderController::UpdateRenderThread()
 
       for( auto&& window : windows )
       {
-        if ( window && !window->IsBeingDeleted() )
-        {
-          Dali::Integration::Scene scene = window->GetScene();
-          Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
+        Dali::Integration::Scene scene = window->GetScene();
+        Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
 
-          if ( scene && windowSurface )
-          {
-            windowSurface->InitializeGraphics();
+        if ( scene && windowSurface )
+        {
+          windowSurface->InitializeGraphics();
 
-            // Render off-screen frame buffers first if any
-            mCore.RenderScene( scene, true );
+          // 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
+          // Switch to the EGL context of the surface
+          windowSurface->PreRender( surfaceResized ); // Switch GL context
 
-            // Render the surface
-            mCore.RenderScene( scene, false );
+          // Render the surface
+          mCore.RenderScene( scene, false );
 
-            windowSurface->PostRender( false, false, surfaceResized ); // Swap Buffer
-          }
+          windowSurface->PostRender( false, false, surfaceResized ); // Swap Buffer
         }
       }
     }
 
     mCore.PostRender( mUploadWithoutRendering );
 
-    mIsRenderingWindows = false;
+    //////////////////////////////
+    // DELETE SURFACE
+    //////////////////////////////
+
+    Dali::RenderSurfaceInterface* deletedSurface = ShouldSurfaceBeDeleted();
+    if( DALI_UNLIKELY( deletedSurface ) )
+    {
+      LOG_UPDATE_RENDER_TRACE_FMT( "Deleting Surface" );
+
+      deletedSurface->DestroySurface();
+
+      SurfaceDeleted();
+    }
 
     AddPerformanceMarker( PerformanceInterface::RENDER_END );
 
@@ -788,12 +818,14 @@ bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bo
            ( 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
@@ -813,6 +845,7 @@ bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bo
   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;
@@ -846,6 +879,22 @@ void CombinedUpdateRenderController::SurfaceReplaced()
   sem_post( &mEventThreadSemaphore );
 }
 
+Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeDeleted()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+
+  Dali::RenderSurfaceInterface* deletedSurface = mDeletedSurface;
+  mDeletedSurface = NULL;
+
+  return deletedSurface;
+}
+
+void CombinedUpdateRenderController::SurfaceDeleted()
+{
+  // Just increment the semaphore
+  sem_post( &mEventThreadSemaphore );
+}
+
 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
 {
   ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
@@ -907,6 +956,7 @@ void CombinedUpdateRenderController::PostRenderWaitForCompletion()
   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
          ! mDestroyUpdateRenderThread )
   {
     mUpdateRenderThreadWaitCondition.Wait( lock );
index ca22517..54cc67d 100644 (file)
@@ -128,6 +128,11 @@ public:
   virtual void ReplaceSurface( Dali::RenderSurfaceInterface* surface );
 
   /**
+   * @copydoc ThreadControllerInterface::DeleteSurface()
+   */
+  virtual void DeleteSurface( Dali::RenderSurfaceInterface* surface );
+
+  /**
    * @copydoc ThreadControllerInterface::ResizeSurface()
    */
   virtual void ResizeSurface();
@@ -152,11 +157,6 @@ public:
    */
   virtual void AddSurface( Dali::RenderSurfaceInterface* surface );
 
-  /**
-   * @copydoc ThreadControllerInterface::IsRenderingWindows()
-   */
-  bool IsRenderingWindows() const override { return mIsRenderingWindows; }
-
 private:
 
   // Undefined copy constructor.
@@ -250,6 +250,21 @@ private:
   void SurfaceReplaced();
 
   /**
+   * Checks to see if the surface needs to be deleted.
+   * This will lock the mutex in mUpdateRenderThreadWaitCondition.
+   *
+   * @return Pointer to the deleted surface, nullptr otherwise
+   */
+  Dali::RenderSurfaceInterface* ShouldSurfaceBeDeleted();
+
+  /**
+   * Called by the Update/Render thread after a surface has been deleted.
+   *
+   * This will lock the mutex in mEventThreadWaitCondition
+   */
+  void SurfaceDeleted();
+
+  /**
    * Checks to see if the surface needs to be resized.
    * This will lock the mutex in mUpdateRenderThreadWaitCondition.
    *
@@ -365,6 +380,7 @@ private:
   volatile unsigned int             mUseElapsedTimeAfterWait;          ///< Whether we should use the elapsed time after waiting (set by the event-thread, read by the update-render-thread).
 
   Dali::RenderSurfaceInterface* volatile mNewSurface;                  ///< Will be set to the new-surface if requested (set by the event-thread, read & cleared by the update-render thread).
+  Dali::RenderSurfaceInterface* volatile mDeletedSurface;              ///< Will be set to the deleted surface if requested (set by the event-thread, read & cleared by the update-render thread).
 
   volatile unsigned int             mPostRendering;                    ///< Whether post-rendering is taking place (set by the event & render threads, read by the render-thread).
   volatile unsigned int             mSurfaceResized;                   ///< Will be set to resize the surface (set by the event-thread, read & cleared by the update-render thread).
@@ -373,8 +389,6 @@ private:
   volatile unsigned int             mUploadWithoutRendering;           ///< Will be set to upload the resource only (with no rendering)
 
   volatile unsigned int             mFirstFrameAfterResume;            ///< Will be set to check the first frame after resume (for log)
-
-  std::atomic<bool>                 mIsRenderingWindows;               ///< This is set only from the render thread and read only from the event thread
 };
 
 } // namespace Adaptor
index 94276ff..6b9055b 100644 (file)
@@ -93,6 +93,12 @@ public:
   virtual void ReplaceSurface( Dali::RenderSurfaceInterface* surface ) = 0;
 
   /**
+   * Deletes the surface.
+   * @param[in] surface The surface to be deleted
+   */
+  virtual void DeleteSurface( Dali::RenderSurfaceInterface* surface ) = 0;
+
+  /**
    * Resize the surface.
    */
   virtual void ResizeSurface() = 0;
@@ -118,11 +124,6 @@ public:
    */
   virtual void AddSurface( Dali::RenderSurfaceInterface* surface ) = 0;
 
-  /**
-   * @copydoc Dali::Adaptor::IsRenderingWindows()
-   */
-  virtual bool IsRenderingWindows() const = 0;
-
 protected:
 
   /**
index 605c76d..a9054ec 100644 (file)
@@ -90,6 +90,11 @@ void ThreadController::ReplaceSurface( Dali::RenderSurfaceInterface* newSurface
   mThreadControllerInterface->ReplaceSurface( newSurface );
 }
 
+void ThreadController::DeleteSurface( Dali::RenderSurfaceInterface* surface )
+{
+  mThreadControllerInterface->DeleteSurface( surface );
+}
+
 void ThreadController::ResizeSurface()
 {
   mThreadControllerInterface->ResizeSurface();
@@ -115,11 +120,6 @@ void ThreadController::AddSurface( Dali::RenderSurfaceInterface* newSurface )
   mThreadControllerInterface->AddSurface( newSurface );
 }
 
-bool ThreadController::IsRenderingWindows() const
-{
-  return mThreadControllerInterface->IsRenderingWindows();
-}
-
 } // namespace Adaptor
 
 } // namespace Internal
index 471a5f9..c4f3961 100644 (file)
@@ -112,6 +112,12 @@ public:
   void ReplaceSurface( Dali::RenderSurfaceInterface* surface );
 
   /**
+   * Deletes the surface.
+   * @param surface The surface to be deleted
+   */
+  void DeleteSurface( Dali::RenderSurfaceInterface* surface );
+
+  /**
    * Resize the surface.
    */
   void ResizeSurface();
@@ -138,11 +144,6 @@ public:
    */
   void AddSurface( Dali::RenderSurfaceInterface* surface );
 
-  /**
-   * @copydoc Dali::Adaptor::IsRenderingWindows()
-   */
-  bool IsRenderingWindows() const;
-
 private:
 
   // Undefined copy constructor.
index a0fd809..5321782 100644 (file)
@@ -99,13 +99,6 @@ Window::Window()
 
 Window::~Window()
 {
-  mIsBeingDeleted = true;
-
-  while ( mAdaptor && mAdaptor->IsRenderingWindows() )
-  {
-    std::this_thread::yield(); // to allow other threads to run
-  }
-
   if ( mEventHandler )
   {
     mEventHandler->RemoveObserver( *this );
index e1a344f..c95d508 100644 (file)
@@ -85,11 +85,6 @@ WindowRenderSurface::~WindowRenderSurface()
   {
     delete mRotationTrigger;
   }
-
-  if ( mEGLSurface )
-  {
-    DestroySurface();
-  }
 }
 
 void WindowRenderSurface::Initialize( Any surface )
@@ -264,7 +259,13 @@ void WindowRenderSurface::DestroySurface()
     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
 
     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
     eglImpl.DestroySurface( mEGLSurface );
+    mEGLSurface = nullptr;
+
+    // Destroy context also
+    eglImpl.DestroyContext( mEGLContext );
+    mEGLContext = nullptr;
 
     mWindowBase->DestroyEglWindow();
   }