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;
}
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);
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();
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;
}
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);
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();
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;
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;
}
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);
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();
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();
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();
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;
}
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;
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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
+++ /dev/null
-/*
- * 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
+++ /dev/null
-#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
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);
{
control.GetImplementation().RemoveCacheRenderer();
control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::NONE);
+
+ mCamera.Unparent();
}
DestroyFrameBuffer();
{
DestroyFrameBuffer();
+ mCamera.SetPerspectiveProjection(GetTargetSize());
+
CreateFrameBuffer();
mRenderTask.SetFrameBuffer(mFrameBuffer);
}
mRenderTask = taskList.CreateTask();
mRenderTask.SetSourceActor(control);
- mRenderTask.SetCameraActor(GetCameraActor());
+ mRenderTask.SetCameraActor(mCamera);
mRenderTask.SetExclusive(true);
mRenderTask.SetInputEnabled(true);
mRenderTask.SetFrameBuffer(mFrameBuffer);
private:
RenderTask mRenderTask;
+ CameraActor mCamera;
FrameBuffer mFrameBuffer;
DevelControl::OffScreenRenderingType mType;
};
RenderEffectImpl::RenderEffectImpl()
: mRenderer(),
- mCamera(),
mOwnerControl(),
mSizeNotification(),
mTargetSize(Vector2::ZERO),
return mTargetSize;
}
-CameraActor RenderEffectImpl::GetCameraActor() const
-{
- return mCamera;
-}
-
void RenderEffectImpl::Activate()
{
if(!IsActivated() && IsActivateValid())
}
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();
// Deactivate logic for subclass.
OnDeactivate();
-
- if(mCamera)
- {
- mCamera.Unparent();
- }
}
}
}
else
{
- mCamera.SetPerspectiveProjection(GetTargetSize());
OnRefresh();
}
}
// 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>
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);
*/
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
*/
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
*/
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.
*/
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.
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
${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
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];
};
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;
}
// 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
: 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
*/
// 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.
{
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
/**
* @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
{
}
+void RenderEffect::Activate()
+{
+ GetImplementation(*this).Activate();
+}
+
+void RenderEffect::Deactivate()
+{
+ GetImplementation(*this).Deactivate();
+}
} // namespace Toolkit
} // namespace Dali
*/
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
/**