Synchronize framebuffer textures on different contexts 40/283240/6
authorDavid Steele <david.steele@samsung.com>
Thu, 20 Oct 2022 18:29:56 +0000 (19:29 +0100)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 27 Oct 2022 00:59:49 +0000 (09:59 +0900)
If a framebuffer's texture is read on a different context to
the one it was written on, then it needs synchronizing first.

This patch introduces a glFenceSync at the end of every render pass,
and calls GlWaitSync just before the texture is bound for a draw call.

The fenceSync is removed after 2 frames, as it cannot be re-used.
Unused fences are deleted at the end of the frame they are created.

Change-Id: I8ca2e7583836132f879d939377ed46c0b8a56556

dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/graphics/gles-impl/egl-graphics-controller.h
dali/internal/graphics/gles-impl/file.list
dali/internal/graphics/gles-impl/gles-context.cpp
dali/internal/graphics/gles-impl/gles-context.h
dali/internal/graphics/gles-impl/gles-graphics-texture.h
dali/internal/graphics/gles-impl/gles-sync-pool.cpp [new file with mode: 0644]
dali/internal/graphics/gles-impl/gles-sync-pool.h [new file with mode: 0644]
dali/internal/graphics/gles-impl/gles-texture-dependency-checker.cpp [new file with mode: 0644]
dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h [new file with mode: 0644]
dali/internal/graphics/gles/egl-graphics.cpp

index b903c0c..8717f7f 100644 (file)
@@ -109,6 +109,12 @@ const uint32_t TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB = 1;
 
 } // namespace
 
+EglGraphicsController::EglGraphicsController()
+: mTextureDependencyChecker(*this),
+  mSyncPool(*this)
+{
+}
+
 EglGraphicsController::~EglGraphicsController()
 {
   while(!mPresentationCommandBuffers.empty())
@@ -190,6 +196,12 @@ void EglGraphicsController::ResolvePresentRenderTarget(GLES::RenderTarget* rende
   }
 }
 
