[Tizen] Clear pipelie cache if geometry destroyed or buffer changed 61/320661/1 accepted/tizen/7.0/unified/20250306.110532 accepted/tizen/7.0/unified/20250306.122056
authorEunki, Hong <eunkiki.hong@samsung.com>
Mon, 24 Feb 2025 13:39:07 +0000 (22:39 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Wed, 5 Mar 2025 09:09:21 +0000 (18:09 +0900)
We also cache pipeline cache the Render::Geometry by the raw pointer.
If someone use duplicated pointer, it might return invalid pipeline
with unmatched vertexInputState.

To avoid this issue, let we erase cache if Render::Geometry destroyed,
same as Render::Program

 - This is the commit message #2:

Reset cached pipeline if geometry buffer changed

Until now, we don't re-cache the geometry
if the vertex buffer added/removed, or data changed.

Since the vertex attribute might be changed if we try to use
same geometry, the rendering result
show some non-common results.

To fix this cache issue, let we ensure to reset the cached infomations
if the vertex buffer / indices buffer changed.

Change-Id: I0dc5b4fb6b0645d4b7763d7aa890d6ad946d54c6
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/render/renderers/pipeline-cache.cpp
dali/internal/render/renderers/pipeline-cache.h
dali/internal/render/renderers/render-geometry.cpp
dali/internal/render/renderers/render-geometry.h
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/renderers/render-renderer.h

index d89244f1cecb833d69828207a0d07aacba9bb3eb..30a48b48f974bee59e3d6b2861a575d416b82401 100644 (file)
@@ -455,6 +455,7 @@ PipelineCache::~PipelineCache()
   {
     level0node.geometry->RemoveLifecycleObserver(*this);
   }
+  level0nodes.clear();
 }
 
 PipelineResult PipelineCache::GetPipeline(const PipelineCacheQueryInfo& queryInfo, bool createNewIfNotFound)
@@ -528,6 +529,14 @@ void PipelineCache::ResetPipeline(PipelineCachePtr pipelineCache)
   pipelineCache->referenceCount--;
 }
 
+Geometry::LifecycleObserver::NotifyReturnType PipelineCache::GeometryBufferChanged(const Geometry* geometry)
+{
+  // Let just run the same logic with geometry destroyed cases.
+  GeometryDestroyed(geometry);
+
+  return Geometry::LifecycleObserver::NotifyReturnType::STOP_OBSERVING;
+}
+
 void PipelineCache::GeometryDestroyed(const Geometry* geometry)
 {
   // Remove cached items what cache hold now.
index 859dac90c80044318d8969b72138e19582f0dae7..9928334eee5cf2e73b13ca89fd056e75445b9caa 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/internal/common/blending-options.h>
 #include <dali/public-api/common/list-wrapper.h>
 #include <dali/internal/render/renderers/render-geometry.h> ///< For Geometry::LifecycleObserver
+#include <dali/internal/render/shaders/program.h>           ///< For Program::LifecycleObserver
 
 namespace Dali::Internal
 {
@@ -159,6 +160,11 @@ public:
   void ResetPipeline(PipelineCachePtr pipelineCache);
 
 public: // From Geometry::LifecycleObserver
+  /**
+   * @copydoc Dali::Internal::Geometry::LifecycleObserver::GeometryBufferChanged()
+   */
+  Geometry::LifecycleObserver::NotifyReturnType GeometryBufferChanged(const Geometry* geometry);
+
   /**
    * @copydoc Dali::Internal::Geometry::LifecycleObserver::GeometryDestroyed()
    */
index 3f58bc482ab8f2cc5d4181976f75bf0fb14bc770..27095bc4670f3a91cdb244df6e05513bde9ee006 100644 (file)
@@ -163,6 +163,25 @@ void Geometry::Upload(Graphics::Controller& graphicsController)
     }
 
     mHasBeenUploaded = true;
+
+    // Notify to observers that geometry informations are changed
+    if(mUpdated)
+    {
+      mObserverNotifying = true;
+      for(auto iter = mLifecycleObservers.begin(); iter != mLifecycleObservers.end();)
+      {
+        auto returnValue = (*iter).first->GeometryBufferChanged(this);
+        if(returnValue == LifecycleObserver::KEEP_OBSERVING)
+        {
+          ++iter;
+        }
+        else
+        {
+          iter = mLifecycleObservers.erase(iter);
+        }
+      }
+      mObserverNotifying = false;
+    }
   }
 }
 
