Add render effect blur strength animation 84/321984/22
authorjmm <j0064423.lee@samsung.com>
Thu, 3 Apr 2025 10:33:35 +0000 (19:33 +0900)
committerjmm <j0064423.lee@samsung.com>
Wed, 16 Apr 2025 08:38:35 +0000 (17:38 +0900)
Change-Id: I29d4babfdc95b7d85a8cd7bb59656d8f9bfddfaa
Signed-off-by: jmm <j0064423.lee@samsung.com>
16 files changed:
automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
automated-tests/src/dali-toolkit/utc-Dali-RenderEffect.cpp
dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp [deleted file]
dali-toolkit/internal/controls/render-effects/blur-effect-impl.h [deleted file]
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
dali-toolkit/internal/file.list
dali-toolkit/internal/graphics/shaders/blur-effect.frag
dali-toolkit/public-api/controls/render-effects/background-blur-effect.cpp
dali-toolkit/public-api/controls/render-effects/background-blur-effect.h
dali-toolkit/public-api/controls/render-effects/render-effect.cpp
dali-toolkit/public-api/controls/render-effects/render-effect.h

index f8d749eebfb1a5547f1d45cc357cac67e2742e0a..46ce1c0e6e008fd3cfd7f8e31d5e54506693581b 100644 (file)
@@ -1569,6 +1569,13 @@ int UtcDaliControlOffScreenRenderingSizeSet(void)
   DALI_TEST_EQUALS(control.GetProperty(Actor::Property::SIZE).Get<Vector2>(), Vector2::ZERO, TEST_LOCATION);
   tet_infoline("Size update: a valid size to zero");
 
+  control.SetProperty(DevelControl::Property::OFFSCREEN_RENDERING, DevelControl::OffScreenRenderingType::NONE);
+  control.SetProperty(Actor::Property::SIZE, Vector2(50.0f, 50.0f));
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(control.GetProperty(Actor::Property::SIZE).Get<Vector2>(), Vector2(50.0f, 50.0f), TEST_LOCATION);
+  tet_infoline("Size update when type NONE");
+
   END_TEST;
 }
 
@@ -1634,7 +1641,7 @@ int UtcDaliControlCornerRadius(void)
 
   application.GetScene().Add(control);
 
-  RenderEffect effect = BackgroundBlurEffect::New(0.25f, 50.0f);
+  RenderEffect effect = BackgroundBlurEffect::New(50.0f);
   control.SetRenderEffect(effect);
   control.SetProperty(DevelControl::Property::OFFSCREEN_RENDERING, DevelControl::OffScreenRenderingType::REFRESH_ALWAYS);
 
index 49655ecfbd9f4611cf213d9ce5207413400bf196..01e7293e36e94b93934fdba49af9b6616a613a2f 100644 (file)
@@ -33,7 +33,7 @@ int UtcDaliRenderEffectNewP(void)
   RenderEffect blurEffect = BackgroundBlurEffect::New();
   DALI_TEST_CHECK(blurEffect);
 
-  RenderEffect blurEffect2 = BackgroundBlurEffect::New(0.5f, 10);
+  RenderEffect blurEffect2 = BackgroundBlurEffect::New(10);
   DALI_TEST_CHECK(blurEffect2);
 
   Control control = Control::New();
@@ -60,15 +60,13 @@ int UtcDaliRenderEffectNewN(void)
 
   tet_printf("Check some invalid parameters clamp internally\n");
 
-  RenderEffect blurEffect  = BackgroundBlurEffect::New(-0.5f, 10);
-  RenderEffect blurEffect2 = BackgroundBlurEffect::New(10.0f, 10);
-  RenderEffect blurEffect3 = BackgroundBlurEffect::New(0.5f, 0);
-  RenderEffect blurEffect4 = BackgroundBlurEffect::New(0.5f, 2147483647);
+  RenderEffect blurEffect1 = BackgroundBlurEffect::New(10);
+  RenderEffect blurEffect2 = BackgroundBlurEffect::New(0);
+  RenderEffect blurEffect3 = BackgroundBlurEffect::New(2147483647);
 
-  DALI_TEST_CHECK(blurEffect);
+  DALI_TEST_CHECK(blurEffect1);
   DALI_TEST_CHECK(blurEffect2);
   DALI_TEST_CHECK(blurEffect3);
-  DALI_TEST_CHECK(blurEffect4);
 
   END_TEST;
 }
@@ -149,7 +147,7 @@ int UtcDaliRenderEffectActivateP03(void)
   control.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f));
   scene.Add(control);
 
-  Control newControl = Control::New();
+  Control      newControl = Control::New();
   RenderEffect maskEffect = MaskEffect::New(newControl);
   control.SetRenderEffect(maskEffect);
 
@@ -193,7 +191,7 @@ int UtcDaliRenderEffectDeactivateP(void)
   DALI_TEST_EQUALS(count, control.GetRendererCount(), TEST_LOCATION);
 
   Control newControl = Control::New();
-  count = control.GetRendererCount();
+  count              = control.GetRendererCount();
   control.SetRenderEffect(MaskEffect::New(newControl));
 
   taskList = scene.GetRenderTaskList();
@@ -244,10 +242,10 @@ int UtcDaliRenderEffectActivateDeactivateInplace(void)
   RenderTaskList taskList = scene.GetRenderTaskList();
   DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION);
 
-  control.ClearRenderEffect();
-  control.SetRenderEffect(blurEffect);
-  control.ClearRenderEffect();
-  control.SetRenderEffect(blurEffect);
+  blurEffect.Deactivate();
+  DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION);
+
+  blurEffect.Activate();
   DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION);
 
   END_TEST;
@@ -284,18 +282,60 @@ int UtcDaliRenderEffectResize(void)
   Control            control = Control::New();
   control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
   scene.Add(control);
+
+  RenderTaskList taskList = scene.GetRenderTaskList();
+  DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION);
+  uint32_t count = control.GetRendererCount();
+  DALI_TEST_EQUALS(count, control.GetRendererCount(), TEST_LOCATION);
+
+  ////////////////////////////////////////////
   control.SetRenderEffect(BackgroundBlurEffect::New());
 
   application.SendNotification();
   application.Render();
 
+  DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(count, control.GetRendererCount(), TEST_LOCATION);
+  tet_infoline("size zero owner control's effect is not activated.");
+
   control.SetProperty(Actor::Property::SIZE, Vector2(30.0f, 30.0f));
 
+  application.SendNotification();
+  application.Render();
   application.SendNotification();
   application.Render();
 
+  DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(count + 1, control.GetRendererCount(), TEST_LOCATION);
+
   DALI_TEST_EQUALS(control.GetProperty<float>(Actor::Property::SIZE_WIDTH), 30.0f, TEST_LOCATION);
   DALI_TEST_EQUALS(control.GetProperty<float>(Actor::Property::SIZE_HEIGHT), 30.0f, TEST_LOCATION);
+  tet_infoline("Background blur effect activated.\n");
+
+  control.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
+
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(control.GetProperty<float>(Actor::Property::SIZE_WIDTH), 10.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(control.GetProperty<float>(Actor::Property::SIZE_HEIGHT), 10.0f, TEST_LOCATION);
+  tet_infoline("Background blur effect refreshed.\n");
+
+  control.SetProperty(Actor::Property::SIZE, Vector2(0.0f, 0.0f));
+
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(count, control.GetRendererCount(), TEST_LOCATION);
+
+  DALI_TEST_EQUALS(control.GetProperty<float>(Actor::Property::SIZE_WIDTH), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(control.GetProperty<float>(Actor::Property::SIZE_HEIGHT), 0.0f, TEST_LOCATION);
+  tet_infoline("Background blur effect deactivated.\n");
 
   END_TEST;
 }
@@ -314,7 +354,7 @@ int UtcDaliRenderEffectSynchronizeControlCornerRadius(void)
   blackDimmerMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 0.20f);
   blackDimmerMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::Type::RELATIVE);
   blackDimmerMap.Insert(Toolkit::DevelVisual::Property::CORNER_SQUARENESS, 0.3f);
-  RenderEffect effect = BackgroundBlurEffect::New(0.4f, 40);
+  RenderEffect effect = BackgroundBlurEffect::New(40);
 
   Control control = Control::New();
   DALI_TEST_CHECK(control.GetRendererCount() == 0u);
@@ -367,7 +407,7 @@ int UtcDaliRenderEffectInvalidTargetSize(void)
   control.SetProperty(Actor::Property::SIZE_WIDTH, maxTextureSize + 1000.0f);
   control.SetProperty(Actor::Property::SIZE_HEIGHT, maxTextureSize + 1000.0f);
   scene.Add(control);
-  control.SetRenderEffect(BackgroundBlurEffect::New(0.4f, 40));
+  control.SetRenderEffect(BackgroundBlurEffect::New(40));
 
   application.SendNotification();
   application.Render();
@@ -869,22 +909,47 @@ int UtcDaliRenderEffectReInitialize(void)
   tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex());
   DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION);
 
-  control.SetRenderEffect(BackgroundBlurEffect::New());
+  BackgroundBlurEffect effect = BackgroundBlurEffect::New(40u);
+  control.SetRenderEffect(effect);
+  DALI_TEST_EQUALS(effect.GetBlurRadius(), 40u, TEST_LOCATION);
+
+  application.SendNotification();
+
+  // Render effect activated.
+  DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION);
+  tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex());
+  DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION);
 
+  effect.SetBlurRadius(20u);
   application.SendNotification();
 
   // Render effect activated.
   DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION);
   tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex());
   DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION);
+  DALI_TEST_EQUALS(effect.GetBlurRadius(), 20u, TEST_LOCATION);
+
+  effect.SetBlurRadius(2u); // invalid blur radius value(too small)
+  application.SendNotification();
+
+  DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(effect.GetBlurRadius(), 2u, TEST_LOCATION);
 
   END_TEST;
 }
 
+namespace
+{
+void BlurRenderingFinishedCallback(void)
+{
+  tet_infoline("blur rendering finished signal emitted");
+}
+} // namespace
+
 int UtcDaliRenderEffectBlurOnce(void)
 {
   ToolkitTestApplication application;
-  tet_infoline("UtcDaliRenderEffectBlurOnce with background blur effect");
+  tet_infoline("UtcDaliRenderEffectBlurOnce");
 
   Integration::Scene scene = application.GetScene();
 
@@ -895,7 +960,13 @@ int UtcDaliRenderEffectBlurOnce(void)
   scene.Add(control);
 
   // Add render effect during scene on.
-  control.SetRenderEffect(BackgroundBlurEffect::New(0.5f, 20u, true));
+  BackgroundBlurEffect effect = BackgroundBlurEffect::New(20u);
+  DALI_TEST_EQUALS(effect.GetBlurOnce(), false, TEST_LOCATION);
+
+  effect.SetBlurOnce(true);
+  effect.FinishedSignal().Connect(&application, &BlurRenderingFinishedCallback);
+  control.SetRenderEffect(effect);
+  DALI_TEST_EQUALS(effect.GetBlurOnce(), true, TEST_LOCATION);
 
   application.SendNotification();
 
@@ -906,6 +977,13 @@ int UtcDaliRenderEffectBlurOnce(void)
   tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex());
   DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION);
 
+  effect.SetBlurOnce(false);
+  DALI_TEST_EQUALS(effect.GetBlurOnce(), false, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION);
+  tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex());
+  DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION);
+
   END_TEST;
 }
 
@@ -948,6 +1026,39 @@ int UtcDaliMaskEffect(void)
   END_TEST;
 }
 
