Add RenderEffect.OnRefresh() 79/317879/13
authorjmm <j0064423.lee@samsung.com>
Thu, 9 Jan 2025 08:11:44 +0000 (17:11 +0900)
committerjmm <j0064423.lee@samsung.com>
Mon, 24 Feb 2025 01:58:05 +0000 (10:58 +0900)
Redraw effect without recreating duplicated resources

Change-Id: Ie3c7d88e9a661b5bd35a41f90e8b93ab014d5649

automated-tests/src/dali-toolkit-internal/utc-Dali-RenderEffect-internal.cpp
automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp
dali-toolkit/internal/controls/render-effects/blur-effect-impl.h
dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.cpp
dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.h
dali-toolkit/internal/controls/render-effects/render-effect-impl.cpp
dali-toolkit/internal/controls/render-effects/render-effect-impl.h

index a6b9c531b401f02248a8dd688d4f0f043bec5593..821572a6b4826426afdcbfb589722865ad5a1919 100644 (file)
@@ -99,6 +99,10 @@ protected:
     mOnActivated = false;
   }
 
+  void OnRefresh() override
+  {
+  }
+
 public:
   Dali::Toolkit::Control GetOwnerControl() const
   {
index fe57062ac3687f77738bbd4162150127aa497d2f..522898cf3040704fc0e45fe895e2616b6adae484 100644 (file)
@@ -1518,6 +1518,11 @@ int UtcDaliControlOffScreenRendering(void)
   application.SendNotification();
   application.Render();
 
+  control.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 200.0f));
+  tet_infoline("Size set");
+  application.SendNotification();
+  application.Render();
+
   control.SetProperty(DevelControl::Property::OFFSCREEN_RENDERING, DevelControl::OffScreenRenderingType::NONE);
   DALI_TEST_EQUALS(control.GetProperty(DevelControl::Property::OFFSCREEN_RENDERING).Get<int>(), (int)DevelControl::OffScreenRenderingType::NONE, TEST_LOCATION);
   tet_infoline("Turn off offscreen rendering");
index 1e435af89ab9e6a971774f280a5ad45b6b16a33d..dc2dfc44b719c3269127ba23f33994ea1b37394a 100644 (file)
@@ -1703,22 +1703,26 @@ void Control::Impl::SetOffScreenRendering(int32_t offScreenRenderingType)
   }
 
   DevelControl::OffScreenRenderingType newType = static_cast<DevelControl::OffScreenRenderingType>(offScreenRenderingType);
-  if(newType != mOffScreenRenderingType)
+  if(newType == DevelControl::OffScreenRenderingType::NONE)
   {
-    // update type
-    mOffScreenRenderingType = newType;
-
-    // update effect
     if(mOffScreenRenderingImpl)
     {
       mOffScreenRenderingImpl->ClearOwnerControl();
       mOffScreenRenderingImpl.reset();
     }
-    mOffScreenRenderingImpl = std::make_unique<OffScreenRenderingImpl>(mOffScreenRenderingType);
+  }
+  else if(mOffScreenRenderingType == DevelControl::OffScreenRenderingType::NONE)
+  {
+    mOffScreenRenderingImpl = std::make_unique<OffScreenRenderingImpl>(newType);
 
     Dali::Toolkit::Control handle(mControlImpl.GetOwner());
     mOffScreenRenderingImpl->SetOwnerControl(handle);
   }
+  else
+  {
+    mOffScreenRenderingImpl->SetType(newType);
+  }
+  mOffScreenRenderingType = newType;
 }
 
 void Control::Impl::SetCornerRadius(Vector4 vector, Toolkit::Visual::Transform::Policy::Type policy)
index d3321262d88a5ee97a50322349eb83d6e47689a7..c7962b3b9fd2045b877ba890897b60e6f53d4400 100644 (file)
@@ -271,7 +271,7 @@ void BlurEffectImpl::OnActivate()
   mVerticalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight));
 
   // Set blur
-  CreateFrameBuffers(size, ImageDimensions(downsampledWidth, downsampledHeight));
+  CreateFrameBuffers(ImageDimensions(downsampledWidth, downsampledHeight));
   CreateRenderTasks(GetSceneHolder(), ownerControl);
   SetShaderConstants(downsampledWidth, downsampledHeight);
 
