[Tizen] (TV only) Create NativeTexture sync after eglSwapBuffer 27/316627/1
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 13 Dec 2024 03:21:23 +0000 (12:21 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Mon, 16 Dec 2024 07:49:47 +0000 (16:49 +0900)
Since eglCreateSyncKHR try to allocate full buffer scene at GPU side,
it will increase GPU memory.

It might not a common sense but, let we make eglCreateSyncKHR called
after eglSwapBuffer or glFlush called.

Additionary, let we call glFlush after create sync object.
Since we cannot assume that eglSwapBuffer will be called after now.

Note : This logic only be used for TV profile.
Is it required for common platform?

Change-Id: Ieb8d5c62e9e86fc95c3cc79310e26bcaeea2eb25
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/graphics/gles-impl/gles-context.cpp
dali/internal/graphics/gles-impl/gles-sync-pool.cpp
dali/internal/graphics/gles-impl/gles-sync-pool.h
dali/internal/graphics/gles-impl/gles-texture-dependency-checker.cpp
dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h

index 049ba86fe9a76534829c7520740d2341671b24d6..38d89f8a65c4de236e1a0340464f1d35e3d3525d 100644 (file)
@@ -305,15 +305,43 @@ void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* rende
     surfaceInterface->MakeContextCurrent();
     surfaceInterface->PostRender();
 
-    // Delete discarded surface context sync objects.
+    // Delete discarded surface context sync objects, and create new syncfence for NativeImage texture.
     // NOTE : We can assume that surface context is become current now.
     //        And also can asusme that ResolvePresentRenderTarget() will be called at most 1 times per each frame.
-    mSyncPool.ProcessDiscardSyncObjects(GetSurfaceContext(surfaceInterface));
+    const auto* currentSurfaceContext = GetSurfaceContext(surfaceInterface);
+    mSyncPool.ProcessDiscardSyncObjects(currentSurfaceContext);
+
+#ifdef DALI_PROFILE_TV
+    /// Only TV profile should not create egl sync object before eglSwapBuffers, due to DDK bug. 2024-12-13. eunkiki.hong
+
+    // NOTE : We need to call eglCreateSyncKHR after eglSwapBuffer if that sync will not be used 'before' swap buffer.
+    //        Since given sync fence try to store rendering result of current frame which we usually don't need,
+    //        so GPU memory increased.
+    if(mTextureDependencyChecker.GetNativeTextureCount() > 0)
+    {
+      mTextureDependencyChecker.CreateNativeTextureSync(currentSurfaceContext);
+
+      // Need to call glFlush or eglSwapBuffer after create sync object.
+      mGlAbstraction->Flush();
+    }
+#endif
   }
 }
 
 void EglGraphicsController::PostRender()
 {
+#ifdef DALI_PROFILE_TV
+  /// Only TV profile should not create egl sync object before eglSwapBuffers, due to DDK bug. 2024-12-13. eunkiki.hong
+  // eglCreateSyncKHR for FBO case.
+  if(mTextureDependencyChecker.GetNativeTextureCount() > 0)
+  {
+    mTextureDependencyChecker.CreateNativeTextureSync(mCurrentContext);
+
+    // Need to call glFlush or eglSwapBuffer after create sync object.
+    mGlAbstraction->Flush();
+  }
+#endif
+
   mTextureDependencyChecker.Reset();
   mSyncPool.AgeSyncObjects();
 
index b096617a4a33fdfe1c921a00fdd2bf702d64194a..da2d8020041a736d3103d2c2e0c9c6e3611b7da5 100644 (file)
@@ -923,11 +923,15 @@ void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker)
        */
       dependencyChecker.AddTextures(this, framebuffer);
     }
-  }
 
-  if(dependencyChecker.GetNativeTextureCount() > 0)
-  {
-    dependencyChecker.CreateNativeTextureSync(this);
+    if(dependencyChecker.GetNativeTextureCount() > 0)
+    {
+      dependencyChecker.MarkNativeTextureSyncContext(this);
+#ifndef DALI_PROFILE_TV
+      /// Only TV profile should not create egl sync object before eglSwapBuffers, due to DDK bug. 2024-12-13. eunkiki.hong
+      dependencyChecker.CreateNativeTextureSync(this);
+#endif
+    }
   }
 }
 