+int UtcDaliRenderEffectBlurStrengthAnimation(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectBlurStrengthAnimation");
+
+  Integration::Scene scene = application.GetScene();
+
+  Control control = Control::New();
+  control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f));
+
+  BackgroundBlurEffect effect = BackgroundBlurEffect::New();
+  control.SetRenderEffect(effect);
+  scene.Add(control);
+
+  float     durationSeconds = 0.05f;
+  Animation animation       = Animation::New(durationSeconds);
+
+  effect.AddBlurStrengthAnimation(animation, AlphaFunction::BuiltinFunction::EASE_IN, TimePeriod(0, durationSeconds), 0.0f, 1.0f);
+  animation.Play();
+  application.SendNotification();
+  application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/);
+  animation.Clear();
+  DALI_TEST_EQUALS(effect.GetBlurOnce(), false, TEST_LOCATION);
+
+  effect.SetBlurOnce(true);
+  effect.AddBlurStrengthAnimation(animation, AlphaFunction::BuiltinFunction::EASE_IN, TimePeriod(0, durationSeconds), 0.0f, 1.0f);
+  // animation will not be added but cannot check
+  DALI_TEST_EQUALS(effect.GetBlurOnce(), true, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliMaskEffectScaleN(void)
 {
   ToolkitTestApplication application;
@@ -978,4 +1089,36 @@ int UtcDaliMaskEffectScaleN(void)
   DALI_TEST_EQUALS(3u, taskList.GetTaskCount(), TEST_LOCATION);
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliRenderEffectBlurOpacityAnimation(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectBlurOpacityAnimation");
+
+  Integration::Scene scene = application.GetScene();
+
+  Control control = Control::New();
+  control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f));
+
+  BackgroundBlurEffect effect = BackgroundBlurEffect::New();
+  control.SetRenderEffect(effect);
+  scene.Add(control);
+
+  float     durationSeconds = 0.05f;
+  Animation animation       = Animation::New(durationSeconds);
+
+  effect.AddBlurOpacityAnimation(animation, AlphaFunction::BuiltinFunction::EASE_IN, TimePeriod(0, durationSeconds), 0.0f, 1.0f);
+  animation.Play();
+  application.SendNotification();
+  application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/);
+  DALI_TEST_EQUALS(effect.GetBlurOnce(), false, TEST_LOCATION);
+
+  effect.SetBlurOnce(true);
+  effect.AddBlurOpacityAnimation(animation, AlphaFunction::BuiltinFunction::EASE_IN, TimePeriod(0, durationSeconds), 0.0f, 1.0f);
+  // animation will not be added but cannot check
+  DALI_TEST_EQUALS(effect.GetBlurOnce(), true, TEST_LOCATION);
+
+  END_TEST;
+}
diff --git a/dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.cpp b/dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.cpp
new file mode 100644 (file)
index 0000000..77f79f1
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * Copyright (c) 2025 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-toolkit/internal/controls/render-effects/background-blur-effect-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/custom-actor-impl.h>
+#include <dali/public-api/animation/key-frames.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+
+namespace
+{
+// Default values
+static constexpr float    BLUR_EFFECT_DOWNSCALE_FACTOR = 0.25f;
+static constexpr uint32_t BLUR_EFFECT_BLUR_RADIUS      = 10u;
+
+static constexpr float MINIMUM_DOWNSCALE_FACTOR = 0.1f;
+static constexpr float MAXIMUM_DOWNSCALE_FACTOR = 1.0f;
+
+static constexpr uint32_t MINIMUM_GPU_ARRAY_SIZE = 2u;   // GPU cannot handle array size smaller than 2.
+static constexpr uint32_t MAXIMUM_BLUR_RADIUS    = 500u; ///< Maximum pixel radius for blur effect. (GL_MAX_FRAGMENT_UNIFORM_COMPONENTS(Usually 1024) - 19 (vertex shader used)) / 3 float
+
+static constexpr float   MAXIMUM_BELL_CURVE_WIDTH            = 171.352f; ///< bell curve width for MAXIMUM_BLUR_RADIUS case
+static constexpr int32_t MAXIMUM_BELL_CURVE_LOOP_TRIAL_COUNT = 50;
+
+static constexpr std::string_view UNIFORM_BLUR_STRENGTH_NAME("uAnimationRatio");
+static constexpr std::string_view UNIFORM_BLUR_OPACITY_NAME("uOpacity");
+
+/**
+  * @brief Calculates gaussian weight
+  * @param[in] localOffset Input variable of gaussian distribution
+  * @param[in] sigma Standard deviation of gaussian distribution, the width of the "bell"
+  * @note Expected value of this gaussian distribution is 0.
+  */
+inline float CalculateGaussianWeight(float localOffset, float sigma)
+{
+  return (1.0f / (sigma * sqrt(2.0f * Dali::Math::PI))) * exp(-0.5f * (localOffset / sigma * localOffset / sigma));
+}
+
+/**
+ * @brief
+ * @return Downscaled(optimized) blur radius
+ */
+uint32_t FitBlurRadiusToValidRange(float& downscaleFactor, uint32_t& blurRadius)
+{
+  downscaleFactor = BLUR_EFFECT_DOWNSCALE_FACTOR;
+
+  if(DALI_UNLIKELY(blurRadius > MAXIMUM_BLUR_RADIUS))
+  {
+    const uint32_t fixedBlurRadius      = MAXIMUM_BLUR_RADIUS;
+    const float    fixedDownScaleFactor = Dali::Clamp(
+      downscaleFactor * static_cast<float>(fixedBlurRadius) / static_cast<float>(blurRadius),
+      MINIMUM_DOWNSCALE_FACTOR,
+      MAXIMUM_DOWNSCALE_FACTOR);
+
+    DALI_LOG_ERROR("Blur radius is out of bound: %u. Use %u and make downscale factor %f to %f.\n",
+                   blurRadius,
+                   fixedBlurRadius,
+                   downscaleFactor,
+                   fixedDownScaleFactor);
+
+    downscaleFactor = fixedDownScaleFactor;
+    blurRadius      = fixedBlurRadius;
+  }
+  return static_cast<uint32_t>(blurRadius * downscaleFactor);
+}
+} // namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+#ifdef DEBUG_ENABLED
+extern Debug::Filter* gRenderEffectLogFilter; ///< Define at render-effect-impl.cpp
+#endif
+
+BackgroundBlurEffectImpl::BackgroundBlurEffectImpl()
+: RenderEffectImpl(),
+  mInternalRoot(Actor::New()),
+  mDownscaleFactor(BLUR_EFFECT_DOWNSCALE_FACTOR),
+  mBlurRadius(BLUR_EFFECT_BLUR_RADIUS),
+  mDownscaledBlurRadius(static_cast<uint32_t>(BLUR_EFFECT_BLUR_RADIUS * BLUR_EFFECT_DOWNSCALE_FACTOR)),
+  mBellCurveWidth(Math::MACHINE_EPSILON_1),
+  mSkipBlur(false),
+  mBlurOnce(false)
+{
+}
+
+BackgroundBlurEffectImpl::BackgroundBlurEffectImpl(uint32_t blurRadius)
+: RenderEffectImpl(),
+  mInternalRoot(Actor::New()),
+  mDownscaleFactor(BLUR_EFFECT_DOWNSCALE_FACTOR),
+  mBlurRadius(blurRadius),
+  mDownscaledBlurRadius(BLUR_EFFECT_BLUR_RADIUS),
+  mBellCurveWidth(Math::MACHINE_EPSILON_1),
+  mSkipBlur(false),
+  mBlurOnce(false)
+{
+  mDownscaledBlurRadius = FitBlurRadiusToValidRange(mDownscaleFactor, mBlurRadius);
+  if(DALI_UNLIKELY((mDownscaledBlurRadius >> 1) < MINIMUM_GPU_ARRAY_SIZE))
+  {
+    mSkipBlur = true;
+    DALI_LOG_ERROR("Blur radius is too small. This blur will be ignored.\n");
+  }
+}
+
+BackgroundBlurEffectImpl::~BackgroundBlurEffectImpl()
+{
+}
+
+BackgroundBlurEffectImplPtr BackgroundBlurEffectImpl::New()
+{
+  BackgroundBlurEffectImplPtr handle = new BackgroundBlurEffectImpl();
+  handle->Initialize();
+  return handle;
+}
+
+BackgroundBlurEffectImplPtr BackgroundBlurEffectImpl::New(uint32_t blurRadius)
+{
+  BackgroundBlurEffectImplPtr handle = new BackgroundBlurEffectImpl(blurRadius);
+  handle->Initialize();
+  return handle;
+}
+
+OffScreenRenderable::Type BackgroundBlurEffectImpl::GetOffScreenRenderableType()
+{
+  return mSkipBlur ? OffScreenRenderable::NONE : OffScreenRenderable::BACKWARD;
+}
+
+void BackgroundBlurEffectImpl::GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward)
+{
+  tasks.clear();
+  if(!isForward)
+  {
+    if(mSourceRenderTask)
+    {
+      // Re-initialize source actor of rendertask since it might be changed.
+      // TODO : Should it be required always? Couldn't we skip it?
+      ApplyRenderTaskSourceActor(mSourceRenderTask, GetOwnerControl());
+      tasks.push_back(mSourceRenderTask);
+    }
+    if(mHorizontalBlurTask)
+    {
+      tasks.push_back(mHorizontalBlurTask);
+    }
+    if(mVerticalBlurTask)
+    {
+      tasks.push_back(mVerticalBlurTask);
+    }
+  }
+}
+
+void BackgroundBlurEffectImpl::SetBlurOnce(bool blurOnce)
+{
+  mBlurOnce = blurOnce;
+
+  if(IsActivated()) // if false, no render task exists yet(nothing to do)
+  {
+    if(mBlurOnce)
+    {
+      mSourceRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+      mHorizontalBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+      mVerticalBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+
+      mVerticalBlurTask.FinishedSignal().Connect(this, &BackgroundBlurEffectImpl::OnRenderFinished);
+    }
+    else
+    {
+      mSourceRenderTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+      mHorizontalBlurTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+      mVerticalBlurTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+    }
+  }
+}
+
+bool BackgroundBlurEffectImpl::GetBlurOnce() const
+{
+  return mBlurOnce;
+}
+
+void BackgroundBlurEffectImpl::SetBlurRadius(uint32_t blurRadius)
+{
+  if(mBlurRadius != blurRadius)
+  {
+    if(IsActivated())
+    {
+      OnDeactivate();
+    }
+
+    // Reinitialize blur parameters
+    mBlurRadius           = blurRadius;
+    mDownscaledBlurRadius = FitBlurRadiusToValidRange(mDownscaleFactor, mBlurRadius);
+
+    mSkipBlur = false;
+    if(DALI_UNLIKELY((mDownscaledBlurRadius >> 1) < MINIMUM_GPU_ARRAY_SIZE))
+    {
+      mSkipBlur = true;
+      DALI_LOG_ERROR("Blur radius is too small. This blur will be ignored.\n");
+    }
+
+    OnInitialize();
+
+    if(IsActivated())
+    {
+      OnActivate();
+    }
+  }
+}
+
+uint32_t BackgroundBlurEffectImpl::GetBlurRadius() const
+{
+  return mBlurRadius;
+}
+
+void BackgroundBlurEffectImpl::AddBlurStrengthAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue)
+{
+  if(mBlurOnce)
+  {
+    DALI_LOG_ERROR("This blur effect is set to render only once, so the animation will be ignored. Call SetBlurOnce(false) to render it every frame.");
+    return;
+  }
+
+  fromValue = std::clamp(fromValue, 0.0f, 1.0f);
+  toValue   = std::clamp(toValue, 0.0f, 1.0f);
+
+  KeyFrames keyFrames = KeyFrames::New();
+  keyFrames.Add(0.0f, fromValue, AlphaFunction::BuiltinFunction::LINEAR);
+  keyFrames.Add(1.0f, toValue, AlphaFunction::BuiltinFunction::LINEAR);
+
+  Property::Index horizontalAnimationIndex = mHorizontalBlurActor.GetPropertyIndex(UNIFORM_BLUR_STRENGTH_NAME.data());
+  animation.AnimateBetween(Property(mHorizontalBlurActor, horizontalAnimationIndex), keyFrames, alphaFunction, timePeriod);
+  Property::Index verticalAnimationIndex = mVerticalBlurActor.GetPropertyIndex(UNIFORM_BLUR_STRENGTH_NAME.data());
+  animation.AnimateBetween(Property(mVerticalBlurActor, verticalAnimationIndex), keyFrames, alphaFunction, timePeriod);
+}
+
+void BackgroundBlurEffectImpl::AddBlurOpacityAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue)
+{
+  if(mBlurOnce)
+  {
+    DALI_LOG_ERROR("This blur effect is set to render only once, so the animation will be ignored. Call SetBlurOnce(false) to render it every frame.");
+    return;
+  }
+
+  fromValue = std::clamp(fromValue, 0.0f, 1.0f);
+  toValue   = std::clamp(toValue, 0.0f, 1.0f);
+
+  KeyFrames keyFrames = KeyFrames::New();
+  keyFrames.Add(0.0f, fromValue, AlphaFunction::BuiltinFunction::LINEAR);
+  keyFrames.Add(1.0f, toValue, AlphaFunction::BuiltinFunction::LINEAR);
+
+  Property::Index horizontalAnimationIndex = mHorizontalBlurActor.GetPropertyIndex(UNIFORM_BLUR_OPACITY_NAME.data());
+  animation.AnimateBetween(Property(mHorizontalBlurActor, horizontalAnimationIndex), keyFrames, alphaFunction, timePeriod);
+  Property::Index verticalAnimationIndex = mVerticalBlurActor.GetPropertyIndex(UNIFORM_BLUR_OPACITY_NAME.data());
+  animation.AnimateBetween(Property(mVerticalBlurActor, verticalAnimationIndex), keyFrames, alphaFunction, timePeriod);
+}
+
+void BackgroundBlurEffectImpl::OnInitialize()
+{
+  if(DALI_UNLIKELY(mSkipBlur))
+  {
+    return;
+  }
+
+  // Calculate bell curve width
+  {
+    const float epsilon     = 1e-2f / (mDownscaledBlurRadius * 2);
+    const float localOffset = (mDownscaledBlurRadius * 2) - 1;
+
+    float lowerBoundBellCurveWidth = Dali::Math::MACHINE_EPSILON_10000;
+    float upperBoundBellCurveWidth = MAXIMUM_BELL_CURVE_WIDTH;
+
+    int trialCount = 0;
+    while(trialCount++ < MAXIMUM_BELL_CURVE_LOOP_TRIAL_COUNT && upperBoundBellCurveWidth - lowerBoundBellCurveWidth > Dali::Math::MACHINE_EPSILON_10000)
+    {
+      mBellCurveWidth = (lowerBoundBellCurveWidth + upperBoundBellCurveWidth) * 0.5f;
+      if(CalculateGaussianWeight(localOffset, mBellCurveWidth) < epsilon)
+      {
+        lowerBoundBellCurveWidth = mBellCurveWidth;
+      }
+      else
+      {
+        upperBoundBellCurveWidth = mBellCurveWidth;
+      }
+    }
+  }
+
+  DALI_LOG_INFO(gRenderEffectLogFilter, Debug::Verbose, "[BlurEffect:%p] mBellCurveWidth calculated! [mBlurRadius:%u][mBellCurveWidth:%f]\n", this, mBlurRadius, mBellCurveWidth);
+
+  // Create blur actors
+  {
+    mInternalRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+    // shader
+    std::ostringstream fragmentStringStream;
+    fragmentStringStream << "#define NUM_SAMPLES " << (mDownscaledBlurRadius >> 1) << "\n";
+    fragmentStringStream << SHADER_BLUR_EFFECT_FRAG;
+    std::string fragmentSource(fragmentStringStream.str());
+
+    // Create an actor for performing a horizontal blur on the texture
+    Renderer horizontalBlurRenderer = CreateRenderer(BASIC_VERTEX_SOURCE, fragmentSource.c_str());
+    horizontalBlurRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true); // Always use pre-multiply alpha
+
+    if(mHorizontalBlurActor)
+    {
+      mHorizontalBlurActor.RemoveRenderer(0u);
+      mHorizontalBlurActor.AddRenderer(horizontalBlurRenderer);
+    }
+    else
+    {
+      mHorizontalBlurActor = Actor::New();
+      mHorizontalBlurActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+      mHorizontalBlurActor.AddRenderer(horizontalBlurRenderer);
+      mInternalRoot.Add(mHorizontalBlurActor);
+
+      mHorizontalBlurActor.RegisterProperty(UNIFORM_BLUR_OPACITY_NAME.data(), 1.0f);
+      mHorizontalBlurActor.RegisterProperty(UNIFORM_BLUR_STRENGTH_NAME.data(), 1.0f);
+    }
+
+    // Create an actor for performing a vertical blur on the texture
+    Renderer verticalBlurRenderer = CreateRenderer(BASIC_VERTEX_SOURCE, fragmentSource.c_str());
+    verticalBlurRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true); // Always use pre-multiply alpha
+
+    if(mVerticalBlurActor)
+    {
+      mVerticalBlurActor.RemoveRenderer(0u);
+      mVerticalBlurActor.AddRenderer(verticalBlurRenderer);
+    }
+    else
+    {
+      mVerticalBlurActor = Actor::New();
+      mVerticalBlurActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+      mVerticalBlurActor.AddRenderer(verticalBlurRenderer);
+      mInternalRoot.Add(mVerticalBlurActor);
+
+      mVerticalBlurActor.RegisterProperty(UNIFORM_BLUR_OPACITY_NAME.data(), 1.0f);
+      mVerticalBlurActor.RegisterProperty(UNIFORM_BLUR_STRENGTH_NAME.data(), 1.0f);
+    }
+  }
+}
+
+void BackgroundBlurEffectImpl::OnActivate()
+{
+  if(DALI_UNLIKELY(mSkipBlur))
+  {
+    return;
+  }
+
+  Toolkit::Control ownerControl = GetOwnerControl();
+  DALI_ASSERT_ALWAYS(ownerControl && "Set the owner of RenderEffect before you activate.");
+
+  // Get size
+  Vector2 size = GetTargetSize();
+  DALI_LOG_INFO(gRenderEffectLogFilter, Debug::General, "[BlurEffect:%p] OnActivated! [ID:%d][size:%fx%f]\n", this, ownerControl ? ownerControl.GetProperty<int>(Actor::Property::ID) : -1, size.x, size.y);
+
+  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
+  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);
+    mInternalRoot.Add(mCamera);
+  }
+  mCamera.SetPerspectiveProjection(GetTargetSize());
+
+  if(!mRenderDownsampledCamera)
+  {
+    mRenderDownsampledCamera = CameraActor::New();
+    mRenderDownsampledCamera.SetInvertYAxis(true);
+    mRenderDownsampledCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+    mRenderDownsampledCamera.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+    mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK);
+    mInternalRoot.Add(mRenderDownsampledCamera);
+  }
+  mRenderDownsampledCamera.SetPerspectiveProjection(Size(downsampledWidth, downsampledHeight));
+
+  mHorizontalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight));
+  mVerticalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight));
+
+  // Set blur
+  CreateFrameBuffers(ImageDimensions(downsampledWidth, downsampledHeight));
+  CreateRenderTasks(GetSceneHolder(), ownerControl);
+  SetShaderConstants(downsampledWidth, downsampledHeight);
+
+  // Inject blurred output to control
+  Renderer renderer = GetTargetRenderer();
+  renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Dali::Toolkit::DepthIndex::BACKGROUND_EFFECT);
+  ownerControl.AddRenderer(renderer);
+  SetRendererTexture(renderer, mBlurredOutputFrameBuffer);
+
+  ownerControl.Add(mInternalRoot);
+
+  // Reorder render task
+  // TODO : Can we remove this GetImplementation?
+  GetImplementation(ownerControl).RequestRenderTaskReorder();
+}
+
+void BackgroundBlurEffectImpl::OnDeactivate()
+{
+  if(DALI_UNLIKELY(mSkipBlur))
+  {
+    return;
+  }
+
+  auto ownerControl = GetOwnerControl();
+  if(DALI_LIKELY(ownerControl))
+  {
+    Renderer renderer = GetTargetRenderer();
+    ownerControl.RemoveRenderer(renderer);
+  }
+  DALI_LOG_INFO(gRenderEffectLogFilter, Debug::General, "[BlurEffect:%p] OnDeactivated! [ID:%d]\n", this, ownerControl ? ownerControl.GetProperty<int>(Actor::Property::ID) : -1);
+
+  mInternalRoot.Unparent();
+
+  DestroyFrameBuffers();
+  DestroyRenderTasks();
+}
+
+void BackgroundBlurEffectImpl::OnRefresh()
+{
+  if(DALI_UNLIKELY(mSkipBlur))
+  {
+    return;
+  }
+
+  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
+  mCamera.SetPerspectiveProjection(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 BackgroundBlurEffectImpl::CreateFrameBuffers(const ImageDimensions downsampledSize)
+{
+  uint32_t downsampledWidth  = downsampledSize.GetWidth();
+  uint32_t downsampledHeight = downsampledSize.GetHeight();
+
+  // buffer to draw input texture
+  mInputBackgroundFrameBuffer    = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::DEPTH_STENCIL);
+  Texture inputBackgroundTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
+  mInputBackgroundFrameBuffer.AttachColorTexture(inputBackgroundTexture);
+
+  // buffer to draw half-blurred output
+  mTemporaryFrameBuffer    = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::DEPTH_STENCIL);
+  Texture temporaryTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
+  mTemporaryFrameBuffer.AttachColorTexture(temporaryTexture);
+
+  // buffer to draw blurred output
+  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 BackgroundBlurEffectImpl::DestroyFrameBuffers()
+{
+  mInputBackgroundFrameBuffer.Reset();
+  mTemporaryFrameBuffer.Reset();
+  mBlurredOutputFrameBuffer.Reset();
+}
+
+void BackgroundBlurEffectImpl::CreateRenderTasks(Integration::SceneHolder sceneHolder, const Toolkit::Control sourceControl)
+{
+  RenderTaskList taskList = sceneHolder.GetRenderTaskList();
+
+  // draw input texture
+  mSourceRenderTask = taskList.CreateTask();
+  mSourceRenderTask.SetCameraActor(mCamera);
+  mSourceRenderTask.SetFrameBuffer(mInputBackgroundFrameBuffer);
+  mSourceRenderTask.SetInputEnabled(false);
+
+  ApplyRenderTaskSourceActor(mSourceRenderTask, sourceControl);
+
+  // Clear inputBackgroundTexture as scene holder background.
+  mSourceRenderTask.SetClearEnabled(true);
+  mSourceRenderTask.SetClearColor(sceneHolder.GetBackgroundColor());
+
+  // draw half-blurred output
+  SetRendererTexture(mHorizontalBlurActor.GetRendererAt(0), mInputBackgroundFrameBuffer);
+  mHorizontalBlurTask = taskList.CreateTask();
+  mHorizontalBlurTask.SetSourceActor(mHorizontalBlurActor);
+  mHorizontalBlurTask.SetExclusive(true);
+  mHorizontalBlurTask.SetInputEnabled(false);
+  mHorizontalBlurTask.SetCameraActor(mRenderDownsampledCamera);
+  mHorizontalBlurTask.SetFrameBuffer(mTemporaryFrameBuffer);
+
+  // Clear temporaryTexture as Transparent.
+  mHorizontalBlurTask.SetClearEnabled(true);
+  mHorizontalBlurTask.SetClearColor(Color::TRANSPARENT);
+
+  // draw blurred output
+  SetRendererTexture(mVerticalBlurActor.GetRendererAt(0), mTemporaryFrameBuffer);
+  mVerticalBlurTask = taskList.CreateTask();
+  mVerticalBlurTask.SetSourceActor(mVerticalBlurActor);
+  mVerticalBlurTask.SetExclusive(true);
+  mVerticalBlurTask.SetInputEnabled(false);
+  mVerticalBlurTask.SetCameraActor(mRenderDownsampledCamera);
+  mVerticalBlurTask.SetFrameBuffer(mBlurredOutputFrameBuffer);
+
+  // Clear sourceTexture as Transparent.
+  mVerticalBlurTask.SetClearEnabled(true);
+  mVerticalBlurTask.SetClearColor(Color::TRANSPARENT);
+
+  // Adjust refresh rate
+  if(mBlurOnce)
+  {
+    mSourceRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+    mHorizontalBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+    mVerticalBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+
+    mVerticalBlurTask.FinishedSignal().Connect(this, &BackgroundBlurEffectImpl::OnRenderFinished);
+  }
+  else
+  {
+    mSourceRenderTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+    mHorizontalBlurTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+    mVerticalBlurTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+  }
+}
+
+void BackgroundBlurEffectImpl::OnRenderFinished(Dali::RenderTask& renderTask)
+{
+  mFinishedSignal.Emit();
+}
+
+void BackgroundBlurEffectImpl::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 BackgroundBlurEffectImpl::ApplyRenderTaskSourceActor(RenderTask sourceRenderTask, const Toolkit::Control sourceControl)
+{
+  if(DALI_UNLIKELY(!sourceRenderTask || !sourceControl))
+  {
+    return;
+  }
+
+  bool        isExclusiveRequired = false;
+  Dali::Actor sourceActor         = sourceControl;
+  Dali::Actor stopperActor        = Dali::Actor(); // Give empty handle to invalidate previous render until option.
+
+  stopperActor = sourceControl;
+  while(sourceActor && sourceActor.GetParent())
+  {
+    sourceActor              = sourceActor.GetParent();
+    Toolkit::Control control = Toolkit::Control::DownCast(sourceActor);
+    if(control && GetImplementation(control).GetOffScreenRenderableType() == OffScreenRenderable::Type::FORWARD)
+    {
+      sourceActor         = GetImplementation(control).GetOffScreenRenderableSourceActor();
+      isExclusiveRequired = GetImplementation(control).IsOffScreenRenderTaskExclusive();
+      break;
+    }
+  }
+
+  sourceRenderTask.SetExclusive(isExclusiveRequired);
+  sourceRenderTask.SetSourceActor(sourceActor);
+  sourceRenderTask.RenderUntil(stopperActor);
+}
+
+void BackgroundBlurEffectImpl::SetShaderConstants(uint32_t downsampledWidth, uint32_t downsampledHeight)
+{
+  const uint32_t sampleCount    = mDownscaledBlurRadius >> 1; // compression
+  const uint32_t kernelSize     = sampleCount * 4 - 1;
+  const uint32_t halfKernelSize = kernelSize / 2 + 1; // Gaussian curve is symmetric
+
+  // Output: Gaussian kernel compressed to half size
+  std::vector<float> uvOffsets(sampleCount);
+  std::vector<float> weights(sampleCount);
+
+  // Generate half size kernel
+  std::vector<float> halfSideKernel(halfKernelSize);
+
+  halfSideKernel[0]  = CalculateGaussianWeight(0.0f, mBellCurveWidth);
+  float totalWeights = halfSideKernel[0];
+  for(unsigned int i = 1; i < halfKernelSize; i++)
+  {
+    float w           = CalculateGaussianWeight(i, mBellCurveWidth);
+    halfSideKernel[i] = w;
+    totalWeights += w * 2.0f;
+  }
+  for(unsigned int i = 0; i < halfKernelSize; i++)
+  {
+    halfSideKernel[i] /= totalWeights;
+  }
+  halfSideKernel[0] *= 0.5f;
+
+  // Compress kernel to half size
+  for(unsigned int i = 0; i < sampleCount; i++)
+  {
+    weights[i]   = halfSideKernel[2 * i] + halfSideKernel[2 * i + 1];
+    uvOffsets[i] = 2.0f * i + halfSideKernel[2 * i + 1] / weights[i];
+  }
+
+  // Set shader constants
+  for(unsigned int i = 0; i < sampleCount; ++i)
+  {
+    mHorizontalBlurActor.RegisterProperty(GetSampleOffsetsPropertyName(i), Vector2(uvOffsets[i] / downsampledWidth, 0.0f));
+    mHorizontalBlurActor.RegisterProperty(GetSampleWeightsPropertyName(i), weights[i]);
+
+    mVerticalBlurActor.RegisterProperty(GetSampleOffsetsPropertyName(i), Vector2(0.0f, uvOffsets[i] / downsampledHeight));
+    mVerticalBlurActor.RegisterProperty(GetSampleWeightsPropertyName(i), weights[i]);
+  }
+}
+
+std::string BackgroundBlurEffectImpl::GetSampleOffsetsPropertyName(unsigned int index) const
+{
+  std::ostringstream oss;
+  oss << "uSampleOffsets[" << index << "]";
+  return oss.str();
+}
+
+std::string BackgroundBlurEffectImpl::GetSampleWeightsPropertyName(unsigned int index) const
+{
+  std::ostringstream oss;
+  oss << "uSampleWeights[" << index << "]";
+  return oss.str();
+}
+
+Dali::Toolkit::BackgroundBlurEffect::FinishedSignalType& BackgroundBlurEffectImpl::FinishedSignal()
+{
+  return mFinishedSignal;
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.h b/dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.h
new file mode 100644 (file)
index 0000000..1e04937
--- /dev/null
@@ -0,0 +1,257 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BLUR_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_BLUR_EFFECT_H
+
+/*
+ * Copyright (c) 2025 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/object/weak-handle.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/render-effects/render-effect-impl.h>
+#include <dali-toolkit/public-api/controls/render-effects/background-blur-effect.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class BackgroundBlurEffectImpl;
+using BackgroundBlurEffectImplPtr = IntrusivePtr<BackgroundBlurEffectImpl>;
+
+class BackgroundBlurEffectImpl : public RenderEffectImpl
+{
+public:
+  /**
+   * @brief Creates an initialized BlurEffect implementation, using default settings. As default, blur radius is set to 10u.
+   * @return A handle to a newly allocated Dali resource
+   */
+
+  static BackgroundBlurEffectImplPtr New();
+
+  /**
+   * @brief Creates an initialized BlurEffect implementation.
+   *
+   * @param[in] blurRadius The radius of Gaussian kernel.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static BackgroundBlurEffectImplPtr New(uint32_t blurRadius);
+
+  /**
+   * @copydoc Toolkit::Internal::RenderEffectImpl::GetOffScreenRenderableType
+   */
+  OffScreenRenderable::Type GetOffScreenRenderableType() override;
+
+  /**
+   * @copydoc Toolkit::Internal::RenderEffectImpl::GetOffScreenRenderTasks
+   */
+  void GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward) override;
+
+  /**
+   * @copydoc Toolkit::BackgroundBlurEffect::SetBlurOnce
+   */
+  void SetBlurOnce(bool blurOnce);
+
+  /**
+   * @copydoc Toolkit::BackgroundBlurEffect::GetBlurOnce
+   */
+  bool GetBlurOnce() const;
+
+  /**
+   * @copydoc Toolkit::BackgroundBlurEffect::SetBlurRadius
+   */
+  void SetBlurRadius(uint32_t blurRadius);
+
+  /**
+   * @copydoc Toolkit::BackgroundBlurEffect::GetBlurRadius
+   */
+  uint32_t GetBlurRadius() const;
+
+  /**
+   * @copydoc Toolkit::BackgroundBlurEffect::AddBlurStrengthAnimation
+   */
+  void AddBlurStrengthAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue);
+
+  /**
+   * @copydoc Toolkit::BackgroundBlurEffect::AddBlurOpacityAnimation
+   */
+  void AddBlurOpacityAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue);
+
+  /**
+   * @copydoc Toolkit::BackgroundBlurEffect::FinishedSignal
+   */
+  Dali::Toolkit::BackgroundBlurEffect::FinishedSignalType& FinishedSignal();
+
+protected:
+  /**
+   * @brief Creates an uninitialized blur effect implementation
+   */
+  BackgroundBlurEffectImpl();
+
+  /**
+   * @brief Creates an uninitialized blur effect implementation
+   * @param[in] blurRadius The radius of Gaussian kernel.
+   */
+  BackgroundBlurEffectImpl(uint32_t blurRadius);
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~BackgroundBlurEffectImpl();
+
+  /**
+   * @brief Initializes blur effect
+   */
+  void OnInitialize() override;
+
+  /**
+   * @brief Activates blur effect
+   */
+  void OnActivate() override;
+
+  /**
+   * @brief Dectivates blur effect
+   */
+  void OnDeactivate() override;
+
+  /**
+   * @brief Redraw effect without deactivation
+   */
+  void OnRefresh() override;
+
+private:
+  // Inner functions
+  /**
+   * @brief Sets frame buffers to draw blurred output.
+   * @param[in] downsampledSize Downsampled size for performance.
+   */
+  void CreateFrameBuffers(const ImageDimensions downsampledSize);
+
+  /**
+   * @brief Removes and destroys local frame buffers.
+   */
+  void DestroyFrameBuffers();
+
+  /**
+   * @brief Sets blur render tasks.
+   * Requires initialized buffers, source actors, and source cameras.
+   * @param[in] sceneHolder SceneHolder of source control
+   * @param[in] sourceControl Input source control
+   */
+  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
+   * @param[in] sourceControl Input source control
+   */
+  void ApplyRenderTaskSourceActor(RenderTask sourceRenderTask, const Toolkit::Control sourceControl);
+
+  /**
+   * @brief Sets shader constants, gaussian kernel weights and pixel offsets.
+   * @param[in] downsampledWidth Downsized width of input texture.
+   * @param[in] downsampledHeight Downsized height of input texture.
+   */
+  void SetShaderConstants(uint32_t downsampledWidth, uint32_t downsampledHeight);
+
+  /**
+   * @brief Get an offset property in std::string format
+   * @param[in] index Property's index
+   * @return A string for shader
+   */
+  std::string GetSampleOffsetsPropertyName(unsigned int index) const;
+
+  /**
+   * @brief Get a weight property in std::string format
+   * @param[in] index Property's index
+   * @return A string for shader
+   */
+  std::string GetSampleWeightsPropertyName(unsigned int index) const;
+
+  /**
+   * @brief Emits render finished signal of the effect,
+   * when mBlurOnce is true and finished signal of the last render task(mVerticalBlurTask) is emitted.
+   * @param[in] renderTask that emits source signal.
+   */
+  void OnRenderFinished(Dali::RenderTask& renderTask);
+
+  BackgroundBlurEffectImpl(const BackgroundBlurEffectImpl&) = delete;
+  BackgroundBlurEffectImpl(BackgroundBlurEffectImpl&&)      = delete;
+  BackgroundBlurEffectImpl& operator=(BackgroundBlurEffectImpl&&) = delete;      // no move()
+  BackgroundBlurEffectImpl& operator=(const BackgroundBlurEffectImpl&) = delete; // no copy()
+
+public:
+  Dali::Toolkit::BackgroundBlurEffect::FinishedSignalType mFinishedSignal; // Emits when blur once is enabled
+
+private:
+  // Camera actors
+  CameraActor mCamera;
+  CameraActor mRenderDownsampledCamera;
+
+  // Resource
+  FrameBuffer mInputBackgroundFrameBuffer; // Input. Background. What to blur.
+
+  Actor       mInternalRoot;
+  Actor       mHorizontalBlurActor;
+  RenderTask  mHorizontalBlurTask;
+  FrameBuffer mTemporaryFrameBuffer;
+  Actor       mVerticalBlurActor;
+  RenderTask  mVerticalBlurTask;
+
+  FrameBuffer mBlurredOutputFrameBuffer;
+  RenderTask  mSourceRenderTask;
+
+  // Variables
+  float    mDownscaleFactor;
+  uint32_t mBlurRadius;
+  uint32_t mDownscaledBlurRadius;
+  float    mBellCurveWidth;
+
+  bool mSkipBlur : 1;
+  bool mBlurOnce : 1;
+};
+} // namespace Internal
+
+inline Toolkit::Internal::BackgroundBlurEffectImpl& GetImplementation(Toolkit::BackgroundBlurEffect& obj)
+{
+  BaseObject& handle = obj.GetBaseObject();
+  return static_cast<Toolkit::Internal::BackgroundBlurEffectImpl&>(handle);
+}
+
+inline const Toolkit::Internal::BackgroundBlurEffectImpl& GetImplementation(const Toolkit::BackgroundBlurEffect& obj)
+{
+  const BaseObject& handle = obj.GetBaseObject();
+  return static_cast<const Toolkit::Internal::BackgroundBlurEffectImpl&>(handle);
+}
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BACKGROUND_BLUR_EFFECT_H
diff --git a/dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp b/dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp
deleted file mode 100644 (file)
index 17f83bb..0000000
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Copyright (c) 2025 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-toolkit/internal/controls/render-effects/blur-effect-impl.h>
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/actors/actor-devel.h>
-#include <dali/integration-api/debug.h>
-#include <dali/public-api/actors/custom-actor-impl.h>
-#include <dali/public-api/images/image-operations.h>
-#include <dali/public-api/render-tasks/render-task-list.h>
-#include <dali/public-api/rendering/renderer.h>
-#include <dali/public-api/rendering/shader.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
-#include <dali-toolkit/internal/controls/control/control-renderers.h>
-#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
-#include <dali-toolkit/public-api/controls/control-impl.h>
-
-namespace
-{
-// Default values
-static constexpr float    BLUR_EFFECT_DOWNSCALE_FACTOR = 0.4f;
-static constexpr uint32_t BLUR_EFFECT_PIXEL_RADIUS     = 10u;
-
-static constexpr float MINIMUM_DOWNSCALE_FACTOR = 0.1f;
-static constexpr float MAXIMUM_DOWNSCALE_FACTOR = 1.0f;
-
-static constexpr uint32_t MINIMUM_GPU_ARRAY_SIZE = 2u;   // GPU cannot handle array size smaller than 2.
-static constexpr uint32_t MAXIMUM_BLUR_RADIUS    = 500u; ///< Maximum pixel radius for blur effect. (GL_MAX_FRAGMENT_UNIFORM_COMPONENTS(Usually 1024) - 19 (vertex shader used)) / 3 float
-
-static constexpr float   MAXIMUM_BELL_CURVE_WIDTH            = 171.352f; ///< bell curve width for MAXIMUM_BLUR_RADIUS case
-static constexpr int32_t MAXIMUM_BELL_CURVE_LOOP_TRIAL_COUNT = 50;
-
-/**
-  * @brief Calculates gaussian weight
-  * @param[in] localOffset Input variable of gaussian distribution
-  * @param[in] sigma Standard deviation of gaussian distribution, the width of the "bell"
-  * @note Expected value of this gaussian distribution is 0.
-  */
-inline float CalculateGaussianWeight(float localOffset, float sigma)
-{
-  return (1.0f / (sigma * sqrt(2.0f * Dali::Math::PI))) * exp(-0.5f * (localOffset / sigma * localOffset / sigma));
-}
-} // namespace
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-#ifdef DEBUG_ENABLED
-extern Debug::Filter* gRenderEffectLogFilter; ///< Define at render-effect-impl.cpp
-#endif
-
-BlurEffectImpl::BlurEffectImpl(bool isBackground)
-: RenderEffectImpl(),
-  mInternalRoot(Actor::New()),
-  mDownscaleFactor(BLUR_EFFECT_DOWNSCALE_FACTOR),
-  mPixelRadius(BLUR_EFFECT_PIXEL_RADIUS),
-  mDownscaledPixelRadius(static_cast<uint32_t>(BLUR_EFFECT_PIXEL_RADIUS * BLUR_EFFECT_DOWNSCALE_FACTOR)),
-  mBellCurveWidth(Math::MACHINE_EPSILON_1),
-  mSkipBlur(false),
-  mBlurOnce(false),
-  mIsBackground(isBackground)
-{
-}
-
-BlurEffectImpl::BlurEffectImpl(float downscaleFactor, uint32_t blurRadius, bool blurOnce, bool isBackground)
-: RenderEffectImpl(),
-  mInternalRoot(Actor::New()),
-  mDownscaleFactor(downscaleFactor),
-  mPixelRadius(blurRadius),
-  mDownscaledPixelRadius(BLUR_EFFECT_PIXEL_RADIUS),
-  mBellCurveWidth(Math::MACHINE_EPSILON_1),
-  mSkipBlur(false),
-  mBlurOnce(blurOnce),
-  mIsBackground(isBackground)
-{
-  if(DALI_UNLIKELY(mDownscaleFactor < MINIMUM_DOWNSCALE_FACTOR || mDownscaleFactor > MAXIMUM_DOWNSCALE_FACTOR))
-  {
-    mDownscaleFactor = Dali::Clamp(mDownscaleFactor, MINIMUM_DOWNSCALE_FACTOR, MAXIMUM_DOWNSCALE_FACTOR);
-  }
-
-  if(DALI_UNLIKELY(blurRadius > MAXIMUM_BLUR_RADIUS))
-  {
-    const uint32_t fixedBlurRadius      = MAXIMUM_BLUR_RADIUS;
-    const float    fixedDownScaleFactor = Dali::Clamp(
-      mDownscaleFactor * static_cast<float>(fixedBlurRadius) / static_cast<float>(blurRadius),
-      MINIMUM_DOWNSCALE_FACTOR,
-      MAXIMUM_DOWNSCALE_FACTOR);
-
-    DALI_LOG_ERROR("Blur radius is out of bound: %u. Use %u and make downscale factor %f to %f.\n",
-                   blurRadius,
-                   fixedBlurRadius,
-                   mDownscaleFactor,
-                   fixedDownScaleFactor);
-
-    mDownscaleFactor = fixedDownScaleFactor;
-    mPixelRadius     = fixedBlurRadius;
-  }
-
-  mDownscaledPixelRadius = static_cast<uint32_t>(mPixelRadius * mDownscaleFactor);
-
-  if(DALI_UNLIKELY((mDownscaledPixelRadius >> 1) < MINIMUM_GPU_ARRAY_SIZE))
-  {
-    mSkipBlur = true;
-    DALI_LOG_ERROR("Blur radius is too small. This blur will be ignored.\n");
-  }
-}
-
-BlurEffectImpl::~BlurEffectImpl()
-{
-}
-
-BlurEffectImplPtr BlurEffectImpl::New(bool isBackground)
-{
-  BlurEffectImplPtr handle = new BlurEffectImpl(isBackground);
-  handle->Initialize();
-  return handle;
-}
-
-BlurEffectImplPtr BlurEffectImpl::New(float downscaleFactor, uint32_t blurRadius, bool blurOnce, bool isBackground)
-{
-  BlurEffectImplPtr handle = new BlurEffectImpl(downscaleFactor, blurRadius, blurOnce, isBackground);
-  handle->Initialize();
-  return handle;
-}
-
-OffScreenRenderable::Type BlurEffectImpl::GetOffScreenRenderableType()
-{
-  return mSkipBlur ? OffScreenRenderable::NONE : OffScreenRenderable::BACKWARD;
-}
-
-void BlurEffectImpl::GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward)
-{
-  tasks.clear();
-  if(!isForward && mIsBackground)
-  {
-    if(mSourceRenderTask)
-    {
-      // Re-initialize source actor of rendertask since it might be changed.
-      // TODO : Should it be required always? Couldn't we skip it?
-      ApplyRenderTaskSourceActor(mSourceRenderTask, GetOwnerControl());
-      tasks.push_back(mSourceRenderTask);
-    }
-    if(mHorizontalBlurTask)
-    {
-      tasks.push_back(mHorizontalBlurTask);
-    }
-    if(mVerticalBlurTask)
-    {
-      tasks.push_back(mVerticalBlurTask);
-    }
-  }
-}
-
-void BlurEffectImpl::OnInitialize()
-{
-  if(DALI_UNLIKELY(mSkipBlur))
-  {
-    return;
-  }
-
-  // Calculate bell curve width
-  {
-    const float epsilon     = 1e-2f / (mDownscaledPixelRadius * 2);
-    const float localOffset = (mDownscaledPixelRadius * 2) - 1;
-
-    float lowerBoundBellCurveWidth = Math::MACHINE_EPSILON_10000;
-    float upperBoundBellCurveWidth = MAXIMUM_BELL_CURVE_WIDTH;
-
-    int trialCount = 0;
-    while(trialCount++ < MAXIMUM_BELL_CURVE_LOOP_TRIAL_COUNT && upperBoundBellCurveWidth - lowerBoundBellCurveWidth > Math::MACHINE_EPSILON_10000)
-    {
-      mBellCurveWidth = (lowerBoundBellCurveWidth + upperBoundBellCurveWidth) * 0.5f;
-      if(CalculateGaussianWeight(localOffset, mBellCurveWidth) < epsilon)
-      {
-        lowerBoundBellCurveWidth = mBellCurveWidth;
-      }
-      else
-      {
-        upperBoundBellCurveWidth = mBellCurveWidth;
-      }
-    }
-  }
-
-  DALI_LOG_INFO(gRenderEffectLogFilter, Debug::Verbose, "[BlurEffect:%p] mBellCurveWidth calculated! [mPixelRadius:%u][mBellCurveWidth:%f]\n", this, mPixelRadius, mBellCurveWidth);
-
-  // Create blur actors
-  {
-    mInternalRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-
-    // shader
-    std::ostringstream fragmentStringStream;
-    fragmentStringStream << "#define NUM_SAMPLES " << (mDownscaledPixelRadius >> 1) << "\n";
-    fragmentStringStream << SHADER_BLUR_EFFECT_FRAG;
-    std::string fragmentSource(fragmentStringStream.str());
-
-    // Create an actor for performing a horizontal blur on the texture
-    mHorizontalBlurActor = Actor::New();
-    mHorizontalBlurActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-    Renderer horizontalBlurRenderer = CreateRenderer(BASIC_VERTEX_SOURCE, fragmentSource.c_str());
-    horizontalBlurRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true); // Always use pre-multiply alpha
-    mHorizontalBlurActor.AddRenderer(horizontalBlurRenderer);
-    mInternalRoot.Add(mHorizontalBlurActor);
-
-    // Create an actor for performing a vertical blur on the texture
-    mVerticalBlurActor = Actor::New();
-    mVerticalBlurActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-    Renderer verticalBlurRenderer = CreateRenderer(BASIC_VERTEX_SOURCE, fragmentSource.c_str());
-    verticalBlurRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true); // Always use pre-multiply alpha
-    mVerticalBlurActor.AddRenderer(verticalBlurRenderer);
-    mInternalRoot.Add(mVerticalBlurActor);
-  }
-}
-
-void BlurEffectImpl::OnActivate()
-{
-  if(DALI_UNLIKELY(mSkipBlur))
-  {
-    return;
-  }
-
-  Toolkit::Control ownerControl = GetOwnerControl();
-  DALI_ASSERT_ALWAYS(ownerControl && "Set the owner of RenderEffect before you activate.");
-
-  // Get size
-  Vector2 size = GetTargetSize();
-  DALI_LOG_INFO(gRenderEffectLogFilter, Debug::General, "[BlurEffect:%p] OnActivated! [ID:%d][size:%fx%f]\n", this, ownerControl ? ownerControl.GetProperty<int>(Actor::Property::ID) : -1, size.x, size.y);
-
-  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
-  if(!mRenderDownsampledCamera)
-  {
-    mRenderDownsampledCamera = CameraActor::New();
-    mRenderDownsampledCamera.SetInvertYAxis(true);
-    mRenderDownsampledCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-    mRenderDownsampledCamera.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-    mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK);
-    mInternalRoot.Add(mRenderDownsampledCamera);
-  }
-  mRenderDownsampledCamera.SetPerspectiveProjection(Size(downsampledWidth, downsampledHeight));
-
-  mHorizontalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight));
-  mVerticalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight));
-
-  // Set blur
-  CreateFrameBuffers(ImageDimensions(downsampledWidth, downsampledHeight));
-  CreateRenderTasks(GetSceneHolder(), ownerControl);
-  SetShaderConstants(downsampledWidth, downsampledHeight);
-
-  // Inject blurred output to control
-  Renderer renderer = GetTargetRenderer();
-  if(mIsBackground)
-  {
-    renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Dali::Toolkit::DepthIndex::BACKGROUND_EFFECT);
-  }
-  else
-  {
-    renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Dali::Toolkit::DepthIndex::CONTENT);
-  }
-  ownerControl.AddRenderer(renderer);
-  SetRendererTexture(renderer, mBlurredOutputFrameBuffer);
-
-  ownerControl.Add(mInternalRoot);
-
-  // Reorder render task
-  // TODO : Can we remove this GetImplementation?
-  GetImplementation(ownerControl).RequestRenderTaskReorder();
-}
-
-void BlurEffectImpl::OnDeactivate()
-{
-  if(DALI_UNLIKELY(mSkipBlur))
-  {
-    return;
-  }
-
-  auto ownerControl = GetOwnerControl();
-  if(DALI_LIKELY(ownerControl))
-  {
-    Renderer renderer = GetTargetRenderer();
-    ownerControl.RemoveRenderer(renderer);
-  }
-  DALI_LOG_INFO(gRenderEffectLogFilter, Debug::General, "[BlurEffect:%p] OnDeactivated! [ID:%d]\n", this, ownerControl ? ownerControl.GetProperty<int>(Actor::Property::ID) : -1);
-
-  mInternalRoot.Unparent();
-
-  DestroyFrameBuffers();
-  DestroyRenderTasks();
-}
-
-void BlurEffectImpl::OnRefresh()
-{
-  if(DALI_UNLIKELY(mSkipBlur))
-  {
-    return;
-  }
-
-  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 ImageDimensions downsampledSize)
-{
-  uint32_t downsampledWidth  = downsampledSize.GetWidth();
-  uint32_t downsampledHeight = downsampledSize.GetHeight();
-
-  // buffer to draw input texture
-  mInputBackgroundFrameBuffer    = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::DEPTH_STENCIL);
-  Texture inputBackgroundTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
-  mInputBackgroundFrameBuffer.AttachColorTexture(inputBackgroundTexture);
-
-  // buffer to draw half-blurred output
-  mTemporaryFrameBuffer    = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::DEPTH_STENCIL);
-  Texture temporaryTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
-  mTemporaryFrameBuffer.AttachColorTexture(temporaryTexture);
-
-  // buffer to draw blurred output
-  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)
-{
-  RenderTaskList taskList = sceneHolder.GetRenderTaskList();
-
-  // draw input texture
-  mSourceRenderTask = taskList.CreateTask();
-  mSourceRenderTask.SetCameraActor(GetCameraActor());
-  mSourceRenderTask.SetFrameBuffer(mInputBackgroundFrameBuffer);
-  mSourceRenderTask.SetInputEnabled(false);
-
-  ApplyRenderTaskSourceActor(mSourceRenderTask, sourceControl);
-
-  // Clear inputBackgroundTexture as scene holder background.
-  mSourceRenderTask.SetClearEnabled(true);
-  mSourceRenderTask.SetClearColor(sceneHolder.GetBackgroundColor());
-
-  // draw half-blurred output
-  SetRendererTexture(mHorizontalBlurActor.GetRendererAt(0), mInputBackgroundFrameBuffer);
-  mHorizontalBlurTask = taskList.CreateTask();
-  mHorizontalBlurTask.SetSourceActor(mHorizontalBlurActor);
-  mHorizontalBlurTask.SetExclusive(true);
-  mHorizontalBlurTask.SetInputEnabled(false);
-  mHorizontalBlurTask.SetCameraActor(mRenderDownsampledCamera);
-  mHorizontalBlurTask.SetFrameBuffer(mTemporaryFrameBuffer);
-
-  // Clear temporaryTexture as Transparent.
-  mHorizontalBlurTask.SetClearEnabled(true);
-  mHorizontalBlurTask.SetClearColor(Color::TRANSPARENT);
-
-  // draw blurred output
-  SetRendererTexture(mVerticalBlurActor.GetRendererAt(0), mTemporaryFrameBuffer);
-  mVerticalBlurTask = taskList.CreateTask();
-  mVerticalBlurTask.SetSourceActor(mVerticalBlurActor);
-  mVerticalBlurTask.SetExclusive(true);
-  mVerticalBlurTask.SetInputEnabled(false);
-  mVerticalBlurTask.SetCameraActor(mRenderDownsampledCamera);
-  mVerticalBlurTask.SetFrameBuffer(mBlurredOutputFrameBuffer);
-
-  // Clear sourceTexture as Transparent.
-  mVerticalBlurTask.SetClearEnabled(true);
-  mVerticalBlurTask.SetClearColor(Color::TRANSPARENT);
-
-  // Adjust refresh rate
-  if(mBlurOnce)
-  {
-    mSourceRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
-    mHorizontalBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
-    mVerticalBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
-  }
-  else
-  {
-    mSourceRenderTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
-    mHorizontalBlurTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
-    mVerticalBlurTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
-  }
-}
-
-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))
-  {
-    return;
-  }
-
-  bool        isExclusiveRequired = false;
-  Dali::Actor sourceActor         = sourceControl;
-  Dali::Actor stopperActor        = Dali::Actor(); // Give empty handle to invalidate previous render until option.
-
-  if(mIsBackground)
-  {
-    stopperActor = sourceControl;
-    while(sourceActor && sourceActor.GetParent())
-    {
-      sourceActor              = sourceActor.GetParent();
-      Toolkit::Control control = Toolkit::Control::DownCast(sourceActor);
-      if(control && GetImplementation(control).GetOffScreenRenderableType() == OffScreenRenderable::Type::FORWARD)
-      {
-        sourceActor         = GetImplementation(control).GetOffScreenRenderableSourceActor();
-        isExclusiveRequired = GetImplementation(control).IsOffScreenRenderTaskExclusive();
-        break;
-      }
-    }
-  }
-
-  sourceRenderTask.SetExclusive(isExclusiveRequired);
-  sourceRenderTask.SetSourceActor(sourceActor);
-  sourceRenderTask.RenderUntil(stopperActor);
-}
-
-void BlurEffectImpl::SetShaderConstants(uint32_t downsampledWidth, uint32_t downsampledHeight)
-{
-  const uint32_t sampleCount    = mDownscaledPixelRadius >> 1; // compression
-  const uint32_t kernelSize     = sampleCount * 4 - 1;
-  const uint32_t halfKernelSize = kernelSize / 2 + 1; // Gaussian curve is symmetric
-
-  // Output: Gaussian kernel compressed to half size
-  std::vector<float> uvOffsets(sampleCount);
-  std::vector<float> weights(sampleCount);
-
-  // Generate half size kernel
-  std::vector<float> halfSideKernel(halfKernelSize);
-
-  halfSideKernel[0]  = CalculateGaussianWeight(0.0f, mBellCurveWidth);
-  float totalWeights = halfSideKernel[0];
-  for(unsigned int i = 1; i < halfKernelSize; i++)
-  {
-    float w           = CalculateGaussianWeight(i, mBellCurveWidth);
-    halfSideKernel[i] = w;
-    totalWeights += w * 2.0f;
-  }
-  for(unsigned int i = 0; i < halfKernelSize; i++)
-  {
-    halfSideKernel[i] /= totalWeights;
-  }
-  halfSideKernel[0] *= 0.5f;
-
-  // Compress kernel to half size
-  for(unsigned int i = 0; i < sampleCount; i++)
-  {
-    weights[i]   = halfSideKernel[2 * i] + halfSideKernel[2 * i + 1];
-    uvOffsets[i] = 2.0f * i + halfSideKernel[2 * i + 1] / weights[i];
-  }
-
-  // Set shader constants
-  for(unsigned int i = 0; i < sampleCount; ++i)
-  {
-    mHorizontalBlurActor.RegisterProperty(GetSampleOffsetsPropertyName(i), Vector2(uvOffsets[i] / downsampledWidth, 0.0f));
-    mHorizontalBlurActor.RegisterProperty(GetSampleWeightsPropertyName(i), weights[i]);
-
-    mVerticalBlurActor.RegisterProperty(GetSampleOffsetsPropertyName(i), Vector2(0.0f, uvOffsets[i] / downsampledHeight));
-    mVerticalBlurActor.RegisterProperty(GetSampleWeightsPropertyName(i), weights[i]);
-  }
-}
-
-std::string BlurEffectImpl::GetSampleOffsetsPropertyName(unsigned int index) const
-{
-  std::ostringstream oss;
-  oss << "uSampleOffsets[" << index << "]";
-  return oss.str();
-}
-
-std::string BlurEffectImpl::GetSampleWeightsPropertyName(unsigned int index) const
-{
-  std::ostringstream oss;
-  oss << "uSampleWeights[" << index << "]";
-  return oss.str();
-}
-
-} // namespace Internal
-} // namespace Toolkit
-} // namespace Dali
diff --git a/dali-toolkit/internal/controls/render-effects/blur-effect-impl.h b/dali-toolkit/internal/controls/render-effects/blur-effect-impl.h
deleted file mode 100644 (file)
index 5040805..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-#ifndef DALI_TOOLKIT_INTERNAL_BLUR_EFFECT_H
-#define DALI_TOOLKIT_INTERNAL_BLUR_EFFECT_H
-
-/*
- * Copyright (c) 2025 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.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/adaptor-framework/scene-holder.h>
-#include <dali/public-api/actors/actor.h>
-#include <dali/public-api/actors/camera-actor.h>
-#include <dali/public-api/images/image-operations.h>
-#include <dali/public-api/object/weak-handle.h>
-#include <dali/public-api/render-tasks/render-task.h>
-#include <dali/public-api/rendering/frame-buffer.h>
-#include <string>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/controls/render-effects/render-effect-impl.h>
-#include <dali-toolkit/public-api/controls/render-effects/background-blur-effect.h>
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Internal
-{
-class BlurEffectImpl;
-using BlurEffectImplPtr = IntrusivePtr<BlurEffectImpl>;
-
-class BlurEffectImpl : public RenderEffectImpl
-{
-public:
-  /**
-   * @brief Creates an initialized BlurEffect implementation, using default settings. The default settings are:
-   *
-   * downscaleFactor = 0.4f
-   * pixelRadius = 5u
-   *
-   * This blur algorithm is used for both foreground and background blurs.
-   *
-   * @param[in] isBackground True when blurring background, False otherwise
-   * @return A handle to a newly allocated Dali resource
-   */
-
-  static BlurEffectImplPtr New(bool isBackground);
-
-  /**
-   * @brief Creates an initialized BlurEffect implementation.
-   * This blur algorithm is used for both foreground and background blurs.
-   *
-   * @param[in] downscaleFactor This value should reside in the range [0.0, 1.0].
-   * @param[in] blurRadius The radius of Gaussian kernel.
-   * @param[in] blurOnce Whether to blur once or always. Default is false(always).
-   * @param[in] isBackground True when blurring background, False otherwise
-   * @return A handle to a newly allocated Dali resource
-   */
-  static BlurEffectImplPtr New(float downscaleFactor, uint32_t blurRadius, bool blurOnce, bool isBackground);
-
-  /**
-   * @copydoc Toolkit::Internal::RenderEffectImpl::GetOffScreenRenderableType
-   */
-  OffScreenRenderable::Type GetOffScreenRenderableType() override;
-
-  /**
-   * @copydoc Toolkit::Internal::RenderEffectImpl::GetOffScreenRenderTasks
-   */
-  void GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward) override;
-
-protected:
-  /**
-   * @brief Creates an uninitialized blur effect implementation
-   * @param[in] isBackground True when blurring background, False otherwise
-   */
-  BlurEffectImpl(bool isBackground);
-
-  /**
-   * @brief Creates an uninitialized blur effect implementation
-   * @param[in] downscaleFactor This value should reside in the range [0.0, 1.0].
-   * @param[in] blurRadius The radius of Gaussian kernel.
-   * @param[in] blurOnce Whether to blur once or always. Default is false(always).
-   * @param[in] isBackground True when blurring background, False otherwise
-   */
-  BlurEffectImpl(float downscaleFactor, uint32_t blurRadius, bool blurOnce, bool isBackground);
-
-  /**
-   * @brief Destructor
-   */
-  virtual ~BlurEffectImpl();
-
-  /**
-   * @brief Initializes blur effect
-   */
-  void OnInitialize() override;
-
-  /**
-   * @brief Activates blur effect
-   */
-  void OnActivate() override;
-
-  /**
-   * @brief Dectivates blur effect
-   */
-  void OnDeactivate() override;
-
-  /**
-   * @brief Redraw effect without deactivation
-   */
-  void OnRefresh() override;
-
-private:
-  // Inner functions
-  /**
-   * @brief Sets frame buffers to draw blurred output.
-   * @param[in] downsampledSize Downsampled size for performance.
-   */
-  void CreateFrameBuffers(const ImageDimensions downsampledSize);
-
-  /**
-   * @brief Removes and destroys local frame buffers.
-   */
-  void DestroyFrameBuffers();
-
-  /**
-   * @brief Sets blur render tasks.
-   * Requires initialized buffers, source actors, and source cameras.
-   * @param[in] sceneHolder SceneHolder of source control
-   * @param[in] sourceControl Input source control
-   */
-  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
-   * @param[in] sourceControl Input source control
-   */
-  void ApplyRenderTaskSourceActor(RenderTask sourceRenderTask, const Toolkit::Control sourceControl);
-
-  /**
-   * @brief Sets shader constants, gaussian kernel weights and pixel offsets.
-   * @param[in] downsampledWidth Downsized width of input texture.
-   * @param[in] downsampledHeight Downsized height of input texture.
-   */
-  void SetShaderConstants(uint32_t downsampledWidth, uint32_t downsampledHeight);
-
-  /**
-   * @brief Get an offset property in std::string format
-   * @param[in] index Property's index
-   * @return A string for shader
-   */
-  std::string GetSampleOffsetsPropertyName(unsigned int index) const;
-
-  /**
-   * @brief Get a weight property in std::string format
-   * @param[in] index Property's index
-   * @return A string for shader
-   */
-  std::string GetSampleWeightsPropertyName(unsigned int index) const;
-
-  BlurEffectImpl(const BlurEffectImpl&) = delete;
-  BlurEffectImpl(BlurEffectImpl&&)      = delete;
-  BlurEffectImpl& operator=(BlurEffectImpl&&) = delete;      // no move()
-  BlurEffectImpl& operator=(const BlurEffectImpl&) = delete; // no copy()
-
-private:
-  // Camera actors
-  CameraActor mRenderDownsampledCamera;
-
-  // Resource
-  FrameBuffer mInputBackgroundFrameBuffer; // Input. Background. What to blur.
-
-  Actor       mInternalRoot;
-  Actor       mHorizontalBlurActor;
-  RenderTask  mHorizontalBlurTask;
-  FrameBuffer mTemporaryFrameBuffer;
-  Actor       mVerticalBlurActor;
-  RenderTask  mVerticalBlurTask;
-
-  FrameBuffer mBlurredOutputFrameBuffer;
-  RenderTask  mSourceRenderTask;
-
-  // Variables
-  float    mDownscaleFactor;
-  uint32_t mPixelRadius;
-  uint32_t mDownscaledPixelRadius;
-  float    mBellCurveWidth;
-
-  bool mSkipBlur : 1;
-  bool mBlurOnce : 1;
-  bool mIsBackground : 1;
-};
-} // namespace Internal
-
-inline Toolkit::Internal::BlurEffectImpl& GetImplementation(Toolkit::BackgroundBlurEffect& obj)
-{
-  BaseObject& handle = obj.GetBaseObject();
-  return static_cast<Toolkit::Internal::BlurEffectImpl&>(handle);
-}
-
-inline const Toolkit::Internal::BlurEffectImpl& GetImplementation(const Toolkit::BackgroundBlurEffect& obj)
-{
-  const BaseObject& handle = obj.GetBaseObject();
-  return static_cast<const Toolkit::Internal::BlurEffectImpl&>(handle);
-}
-
-} // namespace Toolkit
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_INTERNAL_BACKGROUND_BLUR_EFFECT_H
index b8d82c279b4e1804f2ff6051e963da879947b753..2f5358152afe313845aa115e66d37390749fd027 100644 (file)
@@ -74,6 +74,17 @@ void OffScreenRenderingImpl::OnActivate()
     return;
   }
 
