Support RenderEffect 09/309609/42
authorjmm <j0064423.lee@samsung.com>
Fri, 12 Apr 2024 04:35:02 +0000 (13:35 +0900)
committerjmm <j0064423.lee@samsung.com>
Thu, 13 Jun 2024 06:01:16 +0000 (15:01 +0900)
Change-Id: I9c302358dd984906bf26dc7423c9ce7f02de0f8e

22 files changed:
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/utc-Dali-RenderEffect.cpp [new file with mode: 0644]
dali-scene3d/public-api/controls/scene-view/scene-view.h
dali-toolkit/dali-toolkit.h
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/render-effects/blur-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/render-effects/render-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/render-effects/render-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/internal/graphics/shaders/control-renderers.frag
dali-toolkit/internal/graphics/shaders/control-renderers.vert
dali-toolkit/internal/graphics/shaders/gaussian-blur-view.frag
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/control-impl.h
dali-toolkit/public-api/controls/control.cpp
dali-toolkit/public-api/controls/control.h
dali-toolkit/public-api/controls/render-effects/background-blur-effect.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/render-effects/background-blur-effect.h [new file with mode: 0644]
dali-toolkit/public-api/controls/render-effects/render-effect.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/render-effects/render-effect.h [new file with mode: 0644]
dali-toolkit/public-api/file.list

index 8d33504..75f2eb6 100755 (executable)
@@ -11,6 +11,7 @@ SET(TC_SOURCES
   utc-Dali-AnimatedImageVisual.cpp
   utc-Dali-AnimatedVectorImageVisual.cpp
   utc-Dali-ArcVisual.cpp
+  utc-Dali-RenderEffect.cpp
   utc-Dali-BloomView.cpp
   utc-Dali-BubbleEmitter.cpp
   utc-Dali-Builder.cpp
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-RenderEffect.cpp b/automated-tests/src/dali-toolkit/utc-Dali-RenderEffect.cpp
new file mode 100644 (file)
index 0000000..5f1933b
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/public-api/controls/render-effects/background-blur-effect.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+int UtcDaliRenderEffectNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectNewP");
+
+  BackgroundBlurEffect blurEffect = BackgroundBlurEffect::New();
+  DALI_TEST_CHECK(blurEffect);
+
+  BackgroundBlurEffect blurEffect2 = BackgroundBlurEffect::New(0.5f, 10.0f, 10.0f);
+  DALI_TEST_CHECK(blurEffect2);
+
+  END_TEST;
+}
+
+int UtcDaliRenderEffectNewN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectNewN");
+
+  try
+  {
+    BackgroundBlurEffect blurEffect = BackgroundBlurEffect::New(-0.5f, 10.0f, 10.0f);
+    BackgroundBlurEffect blurEffect2 = BackgroundBlurEffect::New(10.0f, 10.0f, 10.0f);
+    DALI_TEST_CHECK(!blurEffect && !blurEffect2);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_PRINT_ASSERT(e);
+    DALI_TEST_CHECK(true);
+  }
+  END_TEST;
+}
+
+int UtcDaliRenderEffectActivateP01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectActivateP01");
+
+  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));
+
+  Control childControl = Control::New();
+  childControl.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f));
+
+  scene.Add(control);
+  control.Add(childControl);
+
+  RenderTaskList taskList = scene.GetRenderTaskList();
+  DALI_TEST_CHECK(1u == taskList.GetTaskCount());
+
+  childControl.SetRenderEffect(BackgroundBlurEffect::New());
+
+  taskList = scene.GetRenderTaskList();
+  DALI_LOG_ERROR("%d\n", taskList.GetTaskCount());
+  DALI_TEST_CHECK(4u == taskList.GetTaskCount());
+
+  END_TEST;
+}
+
+int UtcDaliRenderEffectActivateP02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectActivateP02");
+
+  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));
+  scene.Add(control);
+
+  BackgroundBlurEffect blurEffect = BackgroundBlurEffect::New();
+  control.SetRenderEffect(blurEffect);
+
+  RenderTaskList taskList = scene.GetRenderTaskList();
+  DALI_TEST_CHECK(4u == taskList.GetTaskCount());
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control2.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f));
+  scene.Add(control2);
+
+  control2.SetRenderEffect(blurEffect); // Ownership changed.
+  taskList = scene.GetRenderTaskList();
+  DALI_TEST_CHECK(4u == taskList.GetTaskCount());
+
+  END_TEST;
+}
+
+int UtcDaliRenderEffectDeactivateP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectDeactivateP");
+
+  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));
+  scene.Add(control);
+
+  uint32_t count = control.GetRendererCount();
+  control.SetRenderEffect(BackgroundBlurEffect::New());
+
+  RenderTaskList taskList = scene.GetRenderTaskList();
+  DALI_TEST_CHECK(4u == taskList.GetTaskCount());
+  DALI_TEST_CHECK(count + 1 == control.GetRendererCount());
+
+  control.ClearRenderEffect();
+  taskList = scene.GetRenderTaskList();
+  DALI_TEST_CHECK(1u == taskList.GetTaskCount());
+  DALI_TEST_CHECK(count == control.GetRendererCount());
+
+  END_TEST;
+}
+
+int UtcDaliRenderEffectDeactivateN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectDeactivateN");
+
+  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));
+  scene.Add(control);
+
+  try
+  {
+    control.ClearRenderEffect();
+    DALI_TEST_CHECK(false);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_PRINT_ASSERT(e);
+    DALI_TEST_CHECK(true);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliRenderEffectRepeatActivateDeactivate(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliRenderEffectRepeatActivateDeactivate");
+
+  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));
+  scene.Add(control);
+
+  BackgroundBlurEffect blurEffect = BackgroundBlurEffect::New();
+  for(int i = 0; i < 3; i++)
+  {
+    control.SetRenderEffect(blurEffect); // Activate
+    RenderTaskList taskList = scene.GetRenderTaskList();
+    DALI_TEST_CHECK(4u == taskList.GetTaskCount());
+    //control.ClearRenderEffect(); // Deactivate, Done automatically on duplicated jobs.
+  }
+
+  END_TEST;
+}
index 79e9751..7dc26c0 100644 (file)
@@ -88,6 +88,7 @@ class SceneView;
  * And since SceneView is a Control, it can be placed together with other 2D UI components in the DALi window.
  *
  * @note We support to render model well only if glsl version is higher than 300.