index b3e69635906b90c6a07bb9d552b0ac84c9e2fc55..13a480eeb9d734616b13eb43be413b7a67dcd86f 100644 (file)
@@ -152,7 +152,11 @@ SyncPool::SyncObjectId SyncPool::AllocateSyncObject(const Context* writeContext,
 {
   auto agingSyncObject = std::make_unique<AgingSyncObject>(mController, writeContext, (syncContext == SyncContext::EGL));
 
-  auto syncPoolObjectId = mSyncObjectId++;
+  auto syncPoolObjectId = ++mSyncObjectId;
+  if(DALI_UNLIKELY(syncPoolObjectId == INVALID_SYNC_OBJECT_ID))
+  {
+    syncPoolObjectId = ++mSyncObjectId;
+  }
 
   // Take ownership of sync object
   mSyncObjects.insert(std::make_pair(syncPoolObjectId, std::move(agingSyncObject)));
index c826c0df36bbe54c5fcf2c30a25f48139bf8ad37..c98767fe3fe0dfdafb196574d3392d7071fc8440 100644 (file)
@@ -55,6 +55,8 @@ class SyncPool
 public:
   using SyncObjectId = uint32_t;
 
+  static constexpr SyncObjectId INVALID_SYNC_OBJECT_ID = 0u;
+
   enum class SyncContext
   {
     EGL, ///< Use EGL sync when syncing between multiple contexts
@@ -77,27 +79,27 @@ public:
 
   /**
    * Check whether given object is synced in the CPU
-   * @param syncPoolObjectId The id of object to check synced.
+   * @param syncPoolObjectId The id of object to check synced. If it's invalid, return false immediately.
    * @return true if the sync object was signaled, false if it timed out
    */
   bool IsSynced(SyncObjectId syncPoolObjectId);
 
   /**
    * Wait on a sync object in any context in the GPU
-   * @param syncPoolObjectId The id of object to wait on.
+   * @param syncPoolObjectId The id of object to wait on. If it's invalid, do nothing.
    */
   void Wait(SyncObjectId syncPoolObjectId);
 
   /**
    * Wait on a sync object in any context in the CPU
-   * @param syncPoolObjectId The id of object to wait on.
+   * @param syncPoolObjectId The id of object to wait on. If it's invalid, return false immediately.
    * @return true if the sync object was signaled, false if it timed out
    */
   bool ClientWait(SyncObjectId syncPoolObjectId);
 
   /**
    * Delete the sync object if it's not needed.
-   * @param syncPoolObjectId The id of object to delete.
+   * @param syncPoolObjectId The id of object to delete. If it's invalid, do nothing.
    */
   void FreeSyncObject(SyncObjectId syncPoolObjectId);
 
@@ -168,7 +170,7 @@ private:
 
   EglGraphicsController& mController;
 
-  SyncObjectId mSyncObjectId{0u};
+  SyncObjectId mSyncObjectId{INVALID_SYNC_OBJECT_ID};
 };
 
 } // namespace GLES
index d4f9bac696d4b8d2fb4fdb7fabafb12749a25130..01e7983206cc2489a6377498a4fbe5a8be4e84e5 100644 (file)
@@ -68,7 +68,7 @@ void TextureDependencyChecker::Reset()
 
   if(!mNativeTextureDependencies[0].empty() || !mNativeTextureDependencies[1].empty())
   {
-    DALI_ASSERT_ALWAYS(mIsFirstPreparedNativeTextureDependency && "CreateNativeTextureSync should be called before PostRender!");
+    DALI_ASSERT_ALWAYS(mIsFirstPreparedNativeTextureDependency && "MarkNativeTextureSyncContext should be called before PostRender!");
 
     // Remove all infomations about previous native textures
     for(auto& nativeTextureDependency : mNativeTextureDependencies[mPreviousNativeTextureDependencyIndex])
@@ -128,7 +128,7 @@ void TextureDependencyChecker::CheckNeedsSync(const GLES::Context* readContext,
   if(dependencyIndex < mFramebufferTextureDependencies.size())
   {
     auto& textureDependency = mFramebufferTextureDependencies[dependencyIndex];
-    if(!textureDependency.syncing && textureDependency.writeContext != readContext)
+    if(!textureDependency.syncing && textureDependency.writeContext != readContext && textureDependency.agingSyncObjectId != INVALID_SYNC_OBJECT_ID)
     {
       // Needs syncing!
       textureDependency.syncing = true;
@@ -136,7 +136,13 @@ void TextureDependencyChecker::CheckNeedsSync(const GLES::Context* readContext,
       if(cpu)
       {
         DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CheckNeedsSync Insert CPU WAIT");
-        mController.GetSyncPool().ClientWait(textureDependency.agingSyncObjectId);
+        const bool synced = mController.GetSyncPool().ClientWait(textureDependency.agingSyncObjectId);
+        if(DALI_LIKELY(synced))
+        {
+          // Object discarded, and will be free when write context be currnt.
+          mController.GetSyncPool().FreeSyncObject(textureDependency.agingSyncObjectId);
+          textureDependency.agingSyncObjectId = INVALID_SYNC_OBJECT_ID;
+        }
       }
       else
       {
@@ -155,9 +161,9 @@ void TextureDependencyChecker::CheckNeedsSync(const GLES::Context* readContext,
     // TODO : Optimize here. For now, we don't have too much EndPass call. So just keep this logic.
     for(auto& nativeTextureDependency : mNativeTextureDependencies[mPreviousNativeTextureDependencyIndex])
     {
-      if(nativeTextureDependency.synced)
+      if(nativeTextureDependency.synced || nativeTextureDependency.agingSyncObjectId == INVALID_SYNC_OBJECT_ID)
       {
-        // Fast-out if we know it is already synced
+        // Fast-out if we know it is already synced, or if there's no sync object.
         continue;
       }
 
@@ -169,10 +175,11 @@ void TextureDependencyChecker::CheckNeedsSync(const GLES::Context* readContext,
           DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CheckNeedsSync (for native) Insert CPU WAIT");
           nativeTextureDependency.synced = mController.GetSyncPool().ClientWait(nativeTextureDependency.agingSyncObjectId);
 
-          if(DALI_LIKELY(nativeTextureDependency.synced) && readContext == nativeTextureDependency.writeContext)
+          if(DALI_LIKELY(nativeTextureDependency.synced))
           {
-            // We can free sync object immediatly if we are using same context.
+            // Object discarded, and will be free when write context be currnt.
             mController.GetSyncPool().FreeSyncObject(nativeTextureDependency.agingSyncObjectId);
+            nativeTextureDependency.agingSyncObjectId = INVALID_SYNC_OBJECT_ID;
           }
         }
         else
@@ -242,7 +249,7 @@ void TextureDependencyChecker::DiscardNativeTexture(const GLES::Texture* texture
   }
 }
 
-void TextureDependencyChecker::CreateNativeTextureSync(const GLES::Context* writeContext)
+void TextureDependencyChecker::MarkNativeTextureSyncContext(const GLES::Context* writeContext)
 {
   if(mIsFirstPreparedNativeTextureDependency)
   {
@@ -256,9 +263,19 @@ void TextureDependencyChecker::CreateNativeTextureSync(const GLES::Context* writ
   {
     auto& nativeTextureDependency        = mNativeTextureDependencies[mCurrentNativeTextureDependencyIndex].back();
     nativeTextureDependency.writeContext = writeContext; // Store write context
+  }
+}
 
-    DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CreateNativeTextureSync() Allocating sync object\n");
-    nativeTextureDependency.agingSyncObjectId = mController.GetSyncPool().AllocateSyncObject(writeContext, SyncPool::SyncContext::EGL);
+void TextureDependencyChecker::CreateNativeTextureSync(const GLES::Context* currentContext)
+{
+  // TODO : Optimize here. For now, we don't have too much EndPass call. So just keep this logic.
+  for(auto& nativeTextureDependency : mNativeTextureDependencies[mCurrentNativeTextureDependencyIndex])
+  {
+    if(nativeTextureDependency.writeContext == currentContext && nativeTextureDependency.agingSyncObjectId == INVALID_SYNC_OBJECT_ID)
+    {
+      DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CreateNativeTextureSync(%p) Allocating sync object\n", currentContext);
+      nativeTextureDependency.agingSyncObjectId = mController.GetSyncPool().AllocateSyncObject(currentContext, SyncPool::SyncContext::EGL);
+    }
   }
 }
 
index 90e8876009eddeca53a757cac45f90fe93a0deee..01e793cba26115dd3b3808e04625a67b17a63b23 100644 (file)
@@ -110,20 +110,28 @@ public: ///< For NativeTexture dependency checker
   void DiscardNativeTexture(const Texture* texture);
 
   /**
-   * @brief Create Sync object for native images.
+   * @brief Mark that native images write context.
    * It will be called at EndRenderPass.
    */
-  void CreateNativeTextureSync(const Context* writeContext);
+  void MarkNativeTextureSyncContext(const Context* writeContext);
+
+  /**
+   * @brief Create Sync object for native images.
+   * It will be called after eglSwapBuffers.
+   */
+  void CreateNativeTextureSync(const Context* currentContext);
 
 private:
   using SyncObjectId = uint32_t; ///< Note : It should be matched with Dali::Graphics::GLES::SyncPool:SyncObjectId.
 
+  static constexpr SyncObjectId INVALID_SYNC_OBJECT_ID = 0u; ///< Note : It should be matched with Dali::Graphics::GLES::SyncPool:INVALID_SYNC_OBJECT_ID.
+
   struct FramebufferTextureDependency
   {
     std::vector<Texture*> textures;
     Context*              writeContext{nullptr};
     Framebuffer*          framebuffer{nullptr};
-    SyncObjectId          agingSyncObjectId{0u};
+    SyncObjectId          agingSyncObjectId{INVALID_SYNC_OBJECT_ID};
     bool                  syncing{false};
   };
   std::vector<FramebufferTextureDependency> mFramebufferTextureDependencies;
@@ -132,7 +140,7 @@ private:
   {
     std::unordered_set<const Texture*> textures;
     const Context*                     writeContext{nullptr};
-    SyncObjectId                       agingSyncObjectId{0u};
+    SyncObjectId                       agingSyncObjectId{INVALID_SYNC_OBJECT_ID};
     bool                               synced{false};
   };
   std::vector<NativeTextureDependency> mNativeTextureDependencies[2];