@@ -286,7 +286,7 @@ void BlurEffectImpl::OnActivate()
     renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Dali::Toolkit::DepthIndex::CONTENT);
   }
   ownerControl.AddRenderer(renderer);
-  SetRendererTexture(renderer, mSourceFrameBuffer);
+  SetRendererTexture(renderer, mBlurredOutputFrameBuffer);
 
   ownerControl.Add(mInternalRoot);
 
@@ -312,25 +312,39 @@ void BlurEffectImpl::OnDeactivate()
 
   mInternalRoot.Unparent();
 
-  mInputBackgroundFrameBuffer.Reset();
-  mTemporaryFrameBuffer.Reset();
-  mSourceFrameBuffer.Reset();
+  DestroyFrameBuffers();
+  DestroyRenderTasks();
+}
 
-  auto sceneHolder = GetSceneHolder();
-  if(DALI_LIKELY(sceneHolder))
+void BlurEffectImpl::OnRefresh()
+{
+  if(DALI_UNLIKELY(mSkipBlur))
   {
-    RenderTaskList taskList = sceneHolder.GetRenderTaskList();
-    taskList.RemoveTask(mHorizontalBlurTask);
-    taskList.RemoveTask(mVerticalBlurTask);
-    taskList.RemoveTask(mSourceRenderTask);
+    return;
   }
 
-  mHorizontalBlurTask.Reset();
-  mVerticalBlurTask.Reset();
-  mSourceRenderTask.Reset();
+  mInputBackgroundFrameBuffer.Reset();
+  mTemporaryFrameBuffer.Reset();
+  mBlurredOutputFrameBuffer.Reset();
+
+  Vector2  size              = GetTargetSize();
+  uint32_t downsampledWidth  = std::max(static_cast<uint32_t>(size.width * mDownscaleFactor), 1u);
+  uint32_t downsampledHeight = std::max(static_cast<uint32_t>(size.height * mDownscaleFactor), 1u);
+
+  // Set size
+  mRenderDownsampledCamera.SetPerspectiveProjection(Size(downsampledWidth, downsampledHeight));
+  mHorizontalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight));
+  mVerticalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight));
+
+  CreateFrameBuffers(ImageDimensions(downsampledWidth, downsampledHeight));
+  SetShaderConstants(downsampledWidth, downsampledHeight);
+
+  mSourceRenderTask.SetFrameBuffer(mInputBackgroundFrameBuffer);
+  mHorizontalBlurTask.SetFrameBuffer(mTemporaryFrameBuffer);
+  mVerticalBlurTask.SetFrameBuffer(mBlurredOutputFrameBuffer);
 }
 
-void BlurEffectImpl::CreateFrameBuffers(const Vector2 size, const ImageDimensions downsampledSize)
+void BlurEffectImpl::CreateFrameBuffers(const ImageDimensions downsampledSize)
 {
   uint32_t downsampledWidth  = downsampledSize.GetWidth();
   uint32_t downsampledHeight = downsampledSize.GetHeight();
@@ -346,9 +360,16 @@ void BlurEffectImpl::CreateFrameBuffers(const Vector2 size, const ImageDimension
   mTemporaryFrameBuffer.AttachColorTexture(temporaryTexture);
 
   // buffer to draw blurred output
-  mSourceFrameBuffer    = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::DEPTH_STENCIL);
-  Texture sourceTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
-  mSourceFrameBuffer.AttachColorTexture(sourceTexture);
+  mBlurredOutputFrameBuffer = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::DEPTH_STENCIL);
+  Texture sourceTexture     = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
+  mBlurredOutputFrameBuffer.AttachColorTexture(sourceTexture);
+}
+
+void BlurEffectImpl::DestroyFrameBuffers()
+{
+  mInputBackgroundFrameBuffer.Reset();
+  mTemporaryFrameBuffer.Reset();
+  mBlurredOutputFrameBuffer.Reset();
 }
 
 void BlurEffectImpl::CreateRenderTasks(Integration::SceneHolder sceneHolder, const Toolkit::Control sourceControl)
@@ -387,13 +408,29 @@ void BlurEffectImpl::CreateRenderTasks(Integration::SceneHolder sceneHolder, con
   mVerticalBlurTask.SetExclusive(true);
   mVerticalBlurTask.SetInputEnabled(false);
   mVerticalBlurTask.SetCameraActor(mRenderDownsampledCamera);
-  mVerticalBlurTask.SetFrameBuffer(mSourceFrameBuffer);
+  mVerticalBlurTask.SetFrameBuffer(mBlurredOutputFrameBuffer);
 
   // Clear sourceTexture as Transparent.
   mVerticalBlurTask.SetClearEnabled(true);
   mVerticalBlurTask.SetClearColor(Color::TRANSPARENT);
 }
 