+ * @note We do not support Toolkit::RenderEffect when UseFrameBuffer(false).
  *
  * @SINCE_2_1.38
  * @code
@@ -377,6 +378,7 @@ public:
    * @brief Sets whether to use FBO or not for the SceneView.
    * If useFramebuffer is true, rendering result of SceneView is drawn on FBO and it is mapping on this SceneView plane.
    * If useFramebuffer is false, each item in SceneView is rendered on window directly.
+   * Note that Toolkit::RenderEffect is not supported in this case.
    * Default is false.
    *
    * @SINCE_2_1.38
index edee27e..f80d0ac 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_H
 
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -61,6 +61,9 @@
 
 #include <dali-toolkit/public-api/styling/style-manager.h>
 
+#include <dali-toolkit/public-api/controls/render-effects/background-blur-effect.h>
+#include <dali-toolkit/public-api/controls/render-effects/render-effect.h>
+
 #include <dali-toolkit/public-api/text/text-enumerations.h>
 
 #include <dali-toolkit/public-api/transition/fade-transition.h>
index 0641764..fff6769 100644 (file)
@@ -20,9 +20,9 @@
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/accessibility.h>
+#include <dali/integration-api/processor-interface.h>
 #include <dali/public-api/object/property-notification.h>
 #include <dali/public-api/object/type-registry.h>
-#include <dali/integration-api/processor-interface.h>
 #include <string>
 
 // INTERNAL INCLUDES
@@ -34,6 +34,7 @@
 #include <dali-toolkit/internal/controls/tooltip/tooltip.h>
 #include <dali-toolkit/internal/visuals/visual-event-observer.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/render-effects/render-effect.h>
 #include <dali-toolkit/public-api/visuals/visual-properties.h>
 #include <dali/devel-api/common/owner-container.h>
 #include <dali/integration-api/debug.h>
@@ -600,6 +601,7 @@ public:
   RegisteredVisualContainer                 mVisuals; ///< Stores visuals needed by the control, non trivial type so std::vector used.
   std::string                               mStyleName;
   Vector4                                   mBackgroundColor;    ///< The color of the background visual
+  RenderEffect                              mRenderEffect;       ///< The render effect on this control
   Vector3*                                  mStartingPinchScale; ///< The scale when a pinch gesture starts, TODO: consider removing this
   Extents                                   mMargin;             ///< The margin values
   Extents                                   mPadding;            ///< The padding values