+  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);
+  }
+  mCamera.SetPerspectiveProjection(GetTargetSize());
+  GetOwnerControl().Add(mCamera);
+
   CreateFrameBuffer();
   CreateRenderTask();
   SetType(mType);
@@ -94,6 +105,8 @@ void OffScreenRenderingImpl::OnDeactivate()
   {
     control.GetImplementation().RemoveCacheRenderer();
     control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::NONE);
+
+    mCamera.Unparent();
   }
 
   DestroyFrameBuffer();
@@ -104,6 +117,8 @@ void OffScreenRenderingImpl::OnRefresh()
 {
   DestroyFrameBuffer();
 
+  mCamera.SetPerspectiveProjection(GetTargetSize());
+
   CreateFrameBuffer();
   mRenderTask.SetFrameBuffer(mFrameBuffer);
 }
@@ -130,7 +145,7 @@ void OffScreenRenderingImpl::CreateRenderTask()
 
   mRenderTask = taskList.CreateTask();
   mRenderTask.SetSourceActor(control);
-  mRenderTask.SetCameraActor(GetCameraActor());
+  mRenderTask.SetCameraActor(mCamera);
   mRenderTask.SetExclusive(true);
   mRenderTask.SetInputEnabled(true);
   mRenderTask.SetFrameBuffer(mFrameBuffer);