+void BlurEffectImpl::DestroyRenderTasks()
+{
+  auto sceneHolder = GetSceneHolder();
+  if(DALI_LIKELY(sceneHolder))
+  {
+    RenderTaskList taskList = sceneHolder.GetRenderTaskList();
+    taskList.RemoveTask(mHorizontalBlurTask);
+    taskList.RemoveTask(mVerticalBlurTask);
+    taskList.RemoveTask(mSourceRenderTask);
+  }
+
+  mHorizontalBlurTask.Reset();
+  mVerticalBlurTask.Reset();
+  mSourceRenderTask.Reset();
+}
+
 void BlurEffectImpl::ApplyRenderTaskSourceActor(RenderTask sourceRenderTask, const Toolkit::Control sourceControl)
 {
   if(DALI_UNLIKELY(!sourceRenderTask || !sourceControl))
index 655b1847145ed16873b543527ef88c88bef51719..5c895672a5e3f9634c79cf1be0a053f60a1ce923 100644 (file)
@@ -118,14 +118,23 @@ protected:
    */
   void OnDeactivate() override;
 
+  /**
+   * @brief Redraw effect without deactivation
+   */
+  void OnRefresh() override;
+
 private:
   // Inner functions
   /**
    * @brief Sets frame buffers to draw blurred output.
-   * @param[in] size Full size of input.
    * @param[in] downsampledSize Downsampled size for performance.
    */
-  void CreateFrameBuffers(const Vector2 size, const ImageDimensions downsampledSize);
+  void CreateFrameBuffers(const ImageDimensions downsampledSize);
+
+  /**
+   * @brief Removes and destroys local frame buffers.
+   */
+  void DestroyFrameBuffers();
 
   /**
    * @brief Sets blur render tasks.
@@ -135,6 +144,11 @@ private:
    */
   void CreateRenderTasks(Integration::SceneHolder sceneHolder, const Toolkit::Control sourceControl);
 
+  /**
+   * @brief Removes and destroys local render tasks.
+   */
+  void DestroyRenderTasks();
+
   /**
    * @brief Apply render tasks source actor, and some other options.
    * @param[in] renderTask Target render task to change source actor and exclusiveness
@@ -182,7 +196,7 @@ private:
   Actor       mVerticalBlurActor;
   RenderTask  mVerticalBlurTask;
 
-  FrameBuffer mSourceFrameBuffer; // Output. Blurred background texture for mOwnerControl and mRenderer.
+  FrameBuffer mBlurredOutputFrameBuffer;
   RenderTask  mSourceRenderTask;
 
   // Variables
index 58b12c07e384a15e9a23dccb755d0066e25817b9..23217b524ccf397fbb5452829fb06a02d1a406b6 100644 (file)
@@ -37,6 +37,23 @@ OffScreenRenderingImpl::OffScreenRenderingImpl(DevelControl::OffScreenRenderingT
   Initialize();
 }
 
+void OffScreenRenderingImpl::SetType(DevelControl::OffScreenRenderingType type)
+{
+  mType = type;
+
+  if(mRenderTask)
+  {
+    if(mType == DevelControl::OffScreenRenderingType::REFRESH_ALWAYS)
+    {
+      mRenderTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+    }
+    else if(mType == DevelControl::OffScreenRenderingType::REFRESH_ONCE)
+    {
+      mRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+    }
+  }
+}
+
 RenderEffectImplPtr OffScreenRenderingImpl::Clone() const
 {
   DALI_LOG_ERROR("Cloning offscreen rendering is not allowed.\n");
@@ -63,17 +80,60 @@ void OffScreenRenderingImpl::OnActivate()
     return;
   }
 
-  // Create resources
+  CreateFrameBuffer();
+  CreateRenderTask();
+  SetType(mType);
+
+  Renderer renderer = GetTargetRenderer();
+  SetRendererTexture(renderer, mFrameBuffer);
+
   Toolkit::Control control = GetOwnerControl();
-  const Size       size    = GetTargetSize();
+  control.GetImplementation().SetCacheRenderer(renderer);
+  control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::FORWARD);
+}
+
+void OffScreenRenderingImpl::OnDeactivate()
+{
+  Toolkit::Control control = GetOwnerControl();
+  if(DALI_LIKELY(control))
+  {
+    control.GetImplementation().RemoveCacheRenderer();
+    control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::NONE);
+  }
+
+  DestroyFrameBuffer();
+  DestroyRenderTask();
+}
+
+void OffScreenRenderingImpl::OnRefresh()
+{
+  DestroyFrameBuffer();
+
+  CreateFrameBuffer();
+  mRenderTask.SetFrameBuffer(mFrameBuffer);
+}
+
+void OffScreenRenderingImpl::CreateFrameBuffer()
+{
+  const Size size = GetTargetSize();
 
   mFrameBuffer    = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
   Texture texture = Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, size.width, size.height);
   mFrameBuffer.AttachColorTexture(texture);
+}
+
+void OffScreenRenderingImpl::DestroyFrameBuffer()
+{
+  mFrameBuffer.Reset();
+}
 
+void OffScreenRenderingImpl::CreateRenderTask()
+{
+  Toolkit::Control         control     = GetOwnerControl();
   Integration::SceneHolder sceneHolder = GetSceneHolder();
   RenderTaskList           taskList    = sceneHolder.GetRenderTaskList();
-  mRenderTask                          = taskList.CreateTask();
+
+  mRenderTask = taskList.CreateTask();
   mRenderTask.SetSourceActor(control);
   mRenderTask.SetCameraActor(GetCameraActor());
   mRenderTask.SetExclusive(true);
@@ -81,33 +141,10 @@ void OffScreenRenderingImpl::OnActivate()
   mRenderTask.SetFrameBuffer(mFrameBuffer);
   mRenderTask.SetClearEnabled(true);
   mRenderTask.SetClearColor(sceneHolder.GetBackgroundColor());
-
-  Renderer renderer = GetTargetRenderer();
-  SetRendererTexture(renderer, mFrameBuffer);
-
-  control.GetImplementation().SetCacheRenderer(renderer);
-  control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::FORWARD);
-
-  // Set refresh rate
-  if(mType == DevelControl::OffScreenRenderingType::REFRESH_ALWAYS)
-  {
-    mRenderTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
-  }
-  else if(mType == DevelControl::OffScreenRenderingType::REFRESH_ONCE)
-  {
-    mRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
-  }
 }
 
-void OffScreenRenderingImpl::OnDeactivate()
+void OffScreenRenderingImpl::DestroyRenderTask()
 {
-  Toolkit::Control control = GetOwnerControl();
-  if(DALI_LIKELY(control))
-  {
-    control.GetImplementation().RemoveCacheRenderer();
-    control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::NONE);
-  }
-
   auto sceneHolder = GetSceneHolder();
   if(DALI_LIKELY(sceneHolder))
   {
@@ -115,7 +152,6 @@ void OffScreenRenderingImpl::OnDeactivate()
     taskList.RemoveTask(mRenderTask);
   }
 
-  mFrameBuffer.Reset();
   mRenderTask.Reset();
 }
 
index 16034d7611dc42f9c3f0f729c1bdb51d4c4e8f50..3e986aa86903a08b82560717ced05fc41b1bccbb 100644 (file)
@@ -40,18 +40,60 @@ namespace Toolkit
 {
 namespace Internal
 {
+/**
+ * @brief This effect renders all children(including self) at off screen framebuffer.
+ * This effect is handleless, so initiate an instance through setting DevelControl::Property::OFFSCREEN_RENDERING
+ * The instance will be saved internally, thus outer modification is impossible.
+ */
 class OffScreenRenderingImpl : public RenderEffectImpl
 {
 public:
+  /**
+   * @brief Constructor
+   * @param[in] type Defines whether effect is enabled or not, and its refresh rate
+   */
   OffScreenRenderingImpl(DevelControl::OffScreenRenderingType type);
-  RenderEffectImplPtr       Clone() const override;
+  /**
+   * @brief Set OffScreenRenderingType explicitly
+   * @param[in] type Defines whether effect is enabled or not, and its refresh rate
+   */
+  void SetType(DevelControl::OffScreenRenderingType type);
+
+  // @copydoc Dali::Toolkit::Internal::RenderEffectImpl::Clone
+  RenderEffectImplPtr Clone() const override;
+  // @copydoc Dali::Toolkit::Internal::RenderEffectImpl::GetOffScreenRenderableType
   OffScreenRenderable::Type GetOffScreenRenderableType() override;
-  void                      GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward) override;
+  // @copydoc Dali::Toolkit::Internal::RenderEffectImpl::GetOffScreenRenderTasks
+  void GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward) override;
 
 protected:
+  // @copydoc Dali::Toolkit::Internal::RenderEffectImpl::OnInitialize
   void OnInitialize() override;
+  // @copydoc Dali::Toolkit::Internal::RenderEffectImpl::OnActivate
   void OnActivate() override;
+  // @copydoc Dali::Toolkit::Internal::RenderEffectImpl::OnDeactivate
   void OnDeactivate() override;
+  // @copydoc Dali::Toolkit::Internal::RenderEffectImpl::OnRefresh
+  void OnRefresh() override;
+
+private:
+  /**
+   * @brief Initializes off screen buffer to draw subtree
+   */
+  void CreateFrameBuffer();
+  /**
+   * @brief
+   */
+  void DestroyFrameBuffer();
+
+  /**
+   * @brief Initializes render task for offscreen rendering
+   */
+  void CreateRenderTask();
+  /**
+   * @brief
+   */
+  void DestroyRenderTask();
 
 private:
   RenderTask                           mRenderTask;
index 6139943d37c0e55f75293d5470cfc472234b2785..a74a132c2efc1971ca2bc7d512ccbf8912351da6 100644 (file)
@@ -125,11 +125,25 @@ bool RenderEffectImpl::IsActivated() const
 
 void RenderEffectImpl::Initialize()
 {
-  mCamera = CameraActor::New();
-  mCamera.SetInvertYAxis(true);
-  mCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-  mCamera.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  mCamera.SetType(Dali::Camera::FREE_LOOK);
+  if(!mCamera)
+  {
+    mCamera = CameraActor::New();
+    mCamera.SetInvertYAxis(true);
+    mCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+    mCamera.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+    mCamera.SetType(Dali::Camera::FREE_LOOK);
+  }
+
+  if(!mRenderer)
+  {
+    mRenderer = CreateRenderer(SHADER_RENDER_EFFECT_VERT, SHADER_RENDER_EFFECT_FRAG);
+    mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true); // Always use pre-multiply alpha
+
+    Shader shader = mRenderer.GetShader();
+    shader.RegisterProperty("uCornerRadius", Vector4::ZERO);
+    shader.RegisterProperty("uCornerSquareness", Vector4::ZERO);
+    shader.RegisterProperty("uCornerRadiusPolicy", static_cast<float>(1.0f));
+  }
 
   OnInitialize();
 }