diff --git a/dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp b/dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp
new file mode 100644 (file)
index 0000000..4408e0a
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2024 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/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/common/stage.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>
+
+namespace
+{
+// Default values
+static constexpr float    BLUR_EFFECT_DOWNSCALE_FACTOR    = 0.4f;
+static constexpr uint32_t BLUR_EFFECT_PIXEL_RADIUS        = 5u;
+static constexpr float    BLUR_EFFECT_BELL_CURVE_WIDTH    = 1.5f;
+static constexpr int32_t  BLUR_EFFECT_ORDER_INDEX         = 101;
+static constexpr float    BLUR_EFFECT_DIVIDE_ZERO_EPSILON = 0.001f;
+} // namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+// mMultiplierForFraction and mDenominator are for CalculateGaussianWeight().
+// The original equation,
+//   (1.0f / sqrt(2.0f * Math::PI * mBellCurveWidth)) * exp(-(localOffset * localOffset) * (1.0f / (2.0f * mBellCurveWidth * mBellCurveWidth)));
+// is simplified as below:
+//   mDenominator * exp(-(localOffset * localOffset) * mMultiplierForFraction);
+
+BlurEffectImpl::BlurEffectImpl(bool isBackground)
+: RenderEffectImpl(),
+  mInternalRoot(Actor::New()),
+  mDownscaleFactor(BLUR_EFFECT_DOWNSCALE_FACTOR),
+  mPixelRadius(BLUR_EFFECT_PIXEL_RADIUS),
+  mBellCurveWidth(BLUR_EFFECT_BELL_CURVE_WIDTH),
+  mMultiplierForFraction(1.0f / (2.0f * mBellCurveWidth * mBellCurveWidth)),
+  mDenominator(1.0f / sqrt(2.0f * Math::PI * mBellCurveWidth)),
+  mIsActivated(false),
+  mIsBackground(isBackground)
+{
+}
+
+BlurEffectImpl::BlurEffectImpl(float downscaleFactor, uint32_t blurRadius, float bellCurveWidth, bool isBackground)
+: RenderEffectImpl(),
+  mInternalRoot(Actor::New()),
+  mDownscaleFactor(downscaleFactor),
+  mPixelRadius((blurRadius >> 2) + 1),
+  mBellCurveWidth(std::max(bellCurveWidth, BLUR_EFFECT_DIVIDE_ZERO_EPSILON)),
+  mMultiplierForFraction(1.0f / (2.0f * mBellCurveWidth * mBellCurveWidth)),
+  mDenominator(1.0f / sqrt(2.0f * Math::PI * mBellCurveWidth)),
+  mIsActivated(false),
+  mIsBackground(isBackground)
+{
+  DALI_ASSERT_ALWAYS(downscaleFactor <= 1.0 && 0.0 < downscaleFactor);
+}
+
+BlurEffectImpl::~BlurEffectImpl()
+{
+}
+
+BlurEffectImplPtr BlurEffectImpl::New(bool isBackground)
+{
+  BlurEffectImplPtr handle = new BlurEffectImpl(isBackground);
+  handle->Initialize();
+  return handle;
+}
+
+BlurEffectImplPtr BlurEffectImpl::New(float downscaleFactor, uint32_t blurRadius, float bellCurveWidth, bool isBackground)
+{
+  BlurEffectImplPtr handle = new BlurEffectImpl(downscaleFactor, blurRadius, bellCurveWidth, isBackground);
+  handle->Initialize();
+  return handle;
+}
+
+void BlurEffectImpl::Initialize()
+{
+  RegisterObject(); // of parent's parent class
+
+  mRenderFullSizeCamera = CameraActor::New();
+  mRenderFullSizeCamera.SetInvertYAxis(true);
+  mRenderFullSizeCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
+  mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK);
+  mRenderFullSizeCamera.SetFieldOfView(Math::PI / 4.0f);
+  mInternalRoot.Add(mRenderFullSizeCamera);
+
+  mRenderDownsampledCamera = CameraActor::New();
+  mRenderDownsampledCamera.SetInvertYAxis(true);
+  mRenderDownsampledCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
+  mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK);
+  mRenderDownsampledCamera.SetFieldOfView(Math::PI / 4.0f);
+  mInternalRoot.Add(mRenderDownsampledCamera);
+
+  //////////////////////////////////////////////////////
+  // Create shaders
+
+  std::ostringstream fragmentStringStream;
+  fragmentStringStream << "#define NUM_SAMPLES " << mPixelRadius << "\n";
+  fragmentStringStream << SHADER_GAUSSIAN_BLUR_VIEW_FRAG;
+  std::string fragmentSource(fragmentStringStream.str());
+
+  //////////////////////////////////////////////////////
+  // Create actors
+  mInternalRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  // 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());
+  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());
+  mVerticalBlurActor.AddRenderer(verticalBlurRenderer);
+  mInternalRoot.Add(mVerticalBlurActor);
+}
+
+void BlurEffectImpl::Activate()
+{
+  DALI_ASSERT_ALWAYS(!mIsActivated &&
+                     "This effect is already taken. Call Toolkit::Control::ClearRenderEffect(); to free the effect.");
+
+  Toolkit::Control handle = GetOwnerControl();
+  DALI_ASSERT_ALWAYS(handle); // RenderEffect::SetOwnerControl(mOwnerControl); was done.
+
+  // Get input texture size
+  Vector2 size = GetTargetSize();
+  if(size == Vector2::ZERO)
+  {
+    size = handle.GetNaturalSize();
+    if(size == Vector2::ZERO)
+    {
+      return;
+    }
+  }
+  DALI_ASSERT_ALWAYS(!(size.x < 0.0f || size.y < 0.0f || uint32_t(size.x) > Dali::GetMaxTextureSize() || uint32_t(size.y) > Dali::GetMaxTextureSize()) && "You need to pass a valid texture size.");
+
+  uint32_t downsampledWidth  = static_cast<uint32_t>(size.width * mDownscaleFactor);
+  uint32_t downsampledHeight = static_cast<uint32_t>(size.height * mDownscaleFactor);
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  // Prepare resource
+  // original texture output
+  mInputBackgroundFrameBuffer    = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::NONE);
+  Texture inputBackgroundTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
+  mInputBackgroundFrameBuffer.AttachColorTexture(inputBackgroundTexture);
+
+  // half-blurred output
+  mTemporaryFrameBuffer    = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::NONE);
+  Texture temporaryTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
+  mTemporaryFrameBuffer.AttachColorTexture(temporaryTexture);
+
+  // blurred output
+  mSourceFrameBuffer    = FrameBuffer::New(downsampledWidth, downsampledHeight, FrameBuffer::Attachment::NONE);
+  Texture sourceTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, downsampledWidth, downsampledHeight);
+  mSourceFrameBuffer.AttachColorTexture(sourceTexture);
+
+  // Add BlurActors
+  mHorizontalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight)); // mTemporaryFrameBuffer
+  mVerticalBlurActor.SetProperty(Actor::Property::SIZE, Vector2(downsampledWidth, downsampledHeight));   // mSourceFrameBuffer
+
+  // Add CameraActors
+  float cameraPosConstraintScale = 0.5f / tanf(Math::PI / 4.0f * 0.5f);
+
+  mRenderFullSizeCamera.SetAspectRatio(size.width / size.height);
+  mRenderFullSizeCamera.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, cameraPosConstraintScale * size.height));
+
+  mRenderDownsampledCamera.SetAspectRatio(float(downsampledWidth) / float(downsampledHeight));
+  mRenderDownsampledCamera.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, cameraPosConstraintScale * size.height * mDownscaleFactor));
+
+  SetShaderConstants(downsampledWidth, downsampledHeight);
+
+  // Prepare input texture
+  mSourceRenderTask = taskList.CreateTask();
+  if(mIsBackground)
+  {
+    mSourceRenderTask.SetSourceActor(Stage::GetCurrent().GetRootLayer());
+    mSourceRenderTask.RenderUntil(handle);
+  }
+  else
+  {
+    mSourceRenderTask.SetSourceActor(handle);
+  }
+  mSourceRenderTask.SetOrderIndex(BLUR_EFFECT_ORDER_INDEX);
+  mSourceRenderTask.SetCameraActor(mRenderFullSizeCamera);
+  mSourceRenderTask.SetFrameBuffer(mInputBackgroundFrameBuffer);
+  mSourceRenderTask.SetInputEnabled(false);
+  mSourceRenderTask.SetExclusive(false);
+
+  // Blur tasks
+  SetRendererTexture(mHorizontalBlurActor.GetRendererAt(0), mInputBackgroundFrameBuffer);
+  mHorizontalBlurTask = taskList.CreateTask();
+  mHorizontalBlurTask.SetSourceActor(mHorizontalBlurActor);
+  mHorizontalBlurTask.SetOrderIndex(BLUR_EFFECT_ORDER_INDEX + 1);
+  mHorizontalBlurTask.SetExclusive(true);
+  mHorizontalBlurTask.SetInputEnabled(false);
+  mHorizontalBlurTask.SetCameraActor(mRenderDownsampledCamera);
+  mHorizontalBlurTask.SetFrameBuffer(mTemporaryFrameBuffer);
+
+  SetRendererTexture(mVerticalBlurActor.GetRendererAt(0), mTemporaryFrameBuffer);
+  mVerticalBlurTask = taskList.CreateTask();
+  mVerticalBlurTask.SetSourceActor(mVerticalBlurActor);
+  mVerticalBlurTask.SetOrderIndex(BLUR_EFFECT_ORDER_INDEX + 2);
+  mVerticalBlurTask.SetExclusive(true);
+  mVerticalBlurTask.SetInputEnabled(false);
+  mVerticalBlurTask.SetCameraActor(mRenderDownsampledCamera);
+  mVerticalBlurTask.SetFrameBuffer(mSourceFrameBuffer);
+
+  // Inject output to control
+  Renderer renderer = GetTargetRenderer();
+  if(mIsBackground)
+  {
+    renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Dali::Toolkit::DepthIndex::BACKGROUND - 3);
+  }
+  else
+  {
+    renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Dali::Toolkit::DepthIndex::CONTENT);
+  }
+  handle.AddRenderer(renderer);
+  SetRendererTexture(renderer, mSourceFrameBuffer);
+
+  handle.Add(mInternalRoot);
+  mIsActivated = true;
+}
+
+void BlurEffectImpl::Deactivate()
+{
+  mIsActivated = false;
+
+  mInternalRoot.Unparent();
+
+  mInputBackgroundFrameBuffer.Reset();
+  mTemporaryFrameBuffer.Reset();
+  mSourceFrameBuffer.Reset();
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  taskList.RemoveTask(mHorizontalBlurTask);
+  taskList.RemoveTask(mVerticalBlurTask);
+  taskList.RemoveTask(mSourceRenderTask);
+
+  auto ownerControl = GetOwnerControl();
+  if(ownerControl)
+  {
+    Renderer renderer = GetTargetRenderer();
+    ownerControl.RemoveRenderer(renderer);
+  }
+}
+
+void BlurEffectImpl::SetShaderConstants(float downsampledWidth, float downsampledHeight)
+{
+  std::vector<float> uvOffsets(mPixelRadius);
+  std::vector<float> weights(mPixelRadius);
+
+  // generate bell curve kernel
+  unsigned int       halfSize = mPixelRadius * 2;
+  std::vector<float> halfSideKernel(halfSize);
+
+  halfSideKernel[0]  = CalculateGaussianWeight(0.0f);
+  float totalWeights = halfSideKernel[0];
+  for(unsigned int i = 1; i < halfSize; i++)
+  {
+    float w           = CalculateGaussianWeight(i);
+    halfSideKernel[i] = w;
+    totalWeights += w * 2.0f;
+  }
+  for(unsigned int i = 0; i < halfSize; i++)
+  {
+    halfSideKernel[i] /= totalWeights;
+  }
+  halfSideKernel[0] *= 0.5f;
+
+  // compress kernel
+  for(unsigned int i = 0; i < mPixelRadius; 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 < mPixelRadius; ++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
new file mode 100644 (file)
index 0000000..eb3fdc2
--- /dev/null
@@ -0,0 +1,185 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BLUR_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_BLUR_EFFECT_H
+
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// 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
+{
+class BlurEffectImpl;
+
+namespace Internal
+{
+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
+   * bellCurveWidth = 1.5f
+   *
+   * 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] bellCurveWidth Blur intensity.
+   * @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, float bellCurveWidth, bool isBackground);
+
+  /**
+   * @brief Activates blur effect
+   */
+  void Activate() override;
+
+  /**
+   * @brief Dectivates blur effect
+   */
+  void Deactivate() 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] bellCurveWidth Blur intensity.
+   * @param[in] isBackground True when blurring background, False otherwise
+   */
+  BlurEffectImpl(float downscaleFactor, uint32_t blurRadius, float bellCurveWidth, bool isBackground);
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~BlurEffectImpl();
+
+  /**
+   * @brief Initializes effect
+   */
+  void Initialize() override;
+
+private:
+  // Inner functions
+
+  /**
+   * @brief Calculates gaussian weight
+   * @param[in] localOffset Input to the function
+   */
+  inline float CalculateGaussianWeight(float localOffset) const
+  {
+    return mDenominator * exp(-(localOffset * localOffset) * mMultiplierForFraction);
+  }
+
+  /**
+   * @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(float downsampledWidth, float 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 mRenderFullSizeCamera;
+  CameraActor mRenderDownsampledCamera;
+
+  // Resource
+  FrameBuffer mInputBackgroundFrameBuffer; // Input. Background. What to blur.
+
+  Actor       mInternalRoot;
+  Actor       mHorizontalBlurActor;
+  RenderTask  mHorizontalBlurTask;
+  FrameBuffer mTemporaryFrameBuffer;
+  Actor       mVerticalBlurActor;
+  RenderTask  mVerticalBlurTask;
+
+  FrameBuffer mSourceFrameBuffer; // Output. Blurred background texture for mOwnerControl and mRenderer.
+  RenderTask  mSourceRenderTask;
+
+  // Variables
+  Pixel::Format mPixelFormat;
+  float         mDownscaleFactor;
+  uint32_t      mPixelRadius;
+  float         mBellCurveWidth;
+  float         mMultiplierForFraction;
+  float         mDenominator;
+
+  bool mIsActivated : 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
diff --git a/dali-toolkit/internal/controls/render-effects/render-effect-impl.cpp b/dali-toolkit/internal/controls/render-effects/render-effect-impl.cpp
new file mode 100644 (file)
index 0000000..ae3a36d
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2024 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/render-effect-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+
+namespace
+{
+static constexpr float SIZE_STEP_CONDITION = 3.0f;
+} // namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+RenderEffectImpl::~RenderEffectImpl() = default;
+
+void RenderEffectImpl::SetOwnerControl(Dali::Toolkit::Control control)
+{
+  if(mOwnerControl)
+  {
+    Deactivate();
+    mOwnerControl.RemovePropertyNotification(mSizeNotification);
+  }
+
+  mOwnerControl = control;
+
+  if(mOwnerControl)
+  {
+    mTargetSize = mOwnerControl.GetProperty<Vector2>(Actor::Property::SIZE);
+    mRenderer   = CreateRenderer(BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE);
+
+    mSizeNotification = control.AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
+    mSizeNotification.NotifySignal().Connect(this, &RenderEffectImpl::OnSizeSet);
+  }
+}
+
+void RenderEffectImpl::OnSizeSet(PropertyNotification& source)
+{
+  mTargetSize = mOwnerControl.GetProperty<Vector2>(Actor::Property::SIZE);
+  Deactivate();
+  Activate();
+}
+
+Renderer RenderEffectImpl::GetTargetRenderer() const
+{
+  return mRenderer;
+}
+
+Toolkit::Control RenderEffectImpl::GetOwnerControl() const
+{
+  return mOwnerControl;
+}
+
+Vector2 RenderEffectImpl::GetTargetSize() const
+{
+  return mTargetSize;
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/render-effects/render-effect-impl.h b/dali-toolkit/internal/controls/render-effects/render-effect-impl.h
new file mode 100644 (file)
index 0000000..8a21c84
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BACKGROUND_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_BACKGROUND_EFFECT_H
+
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/render-effects/render-effect.h>
+
+// EXTERNAL INCLUDE
+#include <dali/public-api/dali-core.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+class RenderEffectImpl;
+
+namespace Internal
+{
+using RenderEffectImplPtr = IntrusivePtr<RenderEffectImpl>;
+
+class RenderEffectImpl : public BaseObject, public ConnectionTracker
+{
+public:
+  /**
+   * @brief Sets owner Control. Applies effect on the owner.
+   * @param[in] control The owner control to apply RenderEffect.
+   */
+  void SetOwnerControl(Dali::Toolkit::Control control);
+
+  /**
+   * @brief Get Owner control.
+   * @return mOwnerControl
+   */
+  Toolkit::Control GetOwnerControl() const;
+
+  /**
+   * @brief Activate effect.
+   */
+  virtual void Activate() = 0;
+
+  /**
+   * @brief Deactivate effect.
+   */
+  virtual void Deactivate() = 0;
+
+protected:
+  /**
+   * @copydoc Dali::Toolkit::RenderEffect::RenderEffect
+   */
+  RenderEffectImpl() = default;
+
+  /**
+   * @copydoc Dali::Toolkit::RenderEffect::~RenderEffect
+   */
+  virtual ~RenderEffectImpl() override;
+
+  RenderEffectImpl(const RenderEffectImpl&) = delete;
+  RenderEffectImpl(RenderEffectImpl&&)      = delete;
+  RenderEffectImpl& operator=(RenderEffectImpl&&) = delete;      // no move()
+  RenderEffectImpl& operator=(const RenderEffectImpl&) = delete; // no copy()
+
+  virtual void Initialize() = 0;
+
+  /**
+   * @brief Get target renderer
+   * On internal Activate(), the renderer draws our visual effect and is added to our Owner control.
+   * @return mRenderer
+   */
+  Renderer GetTargetRenderer() const;
+
+  /**
+   * @brief Callback when the size changes.
+   */
+  void OnSizeSet(PropertyNotification& source);
+
+  /**
+   * @brief The final size of the owner after resizing or relayouts.
+   * @return mTargetSize
+   */
+  Vector2 GetTargetSize() const;
+
+private:
+  Dali::Renderer         mRenderer; // An additional renderer for mOwnerControl
+  Dali::Toolkit::Control mOwnerControl;
+
+  Vector2              mTargetSize;       // The final size of mOwnerControl
+  PropertyNotification mSizeNotification; // Resize/Relayout signal
+};
+} // namespace Internal
+
+inline Toolkit::Internal::RenderEffectImpl& GetImplementation(Toolkit::RenderEffect& obj)
+{
+  BaseObject& handle = obj.GetBaseObject();
+  return static_cast<Toolkit::Internal::RenderEffectImpl&>(handle);
+}
+
+inline const Toolkit::Internal::RenderEffectImpl& GetImplementation(const Toolkit::RenderEffect& obj)
+{
+  const BaseObject& handle = obj.GetBaseObject();
+  return static_cast<const Toolkit::Internal::RenderEffectImpl&>(handle);
+}
+
+} // namespace Toolkit
+} // namespace Dali
+#endif // DALI_TOOLKIT_INTERNAL_BACKGROUND_EFFECT_H
index e9ae5b7..771fe8d 100644 (file)
@@ -64,6 +64,8 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/visuals/visual-url.cpp
    ${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/bloom-view/bloom-view-impl.cpp
    ${toolkit_src_dir}/controls/bubble-effect/bubble-emitter-impl.cpp
    ${toolkit_src_dir}/controls/bubble-effect/bubble-renderer.cpp
index e29e6a1..e0d08bf 100644 (file)
@@ -1,5 +1,5 @@
-precision mediump float;
-varying mediump vec2 vTexCoord;
+precision highp float;
+varying highp vec2 vTexCoord;
 uniform sampler2D sTexture;
 uniform vec4 uColor;
 
index e7e930f..0183ee4 100644 (file)
@@ -1,12 +1,12 @@
-precision mediump float;
-attribute mediump vec2 aPosition;
-varying mediump vec2 vTexCoord;
-uniform mediump mat4 uMvpMatrix;
-uniform mediump vec3 uSize;
+precision highp float;
+attribute highp vec2 aPosition;
+varying highp vec2 vTexCoord;
+uniform highp mat4 uMvpMatrix;
+uniform highp vec3 uSize;
 
 void main()
 {
-  mediump vec4 vertexPosition = vec4(aPosition * uSize.xy, 0.0, 1.0);
+  highp vec4 vertexPosition = vec4(aPosition * uSize.xy, 0.0, 1.0);
   vTexCoord = aPosition + vec2(0.5);
   gl_Position = uMvpMatrix * vertexPosition;
 }
index 6613b0f..626d27b 100644 (file)
@@ -1,15 +1,15 @@
-varying mediump vec2 vTexCoord;
+varying highp vec2 vTexCoord;
 uniform sampler2D sTexture;
 uniform lowp vec4 uColor;
-uniform mediump vec2 uSampleOffsets[NUM_SAMPLES];
-uniform mediump float uSampleWeights[NUM_SAMPLES];
+uniform highp vec2 uSampleOffsets[NUM_SAMPLES];
+uniform highp float uSampleWeights[NUM_SAMPLES];
 
 void main()
 {
-  mediump vec4 col = texture2D(sTexture, vTexCoord + uSampleOffsets[0]) * uSampleWeights[0];
-  for (int i=1; i<NUM_SAMPLES; ++i)
+  highp vec4 col = vec4(0.0);
+  for (int i=0; i<NUM_SAMPLES; ++i)
   {
-    col += texture2D(sTexture, vTexCoord + uSampleOffsets[i]) * uSampleWeights[i];
+    col += (texture2D(sTexture, vTexCoord + uSampleOffsets[i]) + texture2D(sTexture, vTexCoord - uSampleOffsets[i])) * uSampleWeights[i];
   }
   gl_FragColor = col;
 }
index 914e812..f78c02c 100644 (file)
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
-#include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/controls/render-effects/render-effect-impl.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/public-api/align-enumerations.h>
 #include <dali-toolkit/public-api/controls/control.h>
@@ -166,6 +167,36 @@ void Control::ClearBackground()
   RelayoutRequest();
 }
 