index 29cd2c0de847489f393a2c3809e9aa06aca4efc9..c000a21254579856710d5a3491e83400ac8ff1ba 100644 (file)
@@ -95,6 +95,7 @@ private:
 
 private:
   RenderTask                           mRenderTask;
+  CameraActor                          mCamera;
   FrameBuffer                          mFrameBuffer;
   DevelControl::OffScreenRenderingType mType;
 };
index 7e569fccf94dbe1debb17665018485d36d8e1d25..753d80a6f1aa5cc12eff9f88f7d32617cf8148ff 100644 (file)
@@ -47,7 +47,6 @@ Debug::Filter* gRenderEffectLogFilter = Debug::Filter::New(Debug::NoLogging, fal
 
 RenderEffectImpl::RenderEffectImpl()
 : mRenderer(),
-  mCamera(),
   mOwnerControl(),
   mSizeNotification(),
   mTargetSize(Vector2::ZERO),
@@ -159,11 +158,6 @@ Vector2 RenderEffectImpl::GetTargetSize() const
   return mTargetSize;
 }
 
-CameraActor RenderEffectImpl::GetCameraActor() const
-{
-  return mCamera;
-}
-
 void RenderEffectImpl::Activate()
 {
   if(!IsActivated() && IsActivateValid())
@@ -182,17 +176,6 @@ void RenderEffectImpl::Activate()
     }
     mPlacementSceneHolder = sceneHolder;
 