+void EglGraphicsController::PostRender()
+{
+  mTextureDependencyChecker.Reset();
+  mSyncPool.AgeSyncObjects();
+}
+
 Integration::GlAbstraction& EglGraphicsController::GetGlAbstraction()
 {
   DALI_ASSERT_DEBUG(mGlAbstraction && "Graphics controller not initialized");
@@ -451,17 +463,17 @@ void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& comm
       }
       case GLES::CommandType::DRAW:
       {
-        mCurrentContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::DRAW_INDEXED:
       {
-        mCurrentContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
       {
-        mCurrentContext->Flush(false, cmd.draw);
+        mCurrentContext->Flush(false, cmd.draw, mTextureDependencyChecker);
         break;
       }
       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
@@ -557,12 +569,15 @@ void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& comm
         }
 
         mCurrentContext->BeginRenderPass(cmd.beginRenderPass);
+
         break;
       }
       case GLES::CommandType::END_RENDERPASS:
       {
-        mCurrentContext->EndRenderPass();
+        mCurrentContext->EndRenderPass(mTextureDependencyChecker);
 
+        // This sync object is to enable cpu to wait for rendering to complete, not gpu.
+        // It's only needed for reading the framebuffer texture in the client.
         auto syncObject = const_cast<GLES::SyncObject*>(static_cast<const GLES::SyncObject*>(cmd.endRenderPass.syncObject));
         if(syncObject)
         {
index 8999a06..44f52ff 100644 (file)
@@ -35,6 +35,8 @@
 #include <dali/internal/graphics/gles-impl/gles-graphics-shader.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-types.h>
+#include <dali/internal/graphics/gles-impl/gles-sync-pool.h>
+#include <dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h>
 #include <dali/internal/graphics/gles-impl/gles2-graphics-memory.h>
 
 namespace Dali
@@ -51,6 +53,8 @@ namespace GLES
 {
 class CommandBuffer;
 class PipelineCache;
+class SyncPool;
+class TextureDependencyChecker;
 } // namespace GLES
 
 /**
@@ -62,9 +66,9 @@ class EglGraphicsController : public Graphics::Controller
 {
 public:
   /**
-   * @brief Deault constructor
+   * @brief Constructor
    */
-  EglGraphicsController() = default;
+  EglGraphicsController();
 
   /**
    * @brief Destructor
@@ -722,6 +726,11 @@ public:
   void ResolvePresentRenderTarget(GLES::RenderTarget* renderTarget);
 
   /**
+   * Invoked after all rendering has finished. Used to clean up sync resources
+   */
+  void PostRender();
+
+  /**
    * Creates a GLES context for the given render surface
    *
    * @param[in] surface The surface whose GLES context to be created.
@@ -767,6 +776,11 @@ public:
     return mSharedContext;
   }
 
+  GLES::SyncPool& GetSyncPool()
+  {
+    return mSyncPool;
+  }
+
 private:
   Integration::GlAbstraction*              mGlAbstraction{nullptr};
   Integration::GlContextHelperAbstraction* mGlContextHelperAbstraction{nullptr};
@@ -812,6 +826,9 @@ private:
   std::queue<const GLES::CommandBuffer*> mPresentationCommandBuffers{}; ///< Queue of reusable command buffers used by presentation engine
 
   void* mSharedContext{nullptr}; ///< Shared EGL context
+
+  GLES::TextureDependencyChecker mTextureDependencyChecker; // Checks if FBO textures need syncing
+  GLES::SyncPool                 mSyncPool;
 };
 
 } // namespace Graphics
index 1b0af65..2fa21f0 100644 (file)
@@ -20,6 +20,8 @@ SET( adaptor_graphics_gles_src_files ${adaptor_graphics_gles_src_files}
     ${adaptor_graphics_dir}/gles-impl/gles-graphics-texture.cpp
     ${adaptor_graphics_dir}/gles-impl/gles-graphics-pipeline-cache.cpp
     ${adaptor_graphics_dir}/gles-impl/gles-context.cpp
+    ${adaptor_graphics_dir}/gles-impl/gles-sync-pool.cpp
     ${adaptor_graphics_dir}/gles-impl/gles-sync-object.cpp
     ${adaptor_graphics_dir}/gles-impl/gles-framebuffer-state-cache.cpp
+    ${adaptor_graphics_dir}/gles-impl/gles-texture-dependency-checker.cpp
 )
index ff38d44..f2962a0 100644 (file)
@@ -28,6 +28,7 @@
 #include "gles-graphics-program.h"
 #include "gles-graphics-render-pass.h"
 #include "gles-graphics-render-target.h"
+#include "gles-texture-dependency-checker.h"
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -232,7 +233,7 @@ Context::~Context()
   }
 }
 
-void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
+void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker)
 {
   auto& gl = *mImpl->mController.GetGL();
 
@@ -286,10 +287,13 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
     {
       // Attempt to reinitialize
       // @todo need to put this somewhere else where it isn't const.
-      // Maybe post it back on end of initialize queue if initialization fails?
+      // Maybe post it bac/k on end of initialize queue if initialization fails?
       texture->InitializeResource();
     }
 
+    // Warning, this may cause glWaitSync to occur on the GPU.
+    dependencyChecker.CheckNeedsSync(this, texture);
+
     texture->Bind(binding);
 
     texture->Prepare(); // @todo also non-const.
@@ -355,6 +359,7 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
         mImpl->FlushVertexAttributeLocations();
       }
 
+      //@todo Wait if textures need syncing
       gl.DrawArrays(GLESTopology(ia->topology),
                     drawCall.draw.firstVertex,
                     drawCall.draw.vertexCount);
@@ -629,7 +634,8 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
   else if(targetInfo.framebuffer)
   {
     // bind framebuffer and swap.
-    renderTarget.GetFramebuffer()->Bind();
+    auto framebuffer = renderTarget.GetFramebuffer();
+    framebuffer->Bind();
   }
 
   // clear (ideally cache the setup)
@@ -641,6 +647,7 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
   const auto& attachments = *renderPass.GetCreateInfo().attachments;
   const auto& color0      = attachments[0];
   GLuint      mask        = 0;
+
   if(color0.loadOp == AttachmentLoadOp::CLEAR)
   {
     mask |= GL_COLOR_BUFFER_BIT;
@@ -703,14 +710,28 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
   mImpl->mCurrentRenderTarget = &renderTarget;
 }
 
-void Context::EndRenderPass()
+void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker)
 {
   if(mImpl->mCurrentRenderTarget)
   {
-    if(mImpl->mCurrentRenderTarget->GetFramebuffer())
+    GLES::Framebuffer* framebuffer = mImpl->mCurrentRenderTarget->GetFramebuffer();
+    if(framebuffer)
     {
       auto& gl = *mImpl->mController.GetGL();
       gl.Flush();
+
+      /* @todo Full dependency checking would need to store textures in Begin, and create
+       * fence objects here; but we're going to draw all fbos on shared context in serial,
+       * so no real need (yet). Might want to consider ensuring order of render passes,
+       * but that needs doing in the controller, and would need doing before ProcessCommandQueues.
+       *
+       * Currently up to the client to create render tasks in the right order.
+       */
+
+      /* Create fence sync objects. Other contexts can then wait on these fences before reading
+       * textures.
+       */
+      dependencyChecker.AddTextures(this, framebuffer);
     }
   }
 }