index eedfb380a5b3c6f1e7acb89df418a3633f95524d..c5432696a7f1529c48d443a8d2766782d05ea4a9 100644 (file)
@@ -60,10 +60,24 @@ public:
   class LifecycleObserver
   {
   public:
+    enum NotifyReturnType
+    {
+      STOP_OBSERVING,
+      KEEP_OBSERVING,
+    };
+
+  public:
+    /**
+     * Called shortly if the geometry indices or vertex buffers are changed.
+     * @return NotifyReturnType::STOP_OBSERVING if we will not observe this object after this called
+     *         NotifyReturnType::KEEP_OBSERVING if we will observe this object after this called.
+     */
+    virtual NotifyReturnType GeometryBufferChanged(const Geometry* geometry) = 0;
+
     /**
-     * Called shortly before the program is destroyed.
+     * Called shortly before the geometry is destroyed.
      */
-    virtual void GeometryDestroyed(const Geometry* program) = 0;
+    virtual void GeometryDestroyed(const Geometry* geometry) = 0;
 
   protected:
     /**
index bfbbe2f0f4c210b1a3035e77927c4733937a05d8..c81b5b1034325eb3a904a9fb4da8b09593a644e0 100644 (file)
@@ -205,6 +205,12 @@ void Renderer::Initialize(Graphics::Controller& graphicsController, ProgramCache
   mShaderCache          = &shaderCache;
   mUniformBufferManager = &uniformBufferManager;
   mPipelineCache        = &pipelineCache;
+
+  // Add Observer now
+  if(mGeometry)
+  {
+    mGeometry->AddLifecycleObserver(*this);
+  }
 }
 
 Renderer::~Renderer()
@@ -215,18 +221,38 @@ Renderer::~Renderer()
     mPipelineCache->ResetPipeline(mPipeline);
     mPipelineCached = false;
   }
+
+  // Stop observing
+  if(mGeometry)
+  {
+    mGeometry->RemoveLifecycleObserver(*this);
+    mGeometry = nullptr;
+  }
 }
 
 void Renderer::SetGeometry(Render::Geometry* geometry)
 {
-  mGeometry = geometry;
-  mUpdated  = true;
-
-  // Reset old pipeline
-  if(DALI_LIKELY(mPipelineCached))
+  if(mGeometry != geometry)
   {
-    mPipelineCache->ResetPipeline(mPipeline);
-    mPipelineCached = false;
+    if(mGeometry)
+    {
+      mGeometry->RemoveLifecycleObserver(*this);
+    }
+
+    mGeometry = geometry;
+
+    if(mGeometry)
+    {
+      mGeometry->AddLifecycleObserver(*this);
+    }
+
+    // Reset old pipeline
+    if(DALI_LIKELY(mPipelineCached))
+    {
+      mPipelineCache->ResetPipeline(mPipeline);
+      mPipelineCached = false;
+    }
+    mUpdated  = true;
   }
 }
 void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size)
@@ -950,6 +976,27 @@ bool Renderer::Updated(BufferIndex bufferIndex, const SceneGraph::NodeDataProvid
   return false;
 }
 
+Geometry::LifecycleObserver::NotifyReturnType Renderer::GeometryBufferChanged(const Geometry* geometry)
+{
+  DALI_ASSERT_ALWAYS(mGeometry == geometry && "Something wrong happend when Render::Renderer observed by geometry!");
+
+  // Reset old pipeline
+  if(DALI_LIKELY(mPipelineCached))
+  {
+    mPipelineCache->ResetPipeline(mPipeline);
+    mPipelineCached = false;
+  }
+
+  return Geometry::LifecycleObserver::NotifyReturnType::KEEP_OBSERVING;
+}
+
+void Renderer::GeometryDestroyed(const Geometry* geometry)
+{
+  // Let just run the same logic with geometry buffer changed cases.
+  [[maybe_unused]] auto ret = GeometryBufferChanged(geometry);
+  mGeometry                 = nullptr;
+}
+
 Graphics::Pipeline& Renderer::PrepareGraphicsPipeline(
   Program&                                             program,
   const Dali::Internal::SceneGraph::RenderInstruction& instruction,
index 468d54989fca467f6da62adc23b0d9e15c13d537..dff79970b22731312e8ee84b3b1370479860cc5a 100644 (file)
@@ -69,7 +69,7 @@ using PipelineCachePtr         = PipelineCacheL2Container::iterator;
  * These objects are used during RenderManager::Render(), so properties modified during
  * the Update must either be double-buffered, or set via a message added to the RenderQueue.
  */
-class Renderer
+class Renderer : public Geometry::LifecycleObserver
 {
 public:
   /**
@@ -454,6 +454,17 @@ public:
     return mFaceCullingMode;
   }
 
+public: // From Geometry::LifecycleObserver
+  /**
+   * @copydoc Dali::Internal::Geometry::LifecycleObserver::GeometryBufferChanged()
+   */
+  Geometry::LifecycleObserver::NotifyReturnType GeometryBufferChanged(const Geometry* geometry);
+
+  /**
+   * @copydoc Dali::Internal::Geometry::LifecycleObserver::GeometryDestroyed()
+   */
+  void GeometryDestroyed(const Geometry* geometry);
+
 private:
   struct UniformIndexMap;