-    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);
-    }
-    mCamera.SetPerspectiveProjection(GetTargetSize());
-    ownerControl.Add(mCamera);
-
     // Activate logic for subclass.
     OnActivate();
 
@@ -224,11 +207,6 @@ void RenderEffectImpl::Deactivate()
 
     // Deactivate logic for subclass.
     OnDeactivate();
-
-    if(mCamera)
-    {
-      mCamera.Unparent();
-    }
   }
 }
 
@@ -315,7 +293,6 @@ void RenderEffectImpl::OnSizeSet(PropertyNotification& source)
         }
         else
         {
-          mCamera.SetPerspectiveProjection(GetTargetSize());
           OnRefresh();
         }
       }
index d352cbebf0e3303e7d19ad100a2e6163cd5161bd..627c9c27cdb55042e1bb5417a42a20d6309c1be2 100644 (file)
@@ -20,7 +20,6 @@
 
 // EXTERNAL INCLUDE
 #include <dali/integration-api/adaptor-framework/scene-holder.h>
-#include <dali/public-api/actors/camera-actor.h>
 #include <dali/public-api/common/intrusive-ptr.h>
 #include <dali/public-api/math/vector2.h>
 #include <dali/public-api/object/base-object.h>
@@ -47,6 +46,7 @@ class RenderEffectImpl : public BaseObject, public ConnectionTracker
 public:
   /**
    * @brief Sets owner Control. Applies effect on the owner.
+   * @note Activates render effect on default.
    * @param[in] control The owner control to apply RenderEffect.
    */
   void SetOwnerControl(Toolkit::Control control);
