From 05be3c4a93d6da36596a99ff04c3ef0ed072362a Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Tue, 4 Jun 2024 21:38:38 +0900 Subject: [PATCH] [Tizen] Fix Animation with EndAction::DISCARD dont reset properties. If Animation::EndAction::DISCARD finisehd normally cases, The mDirtyFlag was not matched with real world For example ResetToBaseValue[0](mDirtyFlag become 1) Animate and finished (mValue[0] changed.) (update) ResetToBaseValue[1](mDirtyFlag become 0) (update) (ResetToBaseValue did not called. So mValue[0] is last frame value) (update) (ResetToBaseValue did not called. So mValue[1] is BaseValue) Now, mValue become flickering. To avoid this problem, let we call ResetToBaseValue at least 2 frames if finished animation's EndAction is DISCARD. (Note that we don't consider Stop() call cases, since Stop() will not Animate Animator, so mValue[0] is BaseValue) And also, There was some issue that visual renderer property changeness not updated to the dirty rect infomation. (Since SG::Renderer don't be mark as updated) To fix this issue, let we ensure to check the visual renderer property dirty. And also, for apply Animation::EndAction::DISCARD case, Let we make visual renderer coefficient use double buffered flags, and age down every frames. TODO : UpdateManager need to ResetBaseValue at least 2 frames if Finished animation is EndAction::DISCARD. This will need update manager side fix. So just keep this bug and fix as another patch. Change-Id: Ibf654f723e1f986843cda620bc741b1121ee95d7 Signed-off-by: Eunki, Hong --- automated-tests/src/dali/utc-Dali-Animation.cpp | 154 ++++++- .../src/dali/utc-Dali-VisualRenderer.cpp | 459 +++++++++++++++++++++ dali/internal/update/common/animatable-property.h | 12 +- dali/internal/update/common/renderer-resetter.h | 1 - dali/internal/update/manager/update-manager.cpp | 28 +- .../update/rendering/scene-graph-renderer.cpp | 22 +- .../update/rendering/scene-graph-renderer.h | 5 - .../scene-graph-visual-renderer-property.h | 59 ++- .../rendering/scene-graph-visual-renderer.cpp | 56 +-- .../update/rendering/scene-graph-visual-renderer.h | 26 +- 10 files changed, 747 insertions(+), 75 deletions(-) diff --git a/automated-tests/src/dali/utc-Dali-Animation.cpp b/automated-tests/src/dali/utc-Dali-Animation.cpp index 55ca82f..6adfc79 100644 --- a/automated-tests/src/dali/utc-Dali-Animation.cpp +++ b/automated-tests/src/dali/utc-Dali-Animation.cpp @@ -890,8 +890,9 @@ int UtcDaliAnimationIsLoopingP(void) END_TEST; } -int UtcDaliAnimationSetEndActionN(void) +int UtcDaliAnimationSetEndActionP01(void) { + tet_infoline("Test Animation::EndAction with Transform\n"); TestApplication application; Actor actor = Actor::New(); @@ -913,7 +914,8 @@ int UtcDaliAnimationSetEndActionN(void) animation.FinishedSignal().Connect(&application, finishCheck); application.SendNotification(); - application.Render(static_cast(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/); + application.Render(static_cast(durationSeconds * 500.0f)); + application.Render(static_cast(durationSeconds * 500.0f) + 1u /*just beyond the animation duration*/); // We did expect the animation to finish application.SendNotification(); @@ -926,6 +928,12 @@ int UtcDaliAnimationSetEndActionN(void) application.Render(0); DALI_TEST_EQUALS(Vector3::ZERO, actor.GetCurrentProperty(Actor::Property::POSITION), TEST_LOCATION); + application.SendNotification(); + application.Render(0); + application.SendNotification(); + application.Render(0); + + tet_printf("Set EndAction::BAKE_FINAL\n"); // Test BakeFinal, animate again, for half the duration finishCheck.Reset(); animation.SetEndAction(Animation::BAKE_FINAL); @@ -938,12 +946,14 @@ int UtcDaliAnimationSetEndActionN(void) // Stop the animation early animation.Stop(); + tet_printf("EndAction::BAKE_FINAL Animation stopped\n"); // We did NOT expect the animation to finish application.SendNotification(); finishCheck.CheckSignalNotReceived(); DALI_TEST_EQUALS(targetPosition * 0.5f, actor.GetCurrentProperty(Actor::Property::POSITION), VECTOR4_EPSILON, TEST_LOCATION); // The position should be same with target position in the next frame + tet_printf("Check current value return well\n"); application.Render(0); DALI_TEST_EQUALS(targetPosition, actor.GetCurrentProperty(Actor::Property::POSITION), TEST_LOCATION); @@ -953,6 +963,12 @@ int UtcDaliAnimationSetEndActionN(void) application.Render(0); DALI_TEST_EQUALS(Vector3::ZERO, actor.GetCurrentProperty(Actor::Property::POSITION), TEST_LOCATION); + application.SendNotification(); + application.Render(0); + application.SendNotification(); + application.Render(0); + + tet_printf("Set EndAction::Discard\n"); // Test EndAction::Discard, animate again, but don't bake this time finishCheck.Reset(); animation.SetEndAction(Animation::DISCARD); @@ -960,22 +976,154 @@ int UtcDaliAnimationSetEndActionN(void) animation.Play(); application.SendNotification(); - application.Render(static_cast(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/); + application.Render(static_cast(durationSeconds * 500.0f)); + application.Render(static_cast(durationSeconds * 500.0f) + 1u /*just beyond the animation duration*/); + // Check whether we need to keep update at least 2 frames after discard-animation finished. + DALI_TEST_CHECK((application.GetUpdateStatus() & Integration::KeepUpdating::ANIMATIONS_RUNNING) != 0u); + + tet_printf("EndAction::Discard Animation finished\n"); // We did expect the animation to finish application.SendNotification(); finishCheck.CheckSignalReceived(); DALI_TEST_EQUALS(targetPosition, actor.GetCurrentProperty(Actor::Property::POSITION), TEST_LOCATION); // The position should be discarded in the next frame + // And also, check whether we need to keep update next frames after discard-animation finished. + tet_printf("Check current value return well\n"); application.Render(0); DALI_TEST_EQUALS(Vector3::ZERO /*discarded*/, actor.GetCurrentProperty(Actor::Property::POSITION), TEST_LOCATION); + DALI_TEST_CHECK((application.GetUpdateStatus() & Integration::KeepUpdating::ANIMATIONS_RUNNING) != 0u); // Check that nothing has changed after a couple of buffer swaps + // After 2 frames rendered, UpdateStatus will not mark as animation runing. application.Render(0); DALI_TEST_EQUALS(Vector3::ZERO, actor.GetCurrentProperty(Actor::Property::POSITION), TEST_LOCATION); + DALI_TEST_CHECK((application.GetUpdateStatus() & Integration::KeepUpdating::ANIMATIONS_RUNNING) == 0u); + application.Render(0); DALI_TEST_EQUALS(Vector3::ZERO, actor.GetCurrentProperty(Actor::Property::POSITION), TEST_LOCATION); + DALI_TEST_CHECK((application.GetUpdateStatus() & Integration::KeepUpdating::ANIMATIONS_RUNNING) == 0u); + END_TEST; +} + +int UtcDaliAnimationSetEndActionP02(void) +{ + tet_infoline("Test Animation::EndAction with non-Transform\n"); + TestApplication application; + + Actor actor = Actor::New(); + application.GetScene().Add(actor); + + Vector4 initialColor(0.0f, 0.0f, 0.0f, 1.0f); + actor.SetProperty(Actor::Property::COLOR, initialColor); + + // Build the animation + float durationSeconds(1.0f); + Animation animation = Animation::New(durationSeconds); + DALI_TEST_CHECK(animation.GetEndAction() == Animation::BAKE); + + Vector4 targetColor(1.0f, 1.0f, 1.0f, 1.0f); + animation.AnimateTo(Property(actor, Actor::Property::COLOR), targetColor, AlphaFunction::LINEAR); + + // Start the animation + animation.Play(); + + bool signalReceived(false); + AnimationFinishCheck finishCheck(signalReceived); + animation.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render(static_cast(durationSeconds * 500.0f)); + application.Render(static_cast(durationSeconds * 500.0f) + 1u /*just beyond the animation duration*/); + + // We did expect the animation to finish + application.SendNotification(); + finishCheck.CheckSignalReceived(); + DALI_TEST_EQUALS(targetColor, actor.GetCurrentProperty(Actor::Property::COLOR), TEST_LOCATION); + + // Go back to the start + actor.SetProperty(Actor::Property::COLOR, initialColor); + application.SendNotification(); + application.Render(0); + DALI_TEST_EQUALS(initialColor, actor.GetCurrentProperty(Actor::Property::COLOR), TEST_LOCATION); + + application.SendNotification(); + application.Render(0); + application.SendNotification(); + application.Render(0); + + tet_printf("Set EndAction::BAKE_FINAL\n"); + // Test BakeFinal, animate again, for half the duration + finishCheck.Reset(); + animation.SetEndAction(Animation::BAKE_FINAL); + DALI_TEST_CHECK(animation.GetEndAction() == Animation::BAKE_FINAL); + animation.Play(); + + application.SendNotification(); + application.Render(static_cast(durationSeconds * 1000.0f * 0.5f) /*half of the animation duration*/); + + // Stop the animation early + animation.Stop(); + + tet_printf("EndAction::BAKE_FINAL Animation stopped\n"); + // We did NOT expect the animation to finish + application.SendNotification(); + finishCheck.CheckSignalNotReceived(); + DALI_TEST_EQUALS((initialColor + targetColor) * 0.5f, actor.GetCurrentProperty(Actor::Property::COLOR), VECTOR4_EPSILON, TEST_LOCATION); + + // The position should be same with target position in the next frame + tet_printf("Check current value return well\n"); + application.Render(0); + DALI_TEST_EQUALS(targetColor, actor.GetCurrentProperty(Actor::Property::COLOR), TEST_LOCATION); + + // Go back to the start + actor.SetProperty(Actor::Property::COLOR, initialColor); + application.SendNotification(); + application.Render(0); + DALI_TEST_EQUALS(initialColor, actor.GetCurrentProperty(Actor::Property::COLOR), TEST_LOCATION); + + application.SendNotification(); + application.Render(0); + application.SendNotification(); + application.Render(0); + + tet_printf("Set EndAction::Discard\n"); + // Test EndAction::Discard, animate again, but don't bake this time + finishCheck.Reset(); + animation.SetEndAction(Animation::DISCARD); + DALI_TEST_CHECK(animation.GetEndAction() == Animation::DISCARD); + animation.Play(); + + application.SendNotification(); + application.Render(static_cast(durationSeconds * 500.0f)); + application.Render(static_cast(durationSeconds * 500.0f) + 1u /*just beyond the animation duration*/); + + // Check whether we need to keep update at least 2 frames after discard-animation finished. + DALI_TEST_CHECK((application.GetUpdateStatus() & Integration::KeepUpdating::ANIMATIONS_RUNNING) != 0u); + + tet_printf("EndAction::Discard Animation finished\n"); + // We did expect the animation to finish + application.SendNotification(); + finishCheck.CheckSignalReceived(); + DALI_TEST_EQUALS(targetColor, actor.GetCurrentProperty(Actor::Property::COLOR), TEST_LOCATION); + + // The position should be discarded in the next frame + // And also, check whether we need to keep update next frames after discard-animation finished. + tet_printf("Check current value return well\n"); + application.Render(0); + DALI_TEST_EQUALS(initialColor /*discarded*/, actor.GetCurrentProperty(Actor::Property::COLOR), TEST_LOCATION); + DALI_TEST_CHECK((application.GetUpdateStatus() & Integration::KeepUpdating::ANIMATIONS_RUNNING) != 0u); + + // Check that nothing has changed after a couple of buffer swaps + // After 2 frames rendered, UpdateStatus will not mark as animation runing. + application.Render(0); + DALI_TEST_EQUALS(initialColor, actor.GetCurrentProperty(Actor::Property::COLOR), TEST_LOCATION); + DALI_TEST_CHECK((application.GetUpdateStatus() & Integration::KeepUpdating::ANIMATIONS_RUNNING) == 0u); + + application.Render(0); + DALI_TEST_EQUALS(initialColor, actor.GetCurrentProperty(Actor::Property::COLOR), TEST_LOCATION); + DALI_TEST_CHECK((application.GetUpdateStatus() & Integration::KeepUpdating::ANIMATIONS_RUNNING) == 0u); END_TEST; } diff --git a/automated-tests/src/dali/utc-Dali-VisualRenderer.cpp b/automated-tests/src/dali/utc-Dali-VisualRenderer.cpp index c86b503..ebe18d0 100644 --- a/automated-tests/src/dali/utc-Dali-VisualRenderer.cpp +++ b/automated-tests/src/dali/utc-Dali-VisualRenderer.cpp @@ -914,3 +914,462 @@ int UtcDaliVisualRendererPartialUpdate(void) END_TEST; } + +int UtcDaliVisualRendererPartialUpdate02(void) +{ + TestApplication application( + TestApplication::DEFAULT_SURFACE_WIDTH, + TestApplication::DEFAULT_SURFACE_HEIGHT, + TestApplication::DEFAULT_HORIZONTAL_DPI, + TestApplication::DEFAULT_VERTICAL_DPI, + true, + true); + + tet_infoline("Test that partial update works well when actor has multiple renderer, and we change only actor's transform"); + + const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams()); + + Shader shader = Shader::New("VertexSource", "FragmentSource"); + Geometry geometry = CreateQuadGeometry(); + VisualRenderer renderer1 = VisualRenderer::New(geometry, shader); + VisualRenderer renderer2 = VisualRenderer::New(geometry, shader); + + Actor actor = Actor::New(); + actor.AddRenderer(renderer1); + actor.AddRenderer(renderer2); + actor[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT; + actor[Actor::Property::POSITION] = Vector3(64.0f, 64.0f, 0.0f); + actor[Actor::Property::SIZE] = Vector3(64.0f, 64.0f, 0.0f); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + application.GetScene().Add(actor); + + application.SendNotification(); + + std::vector> damagedRects; + + // Actor added, damaged rect is added size of actor + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION); + + // Set clippingRect as full surface now. TODO : Set valid rect if we can. + Rect clippingRect = TestApplication::DEFAULT_SURFACE_RECT; + + // Aligned by 16 + DirtyRectChecker(damagedRects, + { + Rect(64, 672, 80, 80), + Rect(64, 672, 80, 80), + }, + true, + TEST_LOCATION); + + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION); + DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION); + DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION); + DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION); + + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // Ensure the damaged rect is empty + DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION); + + // Change the renderer1 and renderer2 transform property. + // To avoid useless float point error, make renderer size as 30x30 + renderer1.SetProperty(VisualRenderer::Property::TRANSFORM_SIZE, Vector2(0.5f - 2.0f / 64.0f, 0.5f - 2.0f / 64.0f)); + renderer1.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET, Vector2(-0.25f, -0.25f)); + renderer2.SetProperty(VisualRenderer::Property::TRANSFORM_SIZE, Vector2(0.5f - 2.0f / 64.0f, 0.5f - 2.0f / 64.0f)); + renderer2.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET, Vector2(0.25f, 0.25f)); + + // Now current actor show two 30x30 rectangle, one center position is (80, 80) and other is (112, 112). + // So, first rectangle's top left position is (65, 65), and seoncd rectangle's bottom right position is (127, 127). + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION); + // Aligned by 16 + // Note, this damagedRect is combine of previous rect and current rect + DirtyRectChecker(damagedRects, + { + Rect(64, 672, 80, 80), + Rect(64, 672, 80, 80), + }, + true, + TEST_LOCATION); + + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::RED); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::BLUE); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION); + + // Aligned by 16 + // Note, this damagedRect don't contain previous rect now. + // So, first rectangle's top left position is (65, 65), and seoncd rectangle's bottom right position is (127, 127). + DirtyRectChecker(damagedRects, + { + Rect(64, 704, 32, 32), + Rect(96, 672, 32, 32), + }, + true, + TEST_LOCATION); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // 3 frame spended after change actor property. Ensure the damaged rect is empty + DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION); + + actor[Actor::Property::POSITION_Y] = 96.0f; + // Change the y position of actor. + // Now current actor show two 32x32 rectangle, one center position is (80, 96) and other is (112, 128). + // So, rectangle's top left position is (64, 80), and bottom right position is (128, 144). + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION); + // Aligned by 16 + // Note, this damagedRect is combine of previous rect and current rect + DirtyRectChecker(damagedRects, + { + Rect(64, 672, 32, 64), + Rect(96, 640, 32, 64), + }, + true, + TEST_LOCATION); + + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::RED); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::BLUE); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION); + + // Aligned by 16 + // Note, this damagedRect don't contain previous rect now. + // Current rectangle's top left position is (64, 80), and bottom right position is (128, 144). + DirtyRectChecker(damagedRects, + { + Rect(64, 672, 32, 32), + Rect(96, 640, 32, 32), + }, + true, + TEST_LOCATION); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // 3 frame spended after change actor property. Ensure the damaged rect is empty + DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliVisualRendererPartialUpdate03(void) +{ + TestApplication application( + TestApplication::DEFAULT_SURFACE_WIDTH, + TestApplication::DEFAULT_SURFACE_HEIGHT, + TestApplication::DEFAULT_HORIZONTAL_DPI, + TestApplication::DEFAULT_VERTICAL_DPI, + true, + true); + + tet_infoline("Test that partial update works well when we animate visual renderer's animated properties with EndAction::DISCARD"); + + const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams()); + + Shader shader = Shader::New("VertexSource", "FragmentSource"); + Geometry geometry = CreateQuadGeometry(); + VisualRenderer renderer = VisualRenderer::New(geometry, shader); + + Actor actor = Actor::New(); + actor.AddRenderer(renderer); + actor[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT; + actor[Actor::Property::POSITION] = Vector3(64.0f, 64.0f, 0.0f); + actor[Actor::Property::SIZE] = Vector3(64.0f, 64.0f, 0.0f); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + application.GetScene().Add(actor); + + application.SendNotification(); + + std::vector> damagedRects; + + // Actor added, damaged rect is added size of actor + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + Rect clippingRect = Rect(64, 672, 80, 80); // in screen coordinates + DALI_TEST_EQUALS>(clippingRect, damagedRects[0], TEST_LOCATION); + + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION); + DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION); + DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION); + DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION); + + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // Ensure the damaged rect is empty + DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION); + + // Set clippingRect as full surface now. TODO : Set valid rect if we can. + clippingRect = TestApplication::DEFAULT_SURFACE_RECT; + + Property::Index index = VisualRenderer::Property::TRANSFORM_OFFSET; + + uint32_t durationMilliseconds = 1000u; + Animation animation = Animation::New(durationMilliseconds / 1000.0f); + animation.SetEndAction(Dali::Animation::EndAction::DISCARD); ///< Discard the animation when it ends. + animation.AnimateTo(Dali::Property(renderer, index), Vector2(1.0f, 1.0f)); + animation.Play(); + + // Now current actor show as 64x64 rectangle, with center position (96, 96) + (64, 64) * time. + + /// Progress 25% + /// Current actor show as 64x64 rectangle, with center position (112, 112). + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(durationMilliseconds / 4, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + // Aligned by 16 + // Note, this damagedRect is combine of previous rect and current rect + DALI_TEST_EQUALS>(Rect(64, 656, 96, 96), damagedRects[0], TEST_LOCATION); + + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::RED); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::BLUE); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + // Note, this damagedRect don't contain previous rect now. + // Current rectangle's top left position is (80, 80), and bottom right position is (144, 144). + DALI_TEST_EQUALS>(Rect(80, 656, 80, 80), damagedRects[0], TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::GREEN); + + /// Progress 50% + /// Current actor show as 64x64 rectangle, with center position (128, 128). + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(durationMilliseconds / 4, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + // Aligned by 16 + // Note, this damagedRect is combine of previous rect and current rect + DALI_TEST_EQUALS>(Rect(80, 640, 96, 96), damagedRects[0], TEST_LOCATION); + + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::RED); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::BLUE); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + // Note, this damagedRect don't contain previous rect now. + // Current rectangle's top left position is (96, 96), and bottom right position is (160, 160). + DALI_TEST_EQUALS>(Rect(96, 640, 80, 80), damagedRects[0], TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::GREEN); + + /// Progress 75% + /// Current actor show as 64x64 rectangle, with center position (144, 144). + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(durationMilliseconds / 4, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + // Aligned by 16 + // Note, this damagedRect is combine of previous rect and current rect + DALI_TEST_EQUALS>(Rect(96, 624, 96, 96), damagedRects[0], TEST_LOCATION); + + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::RED); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::BLUE); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + // Note, this damagedRect don't contain previous rect now. + // Current rectangle's top left position is (112, 112), and bottom right position is (176, 176). + DALI_TEST_EQUALS>(Rect(112, 624, 80, 80), damagedRects[0], TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::GREEN); + + /// Progress 100% + /// Current actor show as 64x64 rectangle, with center position (96, 96). + /// Note. Animation end action is DISCARD. + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(durationMilliseconds / 4 + 1u /* Over the animation */, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + // Aligned by 16 + // Note, this damagedRect is combine of previous rect and current rect + DALI_TEST_EQUALS>(Rect(112, 608, 96, 96), damagedRects[0], TEST_LOCATION); + + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::RED); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::BLUE); + + application.SendNotification(); + damagedRects.clear(); + application.PreRenderWithPartialUpdate(0u, nullptr, damagedRects); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + // Note, this damagedRect don't contain previous rect now. + // Current rectangle's top left position is (64, 64), and bottom right position is (128, 128). + DALI_TEST_EQUALS>(Rect(64, 672, 80, 80), damagedRects[0], TEST_LOCATION); + + // Update dummy property to damangeRect buffer aging + actor.SetProperty(Actor::Property::COLOR, Color::GREEN); + + END_TEST; +} diff --git a/dali/internal/update/common/animatable-property.h b/dali/internal/update/common/animatable-property.h index c2bb6fe..a5471ed 100644 --- a/dali/internal/update/common/animatable-property.h +++ b/dali/internal/update/common/animatable-property.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_SCENE_GRAPH_ANIMATABLE_PROPERTY_H /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,7 +81,7 @@ protected: // for derived classes */ virtual void OnSet() { - mDirtyFlags = SET_FLAG; + mDirtyFlags |= SET_FLAG; } /** @@ -89,7 +89,7 @@ protected: // for derived classes */ virtual void OnBake() { - mDirtyFlags = BAKED_FLAG; + mDirtyFlags |= BAKED_FLAG; } public: @@ -98,7 +98,7 @@ public: */ void MarkAsDirty() { - mDirtyFlags = RESET_FLAG; + mDirtyFlags |= RESET_FLAG; } public: // From PropertyBase @@ -118,8 +118,8 @@ public: // From PropertyBase return true; // Animatable properties are always valid } -protected: // so that ResetToBaseValue can set it directly - uint32_t mDirtyFlags; ///< Flag whether value changed during previous 2 frames +protected: // so that ResetToBaseValue can set it directly + uint8_t mDirtyFlags : 2; ///< Flag whether value changed during previous 2 frames }; /** diff --git a/dali/internal/update/common/renderer-resetter.h b/dali/internal/update/common/renderer-resetter.h index 2883440..fae6dc5 100644 --- a/dali/internal/update/common/renderer-resetter.h +++ b/dali/internal/update/common/renderer-resetter.h @@ -148,7 +148,6 @@ protected: : mRenderer(renderer), mActive(AGING) // Since we make this resetter only initialize case now. { - mRenderer->MarkAsDirty(); } Renderer* mRenderer; ///< The renderer that owns the properties diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index 130ed26..d279c55 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -195,6 +195,7 @@ struct UpdateManager::Impl nodeDirtyFlags(NodePropertyFlags::TRANSFORM), // set to TransformFlag to ensure full update the first time through Update() frameCounter(0), renderingBehavior(DevelStage::Rendering::IF_REQUIRED), + discardAnimationFinishedAge(0u), animationFinishedDuringUpdate(false), previousUpdateScene(false), renderTaskWaiting(false), @@ -317,11 +318,13 @@ struct UpdateManager::Impl uint32_t frameCounter; ///< Frame counter used in debugging to choose which frame to debug and which to ignore. DevelStage::Rendering renderingBehavior; ///< Set via DevelStage::SetRenderingBehavior - bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update() - bool previousUpdateScene; ///< True if the scene was updated in the previous frame (otherwise it was optimized out) - bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered - bool renderersAdded; ///< Flag to keep track when renderers have been added to avoid unnecessary processing - bool renderingRequired; ///< True if required to render the current frame + uint8_t discardAnimationFinishedAge : 2; ///< Age of EndAction::Discard animation Stop/Finished. It will make we call ResetToBaseValue at least 2 frames. + + bool animationFinishedDuringUpdate : 1; ///< Flag whether any animations finished during the Update() + bool previousUpdateScene : 1; ///< True if the scene was updated in the previous frame (otherwise it was optimized out) + bool renderTaskWaiting : 1; ///< A REFRESH_ONCE render task is waiting to be rendered + bool renderersAdded : 1; ///< Flag to keep track when renderers have been added to avoid unnecessary processing + bool renderingRequired : 1; ///< True if required to render the current frame private: Impl(const Impl&); ///< Undefined @@ -772,6 +775,9 @@ void UpdateManager::ResetProperties(BufferIndex bufferIndex) // Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped mImpl->animationFinishedDuringUpdate = false; + // Age down discard animations. + mImpl->discardAnimationFinishedAge >>= 1; + if(mImpl->nodeResetters.Count() > 0u) { // Reset node properties @@ -873,6 +879,12 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished; + // Check whether finished animation is Discard type. If then, we should update scene at least 2 frames. + if(finished && animation->GetEndAction() == Animation::EndAction::DISCARD) + { + mImpl->discardAnimationFinishedAge |= 2u; + } + // queue the notification on finished or stopped if(finished || stopped) { @@ -1107,6 +1119,7 @@ uint32_t UpdateManager::Update(float elapsedSeconds, isAnimationRunning || // ..at least one animation is running OR mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR mImpl->frameCallbackProcessor || // ..a frame callback processor is existed OR + mImpl->discardAnimationFinishedAge > 0u || // ..at least one animation with EndAction::DISCARD finished gestureUpdated; // ..a gesture property was updated uint32_t keepUpdating = 0; @@ -1378,7 +1391,7 @@ uint32_t UpdateManager::KeepUpdatingCheck(float elapsedSeconds) const // If the rendering behavior is set to continuously render, then continue to render. // Keep updating until no messages are received and no animations are running. - // If an animation has just finished, update at least once more for Discard end-actions. + // If an animation has just finished, update at least two frames more for Discard end-actions. // No need to check for renderQueue as there is always a render after update and if that // render needs another update it will tell the adaptor to call update again @@ -1388,7 +1401,8 @@ uint32_t UpdateManager::KeepUpdatingCheck(float elapsedSeconds) const } if(IsAnimationRunning() || - mImpl->animationFinishedDuringUpdate) + mImpl->animationFinishedDuringUpdate || + mImpl->discardAnimationFinishedAge > 0u) { keepUpdatingRequest |= KeepUpdating::ANIMATIONS_RUNNING; } diff --git a/dali/internal/update/rendering/scene-graph-renderer.cpp b/dali/internal/update/rendering/scene-graph-renderer.cpp index 1d404aa..3fbc62d 100644 --- a/dali/internal/update/rendering/scene-graph-renderer.cpp +++ b/dali/internal/update/rendering/scene-graph-renderer.cpp @@ -326,6 +326,12 @@ bool Renderer::PrepareRender(BufferIndex updateBufferIndex) mResendFlag = 0; } + // Age down visual properties dirty flag + if(mVisualProperties) + { + rendererUpdated |= mVisualProperties->PrepareProperties(); + } + // Ensure collected map is up to date UpdateUniformMap(updateBufferIndex); @@ -829,15 +835,6 @@ void Renderer::ResetToBaseValues(BufferIndex updateBufferIndex) } } -void Renderer::MarkAsDirty() -{ - mOpacity.MarkAsDirty(); - if(mVisualProperties) - { - mVisualProperties->MarkAsDirty(); - } -} - uint32_t Renderer::GetMemoryPoolCapacity() { return GetRendererMemoryPool().GetCapacity(); @@ -861,7 +858,12 @@ const CollectedUniformMap& Renderer::GetCollectedUniformMap() const bool Renderer::IsUpdated() const { - if(Updated() || (mShader && mShader->Updated())) + // We should check Whether + // 1. Renderer itself's property changed + // 2. Renderer's opacity changed + // 3. Shader's propperties are changed + // 4. Visual properties are changed + if(IsDirty() || (mShader && mShader->Updated()) || (mVisualProperties && mVisualProperties->Updated())) { return true; } diff --git a/dali/internal/update/rendering/scene-graph-renderer.h b/dali/internal/update/rendering/scene-graph-renderer.h index 5dabf05..a6ad912 100644 --- a/dali/internal/update/rendering/scene-graph-renderer.h +++ b/dali/internal/update/rendering/scene-graph-renderer.h @@ -495,11 +495,6 @@ public: void ResetToBaseValues(BufferIndex updateBufferIndex); /** - * @brief Mark all animatable properties as dirty. - */ - void MarkAsDirty(); - - /** * Get the capacity of the memory pools * @return the capacity of the memory pools */ diff --git a/dali/internal/update/rendering/scene-graph-visual-renderer-property.h b/dali/internal/update/rendering/scene-graph-visual-renderer-property.h index 5360173..7fc74a6 100644 --- a/dali/internal/update/rendering/scene-graph-visual-renderer-property.h +++ b/dali/internal/update/rendering/scene-graph-visual-renderer-property.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_SCENE_GRAPH_VISUAL_RENDERER_PROPERTY_H /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,35 +30,66 @@ namespace Dali::Internal::SceneGraph::VisualRenderer struct VisualRendererCoefficientCacheBase { VisualRendererCoefficientCacheBase() - : mUpdated(true) + : mUpdatedFlag(Dali::Internal::SceneGraph::BAKED_FLAG), + mUpdateCurrentFrame(true), + mCoefficientCalculated(false) { } virtual ~VisualRendererCoefficientCacheBase() = default; /** - * @brief Check whether this cache need to be update. - * After call this API, update flag will be reset. + * @brief Check whether this cache is updated or not. * - * @return True if this coefficient updated. False otherwise. */ - bool IsUpdated() + bool IsUpdated() const { - bool ret = mUpdated; - mUpdated = false; - return ret; + return mUpdateCurrentFrame; } /** * @brief Mark update flag as true. + * @param[in] bake Whether this coefficient updated by OnBake API, or not. */ - void Update() + void Update(bool bake) { - mUpdated = true; + mUpdateCurrentFrame = true; + mUpdatedFlag |= bake ? Dali::Internal::SceneGraph::BAKED_FLAG : Dali::Internal::SceneGraph::SET_FLAG; + } + + /** + * @brief Get whether we already calculate coefficient at this frame or not. + * @return True if we already calculate coefficient at this frame, false otherwise. + */ + bool IsCoefficientCalculated() const + { + return mCoefficientCalculated; + } + + /** + * @brief Mark as we calculate coefficient already at this frame. + */ + void MarkCoefficientCalculated() + { + mCoefficientCalculated = true; + } + + /** + * @brief Reset update flag. + */ + void ResetFlag() + { + mUpdateCurrentFrame = (mUpdatedFlag != Dali::Internal::SceneGraph::CLEAN_FLAG); ///< Keep the flag whether it was updated or not. + mCoefficientCalculated = (!mUpdateCurrentFrame); ///< Re-calculate coefficient only if previous update flag was not clean. + + mUpdatedFlag >>= 1; } private: - bool mUpdated; ///< Updated flag for this coefficient cache. + uint8_t mUpdatedFlag : 2; ///< Updated flag for this coefficient cache. + + bool mUpdateCurrentFrame : 1; ///< Whether we need to update this frame or not. + bool mCoefficientCalculated : 1; ///< Whether we need to re-calculate coefficient or not. }; /** @@ -105,7 +136,7 @@ public: */ void OnSet() override { - GetCacheBaseData()->Update(); + GetCacheBaseData()->Update(false); AnimatablePropertyBase::OnSet(); } @@ -114,7 +145,7 @@ public: */ void OnBake() override { - GetCacheBaseData()->Update(); + GetCacheBaseData()->Update(true); AnimatablePropertyBase::OnBake(); } }; diff --git a/dali/internal/update/rendering/scene-graph-visual-renderer.cpp b/dali/internal/update/rendering/scene-graph-visual-renderer.cpp index 560fd25..904bb2c 100644 --- a/dali/internal/update/rendering/scene-graph-visual-renderer.cpp +++ b/dali/internal/update/rendering/scene-graph-visual-renderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,21 +45,9 @@ void AnimatableVisualProperties::ResetToBaseValues(BufferIndex updateBufferIndex } } -void AnimatableVisualProperties::MarkAsDirty() +bool AnimatableVisualProperties::Updated() const { - mTransformOffset.MarkAsDirty(); - mTransformSize.MarkAsDirty(); - mTransformOrigin.MarkAsDirty(); - mTransformAnchorPoint.MarkAsDirty(); - mTransformOffsetSizeMode.MarkAsDirty(); - mExtraSize.MarkAsDirty(); - mMixColor.MarkAsDirty(); - mPreMultipliedAlpha.MarkAsDirty(); - if(mExtendedProperties) - { - auto* decoratedVisualProperties = static_cast(mExtendedProperties); - decoratedVisualProperties->MarkAsDirty(); - } + return mCoefficient.IsUpdated() || (mExtendedProperties && static_cast(mExtendedProperties)->Updated()); } Vector4 AnimatableVisualProperties::GetVisualTransformedUpdateArea(BufferIndex updateBufferIndex, const Vector4& originalUpdateArea) noexcept @@ -67,7 +55,7 @@ Vector4 AnimatableVisualProperties::GetVisualTransformedUpdateArea(BufferIndex u auto& coefficient = mCoefficient; // Recalculate only if coefficient need to be updated. - if(coefficient.IsUpdated()) + if(!coefficient.IsCoefficientCalculated()) { // VisualProperty const Vector2 transformOffset = mTransformOffset.Get(updateBufferIndex); @@ -119,6 +107,8 @@ Vector4 AnimatableVisualProperties::GetVisualTransformedUpdateArea(BufferIndex u coefficient.coefXB = coefficient.coefXA * transformAnchorPoint + transformOffset * Vector2(1.0f - transformOffsetSizeMode.x, 1.0f - transformOffsetSizeMode.y) + transformOrigin; coefficient.coefCA = transformSize * Vector2(transformOffsetSizeMode.z, transformOffsetSizeMode.w) + extraSize; coefficient.coefCB = coefficient.coefCA * transformAnchorPoint + transformOffset * Vector2(transformOffsetSizeMode.x, transformOffsetSizeMode.y); + + coefficient.MarkCoefficientCalculated(); } float coefD = 0.0f; ///< Default as 0.0f when we don't use decorated renderer. @@ -130,7 +120,7 @@ Vector4 AnimatableVisualProperties::GetVisualTransformedUpdateArea(BufferIndex u auto& decoratedCoefficient = decoratedVisualProperties->mCoefficient; // Recalculate only if coefficient need to be updated. - if(decoratedCoefficient.IsUpdated()) + if(!decoratedCoefficient.IsCoefficientCalculated()) { // DecoratedVisualProperty const float borderlineWidth = decoratedVisualProperties->mBorderlineWidth.Get(updateBufferIndex); @@ -147,6 +137,8 @@ Vector4 AnimatableVisualProperties::GetVisualTransformedUpdateArea(BufferIndex u // D coefficients be used only decoratedVisual. // It can be calculated parallely with visual transform. decoratedCoefficient.coefD = std::max((1.0f + Dali::Clamp(borderlineOffset, -1.0f, 1.0f)) * borderlineWidth, 2.0f * blurRadius) + extraPadding; + + decoratedCoefficient.MarkCoefficientCalculated(); } // Update coefD so we can use this value out of this scope. @@ -185,6 +177,20 @@ Vector4 AnimatableVisualProperties::GetVisualTransformedUpdateArea(BufferIndex u return resultArea; } +bool AnimatableVisualProperties::PrepareProperties() +{ + bool rendererUpdated = mCoefficient.IsUpdated(); + mCoefficient.ResetFlag(); + + if(mExtendedProperties) + { + auto* decoratedVisualProperties = static_cast(mExtendedProperties); + rendererUpdated |= (decoratedVisualProperties->PrepareProperties()); + } + + return rendererUpdated; +} + void AnimatableDecoratedVisualProperties::ResetToBaseValues(BufferIndex updateBufferIndex) { mCornerRadius.ResetToBaseValue(updateBufferIndex); @@ -195,14 +201,16 @@ void AnimatableDecoratedVisualProperties::ResetToBaseValues(BufferIndex updateBu mBlurRadius.ResetToBaseValue(updateBufferIndex); } -void AnimatableDecoratedVisualProperties::MarkAsDirty() +bool AnimatableDecoratedVisualProperties::Updated() const +{ + return mCoefficient.IsUpdated(); +} + +bool AnimatableDecoratedVisualProperties::PrepareProperties() { - mCornerRadius.MarkAsDirty(); - mCornerRadiusPolicy.MarkAsDirty(); - mBorderlineWidth.MarkAsDirty(); - mBorderlineColor.MarkAsDirty(); - mBorderlineOffset.MarkAsDirty(); - mBlurRadius.MarkAsDirty(); + bool rendererUpdated = mCoefficient.IsUpdated(); + mCoefficient.ResetFlag(); + return rendererUpdated; } } // namespace VisualRenderer diff --git a/dali/internal/update/rendering/scene-graph-visual-renderer.h b/dali/internal/update/rendering/scene-graph-visual-renderer.h index c90c735..02244c7 100644 --- a/dali/internal/update/rendering/scene-graph-visual-renderer.h +++ b/dali/internal/update/rendering/scene-graph-visual-renderer.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_SCENE_GRAPH_VISUAL_RENDERER_H /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,9 +56,9 @@ public: // Public API void ResetToBaseValues(BufferIndex updateBufferIndex); /** - * @copydoc Dali::Internal::SceneGraph::Renderer::MarkAsDirty + * @copydoc Dali::Internal::SceneGraph::Renderer::Updated */ - void MarkAsDirty(); + bool Updated() const; /** * @copydoc RenderDataProvider::GetVisualTransformedUpdateArea() @@ -67,6 +67,14 @@ public: // Public API public: /** + * @brief Prepare properties and ready to render sequence + * + * @return True if we need to render this frame. + */ + bool PrepareProperties(); + +public: + /** * @brief Cached coefficient value when we calculate visual transformed update size. * It can reduce complexity of calculate the vertex position. * @@ -140,9 +148,17 @@ public: // Public API void ResetToBaseValues(BufferIndex updateBufferIndex); /** - * @copydoc Dali::Internal::SceneGraph::Renderer::MarkAsDirty + * @copydoc Dali::Internal::SceneGraph::Renderer::Updated + */ + bool Updated() const; + +public: + /** + * @brief Prepare properties and ready to render sequence + * + * @return True if we need to render this frame. */ - void MarkAsDirty(); + bool PrepareProperties(); public: /** -- 2.7.4