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>
{
level0node.geometry->RemoveLifecycleObserver(*this);
}
+ level0nodes.clear();
}
PipelineResult PipelineCache::GetPipeline(const PipelineCacheQueryInfo& queryInfo, bool createNewIfNotFound)
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.
#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
{
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()
*/
}
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;
+ }
}
}
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:
/**
mProgramCache = &programCache;
mUniformBufferManager = &uniformBufferManager;
mPipelineCache = &pipelineCache;
+
+ // Add Observer now
+ if(mGeometry)
+ {
+ mGeometry->AddLifecycleObserver(*this);
+ }
}
Renderer::~Renderer()
mPipelineCache->ResetPipeline(mPipeline);
mPipelineCached = false;
}
+
+ // Stop observing
+ if(mGeometry)
+ {
+ mGeometry->RemoveLifecycleObserver(*this);
+ mGeometry = nullptr;
+ }
}
void Renderer::operator delete(void* ptr)
void Renderer::SetGeometry(Render::Geometry* geometry)
{
- mGeometry = geometry;
-
- // 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;
+ }
}
}
}
}
+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;
+}
+
Vector4 Renderer::GetTextureUpdateArea() const noexcept
{
Vector4 result = Vector4::ZERO;
* 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:
/**
*/
Vector4 GetTextureUpdateArea() const noexcept;
+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;