@@ -85,6 +85,16 @@ public:
    */
   virtual void GetOffScreenRenderTasks(std::vector<Dali::RenderTask>& tasks, bool isForward) = 0;
 
+  /**
+   * @copydoc Dali::Toolkit::RenderEffect::Activate
+   */
+  void Activate();
+
+  /**
+   * @copydoc Dali::Toolkit::RenderEffect::Deactivate
+   */
+  void Deactivate();
+
 protected:
   /**
    * @copydoc Dali::Toolkit::RenderEffect::RenderEffect
@@ -119,12 +129,6 @@ protected:
    */
   Vector2 GetTargetSize() const;
 
-  /**
-   * @brief Get camera that captures full size texture of mOwnerControl
-   * @return mCamera
-   */
-  CameraActor GetCameraActor() const;
-
   /**
    * @brief Get Owner control. It could be return empty handle if owner control is not set, or destroyed.
    * @return mOwnerControl
@@ -160,17 +164,13 @@ protected:
    */
   virtual void OnRefresh() = 0;
 
-private:
   /**
-   * @brief Activates effect on ownerControl
-   */
-  void Activate();
-
-  /**
-   * @brief Deactivates effect
+   * @brief Get whether this effect activated or not.
+   * @return True if effect is activated. False otherwise.
    */