index 12e62cd..2345458 100644 (file)
@@ -31,6 +31,7 @@ class Pipeline;
 class RenderPass;
 class RenderTarget;
 class Texture;
+class TextureDependencyChecker;
 
 /**
  * @brief Context represents single GLES context
@@ -46,11 +47,14 @@ public:
    * @brief Flushes the context
    *
    * Flushes the context by issuing GL calls to set the required
-   * state.
+   * state. Causes a glWaitSync if any drawn textures are dependent
+   * on another context.
    *
    * @param[in] reset If true then state is reset unconditionally
+   * @param[in] drawCall the draws that need flushing
+   * @param[in] dependencyChecker The texture dependecy checker
    */
-  void Flush(bool reset, const GLES::DrawCallDescriptor& drawCall);
+  void Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker);
 
   /**
    * @brief Returns context Id
@@ -125,10 +129,9 @@ public:
   void ResolveStandaloneUniforms();
 
   /**
-   * @brief Begins render pass for sepcified render target
+   * @brief Begins render pass for specified render target
    *
    * @param[in] renderPass render pass object to begin
-   * @param[in] renderTarget render target to be drawn onto
    */
   void BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin);
 
@@ -136,9 +139,9 @@ public:
    * @brief Ends render pass
    *
    * Ending render pass is necessary in order to ensure
-   * proper implicit synchronization is in place
+   * proper explicit synchronization is in place
    */
