From da4a31c19b6496a3af6b399be5e4c2bc0823c93f Mon Sep 17 00:00:00 2001 From: jmm Date: Thu, 3 Apr 2025 19:33:35 +0900 Subject: [PATCH] Add render effect blur strength animation Change-Id: I29d4babfdc95b7d85a8cd7bb59656d8f9bfddfaa Signed-off-by: jmm --- .../src/dali-toolkit/utc-Dali-Control.cpp | 9 +- .../dali-toolkit/utc-Dali-RenderEffect.cpp | 181 +++++++++- ...pl.cpp => background-blur-effect-impl.cpp} | 338 +++++++++++++----- ...t-impl.h => background-blur-effect-impl.h} | 100 ++++-- .../offscreen-rendering-impl.cpp | 17 +- .../render-effects/offscreen-rendering-impl.h | 1 + .../render-effects/render-effect-impl.cpp | 23 -- .../render-effects/render-effect-impl.h | 37 +- dali-toolkit/internal/file.list | 2 +- .../graphics/shaders/blur-effect.frag | 5 +- .../render-effects/background-blur-effect.cpp | 52 ++- .../render-effects/background-blur-effect.h | 94 ++++- .../controls/render-effects/render-effect.cpp | 9 + .../controls/render-effects/render-effect.h | 12 + 14 files changed, 664 insertions(+), 216 deletions(-) rename dali-toolkit/internal/controls/render-effects/{blur-effect-impl.cpp => background-blur-effect-impl.cpp} (61%) rename dali-toolkit/internal/controls/render-effects/{blur-effect-impl.h => background-blur-effect-impl.h} (66%) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp index f8d749eebf..46ce1c0e6e 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp @@ -1569,6 +1569,13 @@ int UtcDaliControlOffScreenRenderingSizeSet(void) DALI_TEST_EQUALS(control.GetProperty(Actor::Property::SIZE).Get(), 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(50.0f, 50.0f), TEST_LOCATION); + tet_infoline("Size update when type NONE"); + END_TEST; } @@ -1634,7 +1641,7 @@ int UtcDaliControlCornerRadius(void) application.GetScene().Add(control); - RenderEffect effect = BackgroundBlurEffect::New(0.25f, 50.0f); + RenderEffect effect = BackgroundBlurEffect::New(50.0f); control.SetRenderEffect(effect); control.SetProperty(DevelControl::Property::OFFSCREEN_RENDERING, DevelControl::OffScreenRenderingType::REFRESH_ALWAYS); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-RenderEffect.cpp b/automated-tests/src/dali-toolkit/utc-Dali-RenderEffect.cpp index 49655ecfbd..01e7293e36 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-RenderEffect.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-RenderEffect.cpp @@ -33,7 +33,7 @@ int UtcDaliRenderEffectNewP(void) RenderEffect blurEffect = BackgroundBlurEffect::New(); DALI_TEST_CHECK(blurEffect); - RenderEffect blurEffect2 = BackgroundBlurEffect::New(0.5f, 10); + RenderEffect blurEffect2 = BackgroundBlurEffect::New(10); DALI_TEST_CHECK(blurEffect2); Control control = Control::New(); @@ -60,15 +60,13 @@ int UtcDaliRenderEffectNewN(void) tet_printf("Check some invalid parameters clamp internally\n"); - RenderEffect blurEffect = BackgroundBlurEffect::New(-0.5f, 10); - RenderEffect blurEffect2 = BackgroundBlurEffect::New(10.0f, 10); - RenderEffect blurEffect3 = BackgroundBlurEffect::New(0.5f, 0); - RenderEffect blurEffect4 = BackgroundBlurEffect::New(0.5f, 2147483647); + RenderEffect blurEffect1 = BackgroundBlurEffect::New(10); + RenderEffect blurEffect2 = BackgroundBlurEffect::New(0); + RenderEffect blurEffect3 = BackgroundBlurEffect::New(2147483647); - DALI_TEST_CHECK(blurEffect); + DALI_TEST_CHECK(blurEffect1); DALI_TEST_CHECK(blurEffect2); DALI_TEST_CHECK(blurEffect3); - DALI_TEST_CHECK(blurEffect4); END_TEST; } @@ -149,7 +147,7 @@ int UtcDaliRenderEffectActivateP03(void) control.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f)); scene.Add(control); - Control newControl = Control::New(); + Control newControl = Control::New(); RenderEffect maskEffect = MaskEffect::New(newControl); control.SetRenderEffect(maskEffect); @@ -193,7 +191,7 @@ int UtcDaliRenderEffectDeactivateP(void) DALI_TEST_EQUALS(count, control.GetRendererCount(), TEST_LOCATION); Control newControl = Control::New(); - count = control.GetRendererCount(); + count = control.GetRendererCount(); control.SetRenderEffect(MaskEffect::New(newControl)); taskList = scene.GetRenderTaskList(); @@ -244,10 +242,10 @@ int UtcDaliRenderEffectActivateDeactivateInplace(void) RenderTaskList taskList = scene.GetRenderTaskList(); DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION); - control.ClearRenderEffect(); - control.SetRenderEffect(blurEffect); - control.ClearRenderEffect(); - control.SetRenderEffect(blurEffect); + blurEffect.Deactivate(); + DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION); + + blurEffect.Activate(); DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION); END_TEST; @@ -284,18 +282,60 @@ int UtcDaliRenderEffectResize(void) Control control = Control::New(); control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); scene.Add(control); + + RenderTaskList taskList = scene.GetRenderTaskList(); + DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION); + uint32_t count = control.GetRendererCount(); + DALI_TEST_EQUALS(count, control.GetRendererCount(), TEST_LOCATION); + + //////////////////////////////////////////// control.SetRenderEffect(BackgroundBlurEffect::New()); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION); + DALI_TEST_EQUALS(count, control.GetRendererCount(), TEST_LOCATION); + tet_infoline("size zero owner control's effect is not activated."); + control.SetProperty(Actor::Property::SIZE, Vector2(30.0f, 30.0f)); + application.SendNotification(); + application.Render(); application.SendNotification(); application.Render(); + DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION); + DALI_TEST_EQUALS(count + 1, control.GetRendererCount(), TEST_LOCATION); + DALI_TEST_EQUALS(control.GetProperty(Actor::Property::SIZE_WIDTH), 30.0f, TEST_LOCATION); DALI_TEST_EQUALS(control.GetProperty(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(Actor::Property::SIZE_WIDTH), 10.0f, TEST_LOCATION); + DALI_TEST_EQUALS(control.GetProperty(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(Actor::Property::SIZE_WIDTH), 0.0f, TEST_LOCATION); + DALI_TEST_EQUALS(control.GetProperty(Actor::Property::SIZE_HEIGHT), 0.0f, TEST_LOCATION); + tet_infoline("Background blur effect deactivated.\n"); END_TEST; } @@ -314,7 +354,7 @@ int UtcDaliRenderEffectSynchronizeControlCornerRadius(void) blackDimmerMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 0.20f); blackDimmerMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::Type::RELATIVE); blackDimmerMap.Insert(Toolkit::DevelVisual::Property::CORNER_SQUARENESS, 0.3f); - RenderEffect effect = BackgroundBlurEffect::New(0.4f, 40); + RenderEffect effect = BackgroundBlurEffect::New(40); Control control = Control::New(); DALI_TEST_CHECK(control.GetRendererCount() == 0u); @@ -367,7 +407,7 @@ int UtcDaliRenderEffectInvalidTargetSize(void) control.SetProperty(Actor::Property::SIZE_WIDTH, maxTextureSize + 1000.0f); control.SetProperty(Actor::Property::SIZE_HEIGHT, maxTextureSize + 1000.0f); scene.Add(control); - control.SetRenderEffect(BackgroundBlurEffect::New(0.4f, 40)); + control.SetRenderEffect(BackgroundBlurEffect::New(40)); application.SendNotification(); application.Render(); @@ -869,22 +909,47 @@ int UtcDaliRenderEffectReInitialize(void) tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex()); DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION); - control.SetRenderEffect(BackgroundBlurEffect::New()); + BackgroundBlurEffect effect = BackgroundBlurEffect::New(40u); + control.SetRenderEffect(effect); + DALI_TEST_EQUALS(effect.GetBlurRadius(), 40u, TEST_LOCATION); + + application.SendNotification(); + + // Render effect activated. + DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION); + tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex()); + DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION); + effect.SetBlurRadius(20u); application.SendNotification(); // Render effect activated. DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION); tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex()); DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION); + DALI_TEST_EQUALS(effect.GetBlurRadius(), 20u, TEST_LOCATION); + + effect.SetBlurRadius(2u); // invalid blur radius value(too small) + application.SendNotification(); + + DALI_TEST_EQUALS(1u, taskList.GetTaskCount(), TEST_LOCATION); + DALI_TEST_EQUALS(effect.GetBlurRadius(), 2u, TEST_LOCATION); END_TEST; } +namespace +{ +void BlurRenderingFinishedCallback(void) +{ + tet_infoline("blur rendering finished signal emitted"); +} +} // namespace + int UtcDaliRenderEffectBlurOnce(void) { ToolkitTestApplication application; - tet_infoline("UtcDaliRenderEffectBlurOnce with background blur effect"); + tet_infoline("UtcDaliRenderEffectBlurOnce"); Integration::Scene scene = application.GetScene(); @@ -895,7 +960,13 @@ int UtcDaliRenderEffectBlurOnce(void) scene.Add(control); // Add render effect during scene on. - control.SetRenderEffect(BackgroundBlurEffect::New(0.5f, 20u, true)); + BackgroundBlurEffect effect = BackgroundBlurEffect::New(20u); + DALI_TEST_EQUALS(effect.GetBlurOnce(), false, TEST_LOCATION); + + effect.SetBlurOnce(true); + effect.FinishedSignal().Connect(&application, &BlurRenderingFinishedCallback); + control.SetRenderEffect(effect); + DALI_TEST_EQUALS(effect.GetBlurOnce(), true, TEST_LOCATION); application.SendNotification(); @@ -906,6 +977,13 @@ int UtcDaliRenderEffectBlurOnce(void) tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex()); DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION); + effect.SetBlurOnce(false); + DALI_TEST_EQUALS(effect.GetBlurOnce(), false, TEST_LOCATION); + + DALI_TEST_EQUALS(4u, taskList.GetTaskCount(), TEST_LOCATION); + tet_printf("order : %d\n", taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex()); + DALI_TEST_EQUALS(INT32_MIN + 2, taskList.GetTask(taskList.GetTaskCount() - 1).GetOrderIndex(), TEST_LOCATION); + END_TEST; } @@ -948,6 +1026,39 @@ int UtcDaliMaskEffect(void) END_TEST; } +int UtcDaliRenderEffectBlurStrengthAnimation(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliRenderEffectBlurStrengthAnimation"); + + Integration::Scene scene = application.GetScene(); + + Control control = Control::New(); + control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + control.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f)); + + BackgroundBlurEffect effect = BackgroundBlurEffect::New(); + control.SetRenderEffect(effect); + scene.Add(control); + + float durationSeconds = 0.05f; + Animation animation = Animation::New(durationSeconds); + + effect.AddBlurStrengthAnimation(animation, AlphaFunction::BuiltinFunction::EASE_IN, TimePeriod(0, durationSeconds), 0.0f, 1.0f); + animation.Play(); + application.SendNotification(); + application.Render(static_cast(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/); + animation.Clear(); + DALI_TEST_EQUALS(effect.GetBlurOnce(), false, TEST_LOCATION); + + effect.SetBlurOnce(true); + effect.AddBlurStrengthAnimation(animation, AlphaFunction::BuiltinFunction::EASE_IN, TimePeriod(0, durationSeconds), 0.0f, 1.0f); + // animation will not be added but cannot check + DALI_TEST_EQUALS(effect.GetBlurOnce(), true, TEST_LOCATION); + + END_TEST; +} + int UtcDaliMaskEffectScaleN(void) { ToolkitTestApplication application; @@ -978,4 +1089,36 @@ int UtcDaliMaskEffectScaleN(void) DALI_TEST_EQUALS(3u, taskList.GetTaskCount(), TEST_LOCATION); END_TEST; -} \ No newline at end of file +} + +int UtcDaliRenderEffectBlurOpacityAnimation(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliRenderEffectBlurOpacityAnimation"); + + Integration::Scene scene = application.GetScene(); + + Control control = Control::New(); + control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + control.SetProperty(Actor::Property::SIZE, Vector2(1.0f, 1.0f)); + + BackgroundBlurEffect effect = BackgroundBlurEffect::New(); + control.SetRenderEffect(effect); + scene.Add(control); + + float durationSeconds = 0.05f; + Animation animation = Animation::New(durationSeconds); + + effect.AddBlurOpacityAnimation(animation, AlphaFunction::BuiltinFunction::EASE_IN, TimePeriod(0, durationSeconds), 0.0f, 1.0f); + animation.Play(); + application.SendNotification(); + application.Render(static_cast(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/); + DALI_TEST_EQUALS(effect.GetBlurOnce(), false, TEST_LOCATION); + + effect.SetBlurOnce(true); + effect.AddBlurOpacityAnimation(animation, AlphaFunction::BuiltinFunction::EASE_IN, TimePeriod(0, durationSeconds), 0.0f, 1.0f); + // animation will not be added but cannot check + DALI_TEST_EQUALS(effect.GetBlurOnce(), true, TEST_LOCATION); + + END_TEST; +} diff --git a/dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp b/dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.cpp similarity index 61% rename from dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp rename to dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.cpp index 17f83bbfaa..77f79f1947 100644 --- a/dali-toolkit/internal/controls/render-effects/blur-effect-impl.cpp +++ b/dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.cpp @@ -16,12 +16,13 @@ */ // CLASS HEADER -#include +#include // EXTERNAL INCLUDES #include #include #include +#include #include #include #include @@ -36,8 +37,8 @@ namespace { // Default values -static constexpr float BLUR_EFFECT_DOWNSCALE_FACTOR = 0.4f; -static constexpr uint32_t BLUR_EFFECT_PIXEL_RADIUS = 10u; +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; @@ -48,6 +49,9 @@ static constexpr uint32_t MAXIMUM_BLUR_RADIUS = 500u; ///< Maximum pixel radi 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 @@ -58,6 +62,34 @@ 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(fixedBlurRadius) / static_cast(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(blurRadius * downscaleFactor); +} } // namespace namespace Dali @@ -70,89 +102,63 @@ namespace Internal extern Debug::Filter* gRenderEffectLogFilter; ///< Define at render-effect-impl.cpp #endif -BlurEffectImpl::BlurEffectImpl(bool isBackground) +BackgroundBlurEffectImpl::BackgroundBlurEffectImpl() : RenderEffectImpl(), mInternalRoot(Actor::New()), mDownscaleFactor(BLUR_EFFECT_DOWNSCALE_FACTOR), - mPixelRadius(BLUR_EFFECT_PIXEL_RADIUS), - mDownscaledPixelRadius(static_cast(BLUR_EFFECT_PIXEL_RADIUS * BLUR_EFFECT_DOWNSCALE_FACTOR)), + mBlurRadius(BLUR_EFFECT_BLUR_RADIUS), + mDownscaledBlurRadius(static_cast(BLUR_EFFECT_BLUR_RADIUS * BLUR_EFFECT_DOWNSCALE_FACTOR)), mBellCurveWidth(Math::MACHINE_EPSILON_1), mSkipBlur(false), - mBlurOnce(false), - mIsBackground(isBackground) + mBlurOnce(false) { } -BlurEffectImpl::BlurEffectImpl(float downscaleFactor, uint32_t blurRadius, bool blurOnce, bool isBackground) +BackgroundBlurEffectImpl::BackgroundBlurEffectImpl(uint32_t blurRadius) : RenderEffectImpl(), mInternalRoot(Actor::New()), - mDownscaleFactor(downscaleFactor), - mPixelRadius(blurRadius), - mDownscaledPixelRadius(BLUR_EFFECT_PIXEL_RADIUS), + mDownscaleFactor(BLUR_EFFECT_DOWNSCALE_FACTOR), + mBlurRadius(blurRadius), + mDownscaledBlurRadius(BLUR_EFFECT_BLUR_RADIUS), mBellCurveWidth(Math::MACHINE_EPSILON_1), mSkipBlur(false), - mBlurOnce(blurOnce), - mIsBackground(isBackground) + mBlurOnce(false) { - 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(fixedBlurRadius) / static_cast(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(mPixelRadius * mDownscaleFactor); - - if(DALI_UNLIKELY((mDownscaledPixelRadius >> 1) < MINIMUM_GPU_ARRAY_SIZE)) + 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"); } } -BlurEffectImpl::~BlurEffectImpl() +BackgroundBlurEffectImpl::~BackgroundBlurEffectImpl() { } -BlurEffectImplPtr BlurEffectImpl::New(bool isBackground) +BackgroundBlurEffectImplPtr BackgroundBlurEffectImpl::New() { - BlurEffectImplPtr handle = new BlurEffectImpl(isBackground); + BackgroundBlurEffectImplPtr handle = new BackgroundBlurEffectImpl(); handle->Initialize(); return handle; } -BlurEffectImplPtr BlurEffectImpl::New(float downscaleFactor, uint32_t blurRadius, bool blurOnce, bool isBackground) +BackgroundBlurEffectImplPtr BackgroundBlurEffectImpl::New(uint32_t blurRadius) { - BlurEffectImplPtr handle = new BlurEffectImpl(downscaleFactor, blurRadius, blurOnce, isBackground); + BackgroundBlurEffectImplPtr handle = new BackgroundBlurEffectImpl(blurRadius); handle->Initialize(); return handle; } -OffScreenRenderable::Type BlurEffectImpl::GetOffScreenRenderableType() +OffScreenRenderable::Type BackgroundBlurEffectImpl::GetOffScreenRenderableType() { return mSkipBlur ? OffScreenRenderable::NONE : OffScreenRenderable::BACKWARD; } -void BlurEffectImpl::GetOffScreenRenderTasks(std::vector& tasks, bool isForward) +void BackgroundBlurEffectImpl::GetOffScreenRenderTasks(std::vector& tasks, bool isForward) { tasks.clear(); - if(!isForward && mIsBackground) + if(!isForward) { if(mSourceRenderTask) { @@ -172,7 +178,111 @@ void BlurEffectImpl::GetOffScreenRenderTasks(std::vector& task } } -void BlurEffectImpl::OnInitialize() +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)) { @@ -181,14 +291,14 @@ void BlurEffectImpl::OnInitialize() // Calculate bell curve width { - const float epsilon = 1e-2f / (mDownscaledPixelRadius * 2); - const float localOffset = (mDownscaledPixelRadius * 2) - 1; + const float epsilon = 1e-2f / (mDownscaledBlurRadius * 2); + const float localOffset = (mDownscaledBlurRadius * 2) - 1; - float lowerBoundBellCurveWidth = Math::MACHINE_EPSILON_10000; + 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 > Math::MACHINE_EPSILON_10000) + 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) @@ -202,7 +312,7 @@ void BlurEffectImpl::OnInitialize() } } - DALI_LOG_INFO(gRenderEffectLogFilter, Debug::Verbose, "[BlurEffect:%p] mBellCurveWidth calculated! [mPixelRadius:%u][mBellCurveWidth:%f]\n", this, mPixelRadius, mBellCurveWidth); + DALI_LOG_INFO(gRenderEffectLogFilter, Debug::Verbose, "[BlurEffect:%p] mBellCurveWidth calculated! [mBlurRadius:%u][mBellCurveWidth:%f]\n", this, mBlurRadius, mBellCurveWidth); // Create blur actors { @@ -210,29 +320,53 @@ void BlurEffectImpl::OnInitialize() // shader std::ostringstream fragmentStringStream; - fragmentStringStream << "#define NUM_SAMPLES " << (mDownscaledPixelRadius >> 1) << "\n"; + 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 - 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); + + 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 - 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); + + 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 BlurEffectImpl::OnActivate() +void BackgroundBlurEffectImpl::OnActivate() { if(DALI_UNLIKELY(mSkipBlur)) { @@ -250,6 +384,17 @@ void BlurEffectImpl::OnActivate() uint32_t downsampledHeight = std::max(static_cast(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(); @@ -271,14 +416,7 @@ void BlurEffectImpl::OnActivate() // 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); - } + renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Dali::Toolkit::DepthIndex::BACKGROUND_EFFECT); ownerControl.AddRenderer(renderer); SetRendererTexture(renderer, mBlurredOutputFrameBuffer); @@ -289,7 +427,7 @@ void BlurEffectImpl::OnActivate() GetImplementation(ownerControl).RequestRenderTaskReorder(); } -void BlurEffectImpl::OnDeactivate() +void BackgroundBlurEffectImpl::OnDeactivate() { if(DALI_UNLIKELY(mSkipBlur)) { @@ -310,7 +448,7 @@ void BlurEffectImpl::OnDeactivate() DestroyRenderTasks(); } -void BlurEffectImpl::OnRefresh() +void BackgroundBlurEffectImpl::OnRefresh() { if(DALI_UNLIKELY(mSkipBlur)) { @@ -326,6 +464,7 @@ void BlurEffectImpl::OnRefresh() uint32_t downsampledHeight = std::max(static_cast(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)); @@ -338,7 +477,7 @@ void BlurEffectImpl::OnRefresh() mVerticalBlurTask.SetFrameBuffer(mBlurredOutputFrameBuffer); } -void BlurEffectImpl::CreateFrameBuffers(const ImageDimensions downsampledSize) +void BackgroundBlurEffectImpl::CreateFrameBuffers(const ImageDimensions downsampledSize) { uint32_t downsampledWidth = downsampledSize.GetWidth(); uint32_t downsampledHeight = downsampledSize.GetHeight(); @@ -359,20 +498,20 @@ void BlurEffectImpl::CreateFrameBuffers(const ImageDimensions downsampledSize) mBlurredOutputFrameBuffer.AttachColorTexture(sourceTexture); } -void BlurEffectImpl::DestroyFrameBuffers() +void BackgroundBlurEffectImpl::DestroyFrameBuffers() { mInputBackgroundFrameBuffer.Reset(); mTemporaryFrameBuffer.Reset(); mBlurredOutputFrameBuffer.Reset(); } -void BlurEffectImpl::CreateRenderTasks(Integration::SceneHolder sceneHolder, const Toolkit::Control sourceControl) +void BackgroundBlurEffectImpl::CreateRenderTasks(Integration::SceneHolder sceneHolder, const Toolkit::Control sourceControl) { RenderTaskList taskList = sceneHolder.GetRenderTaskList(); // draw input texture mSourceRenderTask = taskList.CreateTask(); - mSourceRenderTask.SetCameraActor(GetCameraActor()); + mSourceRenderTask.SetCameraActor(mCamera); mSourceRenderTask.SetFrameBuffer(mInputBackgroundFrameBuffer); mSourceRenderTask.SetInputEnabled(false); @@ -414,6 +553,8 @@ void BlurEffectImpl::CreateRenderTasks(Integration::SceneHolder sceneHolder, con mSourceRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE); mHorizontalBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE); mVerticalBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE); + + mVerticalBlurTask.FinishedSignal().Connect(this, &BackgroundBlurEffectImpl::OnRenderFinished); } else { @@ -423,7 +564,12 @@ void BlurEffectImpl::CreateRenderTasks(Integration::SceneHolder sceneHolder, con } } -void BlurEffectImpl::DestroyRenderTasks() +void BackgroundBlurEffectImpl::OnRenderFinished(Dali::RenderTask& renderTask) +{ + mFinishedSignal.Emit(); +} + +void BackgroundBlurEffectImpl::DestroyRenderTasks() { auto sceneHolder = GetSceneHolder(); if(DALI_LIKELY(sceneHolder)) @@ -439,7 +585,7 @@ void BlurEffectImpl::DestroyRenderTasks() mSourceRenderTask.Reset(); } -void BlurEffectImpl::ApplyRenderTaskSourceActor(RenderTask sourceRenderTask, const Toolkit::Control sourceControl) +void BackgroundBlurEffectImpl::ApplyRenderTaskSourceActor(RenderTask sourceRenderTask, const Toolkit::Control sourceControl) { if(DALI_UNLIKELY(!sourceRenderTask || !sourceControl)) { @@ -450,19 +596,16 @@ void BlurEffectImpl::ApplyRenderTaskSourceActor(RenderTask sourceRenderTask, con 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()) { - 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 = 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; - } + sourceActor = GetImplementation(control).GetOffScreenRenderableSourceActor(); + isExclusiveRequired = GetImplementation(control).IsOffScreenRenderTaskExclusive(); + break; } } @@ -471,9 +614,9 @@ void BlurEffectImpl::ApplyRenderTaskSourceActor(RenderTask sourceRenderTask, con sourceRenderTask.RenderUntil(stopperActor); } -void BlurEffectImpl::SetShaderConstants(uint32_t downsampledWidth, uint32_t downsampledHeight) +void BackgroundBlurEffectImpl::SetShaderConstants(uint32_t downsampledWidth, uint32_t downsampledHeight) { - const uint32_t sampleCount = mDownscaledPixelRadius >> 1; // compression + 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 @@ -516,20 +659,25 @@ void BlurEffectImpl::SetShaderConstants(uint32_t downsampledWidth, uint32_t down } } -std::string BlurEffectImpl::GetSampleOffsetsPropertyName(unsigned int index) const +std::string BackgroundBlurEffectImpl::GetSampleOffsetsPropertyName(unsigned int index) const { std::ostringstream oss; oss << "uSampleOffsets[" << index << "]"; return oss.str(); } -std::string BlurEffectImpl::GetSampleWeightsPropertyName(unsigned int index) const +std::string BackgroundBlurEffectImpl::GetSampleWeightsPropertyName(unsigned int index) const { std::ostringstream oss; oss << "uSampleWeights[" << index << "]"; return oss.str(); } +Dali::Toolkit::BackgroundBlurEffect::FinishedSignalType& BackgroundBlurEffectImpl::FinishedSignal() +{ + return mFinishedSignal; +} + } // namespace Internal } // namespace Toolkit } // namespace Dali diff --git a/dali-toolkit/internal/controls/render-effects/blur-effect-impl.h b/dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.h similarity index 66% rename from dali-toolkit/internal/controls/render-effects/blur-effect-impl.h rename to dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.h index 5040805c06..1e0493701d 100644 --- a/dali-toolkit/internal/controls/render-effects/blur-effect-impl.h +++ b/dali-toolkit/internal/controls/render-effects/background-blur-effect-impl.h @@ -38,37 +38,26 @@ namespace Toolkit { namespace Internal { -class BlurEffectImpl; -using BlurEffectImplPtr = IntrusivePtr; +class BackgroundBlurEffectImpl; +using BackgroundBlurEffectImplPtr = IntrusivePtr; -class BlurEffectImpl : public RenderEffectImpl +class BackgroundBlurEffectImpl : 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 + * @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 BlurEffectImplPtr New(bool isBackground); + static BackgroundBlurEffectImplPtr New(); /** * @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); + static BackgroundBlurEffectImplPtr New(uint32_t blurRadius); /** * @copydoc Toolkit::Internal::RenderEffectImpl::GetOffScreenRenderableType @@ -80,26 +69,57 @@ public: */ void GetOffScreenRenderTasks(std::vector& 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 - * @param[in] isBackground True when blurring background, False otherwise */ - BlurEffectImpl(bool isBackground); + BackgroundBlurEffectImpl(); /** * @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); + BackgroundBlurEffectImpl(uint32_t blurRadius); /** * @brief Destructor */ - virtual ~BlurEffectImpl(); + virtual ~BackgroundBlurEffectImpl(); /** * @brief Initializes blur effect @@ -175,13 +195,24 @@ private: */ 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() + /** + * @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 @@ -199,26 +230,25 @@ private: // Variables float mDownscaleFactor; - uint32_t mPixelRadius; - uint32_t mDownscaledPixelRadius; + uint32_t mBlurRadius; + uint32_t mDownscaledBlurRadius; float mBellCurveWidth; bool mSkipBlur : 1; bool mBlurOnce : 1; - bool mIsBackground : 1; }; } // namespace Internal -inline Toolkit::Internal::BlurEffectImpl& GetImplementation(Toolkit::BackgroundBlurEffect& obj) +inline Toolkit::Internal::BackgroundBlurEffectImpl& GetImplementation(Toolkit::BackgroundBlurEffect& obj) { BaseObject& handle = obj.GetBaseObject(); - return static_cast(handle); + return static_cast(handle); } -inline const Toolkit::Internal::BlurEffectImpl& GetImplementation(const Toolkit::BackgroundBlurEffect& obj) +inline const Toolkit::Internal::BackgroundBlurEffectImpl& GetImplementation(const Toolkit::BackgroundBlurEffect& obj) { const BaseObject& handle = obj.GetBaseObject(); - return static_cast(handle); + return static_cast(handle); } } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.cpp b/dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.cpp index b8d82c279b..2f5358152a 100644 --- a/dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.cpp +++ b/dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.cpp @@ -74,6 +74,17 @@ void OffScreenRenderingImpl::OnActivate() return; } + if(!mCamera) + { + mCamera = CameraActor::New(); + mCamera.SetInvertYAxis(true); + mCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + mCamera.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + mCamera.SetType(Dali::Camera::FREE_LOOK); + } + mCamera.SetPerspectiveProjection(GetTargetSize()); + GetOwnerControl().Add(mCamera); + CreateFrameBuffer(); CreateRenderTask(); SetType(mType); @@ -94,6 +105,8 @@ void OffScreenRenderingImpl::OnDeactivate() { control.GetImplementation().RemoveCacheRenderer(); control.GetImplementation().SetOffScreenRenderableType(OffScreenRenderable::Type::NONE); + + mCamera.Unparent(); } DestroyFrameBuffer(); @@ -104,6 +117,8 @@ void OffScreenRenderingImpl::OnRefresh() { DestroyFrameBuffer(); + mCamera.SetPerspectiveProjection(GetTargetSize()); + CreateFrameBuffer(); mRenderTask.SetFrameBuffer(mFrameBuffer); } @@ -130,7 +145,7 @@ void OffScreenRenderingImpl::CreateRenderTask() mRenderTask = taskList.CreateTask(); mRenderTask.SetSourceActor(control); - mRenderTask.SetCameraActor(GetCameraActor()); + mRenderTask.SetCameraActor(mCamera); mRenderTask.SetExclusive(true); mRenderTask.SetInputEnabled(true); mRenderTask.SetFrameBuffer(mFrameBuffer); diff --git a/dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.h b/dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.h index 29cd2c0de8..c000a21254 100644 --- a/dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.h +++ b/dali-toolkit/internal/controls/render-effects/offscreen-rendering-impl.h @@ -95,6 +95,7 @@ private: private: RenderTask mRenderTask; + CameraActor mCamera; FrameBuffer mFrameBuffer; DevelControl::OffScreenRenderingType mType; }; diff --git a/dali-toolkit/internal/controls/render-effects/render-effect-impl.cpp b/dali-toolkit/internal/controls/render-effects/render-effect-impl.cpp index 7e569fccf9..753d80a6f1 100644 --- a/dali-toolkit/internal/controls/render-effects/render-effect-impl.cpp +++ b/dali-toolkit/internal/controls/render-effects/render-effect-impl.cpp @@ -47,7 +47,6 @@ Debug::Filter* gRenderEffectLogFilter = Debug::Filter::New(Debug::NoLogging, fal RenderEffectImpl::RenderEffectImpl() : mRenderer(), - mCamera(), mOwnerControl(), mSizeNotification(), mTargetSize(Vector2::ZERO), @@ -159,11 +158,6 @@ Vector2 RenderEffectImpl::GetTargetSize() const return mTargetSize; } -CameraActor RenderEffectImpl::GetCameraActor() const -{ - return mCamera; -} - void RenderEffectImpl::Activate() { if(!IsActivated() && IsActivateValid()) @@ -182,17 +176,6 @@ void RenderEffectImpl::Activate() } mPlacementSceneHolder = sceneHolder; - if(!mCamera) - { - mCamera = CameraActor::New(); - mCamera.SetInvertYAxis(true); - mCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); - mCamera.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); - mCamera.SetType(Dali::Camera::FREE_LOOK); - } - mCamera.SetPerspectiveProjection(GetTargetSize()); - ownerControl.Add(mCamera); - // Activate logic for subclass. OnActivate(); @@ -224,11 +207,6 @@ void RenderEffectImpl::Deactivate() // Deactivate logic for subclass. OnDeactivate(); - - if(mCamera) - { - mCamera.Unparent(); - } } } @@ -315,7 +293,6 @@ void RenderEffectImpl::OnSizeSet(PropertyNotification& source) } else { - mCamera.SetPerspectiveProjection(GetTargetSize()); OnRefresh(); } } diff --git a/dali-toolkit/internal/controls/render-effects/render-effect-impl.h b/dali-toolkit/internal/controls/render-effects/render-effect-impl.h index d352cbebf0..627c9c27cd 100644 --- a/dali-toolkit/internal/controls/render-effects/render-effect-impl.h +++ b/dali-toolkit/internal/controls/render-effects/render-effect-impl.h @@ -20,7 +20,6 @@ // EXTERNAL INCLUDE #include -#include #include #include #include @@ -47,6 +46,7 @@ class RenderEffectImpl : public BaseObject, public ConnectionTracker public: /** * @brief Sets owner Control. Applies effect on the owner. + * @note Activates render effect on default. * @param[in] control The owner control to apply RenderEffect. */ void SetOwnerControl(Toolkit::Control control); @@ -85,6 +85,16 @@ public: */ virtual void GetOffScreenRenderTasks(std::vector& tasks, bool isForward) = 0; + /** + * @copydoc Dali::Toolkit::RenderEffect::Activate + */ + void Activate(); + + /** + * @copydoc Dali::Toolkit::RenderEffect::Deactivate + */ + void Deactivate(); + protected: /** * @copydoc Dali::Toolkit::RenderEffect::RenderEffect @@ -119,12 +129,6 @@ protected: */ Vector2 GetTargetSize() const; - /** - * @brief Get camera that captures full size texture of mOwnerControl - * @return mCamera - */ - CameraActor GetCameraActor() const; - /** * @brief Get Owner control. It could be return empty handle if owner control is not set, or destroyed. * @return mOwnerControl @@ -160,17 +164,13 @@ protected: */ virtual void OnRefresh() = 0; -private: /** - * @brief Activates effect on ownerControl - */ - void Activate(); - - /** - * @brief Deactivates effect + * @brief Get whether this effect activated or not. + * @return True if effect is activated. False otherwise. */ - void Deactivate(); + bool IsActivated() const; +private: /** * @brief Check whether it is possible to activate effect or not. * It will check various status, e.g. the control's visibility. @@ -178,12 +178,6 @@ private: */ bool IsActivateValid() const; - /** - * @brief Get whether this effect activated or not. - * @return True if effect is activated. False otherwise. - */ - bool IsActivated() const; - private: /** * @brief Calculates a valid target size for texture. @@ -205,7 +199,6 @@ private: private: Dali::Renderer mRenderer; // An additional renderer for mOwnerControl - CameraActor mCamera; // A camera that captures full size texture of mOwnerControl Dali::WeakHandle mOwnerControl; ///< Weakhandle of owner control. WeakHandle mPlacementSceneHolder; ///< Weakhandle of scene diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 0e66eb83f2..7e746911e1 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -70,8 +70,8 @@ SET( toolkit_src_files ${toolkit_src_dir}/visuals/wireframe/wireframe-visual.cpp ${toolkit_src_dir}/controls/alignment/alignment-impl.cpp ${toolkit_src_dir}/controls/render-effects/render-effect-impl.cpp - ${toolkit_src_dir}/controls/render-effects/blur-effect-impl.cpp ${toolkit_src_dir}/controls/render-effects/mask-effect-impl.cpp + ${toolkit_src_dir}/controls/render-effects/background-blur-effect-impl.cpp ${toolkit_src_dir}/controls/render-effects/offscreen-rendering-impl.cpp ${toolkit_src_dir}/controls/bloom-view/bloom-view-impl.cpp ${toolkit_src_dir}/controls/bubble-effect/bubble-emitter-impl.cpp diff --git a/dali-toolkit/internal/graphics/shaders/blur-effect.frag b/dali-toolkit/internal/graphics/shaders/blur-effect.frag index 65b2551d77..8ddfe964b6 100644 --- a/dali-toolkit/internal/graphics/shaders/blur-effect.frag +++ b/dali-toolkit/internal/graphics/shaders/blur-effect.frag @@ -8,6 +8,8 @@ INPUT highp vec2 vTexCoord; UNIFORM sampler2D sTexture; UNIFORM_BLOCK FragBlock { + UNIFORM highp float uAnimationRatio; + UNIFORM highp float uOpacity; UNIFORM highp vec2 uSampleOffsets[NUM_SAMPLES]; UNIFORM highp float uSampleWeights[NUM_SAMPLES]; }; @@ -17,7 +19,8 @@ void main() highp vec4 col = vec4(0.0); for (int i=0; i // INTERNAL INCLUDES -#include +#include namespace Dali { namespace Toolkit @@ -28,20 +28,60 @@ BackgroundBlurEffect::BackgroundBlurEffect(const BackgroundBlurEffect& handle) : RenderEffect(handle) { } -BackgroundBlurEffect::BackgroundBlurEffect(Internal::BlurEffectImpl* blurEffectImpl) -: RenderEffect(blurEffectImpl) + +BackgroundBlurEffect::BackgroundBlurEffect(Internal::BackgroundBlurEffectImpl* backgroundBlurEffectImpl) +: RenderEffect(backgroundBlurEffectImpl) { } + BackgroundBlurEffect::~BackgroundBlurEffect() = default; + BackgroundBlurEffect BackgroundBlurEffect::New() { - Internal::BlurEffectImplPtr internal = Internal::BlurEffectImpl::New(true); + Internal::BackgroundBlurEffectImplPtr internal = Internal::BackgroundBlurEffectImpl::New(); return BackgroundBlurEffect(internal.Get()); } -BackgroundBlurEffect BackgroundBlurEffect::New(float downscaleFactor, uint32_t blurRadius, bool blurOnce) + +BackgroundBlurEffect BackgroundBlurEffect::New(uint32_t blurRadius) { - Internal::BlurEffectImplPtr internal = Internal::BlurEffectImpl::New(downscaleFactor, blurRadius, blurOnce, true); + Internal::BackgroundBlurEffectImplPtr internal = Internal::BackgroundBlurEffectImpl::New(blurRadius); return BackgroundBlurEffect(internal.Get()); } + +void BackgroundBlurEffect::SetBlurOnce(bool blurOnce) +{ + GetImplementation(*this).SetBlurOnce(blurOnce); +} + +bool BackgroundBlurEffect::GetBlurOnce() const +{ + return GetImplementation(*this).GetBlurOnce(); +} + +void BackgroundBlurEffect::SetBlurRadius(uint32_t blurRadius) +{ + GetImplementation(*this).SetBlurRadius(blurRadius); +} + +uint32_t BackgroundBlurEffect::GetBlurRadius() const +{ + return GetImplementation(*this).GetBlurRadius(); +} + +void BackgroundBlurEffect::AddBlurStrengthAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue) +{ + GetImplementation(*this).AddBlurStrengthAnimation(animation, alphaFunction, timePeriod, fromValue, toValue); +} + +void BackgroundBlurEffect::AddBlurOpacityAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue) +{ + GetImplementation(*this).AddBlurOpacityAnimation(animation, alphaFunction, timePeriod, fromValue, toValue); +} + +BackgroundBlurEffect::FinishedSignalType& BackgroundBlurEffect::FinishedSignal() +{ + return GetImplementation(*this).FinishedSignal(); +} + } // namespace Toolkit } // namespace Dali 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 index 6f675f309c..306e9191d8 100644 --- a/dali-toolkit/public-api/controls/render-effects/background-blur-effect.h +++ b/dali-toolkit/public-api/controls/render-effects/background-blur-effect.h @@ -18,13 +18,17 @@ */ // INTERNAL INCLUDES #include +// EXTERNAL INCLUDES +#include +#include + namespace Dali { namespace Toolkit { namespace Internal DALI_INTERNAL { -class BlurEffectImpl; +class BackgroundBlurEffectImpl; } // namespace DALI_INTERNAL /** * @brief BackgroundBlurEffect is a visual effect that blurs owner control's background. @@ -46,40 +50,106 @@ class DALI_TOOLKIT_API BackgroundBlurEffect : public RenderEffect { public: /** - * @brief Creates an initialized BackgroundBlurEffect, using default settings. The default settings are: - * - * downscaleFactor = 0.4f - * pixelRadius = 5u + * @brief Typedef for finished signals sent by this class. * + * @SINCE_2_4.15 + */ + typedef Signal FinishedSignalType; + + /** + * @brief Creates an initialized BackgroundBlurEffect, using default settings. As default, blur radius is set to 10u. * @SINCE_2_3.28 * @return A handle to a newly allocated Dali resource */ static BackgroundBlurEffect New(); + /** * @brief Creates an initialized BackgroundBlurEffect. - * @param[in] downscaleFactor This value should reside in the range [0.0, 1.0]. * @param[in] blurRadius The radius of Gaussian kernel. - * @param[in] blurOnce Whether to blur once or always. Default is false(always). * @SINCE_2_3.28 * @return A handle to a newly allocated Dali resource */ - static BackgroundBlurEffect New(float downscaleFactor, uint32_t blurRadius, bool blurOnce = false); + static BackgroundBlurEffect New(uint32_t blurRadius); + /** * @brief Creates an uninitialized blur effect. * @SINCE_2_3.28 */ BackgroundBlurEffect(); + /** * @brief Copy constructor. * @SINCE_2_3.28 */ BackgroundBlurEffect(const BackgroundBlurEffect& handle); + /** - * @brief Destructor - * @SINCE_2_3.28 - */ + * @brief Destructor + * @SINCE_2_3.28 + */ ~BackgroundBlurEffect(); + /** + * @brief Set whether to refresh effect once or every frame. + * @param[in] blurOnce If true, renders effect once, else updates effect rendering every frame. + * @SINCE_2_4.15 + */ + void SetBlurOnce(bool blurOnce); + + /** + * @brief Retrives whether effect rendering is done once(true) or every frame(false) + * @SINCE_2_4.15 + */ + bool GetBlurOnce() const; + + /** + * @brief Set blur radius value. + * @param[in] blurRadius The radius of Gaussian kernel. + * @SINCE_2_4.15 + */ + void SetBlurRadius(uint32_t blurRadius); + + /** + * @brief Retrieves blur radius value. + * @SINCE_2_4.15 + */ + uint32_t GetBlurRadius() const; + + /** + * @brief Adds blur strength animation. Blurifies clear texture within given animation parameters. + * @param[in] animation Animation instance to which we add blur strength animation. + * @param[in] alphaFunction AlphaFunction of blur strength animation. + * @param[in] timePeriod TimePeriod of blur strength animation. Default value is animation's duration. + * @param[in] fromValue Starting value of blur strength. Must be in range of [0.0f, 1.0f] + * @param[in] toValue End value of blur strength. Must be in range of [0.0f, 1.0f] + * @note If toValue is smaller than fromValue, animation would show reversed(blurred->clarified) animation. + * @note When choosing alpha function, note that gaussian curve itself is innately non-linear. + * @SINCE_2_4.15 + */ + void AddBlurStrengthAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue); + + /** + * @brief Adds blur opacity animation. Blurifies clear texture within given animation parameters. + * @param[in] animation Animation instance to which we add blur opacity animation. + * @param[in] alphaFunction AlphaFunction of blur opacity animation. + * @param[in] timePeriod TimePeriod of blur opacity animation. Default value is animation's duration. + * @param[in] fromValue Starting value of blur opacity. Must be in range of [0.0f, 1.0f] + * @param[in] toValue End value of blur opacity. Must be in range of [0.0f, 1.0f] + * @note If toValue is smaller than fromValue, animation would show reversed(blurred->clarified) animation. + * @note When choosing alpha function, note that gaussian curve itself is innately non-linear. + * @SINCE_2_4.15 + */ + void AddBlurOpacityAnimation(Animation& animation, AlphaFunction alphaFunction, TimePeriod timePeriod, float fromValue, float toValue); + +public: // Signals + /** + * @brief If blurOnce is true and effect is activated, then connect to this signal to be notified when the + * target actor has been rendered. + * @SINCE_2_4.15 + * @return The finished signal + */ + FinishedSignalType& FinishedSignal(); + public: // Not intended for use by Application developers ///@cond internal /** @@ -87,7 +157,7 @@ public: // Not intended for use by Application developers * @SINCE_2_3.28 * @param[in] blurEffectImpl The UI Control implementation. */ - explicit DALI_INTERNAL BackgroundBlurEffect(Internal::BlurEffectImpl* blurEffectImpl); + explicit DALI_INTERNAL BackgroundBlurEffect(Internal::BackgroundBlurEffectImpl* backgroundBlurEffectImpl); ///@endcond }; } // namespace Toolkit diff --git a/dali-toolkit/public-api/controls/render-effects/render-effect.cpp b/dali-toolkit/public-api/controls/render-effects/render-effect.cpp index 2884ce274d..4c25786c05 100644 --- a/dali-toolkit/public-api/controls/render-effects/render-effect.cpp +++ b/dali-toolkit/public-api/controls/render-effects/render-effect.cpp @@ -35,5 +35,14 @@ RenderEffect::RenderEffect(Internal::RenderEffectImpl* renderEffectImpl) { } +void RenderEffect::Activate() +{ + GetImplementation(*this).Activate(); +} + +void RenderEffect::Deactivate() +{ + GetImplementation(*this).Deactivate(); +} } // namespace Toolkit } // namespace Dali diff --git a/dali-toolkit/public-api/controls/render-effects/render-effect.h b/dali-toolkit/public-api/controls/render-effects/render-effect.h index f7194c1006..0129a85762 100644 --- a/dali-toolkit/public-api/controls/render-effects/render-effect.h +++ b/dali-toolkit/public-api/controls/render-effects/render-effect.h @@ -70,6 +70,18 @@ public: */ RenderEffect(const RenderEffect& handle); + /** + * @brief Activates effect on ownerControl + * @SINCE_2_4.15 + */ + void Activate(); + + /** + * @brief Deactivates effect + * @SINCE_2_4.15 + */ + void Deactivate(); + public: // Not intended for Application developers ///@cond internal /** -- 2.34.1