-  void Deactivate();
+  bool IsActivated() const;
 
+private:
   /**
    * @brief Check whether it is possible to activate effect or not.
    *        It will check various status, e.g. the control's visibility.
@@ -178,12 +178,6 @@ private:
    */
   bool IsActivateValid() const;
 
-  /**
-   * @brief Get whether this effect activated or not.
-   * @return True if effect is activated. False otherwise.
-   */
-  bool IsActivated() const;
-
 private:
   /**
    * @brief Calculates a valid target size for texture.
@@ -205,7 +199,6 @@ private:
 
 private:
   Dali::Renderer mRenderer; // An additional renderer for mOwnerControl
-  CameraActor    mCamera;   // A camera that captures full size texture of mOwnerControl
 
   Dali::WeakHandle<Dali::Toolkit::Control> mOwnerControl;         ///< Weakhandle of owner control.
   WeakHandle<Integration::SceneHolder>     mPlacementSceneHolder; ///< Weakhandle of scene
index 0e66eb83f2c983a020eaae993eece3cdc87ca93b..7e746911e187bc8c76f53425cb85ded030cb81a5 100644 (file)
@@ -70,8 +70,8 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/visuals/wireframe/wireframe-visual.cpp
    ${toolkit_src_dir}/controls/alignment/alignment-impl.cpp
    ${toolkit_src_dir}/controls/render-effects/render-effect-impl.cpp
-   ${toolkit_src_dir}/controls/render-effects/blur-effect-impl.cpp
    ${toolkit_src_dir}/controls/render-effects/mask-effect-impl.cpp
+   ${toolkit_src_dir}/controls/render-effects/background-blur-effect-impl.cpp
    ${toolkit_src_dir}/controls/render-effects/offscreen-rendering-impl.cpp
    ${toolkit_src_dir}/controls/bloom-view/bloom-view-impl.cpp
    ${toolkit_src_dir}/controls/bubble-effect/bubble-emitter-impl.cpp
index 65b2551d7792fff5fc04ed556634604531fe7ccb..8ddfe964b651cb81856b822aa6f6e2a2c857fc18 100644 (file)
@@ -8,6 +8,8 @@ INPUT highp vec2 vTexCoord;
 UNIFORM sampler2D sTexture;
 UNIFORM_BLOCK FragBlock
 {
+  UNIFORM highp float uAnimationRatio;
+  UNIFORM highp float uOpacity;
   UNIFORM highp vec2 uSampleOffsets[NUM_SAMPLES];
   UNIFORM highp float uSampleWeights[NUM_SAMPLES];
 };
@@ -17,7 +19,8 @@ void main()
   highp vec4 col = vec4(0.0);
   for (int i=0; i<NUM_SAMPLES; ++i)
   {
-    col += (TEXTURE(sTexture, vTexCoord + uSampleOffsets[i]) + TEXTURE(sTexture, vTexCoord - uSampleOffsets[i])) * uSampleWeights[i];
+    col += (TEXTURE(sTexture, vTexCoord + uSampleOffsets[i] * uAnimationRatio) + TEXTURE(sTexture, vTexCoord - uSampleOffsets[i] * uAnimationRatio)) * uSampleWeights[i];
   }
+  col.w *= uOpacity;
   gl_FragColor = col;
 }
index 7fc9b52dd35f971abe573e71d6c55979ab209048..3538bba80380947f57a22d2958399e0cc84695d9 100644 (file)
@@ -18,7 +18,7 @@
 // CLASS HEADER
 #include <dali-toolkit/public-api/controls/render-effects/background-blur-effect.h>
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/controls/render-effects/blur-effect-impl.h>
+#include <dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.h>
 namespace Dali
 {
 namespace Toolkit
@@ -28,20 +28,60 @@ BackgroundBlurEffect::BackgroundBlurEffect(const BackgroundBlurEffect& handle)
 : RenderEffect(handle)
 {
 }
-BackgroundBlurEffect::BackgroundBlurEffect(Internal::BlurEffectImpl* blurEffectImpl)
-: RenderEffect(blurEffectImpl)
+
+BackgroundBlurEffect::BackgroundBlurEffect(Internal::BackgroundBlurEffectImpl* backgroundBlurEffectImpl)
+: RenderEffect(backgroundBlurEffectImpl)
 {
 }
+
 BackgroundBlurEffect::~BackgroundBlurEffect() = default;
+
 BackgroundBlurEffect BackgroundBlurEffect::New()
 {
-  Internal::BlurEffectImplPtr internal = Internal::BlurEffectImpl::New(true);
+  Internal::BackgroundBlurEffectImplPtr internal = Internal::BackgroundBlurEffectImpl::New();
   return BackgroundBlurEffect(internal.Get());
 }
-BackgroundBlurEffect BackgroundBlurEffect::New(float downscaleFactor, uint32_t blurRadius, bool blurOnce)
+
+BackgroundBlurEffect BackgroundBlurEffect::New(uint32_t blurRadius)
 {
-  Internal::BlurEffectImplPtr internal = Internal::BlurEffectImpl::New(downscaleFactor, blurRadius, blurOnce, true);
+  Internal::BackgroundBlurEffectImplPtr internal = Internal::BackgroundBlurEffectImpl::New(blurRadius);
   return BackgroundBlurEffect(internal.Get());
 }
+
+void BackgroundBlurEffect::SetBlurOnce(bool blurOnce)
+{
+  GetImplementation(*this).SetBlurOnce(blurOnce);
+}
+
+bool BackgroundBlurEffect::GetBlurOnce() const
+{
+  return GetImplementation(*this).GetBlurOnce();
+}
+
+void BackgroundBlurEffect::SetBlurRadius(uint32_t blurRadius)
+{
+  GetImplementation(*this).SetBlurRadius(blurRadius);
+}
+
+uint32_t BackgroundBlurEffect::GetBlurRadius() const
+{
+  return GetImplementation(*this).GetBlurRadius();
+}
+
+void BackgroundBlurEffect::AddBlurStrengthAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue)
+{
+  GetImplementation(*this).AddBlurStrengthAnimation(animation, alphaFunction, timePeriod, fromValue, toValue);
+}
+
+void BackgroundBlurEffect::AddBlurOpacityAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue)
+{
+  GetImplementation(*this).AddBlurOpacityAnimation(animation, alphaFunction, timePeriod, fromValue, toValue);
+}
+
+BackgroundBlurEffect::FinishedSignalType& BackgroundBlurEffect::FinishedSignal()
+{
+  return GetImplementation(*this).FinishedSignal();
+}
+
 } // namespace Toolkit
 } // namespace Dali
index 6f675f309cbff5fa149119da104156b807e017f3..306e9191d87325fd7a97bf8869955ad1dd0d0b5c 100644 (file)
  */
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/render-effects/render-effect.h>
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/alpha-function.h>
+#include <dali/public-api/animation/time-period.h>
+
 namespace Dali
 {
 namespace Toolkit
 {
 namespace Internal DALI_INTERNAL
 {
-class BlurEffectImpl;
+class BackgroundBlurEffectImpl;
 } // namespace DALI_INTERNAL
 /**
  * @brief BackgroundBlurEffect is a visual effect that blurs owner control's background.
@@ -46,40 +50,106 @@ class DALI_TOOLKIT_API BackgroundBlurEffect : public RenderEffect
 {
 public:
   /**
-   * @brief Creates an initialized BackgroundBlurEffect, using default settings. The default settings are:
-   *
-   * downscaleFactor = 0.4f
-   * pixelRadius = 5u
+   * @brief Typedef for finished signals sent by this class.
    *
+   * @SINCE_2_4.15
+   */
+  typedef Signal<void()> FinishedSignalType;
+
+  /**
+   * @brief Creates an initialized BackgroundBlurEffect, using default settings. As default, blur radius is set to 10u.
    * @SINCE_2_3.28
    * @return A handle to a newly allocated Dali resource
    */
   static BackgroundBlurEffect New();
+
   /**
    * @brief Creates an initialized BackgroundBlurEffect.
-   * @param[in] downscaleFactor This value should reside in the range [0.0, 1.0].
    * @param[in] blurRadius The radius of Gaussian kernel.
-   * @param[in] blurOnce Whether to blur once or always. Default is false(always).
    * @SINCE_2_3.28
    * @return A handle to a newly allocated Dali resource
    */
-  static BackgroundBlurEffect New(float downscaleFactor, uint32_t blurRadius, bool blurOnce = false);
+  static BackgroundBlurEffect New(uint32_t blurRadius);
+
   /**
    * @brief Creates an uninitialized blur effect.
    * @SINCE_2_3.28
    */
   BackgroundBlurEffect();
+
   /**
    * @brief Copy constructor.
    * @SINCE_2_3.28
    */
   BackgroundBlurEffect(const BackgroundBlurEffect& handle);
+
   /**
-  * @brief Destructor
-  * @SINCE_2_3.28
-  */
+   * @brief Destructor
+   * @SINCE_2_3.28
+   */
   ~BackgroundBlurEffect();
 
+  /**
+   * @brief Set whether to refresh effect once or every frame.
+   * @param[in] blurOnce If true, renders effect once, else updates effect rendering every frame.
+   * @SINCE_2_4.15
+   */
+  void SetBlurOnce(bool blurOnce);
+
+  /**
+   * @brief Retrives whether effect rendering is done once(true) or every frame(false)
+   * @SINCE_2_4.15
+   */
+  bool GetBlurOnce() const;
+
+  /**
+   * @brief Set blur radius value.
+   * @param[in] blurRadius The radius of Gaussian kernel.
+   * @SINCE_2_4.15
+   */
+  void SetBlurRadius(uint32_t blurRadius);
+
+  /**
+   * @brief Retrieves blur radius value.
+   * @SINCE_2_4.15
+   */
+  uint32_t GetBlurRadius() const;
+
+  /**
+   * @brief Adds blur strength animation. Blurifies clear texture within given animation parameters.
+   * @param[in] animation Animation instance to which we add blur strength animation.
+   * @param[in] alphaFunction AlphaFunction of blur strength animation.
+   * @param[in] timePeriod TimePeriod of blur strength animation. Default value is animation's duration.
+   * @param[in] fromValue Starting value of blur strength. Must be in range of [0.0f, 1.0f]
+   * @param[in] toValue End value of blur strength. Must be in range of [0.0f, 1.0f]
+   * @note If toValue is smaller than fromValue, animation would show reversed(blurred->clarified) animation.
+   * @note When choosing alpha function, note that gaussian curve itself is innately non-linear.
+   * @SINCE_2_4.15
+   */
+  void AddBlurStrengthAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue);
+
+  /**
+   * @brief Adds blur opacity animation. Blurifies clear texture within given animation parameters.
+   * @param[in] animation Animation instance to which we add blur opacity animation.
+   * @param[in] alphaFunction AlphaFunction of blur opacity animation.
+   * @param[in] timePeriod TimePeriod of blur opacity animation. Default value is animation's duration.
+   * @param[in] fromValue Starting value of blur opacity. Must be in range of [0.0f, 1.0f]
+   * @param[in] toValue End value of blur opacity. Must be in range of [0.0f, 1.0f]
+   * @note If toValue is smaller than fromValue, animation would show reversed(blurred->clarified) animation.
+   * @note When choosing alpha function, note that gaussian curve itself is innately non-linear.
+   * @SINCE_2_4.15
+   */
+  void AddBlurOpacityAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue);
+
+public: // Signals
+  /**
+   * @brief If blurOnce is true and effect is activated, then connect to this signal to be notified when the
+   * target actor has been rendered.
+   * @SINCE_2_4.15
+   * @return The finished signal
+   */
+  FinishedSignalType& FinishedSignal();
+
 public: // Not intended for use by Application developers
   ///@cond internal
   /**
@@ -87,7 +157,7 @@ public: // Not intended for use by Application developers
    * @SINCE_2_3.28
    * @param[in]  blurEffectImpl The UI Control implementation.
    */