+void Control::SetRenderEffect(Toolkit::RenderEffect effect)
+{
+  if(mImpl->mRenderEffect == effect)
+  {
+    return;
+  }
+  mImpl->mRenderEffect = effect;
+
+  BaseObject&                          handle = effect.GetBaseObject();
+  Toolkit::Internal::RenderEffectImpl* object = dynamic_cast<Toolkit::Internal::RenderEffectImpl*>(&handle);
+
+  Dali::Toolkit::Control ownerControl(GetOwner());
+  object->SetOwnerControl(ownerControl);
+  object->Activate();
+}
+
+void Control::ClearRenderEffect()
+{
+  BaseObject&                          handle = mImpl->mRenderEffect.GetBaseObject();
+  Toolkit::Internal::RenderEffectImpl* object = dynamic_cast<Toolkit::Internal::RenderEffectImpl*>(&handle);
+
+  if(!object)
+  {
+    DALI_ASSERT_ALWAYS(false && "Set any render effect before you clear.");
+  }
+
+  object->Deactivate();
+  object->SetOwnerControl(Toolkit::Control());
+}
+
 void Control::SetResourceReady()
 {
   Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(*this);
@@ -602,7 +633,7 @@ void Control::OnPropertySet(Property::Index index, const Property::Value& proper
 
 void Control::OnSizeSet(const Vector3& targetSize)
 {
-  Vector2 size(targetSize);
+  Vector2               size(targetSize);
   Toolkit::Visual::Base visual = mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
   if(visual)
   {
index 9e2915e..4fe0781 100644 (file)
@@ -115,6 +115,16 @@ public:
   void ClearBackground();
 
   /**
+   * @copydoc Dali::Toolkit::Control::SetRenderEffect
+   */
+  void SetRenderEffect(Toolkit::RenderEffect effect);
+
+  /**
+   * @copydoc Dali::Toolkit::Control::ClearRenderEffect
+   */
+  void ClearRenderEffect();
+
+  /**
    * @brief Called when resources of control are ready. this api does not request relayout.
    */
   void SetResourceReady();
index 2e918f0..c163378 100644 (file)
@@ -115,6 +115,16 @@ void Control::ClearBackground()
   Internal::GetImplementation(*this).ClearBackground();
 }
 
+void Control::SetRenderEffect(Toolkit::RenderEffect effect)
+{
+  Internal::GetImplementation(*this).SetRenderEffect(effect);
+}
+
+void Control::ClearRenderEffect()
+{
+  Internal::GetImplementation(*this).ClearRenderEffect();
+}
+
 bool Control::IsResourceReady() const
 {
   return Internal::GetImplementation(*this).IsResourceReady();
index e4e90a2..7da13e8 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_CONTROL_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -33,6 +33,7 @@ namespace Dali
 {
 namespace Toolkit
 {
+class RenderEffect;
 //Forward declarations.
 
 namespace Internal
@@ -147,16 +148,16 @@ public:
      */
     enum Direction
     {
-      LEFT,      ///< Move keyboard focus towards the left direction @SINCE_1_0.0
-      RIGHT,     ///< Move keyboard focus towards the right direction @SINCE_1_0.0
-      UP,        ///< Move keyboard focus towards the up direction @SINCE_1_0.0
-      DOWN,      ///< Move keyboard focus towards the down direction @SINCE_1_0.0
-      PAGE_UP,   ///< Move keyboard focus towards the previous page direction @SINCE_1_2.14
-      PAGE_DOWN, ///< Move keyboard focus towards the next page direction @SINCE_1_2.14
-      FORWARD,   ///< Move keyboard focus towards the forward direction @SINCE_2_1.10
-      BACKWARD,  ///< Move keyboard focus towards the backward direction @SINCE_2_1.10
-      CLOCKWISE,  ///< Move keyboard focus towards the clockwise direction @SINCE_2_1.14
-      COUNTER_CLOCKWISE,  ///< Move keyboard focus towards the counter clockwise direction @SINCE_2_1.14
+      LEFT,              ///< Move keyboard focus towards the left direction @SINCE_1_0.0
+      RIGHT,             ///< Move keyboard focus towards the right direction @SINCE_1_0.0
+      UP,                ///< Move keyboard focus towards the up direction @SINCE_1_0.0
+      DOWN,              ///< Move keyboard focus towards the down direction @SINCE_1_0.0
+      PAGE_UP,           ///< Move keyboard focus towards the previous page direction @SINCE_1_2.14
+      PAGE_DOWN,         ///< Move keyboard focus towards the next page direction @SINCE_1_2.14
+      FORWARD,           ///< Move keyboard focus towards the forward direction @SINCE_2_1.10
+      BACKWARD,          ///< Move keyboard focus towards the backward direction @SINCE_2_1.10
+      CLOCKWISE,         ///< Move keyboard focus towards the clockwise direction @SINCE_2_1.14
+      COUNTER_CLOCKWISE, ///< Move keyboard focus towards the counter clockwise direction @SINCE_2_1.14
     };
   };
 
@@ -172,7 +173,6 @@ public:
   typedef Signal<void(Control)> ResourceReadySignalType;
 
 public: // Creation & Destruction
-
   /**
    * @brief Additional control behaviour flags for the control constructor.
    * @note TODO : Currunt code is hard-coded. We Should sync type values as
@@ -382,6 +382,22 @@ public:
    */
   void ClearBackground();
 
+  /**
+   * @brief Sets RenderEffect to this control.
+   *
+   * @SINCE_2_3.25
+   * @param[in] effect RenderEffect to add.
+   *
+   * @note Every effect inherits RenderEffect.
+   */
+  void SetRenderEffect(Toolkit::RenderEffect effect);
+
+  /**
+   * @brief Clears RenderEffect of this control, if exists.
+   * @SINCE_2_3.25
+   */
+  void ClearRenderEffect();
+
   // Resources
 
   /**
diff --git a/dali-toolkit/public-api/controls/render-effects/background-blur-effect.cpp b/dali-toolkit/public-api/controls/render-effects/background-blur-effect.cpp
new file mode 100644 (file)
index 0000000..32ba804
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2024 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/public-api/controls/render-effects/background-blur-effect.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/render-effects/blur-effect-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+BackgroundBlurEffect::BackgroundBlurEffect() = default;
+
+BackgroundBlurEffect::BackgroundBlurEffect(const BackgroundBlurEffect& handle)
+: RenderEffect(handle)
+{
+}
+
+BackgroundBlurEffect::BackgroundBlurEffect(Internal::BlurEffectImpl* blurEffectImpl)
+: RenderEffect(blurEffectImpl)
+{
+}
+
+BackgroundBlurEffect::~BackgroundBlurEffect() = default;
+
+BackgroundBlurEffect BackgroundBlurEffect::New()
+{
+  Internal::BlurEffectImplPtr internal = Internal::BlurEffectImpl::New(true);
+  return BackgroundBlurEffect(internal.Get());
+}
+
+BackgroundBlurEffect BackgroundBlurEffect::New(float downscaleFactor, uint32_t blurRadius, float bellCurveWidth)
+{
+  Internal::BlurEffectImplPtr internal = Internal::BlurEffectImpl::New(downscaleFactor, blurRadius, bellCurveWidth, true);
+  return BackgroundBlurEffect(internal.Get());
+}
+
+}// namespace Toolkit
+}// namespace Dali
diff --git a/dali-toolkit/public-api/controls/render-effects/background-blur-effect.h b/dali-toolkit/public-api/controls/render-effects/background-blur-effect.h
new file mode 100644 (file)
index 0000000..7d0bf98
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef DALI_TOOLKIT_BACKGROUND_BLUR_EFFECT_H
+#define DALI_TOOLKIT_BACKGROUND_BLUR_EFFECT_H
+
+/*
+ * Copyright (c) 2024 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/render-effects/render-effect.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal DALI_INTERNAL
+{
+class BlurEffectImpl;
+} // namespace DALI_INTERNAL
+
+/**
+ * @brief BackgroundBlurEffect is a visual effect that blurs owner control's background.
+ * This class is a concrete class from RenderEffect interface.
+ * Add this effect to a control, clear manually to deactivate.
+ *
+ * Toolkit::Control control = Toolkit::Control::New();
+ * parent.Add(control);
+ * control.SetRenderEffect(BackgroundBlurEffect::New()); // Activate
+ * ...
+ * control.ClearRenderEffect(); // Deactivate
+ *
+ * Note that tree hierarchy matters for BackgroundBlurEffect. You should determine "what is the background".
+ * Add() should preceed SetRenderEffect(), and the effect cannot have multiple owner controls.
+ *
+ * @SINCE_2_3.28
+ */
+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
+   * bellCurveWidth = 1.5f
+   *
+   * @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] bellCurveWidth Blur intensity.
+   * @SINCE_2_3.28
+   * @return A handle to a newly allocated Dali resource
+   */
+  static BackgroundBlurEffect New(float downscaleFactor, uint32_t blurRadius, float bellCurveWidth);
+
+  /**
+   * @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
+  */
+  ~BackgroundBlurEffect();
+
+public: // Not intended for use by Application developers
+  ///@cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_2_3.28
+   * @param[in]  blurEffectImpl The UI Control implementation.
+   */
+  explicit DALI_INTERNAL BackgroundBlurEffect(Internal::BlurEffectImpl* blurEffectImpl);
+  ///@endcond
+};
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_BACKGROUND_BLUR_EFFECT_H
diff --git a/dali-toolkit/public-api/controls/render-effects/render-effect.cpp b/dali-toolkit/public-api/controls/render-effects/render-effect.cpp
new file mode 100644 (file)
index 0000000..804c8e2
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2024 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/public-api/controls/render-effects/render-effect.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/render-effects/render-effect-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+RenderEffect::RenderEffect(const RenderEffect& handle)
+: BaseHandle(handle)
+{
+}
+
+RenderEffect::RenderEffect(Internal::RenderEffectImpl* renderEffectImpl)
+: BaseHandle(renderEffectImpl)
+{
+}
+
+RenderEffect::~RenderEffect() = default;
+
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/render-effects/render-effect.h b/dali-toolkit/public-api/controls/render-effects/render-effect.h
new file mode 100644 (file)
index 0000000..02516b7
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef DALI_TOOLKIT_RENDER_EFFECT_H
+#define DALI_TOOLKIT_RENDER_EFFECT_H
+
+/*
+ * Copyright (c) 2024 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/public-api/object/base-handle.h>
+#include <dali/public-api/render-tasks/render-task.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+class Control;
+namespace Internal DALI_INTERNAL
+{
+class Control;
+class RenderEffectImpl;
+} // namespace DALI_INTERNAL
+
+/**
+ * @brief
+ * RenderEffect is an interface for visual effects.
+ * You do not ::New() an interface.
+ *
+ * Each effect has a single owner Control.
+ *
+ * Used internal at:
+ * Toolkit::Control::SetRenderEffect(Toolkit::RenderEffect effect);
+ * Toolkit::Control::ClearRenderEffect();
+ *
+ * @SINCE_2_3.28
+ */
+class DALI_TOOLKIT_API RenderEffect : public BaseHandle
+{
+public:
+  /**
+   * @brief Creates an uninitialized effect.
+   * @SINCE_2_3.28
+   */
+  RenderEffect() = default;
+
+  /**
+   * @brief Copy constructor. Creates another handle that points to the same real object.
+   * @SINCE_2_3.28
+   */
+  RenderEffect(const RenderEffect& handle);
+
+  /**
+   * @brief Destructor.
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_2_3.28
+   */
+  ~RenderEffect();
+
+public: // Not intended for Application developers
+  ///@cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_2_3.28
+   * @param[in]  renderEffectImpl The UI Control implementation.
+   */
+  explicit DALI_INTERNAL RenderEffect(Internal::RenderEffectImpl* renderEffectImpl);
+  ///@endcond
+};
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_RENDER_EFFECT_H
index 833bfbf..6da2012 100644 (file)
@@ -13,6 +13,8 @@ SET( public_api_src_files
   ${public_api_src_dir}/controls/image-view/image-view.cpp
   ${public_api_src_dir}/controls/model3d-view/model3d-view.cpp
   ${public_api_src_dir}/controls/progress-bar/progress-bar.cpp
+  ${public_api_src_dir}/controls/render-effects/render-effect.cpp
+  ${public_api_src_dir}/controls/render-effects/background-blur-effect.cpp
   ${public_api_src_dir}/controls/scrollable/item-view/default-item-layout.cpp
   ${public_api_src_dir}/controls/scrollable/item-view/item-layout.cpp
   ${public_api_src_dir}/controls/scrollable/item-view/item-view.cpp
@@ -104,6 +106,11 @@ SET( public_api_progress_bar_header_files
   ${public_api_src_dir}/controls/progress-bar/progress-bar.h
 )
 
+SET( public_api_render_effects_header_files
+  ${public_api_src_dir}/controls/render-effects/render-effect.h
+  ${public_api_src_dir}/controls/render-effects/background-blur-effect.h
+)
+
 SET( public_api_scrollable_header_files
   ${public_api_src_dir}/controls/scrollable/scrollable.h
 )
@@ -198,6 +205,7 @@ SET( PUBLIC_API_HEADERS ${PUBLIC_API_HEADERS}
   ${public_api_item_view_header_files}
   ${public_api_image_loader_header_files}
   ${public_api_progress_bar_header_files}
+  ${public_api_render_effects_header_files}
   ${public_api_scrollable_header_files}
   ${public_api_scroll_view_header_files}
   ${public_api_slider_header_files}