-  void EndRenderPass();
+  void EndRenderPass(TextureDependencyChecker& checker);
 
   /**
    * @brief Returns the cache of GL state in the context
index 32df147..398735e 100644 (file)
@@ -151,6 +151,15 @@ public:
 
   void SetSamplerParameter(uint32_t param, uint32_t& cacheValue, uint32_t value) const;
 
+  uint32_t GetDependencyIndex() const
+  {
+    return mDependencyIndex;
+  }
+  void SetDependencyIndex(uint32_t dependencyIndex)
+  {
+    mDependencyIndex = dependencyIndex;
+  }
+
 private:
   mutable struct SamplerStateCache
   {
@@ -166,6 +175,7 @@ private:
   uint32_t          mTextureId{0u};
   GLenum            mGlTarget{0u};
   uint32_t          mMaxMipMapLevel{0u};
+  uint32_t          mDependencyIndex{0xFFFFFFFF};
   void*             mGLOwnerContext{nullptr};
   bool              mIsCompressed{false};
 };
diff --git a/dali/internal/graphics/gles-impl/gles-sync-pool.cpp b/dali/internal/graphics/gles-impl/gles-sync-pool.cpp
new file mode 100644 (file)
index 0000000..770deb0
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Class header
+#include <dali/internal/graphics/gles-impl/gles-sync-pool.h>
+
+// External Headers
+#include <dali/graphics-api/graphics-sync-object-create-info.h>
+
+// Internal Headers
+#include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
+
+namespace Dali::Graphics::GLES
+{
+AgingSyncObject::AgingSyncObject(Graphics::EglGraphicsController& controller, const Context* writeContext)
+: controller(controller),
+  writeContext(writeContext)
+{
+  auto gl = controller.GetGL();
+  if(gl)
+  {
+    glSyncObject = gl->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+  }
+}
+
+AgingSyncObject::~AgingSyncObject()
+{
+  auto gl = controller.GetGL();
+  if(gl && glSyncObject != nullptr)
+  {
+    gl->DeleteSync(glSyncObject);
+  }
+}
+
+SyncPool::~SyncPool() = default;
+
+AgingSyncObject* SyncPool::AllocateSyncObject(const Context* writeContext)
+{
+  std::unique_ptr<AgingSyncObject> syncObject = std::make_unique<AgingSyncObject>(mController, writeContext);
+  mSyncObjects.push_back(std::move(syncObject));
+  return mSyncObjects.back().get();
+}
+
+void SyncPool::Wait(AgingSyncObject* syncPoolObject)
+{
+  auto gl = mController.GetGL();
+  if(gl && syncPoolObject->glSyncObject != nullptr)
+  {
+    syncPoolObject->syncing = true;
+    gl->WaitSync(syncPoolObject->glSyncObject, 0, GL_TIMEOUT_IGNORED);
+  }
+}
+
+void SyncPool::FreeSyncObject(AgingSyncObject* agingSyncObject)
+{
+  auto iter = std::find_if(mSyncObjects.begin(), mSyncObjects.end(), [&agingSyncObject](AgingSyncPtrRef agingSyncPtr) { return agingSyncPtr.get() == agingSyncObject; });
+  if(iter != mSyncObjects.end())
+  {
+    iter->reset();
+  }
+}
+
+/**
+ * Age sync objects. Call at the end of each frame.
+ * When a sync object is older than 2 frames, delete it.
+ */
+void SyncPool::AgeSyncObjects()
+{
+  if(!mSyncObjects.empty())
+  {
+    // Age the remaining sync objects.
+    for(auto& agingSyncObject : mSyncObjects)
+    {
+      if(agingSyncObject != nullptr && agingSyncObject->glSyncObject != 0)
+      {
+        if(agingSyncObject->age > 0)
+        {
+          agingSyncObject->age--;
+        }
+        else
+        {
+          agingSyncObject.reset();
+        }
+      }
+    }
+  }
+  // Move any old sync objects to the end of the list, and then remove them all.
+  mSyncObjects.erase(std::remove_if(mSyncObjects.begin(), mSyncObjects.end(), [&](std::unique_ptr<AgingSyncObject>& agingSyncObject) { return agingSyncObject == nullptr; }),
+                     mSyncObjects.end());
+}
+
+} // namespace Dali::Graphics::GLES
diff --git a/dali/internal/graphics/gles-impl/gles-sync-pool.h b/dali/internal/graphics/gles-impl/gles-sync-pool.h
new file mode 100644 (file)
index 0000000..d394b03
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef DALI_GRAPHICS_GLES_SYNC_POOL_H
+#define DALI_GRAPHICS_GLES_SYNC_POOL_H
+
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/graphics-api/graphics-types.h>
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali::Graphics
+{
+class EglGraphicsController;
+
+namespace GLES
+{
+class Context;
+
+struct AgingSyncObject
+{
+  AgingSyncObject(Graphics::EglGraphicsController& controller, const Context* writeContext);
+  ~AgingSyncObject();
+
+  EglGraphicsController& controller;
+  const Context*         writeContext;
+  GLsync                 glSyncObject{0};
+  uint8_t                age{2};
+  bool                   syncing{false};
+};
+using AgingSyncPtrRef = std::unique_ptr<AgingSyncObject>&;
+
+/**
+ * A vector of current fence syncs. They only age if glWaitSync is called on them in the
+ * same frame they are created, otherwise they are deleted.
+ * They must be created in the writeContext, but can be synced from a readContext.
+ * (Pool per context? - probably only ever used in resource context!)
+ */
+class SyncPool
+{
+public:
+  explicit SyncPool(Graphics::EglGraphicsController& graphicsController)
+  : mController(graphicsController)
+  {
+  }
+
+  ~SyncPool();
+
+  /**
+   * Allocate a sync object in the writeContext
+   * @param writeContext
+   * @return An owned ptr to a sync object
+   */
+  AgingSyncObject* AllocateSyncObject(const Context* writeContext);
+
+  /**
+   * Wait on a sync object in any context
+   * @param syncPoolObject The object to wait on.
+   */
+  void Wait(AgingSyncObject* syncPoolObject);
+
+  /**
+   * Delete the sync object if it's not needed.
+   *
+   */
+  void FreeSyncObject(AgingSyncObject* agingSyncObject);
+
+  /**
+   * Age outstanding sync objects. Call at the end of each frame.
+   * When a sync object is older than 2 frames, delete it.
+   */
+  void AgeSyncObjects();
+
+private:
+  std::vector<std::unique_ptr<AgingSyncObject>> mSyncObjects;
+  EglGraphicsController&                        mController;
+};
+
+} // namespace GLES
+} // namespace Dali::Graphics
+
+#endif //DALI_GRAPHICS_GLES_SYNC_POOL_H
diff --git a/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.cpp b/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.cpp
new file mode 100644 (file)
index 0000000..0b54e89
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include "gles-texture-dependency-checker.h"
+
+// EXTERNAL INCLUDES
+#include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
+
+namespace Dali::Graphics::GLES
+{
+void TextureDependencyChecker::Reset()
+{
+  for(auto& textureDependency : mTextureDependencies)
+  {
+    for(auto texture : textureDependency.textures)
+    {
+      texture->SetDependencyIndex(0xffffffff);
+    }
+    if(!textureDependency.syncing)
+    {
+      mController.GetSyncPool().FreeSyncObject(textureDependency.agingSyncObject);
+    }
+  }
+  mTextureDependencies.clear();
+}
+
+void TextureDependencyChecker::AddTextures(const GLES::Context* writeContext, const GLES::Framebuffer* framebuffer)
+{
+  uint32_t index = mTextureDependencies.size();
+  mTextureDependencies.emplace_back();
+  TextureDependency& textureDependency = mTextureDependencies.back();
+
+  for(int i = 0; i < 3; ++i)
+  {
+    GLES::Texture* texture{nullptr};
+    switch(i)
+    {
+      case 0:
+        texture = static_cast<GLES::Texture*>(framebuffer->GetCreateInfo().colorAttachments[0].texture);
+        break;
+      case 1:
+        texture = static_cast<GLES::Texture*>(framebuffer->GetCreateInfo().depthStencilAttachment.depthTexture);
+        break;
+      case 2:
+        texture = static_cast<GLES::Texture*>(framebuffer->GetCreateInfo().depthStencilAttachment.stencilTexture);
+        break;
+    }
+    if(texture != nullptr)
+    {
+      textureDependency.textures.push_back(texture);
+      texture->SetDependencyIndex(index);
+    }
+  }
+  textureDependency.writeContext    = const_cast<GLES::Context*>(writeContext);
+  textureDependency.framebuffer     = const_cast<GLES::Framebuffer*>(framebuffer);
+  textureDependency.agingSyncObject = mController.GetSyncPool().AllocateSyncObject(writeContext);
+}
+
+void TextureDependencyChecker::CheckNeedsSync(const GLES::Context* readContext, const GLES::Texture* texture)
+{
+  uint32_t dependencyIndex = texture->GetDependencyIndex();
+  if(dependencyIndex < mTextureDependencies.size())
+  {
+    auto& textureDependency = mTextureDependencies[dependencyIndex];
+    if(!textureDependency.syncing && textureDependency.writeContext != readContext)
+    {
+      // Needs syncing!
+      textureDependency.syncing = true;
+
+      // Wait on the sync object in GPU. This will ensure that the writeContext completes its tasks prior
+      // to the sync point.
+      mController.GetSyncPool().Wait(textureDependency.agingSyncObject);
+    }
+  }
+}
+
+} // namespace Dali::Graphics::GLES
diff --git a/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h b/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h
new file mode 100644 (file)
index 0000000..8861229
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DALI_GLES_TEXTURE_DEPENDENCY_CHECKER_H
+#define DALI_GLES_TEXTURE_DEPENDENCY_CHECKER_H
+
+/*
+ * Copyright (c) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali::Graphics
+{
+class EglGraphicsController;
+
+namespace GLES
+{
+class Context;
+class Framebuffer;
+class Texture;
+class AgingSyncObject;
+
+/**
+ * Class to handle dependency checks between textures on different
+ * GL Contexts.
+ *
+ * We have a shared (resource) context for writing to offscreen framebuffers,
+ * and separate contexts for each window/scene.
+ * If a framebuffer attachment is used in a scene, then it needs a sync point
+ * in the GPU in order to ensure that the first context finishes writing to the
+ * texture before it is read in the scene context.
+ */
+class TextureDependencyChecker
+{
+public:
+  explicit TextureDependencyChecker(EglGraphicsController& controller)
+  : mController(controller)
+  {
+  }
+
+  /**
+   * Clear all the textures. Call at the start of a frame
+   */
+  void Reset();
+
+  /**
+   * Add Texture dependencies
+   *
+   * @param[in] writeContext The context of the framebuffer's render pass
+   * @param[in] framebuffer The framebuffer to collect textures from
+   */
+  void AddTextures(const Context* writeContext, const Framebuffer* framebuffer);
+
+  /**
+   * Check if the given texture needs syncing before being read.  This
+   * will perform a glWaitSync() (GPU side semaphore) if the texture
+   * needs syncing.
+   * @param[in] readContext The context that the texture is being read (drawn with)
+   * @param[in] texture The texture being read
+   */
+  void CheckNeedsSync(const Context* readContext, const Texture* texture);
+
+private:
+  struct TextureDependency
+  {
+    std::vector<Texture*> textures;
+    Context*              writeContext{nullptr};
+    Framebuffer*          framebuffer{nullptr};
+    AgingSyncObject*      agingSyncObject;
+    bool                  syncing{false};
+  };
+  std::vector<TextureDependency> mTextureDependencies;
+  EglGraphicsController&         mController;
+};
+
+} // namespace GLES
+} // namespace Dali::Graphics
+
+#endif //DALI_GLES_TEXTURE_DEPENDENCY_CHECKER_H
index 62563e1..a963e28 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -101,6 +101,8 @@ void EglGraphics::PostRender()
   {
     mGraphicsController.GetCurrentContext()->InvalidateDepthStencilBuffers();
   }
+
+  mGraphicsController.PostRender();
 }
 
 void EglGraphics::SetFirstFrameAfterResume()