-  explicit DALI_INTERNAL BackgroundBlurEffect(Internal::BlurEffectImpl* blurEffectImpl);
+  explicit DALI_INTERNAL BackgroundBlurEffect(Internal::BackgroundBlurEffectImpl* backgroundBlurEffectImpl);
   ///@endcond
 };
 } // namespace Toolkit
index 2884ce274d1e24433e03bb439336cb718f008e3e..4c25786c0525241f8111c3a9bcdc4feb9ec04adc 100644 (file)
@@ -35,5 +35,14 @@ RenderEffect::RenderEffect(Internal::RenderEffectImpl* renderEffectImpl)
 {
 }
 
+void RenderEffect::Activate()
+{
+  GetImplementation(*this).Activate();
+}
+
+void RenderEffect::Deactivate()
+{
+  GetImplementation(*this).Deactivate();
+}
 } // namespace Toolkit
 } // namespace Dali
index f7194c10062d70b31588c2b27b6586533139147b..0129a8576209d573f194a87a0b2fb65aa9d2d3af 100644 (file)
@@ -70,6 +70,18 @@ public:
    */
   RenderEffect(const RenderEffect& handle);
 
+  /**
+   * @brief Activates effect on ownerControl
+   * @SINCE_2_4.15
+   */
+  void Activate();
+
+  /**
+   * @brief Deactivates effect
+   * @SINCE_2_4.15
+   */
+  void Deactivate();
+
 public: // Not intended for Application developers
   ///@cond internal
   /**