@@ -177,17 +191,6 @@ void RenderEffectImpl::Activate()
     }
     mPlacementSceneHolder = sceneHolder;
 
-    if(!mRenderer)
-    {
-      mRenderer = CreateRenderer(SHADER_RENDER_EFFECT_VERT, SHADER_RENDER_EFFECT_FRAG);
-      mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true); // Always use pre-multiply alpha
-
-      Shader shader = mRenderer.GetShader();
-      shader.RegisterProperty("uCornerRadius", Vector4::ZERO);
-      shader.RegisterProperty("uCornerSquareness", Vector4::ZERO);
-      shader.RegisterProperty("uCornerRadiusPolicy", static_cast<float>(1.0f));
-    }
-
     Vector2 size = GetTargetSize();
     if(size != Vector2::ZERO)
     {
@@ -299,8 +302,8 @@ void RenderEffectImpl::OnSizeSet(PropertyNotification& source)
     if(mTargetSize != targetSize && IsActivated())
     {
       UpdateTargetSize();
-      Deactivate();
-      Activate();
+      mCamera.SetPerspectiveProjection(GetTargetSize());
+      OnRefresh();
     }
   }
 }
index 43afef9bbb63e1fb06886af8f9ae517597b856e6..acd1b946bd7596ee3ee632d40256b48308b17cb8 100644 (file)
@@ -160,6 +160,12 @@ protected:
    */
   virtual void OnDeactivate() = 0;
 
+  /**
+   * @brief Redraws effect without deactivation
+   * @note Assumes activation
+   */
+  virtual void OnRefresh() = 0;
+
 private:
   /**
    * @brief Activates effect on ownerControl