From 20926d27b9c60f8a7b0bf82acd6a4dc2fa91e608 Mon Sep 17 00:00:00 2001 From: Anton Obzhirov Date: Tue, 14 Apr 2020 15:59:45 +0100 Subject: [PATCH] Partial update implementation, first phase. Change-Id: I7d2a70c747247c057af6d00d8c147594bf6c7a3d --- .../dali-test-suite-utils/test-application.cpp | 38 ++- .../dali/dali-test-suite-utils/test-application.h | 6 +- automated-tests/src/dali/utc-Dali-Actor.cpp | 361 +++++++++++++++++++++ dali/devel-api/actors/actor-devel.h | 7 + dali/integration-api/core-enumerations.h | 9 + dali/integration-api/core.cpp | 16 +- dali/integration-api/core.h | 28 +- dali/internal/common/core-impl.cpp | 15 +- dali/internal/common/core-impl.h | 15 +- dali/internal/event/actors/actor-impl.cpp | 26 ++ dali/internal/event/actors/actor-impl.h | 12 + .../internal/event/common/property-buffer-impl.cpp | 15 + dali/internal/event/common/property-input-impl.h | 66 ++++ dali/internal/render/common/render-algorithms.cpp | 33 +- dali/internal/render/common/render-algorithms.h | 7 +- dali/internal/render/common/render-item.cpp | 10 +- dali/internal/render/common/render-item.h | 4 +- dali/internal/render/common/render-manager.cpp | 335 ++++++++++++++++++- dali/internal/render/common/render-manager.h | 28 +- dali/internal/render/renderers/render-renderer.cpp | 71 +++- dali/internal/render/renderers/render-renderer.h | 11 + .../update/animation/scene-graph-animator.h | 5 + dali/internal/update/common/property-owner.h | 18 + .../manager/render-instruction-processor.cpp | 87 +++-- dali/internal/update/nodes/node.cpp | 1 + dali/internal/update/nodes/node.h | 31 ++ .../update/render-tasks/scene-graph-camera.cpp | 5 + .../update/render-tasks/scene-graph-camera.h | 6 + dali/public-api/common/list-wrapper.h | 64 ++++ dali/public-api/file.list | 1 + dali/public-api/math/rect.h | 84 ++++- 31 files changed, 1327 insertions(+), 88 deletions(-) create mode 100644 dali/public-api/common/list-wrapper.h diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-application.cpp b/automated-tests/src/dali/dali-test-suite-utils/test-application.cpp index e8c0d12..b2a3fb9 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-application.cpp +++ b/automated-tests/src/dali/dali-test-suite-utils/test-application.cpp @@ -26,13 +26,15 @@ TestApplication::TestApplication( uint32_t surfaceWidth, uint32_t surfaceHeight, uint32_t horizontalDpi, uint32_t verticalDpi, - bool initialize ) + bool initialize, + bool enablePartialUpdate ) : mCore( NULL ), mSurfaceWidth( surfaceWidth ), mSurfaceHeight( surfaceHeight ), mFrame( 0u ), mDpi{ horizontalDpi, verticalDpi }, - mLastVSyncTime(0u) + mLastVSyncTime(0u), + mPartialUpdateEnabled(enablePartialUpdate) { if( initialize ) { @@ -59,7 +61,8 @@ void TestApplication::CreateCore() mGlContextHelperAbstraction, Integration::RenderToFrameBuffer::FALSE, Integration::DepthBufferAvailable::TRUE, - Integration::StencilBufferAvailable::TRUE ); + Integration::StencilBufferAvailable::TRUE, + mPartialUpdateEnabled ? Integration::PartialUpdateAvailable::TRUE : Integration::PartialUpdateAvailable::FALSE ); mCore->ContextCreated(); @@ -193,8 +196,8 @@ bool TestApplication::Render( uint32_t intervalMilliseconds, const char* locatio mRenderStatus.SetNeedsPostRender( false ); mCore->PreRender( mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ ); - mCore->RenderScene( mRenderStatus, mScene, true /*render the off-screen buffers*/); - mCore->RenderScene( mRenderStatus, mScene, false /*render the surface*/); + mCore->RenderScene( mRenderStatus, mScene, true /*render the off-screen buffers*/ ); + mCore->RenderScene( mRenderStatus, mScene, false /*render the surface*/ ); mCore->PostRender( false /*do not skip rendering*/ ); mFrame++; @@ -202,6 +205,27 @@ bool TestApplication::Render( uint32_t intervalMilliseconds, const char* locatio return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate(); } +bool TestApplication::PreRenderWithPartialUpdate(uint32_t intervalMilliseconds, const char* location, std::vector>& damagedRects) +{ + DoUpdate(intervalMilliseconds, location); + + mCore->PreRender(mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ ); + mCore->PreRender(mScene, damagedRects); + + return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate(); +} + +bool TestApplication::RenderWithPartialUpdate(std::vector>& damagedRects, Rect& clippingRect) +{ + mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/, clippingRect); + mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/, clippingRect); + mCore->PostRender(false /*do not skip rendering*/); + + mFrame++; + + return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate(); +} + uint32_t TestApplication::GetUpdateStatus() { return mStatus.KeepUpdating(); @@ -227,8 +251,8 @@ bool TestApplication::RenderOnly( ) { // Update Time values mCore->PreRender( mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ ); - mCore->RenderScene( mRenderStatus, mScene, true /*render the off-screen buffers*/); - mCore->RenderScene( mRenderStatus, mScene, false /*render the surface*/); + mCore->RenderScene( mRenderStatus, mScene, true /*render the off-screen buffers*/ ); + mCore->RenderScene( mRenderStatus, mScene, false /*render the surface*/ ); mCore->PostRender( false /*do not skip rendering*/ ); mFrame++; diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-application.h b/automated-tests/src/dali/dali-test-suite-utils/test-application.h index e96f759..1df0743 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-application.h +++ b/automated-tests/src/dali/dali-test-suite-utils/test-application.h @@ -51,7 +51,8 @@ public: uint32_t surfaceHeight = DEFAULT_SURFACE_HEIGHT, uint32_t horizontalDpi = DEFAULT_HORIZONTAL_DPI, uint32_t verticalDpi = DEFAULT_VERTICAL_DPI, - bool initialize = true ); + bool initialize = true, + bool enablePartialUpdate = false ); void Initialize(); void CreateCore(); @@ -69,6 +70,8 @@ public: void ProcessEvent(const Integration::Event& event); void SendNotification(); bool Render( uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL, const char* location=NULL ); + bool PreRenderWithPartialUpdate(uint32_t intervalMilliseconds, const char* location, std::vector>& damagedRects); + bool RenderWithPartialUpdate(std::vector>& damagedRects, Rect& clippingRect); uint32_t GetUpdateStatus(); bool UpdateOnly( uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL ); bool RenderOnly( ); @@ -108,6 +111,7 @@ protected: struct { uint32_t x; uint32_t y; } mDpi; uint32_t mLastVSyncTime; + bool mPartialUpdateEnabled; static bool mLoggingEnabled; }; diff --git a/automated-tests/src/dali/utc-Dali-Actor.cpp b/automated-tests/src/dali/utc-Dali-Actor.cpp index 675d923..09ee3c7 100644 --- a/automated-tests/src/dali/utc-Dali-Actor.cpp +++ b/automated-tests/src/dali/utc-Dali-Actor.cpp @@ -7497,3 +7497,364 @@ int utcDaliActorGetSizeAfterAnimation(void) END_TEST; } + +int utcDaliActorPartialUpdate(void) +{ + TestApplication application( + TestApplication::DEFAULT_SURFACE_WIDTH, + TestApplication::DEFAULT_SURFACE_HEIGHT, + TestApplication::DEFAULT_HORIZONTAL_DPI, + TestApplication::DEFAULT_VERTICAL_DPI, + true, + true); + + tet_infoline("Check the damaged area"); + + const TestGlAbstraction::ScissorParams& glScissorParams( application.GetGlAbstraction().GetScissorParams() ); + + std::vector> damagedRects; + Rect clippingRect; + application.SendNotification(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + + // First render pass, nothing to render, adaptor would just do swap buffer. + DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + Actor actor = CreateRenderableActor(); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + actor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f)); + actor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f)); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + Stage::GetCurrent().Add(actor); + + application.SendNotification(); + + // 1. Actor added, damaged rect is added size of actor + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + clippingRect = Rect(16, 768, 32, 32); // in screen coordinates, includes 3 last frames updates + 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); + + // 2. Set new size + actor.SetProperty(Actor::Property::SIZE, Vector3(32.0f, 32.0f, 0)); + application.SendNotification(); + + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + clippingRect = Rect(16, 752, 48, 48); // in screen coordinates, includes 3 last frames updates + 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); + + // 3. Set new position + actor.SetProperty(Actor::Property::POSITION, Vector3(32.0f, 32.0f, 0)); + application.SendNotification(); + + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + clippingRect = Rect(16, 736, 64, 64); // in screen coordinates, includes 3 last frames updates + 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); + + Stage::GetCurrent().Remove(actor); + application.SendNotification(); + + // Actor removed, last 3 dirty rects are reported. Adaptor would merge them together. + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 3, TEST_LOCATION); + + clippingRect = damagedRects[0]; + clippingRect.Merge(damagedRects[1]); + clippingRect.Merge(damagedRects[2]); + + DALI_TEST_EQUALS(clippingRect.IsEmpty(), false, TEST_LOCATION); + DALI_TEST_EQUALS(clippingRect.IsValid(), true, TEST_LOCATION); + DALI_TEST_EQUALS>(clippingRect, Rect(16, 736, 64, 64), 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); + + END_TEST; +} + +int utcDaliActorPartialUpdateSetColor(void) +{ + TestApplication application( + TestApplication::DEFAULT_SURFACE_WIDTH, + TestApplication::DEFAULT_SURFACE_HEIGHT, + TestApplication::DEFAULT_HORIZONTAL_DPI, + TestApplication::DEFAULT_VERTICAL_DPI, + true, + true); + + tet_infoline("Check uniform update"); + + const TestGlAbstraction::ScissorParams& glScissorParams( application.GetGlAbstraction().GetScissorParams() ); + + std::vector> damagedRects; + Rect clippingRect; + application.SendNotification(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + + // First render pass, nothing to render, adaptor would just do swap buffer. + DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + Actor actor = CreateRenderableActor(); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + actor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f)); + actor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f)); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + Stage::GetCurrent().Add(actor); + + application.SendNotification(); + + // 1. Actor added, damaged rect is added size of actor + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + clippingRect = Rect(16, 768, 32, 32); // in screen coordinates, includes 3 last frames updates + 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); + + // 2. Set new color + actor.SetProperty(Actor::Property::COLOR, Vector3(1.0f, 0.0f, 0.0f)); + application.SendNotification(); + + damagedRects.clear(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + clippingRect = Rect(16, 768, 32, 32); // in screen coordinates, includes 3 last frames updates + 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); + + END_TEST; +} + +const std::string SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME("uLightCameraProjectionMatrix"); +const std::string SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME("uLightCameraViewMatrix"); +const std::string SHADER_SHADOW_COLOR_PROPERTY_NAME("uShadowColor"); +const char* const RENDER_SHADOW_VERTEX_SOURCE = + " uniform mediump mat4 uLightCameraProjectionMatrix;\n" + " uniform mediump mat4 uLightCameraViewMatrix;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = uProjection * uModelView * vec4(aPosition,1.0);\n" + " vec4 textureCoords = uLightCameraProjectionMatrix * uLightCameraViewMatrix * uModelMatrix * vec4(aPosition,1.0);\n" + " vTexCoord = 0.5 + 0.5 * (textureCoords.xy/textureCoords.w);\n" + "}\n"; + +const char* const RENDER_SHADOW_FRAGMENT_SOURCE = + "uniform lowp vec4 uShadowColor;\n" + "void main()\n" + "{\n" + " lowp float alpha;\n" + " alpha = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y)).a;\n" + " gl_FragColor = vec4(uShadowColor.rgb, uShadowColor.a * alpha);\n" + "}\n"; + +int utcDaliActorPartialUpdateSetProperty(void) +{ + TestApplication application( + TestApplication::DEFAULT_SURFACE_WIDTH, + TestApplication::DEFAULT_SURFACE_HEIGHT, + TestApplication::DEFAULT_HORIZONTAL_DPI, + TestApplication::DEFAULT_VERTICAL_DPI, + true, + true); + + tet_infoline( "Set/Update property with partial update" ); + + const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams()); + + std::vector> damagedRects; + Rect clippingRect; + application.SendNotification(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + + // First render pass, nothing to render, adaptor would just do swap buffer. + DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION); + application.RenderWithPartialUpdate(damagedRects, clippingRect); + + Texture image = Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, 4u, 4u); + Actor actor = CreateRenderableActor(image, RENDER_SHADOW_VERTEX_SOURCE, RENDER_SHADOW_FRAGMENT_SOURCE); + actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + actor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f)); + actor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f)); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + Stage::GetCurrent().Add(actor); + + actor.RegisterProperty(SHADER_SHADOW_COLOR_PROPERTY_NAME, Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + + damagedRects.clear(); + application.SendNotification(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + // Aligned by 16 + clippingRect = Rect(16, 768, 32, 32); // in screen coordinates, includes 3 last frames updates + 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); + + Property::Index shadowColorPropertyIndex = actor.GetPropertyIndex( SHADER_SHADOW_COLOR_PROPERTY_NAME ); + actor.SetProperty(shadowColorPropertyIndex, Vector4(1.0f, 1.0f, 0.0f, 1.0f)); + + damagedRects.clear(); + application.SendNotification(); + application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + 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); + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + 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); + DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION); + + END_TEST; +} + +int utcDaliActorPartialUpdateTwoActors(void) +{ + TestApplication application( + TestApplication::DEFAULT_SURFACE_WIDTH, + TestApplication::DEFAULT_SURFACE_HEIGHT, + TestApplication::DEFAULT_HORIZONTAL_DPI, + TestApplication::DEFAULT_VERTICAL_DPI, + true, + true); + + tet_infoline("Check the damaged rects with partial update and two actors"); + + const TestGlAbstraction::ScissorParams& glScissorParams( application.GetGlAbstraction().GetScissorParams() ); + + Actor actor = CreateRenderableActor(); + actor.SetProperty(Actor::Property::POSITION, Vector3(100.0f, 100.0f, 0.0f)); + actor.SetProperty(Actor::Property::SIZE, Vector3(50.0f, 50.0f, 0.0f)); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + Stage::GetCurrent().Add(actor); + + Actor actor2 = CreateRenderableActor(); + actor2.SetProperty(Actor::Property::POSITION, Vector3(150.0f, 150.0f, 0.0f)); + actor2.SetProperty(Actor::Property::SIZE, Vector3(100.0f, 100.0f, 0.0f)); + actor2.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + Stage::GetCurrent().Add(actor2); + + application.SendNotification(); + std::vector> damagedRects; + application.PreRenderWithPartialUpdate(TestApplication::DEFAULT_RENDER_INTERVAL, nullptr, damagedRects); + + DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION); + DALI_TEST_EQUALS>(Rect(64, 672, 64, 64), damagedRects[0], TEST_LOCATION); + DALI_TEST_EQUALS>(Rect(96, 592, 112, 112), damagedRects[1], TEST_LOCATION); + + // in screen coordinates, adaptor would calculate it using previous frames information + Rect clippingRect = Rect(64, 592, 144, 192); + 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); + + END_TEST; +} + +int utcDaliActorPartialUpdateActorsWithSizeHint(void) +{ + TestApplication application( + TestApplication::DEFAULT_SURFACE_WIDTH, + TestApplication::DEFAULT_SURFACE_HEIGHT, + TestApplication::DEFAULT_HORIZONTAL_DPI, + TestApplication::DEFAULT_VERTICAL_DPI, + true, + true); + + tet_infoline( "Check the damaged rect with partial update and actor size hint" ); + + const TestGlAbstraction::ScissorParams& glScissorParams( application.GetGlAbstraction().GetScissorParams() ); + + Actor actor = CreateRenderableActor(); + actor.SetProperty(Actor::Property::POSITION, Vector3(75.0f, 150.0f, 0.0f)); + actor.SetProperty(Actor::Property::SIZE, Vector3(75.0f, 150.0f, 0.0f)); + actor.SetProperty(DevelActor::Property::UPDATE_SIZE_HINT, Vector3(150, 300, 0)); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + Stage::GetCurrent().Add(actor); + + application.SendNotification(); + std::vector> damagedRects; + application.PreRenderWithPartialUpdate(TestApplication::DEFAULT_RENDER_INTERVAL, nullptr, damagedRects); + + DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION); + + Rect clippingRect = Rect(0, 496, 160, 320); + 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); + + END_TEST; +} + diff --git a/dali/devel-api/actors/actor-devel.h b/dali/devel-api/actors/actor-devel.h index a72418b..9eccc32 100644 --- a/dali/devel-api/actors/actor-devel.h +++ b/dali/devel-api/actors/actor-devel.h @@ -107,6 +107,13 @@ enum Type * sibling order. The values set by this Property will likely change. */ SIBLING_ORDER = KEYBOARD_FOCUSABLE + 1, + + /** + * @brief Sets the update size hint of the actor. + * @details Name "updateSizeHint", type Property::VECTOR2. + * @note Overrides the size used for the actor damaged area calculation. Affected by the actor model view matrix. + */ + UPDATE_SIZE_HINT = SIBLING_ORDER + 1, }; } // namespace Property diff --git a/dali/integration-api/core-enumerations.h b/dali/integration-api/core-enumerations.h index e11dc63..ff6153c 100644 --- a/dali/integration-api/core-enumerations.h +++ b/dali/integration-api/core-enumerations.h @@ -59,6 +59,15 @@ enum class StencilBufferAvailable TRUE }; +/** + * @brief Enumerations to specify whether the stencil buffer is available. + */ +enum class PartialUpdateAvailable +{ + FALSE = 0, + TRUE +}; + } // namespace Integration } // namespace Dali diff --git a/dali/integration-api/core.cpp b/dali/integration-api/core.cpp index 47eb713..ee0b608 100644 --- a/dali/integration-api/core.cpp +++ b/dali/integration-api/core.cpp @@ -41,7 +41,8 @@ Core* Core::New( RenderController& renderController, GlContextHelperAbstraction& glContextHelperAbstraction, RenderToFrameBuffer renderToFboEnabled, DepthBufferAvailable depthBufferAvailable, - StencilBufferAvailable stencilBufferAvailable ) + StencilBufferAvailable stencilBufferAvailable, + PartialUpdateAvailable partialUpdateAvailable ) { Core* instance = new Core; instance->mImpl = new Internal::Core( renderController, @@ -51,7 +52,8 @@ Core* Core::New( RenderController& renderController, glContextHelperAbstraction, renderToFboEnabled, depthBufferAvailable, - stencilBufferAvailable ); + stencilBufferAvailable, + partialUpdateAvailable ); return instance; } @@ -116,11 +118,21 @@ void Core::PreRender( RenderStatus& status, bool forceClear, bool uploadOnly ) mImpl->PreRender( status, forceClear, uploadOnly ); } +void Core::PreRender( Integration::Scene& scene, std::vector>& damagedRects ) +{ + mImpl->PreRender( scene, damagedRects ); +} + void Core::RenderScene( RenderStatus& status, Integration::Scene& scene, bool renderToFbo ) { mImpl->RenderScene( status, scene, renderToFbo ); } +void Core::RenderScene( RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect ) +{ + mImpl->RenderScene( status, scene, renderToFbo, clippingRect ); +} + void Core::PostRender( bool uploadOnly ) { mImpl->PostRender( uploadOnly ); diff --git a/dali/integration-api/core.h b/dali/integration-api/core.h index f1a7e63..a897631 100644 --- a/dali/integration-api/core.h +++ b/dali/integration-api/core.h @@ -23,6 +23,8 @@ // INTERNAL INCLUDES #include +#include +#include #include #include @@ -228,6 +230,7 @@ public: * @param[in] renderToFboEnabled Whether rendering into the Frame Buffer Object is enabled. * @param[in] depthBufferAvailable Whether the depth buffer is available * @param[in] stencilBufferAvailable Whether the stencil buffer is available + * @param[in] partialUpdateAvailable Whether the partial update is available * @return A newly allocated Core. */ static Core* New( RenderController& renderController, @@ -237,7 +240,8 @@ public: GlContextHelperAbstraction& glContextHelperAbstraction, RenderToFrameBuffer renderToFboEnabled, DepthBufferAvailable depthBufferAvailable, - StencilBufferAvailable stencilBufferAvailable ); + StencilBufferAvailable stencilBufferAvailable, + PartialUpdateAvailable partialUpdateAvailable); /** * Non-virtual destructor. Core is not intended as a base class. @@ -349,6 +353,16 @@ public: void PreRender( RenderStatus& status, bool forceClear, bool uploadOnly ); /** + * This is called before rendering any scene in the next frame. This method should be preceded + * by a call up Update. + * Multi-threading note: this method should be called from a dedicated rendering thread. + * @pre The GL context must have been created, and made current. + * @param[in] scene The scene to be rendered. + * @param[out] damagedRects containing damaged render items rects for this pass. + */ + void PreRender( Integration::Scene& scene, std::vector>& damagedRects ); + + /** * Render a scene in the next frame. This method should be preceded by a call up PreRender. * This method should be called twice. The first pass to render off-screen frame buffers if any, * and the second pass to render the surface. @@ -360,6 +374,18 @@ public: */ void RenderScene( RenderStatus& status, Integration::Scene& scene, bool renderToFbo ); + /** + * Render a scene in the next frame. This method should be preceded by a call up PreRender. + * This method should be called twice. The first pass to render off-screen frame buffers if any, + * and the second pass to render the surface. + * Multi-threading note: this method should be called from a dedicated rendering thread. + * @pre The GL context must have been created, and made current. + * @param[out] status Contains the rendering flags. + * @param[in] scene The scene to be rendered. + * @param[in] renderToFbo True to render off-screen frame buffers only if any, and False to render the surface only. + * @param[in] clippingRect The rect to clip rendered scene. + */ + void RenderScene( RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect ); /** * This is called after rendering all the scenes in the next frame. This method should be diff --git a/dali/internal/common/core-impl.cpp b/dali/internal/common/core-impl.cpp index 5da52a4..fd17bd2 100644 --- a/dali/internal/common/core-impl.cpp +++ b/dali/internal/common/core-impl.cpp @@ -87,7 +87,8 @@ Core::Core( RenderController& renderController, GlContextHelperAbstraction& glContextHelperAbstraction, Integration::RenderToFrameBuffer renderToFboEnabled, Integration::DepthBufferAvailable depthBufferAvailable, - Integration::StencilBufferAvailable stencilBufferAvailable ) + Integration::StencilBufferAvailable stencilBufferAvailable, + Integration::PartialUpdateAvailable partialUpdateAvailable ) : mRenderController( renderController ), mPlatform(platform), mProcessingEvent(false), @@ -107,7 +108,7 @@ Core::Core( RenderController& renderController, mRenderTaskProcessor = new SceneGraph::RenderTaskProcessor(); - mRenderManager = RenderManager::New( glAbstraction, glSyncAbstraction, glContextHelperAbstraction, depthBufferAvailable, stencilBufferAvailable ); + mRenderManager = RenderManager::New( glAbstraction, glSyncAbstraction, glContextHelperAbstraction, depthBufferAvailable, stencilBufferAvailable, partialUpdateAvailable ); RenderQueue& renderQueue = mRenderManager->GetRenderQueue(); @@ -221,11 +222,21 @@ void Core::PreRender( RenderStatus& status, bool forceClear, bool uploadOnly ) mRenderManager->PreRender( status, forceClear, uploadOnly ); } +void Core::PreRender( Integration::Scene& scene, std::vector>& damagedRects ) +{ + mRenderManager->PreRender( scene, damagedRects ); +} + void Core::RenderScene( RenderStatus& status, Integration::Scene& scene, bool renderToFbo ) { mRenderManager->RenderScene( status, scene, renderToFbo ); } +void Core::RenderScene( RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect ) +{ + mRenderManager->RenderScene( status, scene, renderToFbo, clippingRect ); +} + void Core::PostRender( bool uploadOnly ) { mRenderManager->PostRender( uploadOnly ); diff --git a/dali/internal/common/core-impl.h b/dali/internal/common/core-impl.h index cbe41a4..f2b6b62 100644 --- a/dali/internal/common/core-impl.h +++ b/dali/internal/common/core-impl.h @@ -86,7 +86,8 @@ public: Integration::GlContextHelperAbstraction& glContextHelperAbstraction, Integration::RenderToFrameBuffer renderToFboEnabled, Integration::DepthBufferAvailable depthBufferAvailable, - Integration::StencilBufferAvailable stencilBufferAvailable ); + Integration::StencilBufferAvailable stencilBufferAvailable, + Integration::PartialUpdateAvailable partialUpdateAvailable ); /** * Destructor @@ -129,16 +130,26 @@ public: void Update( float elapsedSeconds, uint32_t lastVSyncTimeMilliseconds, uint32_t nextVSyncTimeMilliseconds, Integration::UpdateStatus& status, bool renderToFboEnabled, bool isRenderingToFbo ); /** - * @copydoc Dali::Integration::Core::Render() + * @copydoc Dali::Integration::Core::PreRender() */ void PreRender( Integration::RenderStatus& status, bool forceClear, bool uploadOnly ); /** + * @copydoc Dali::Integration::Core::PreRender() + */ + void PreRender( Integration::Scene& scene, std::vector>& damagedRects ); + + /** * @copydoc Dali::Integration::Core::RenderScene() */ void RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo ); /** + * @copydoc Dali::Integration::Core::RenderScene() + */ + void RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect ); + + /** * @copydoc Dali::Integration::Core::Render() */ void PostRender( bool uploadOnly ); diff --git a/dali/internal/event/actors/actor-impl.cpp b/dali/internal/event/actors/actor-impl.cpp index b387d33..65e9ee2 100644 --- a/dali/internal/event/actors/actor-impl.cpp +++ b/dali/internal/event/actors/actor-impl.cpp @@ -219,6 +219,7 @@ DALI_PROPERTY( "isLayer", BOOLEAN, false, false, false, Dali: DALI_PROPERTY( "connectedToScene", BOOLEAN, false, false, false, Dali::Actor::Property::CONNECTED_TO_SCENE ) DALI_PROPERTY( "keyboardFocusable", BOOLEAN, true, false, false, Dali::Actor::Property::KEYBOARD_FOCUSABLE ) DALI_PROPERTY( "siblingOrder", INTEGER, true, false, false, Dali::DevelActor::Property::SIBLING_ORDER ) +DALI_PROPERTY( "updateSizeHint", VECTOR2, true, false, false, Dali::DevelActor::Property::UPDATE_SIZE_HINT ) DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX, ActorDefaultProperties ) // Signals @@ -2800,6 +2801,12 @@ void Actor::SetDefaultProperty( Property::Index index, const Property::Value& pr break; } + case Dali::DevelActor::Property::UPDATE_SIZE_HINT: + { + SetUpdateSizeHint( property.Get< Vector2 >() ); + break; + } + default: { // this can happen in the case of a non-animatable default property so just do nothing @@ -4118,6 +4125,12 @@ bool Actor::GetCurrentPropertyValue( Property::Index index, Property::Value& val break; } + case Dali::DevelActor::Property::UPDATE_SIZE_HINT: + { + value = GetUpdateSizeHint(); + break; + } + default: { // Must be an event-side only property @@ -5187,6 +5200,19 @@ void Actor::InheritLayoutDirectionRecursively( ActorPtr actor, Dali::LayoutDirec } } +void Actor::SetUpdateSizeHint( const Vector2& updateSizeHint ) +{ + // node is being used in a separate thread; queue a message to set the value & base value + SceneGraph::NodePropertyMessage::Send( GetEventThreadServices(), &GetNode(), &GetNode().mUpdateSizeHint, &AnimatableProperty::Bake, Vector3(updateSizeHint.width, updateSizeHint.height, 0.f ) ); +} + +Vector2 Actor::GetUpdateSizeHint() const +{ + // node is being used in a separate thread, the value from the previous update is the same, set by user + Vector3 updateSizeHint = GetNode().GetUpdateSizeHint(); + return Vector2( updateSizeHint.width, updateSizeHint.height ); +} + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/actors/actor-impl.h b/dali/internal/event/actors/actor-impl.h index bf58f23..4e57518 100755 --- a/dali/internal/event/actors/actor-impl.h +++ b/dali/internal/event/actors/actor-impl.h @@ -1946,6 +1946,18 @@ private: */ void InheritLayoutDirectionRecursively( ActorPtr actor, Dali::LayoutDirection::Type direction, bool set = false ); + /** + * @brief Sets the update size hint of an actor. + * @param [in] updateSizeHint The update size hint. + */ + void SetUpdateSizeHint( const Vector2& updateSizeHint ); + + /** + * @brief Return the update size hint of actor + * @return Return the update size hint + */ + Vector2 GetUpdateSizeHint() const; + protected: Scene* mScene; ///< The scene the actor is added to diff --git a/dali/internal/event/common/property-buffer-impl.cpp b/dali/internal/event/common/property-buffer-impl.cpp index c44df2c..242aa67 100644 --- a/dali/internal/event/common/property-buffer-impl.cpp +++ b/dali/internal/event/common/property-buffer-impl.cpp @@ -22,6 +22,21 @@ #include #include +#ifdef ANDROID +namespace std +{ + uint64_t _Hash_bytes(const void* bytes, uint64_t size, uint64_t seed) + { + for (uint64_t i = 0; i < size; i++) + { + seed = seed * 31 + reinterpret_cast(bytes)[i]; + } + + return seed; + } +} +#endif + namespace Dali { namespace Internal diff --git a/dali/internal/event/common/property-input-impl.h b/dali/internal/event/common/property-input-impl.h index ca46246..297332f 100644 --- a/dali/internal/event/common/property-input-impl.h +++ b/dali/internal/event/common/property-input-impl.h @@ -31,6 +31,15 @@ #include #include +#ifdef ANDROID +namespace std +{ + +uint64_t _Hash_bytes(const void* bytes, uint64_t size, uint64_t seed); + +} +#endif + namespace Dali { @@ -307,6 +316,63 @@ public: return false; } + std::uint64_t Hash(BufferIndex bufferIndex, uint64_t seed) const + { + switch ( GetType() ) + { + case Property::BOOLEAN: + { + return std::_Hash_bytes(&GetBoolean(bufferIndex), sizeof(bool), seed); + } + + case Property::INTEGER: + { + return std::_Hash_bytes(&GetInteger(bufferIndex), sizeof(int), seed); + } + + case Property::FLOAT: + { + return std::_Hash_bytes(&GetFloat(bufferIndex), sizeof(float), seed); + } + + case Property::VECTOR2: + { + return std::_Hash_bytes(&GetVector2(bufferIndex), sizeof(Vector2), seed); + } + + case Property::VECTOR3: + { + return std::_Hash_bytes(&GetVector3(bufferIndex), sizeof(Vector3), seed); + } + + case Property::VECTOR4: + { + return std::_Hash_bytes(&GetVector4(bufferIndex), sizeof(Vector4), seed); + } + + case Property::ROTATION: + { + return std::_Hash_bytes(&GetQuaternion(bufferIndex), sizeof(Quaternion), seed); + } + + case Property::MATRIX: + { + return std::_Hash_bytes(&GetMatrix(bufferIndex), sizeof(Matrix), seed); + } + + case Property::MATRIX3: + { + return std::_Hash_bytes(&GetMatrix3(bufferIndex), sizeof(Matrix3), seed); + } + + default: + break; // print nothing + } + + return seed; + } + + /** * Print the property value using a stream. * @param[in] debugStream The output stream. diff --git a/dali/internal/render/common/render-algorithms.cpp b/dali/internal/render/common/render-algorithms.cpp index 01bba05..cfd1f92 100644 --- a/dali/internal/render/common/render-algorithms.cpp +++ b/dali/internal/render/common/render-algorithms.cpp @@ -271,7 +271,7 @@ inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Cont // This is a clipping node. We generate the AABB for this node and intersect it with the previous intersection further up the tree. // Get the AABB bounding box for the current render item. - const ClippingBox scissorBox( item.CalculateViewportSpaceAABB( mViewportRectangle.width, mViewportRectangle.height ) ); + const ClippingBox scissorBox( item.CalculateViewportSpaceAABB( item.mSize, mViewportRectangle.width, mViewportRectangle.height ) ); // Get the AABB for the parent item that we must intersect with. const ClippingBox& parentBox( mScissorStack.back() ); @@ -391,7 +391,8 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList, Integration::DepthBufferAvailable depthBufferAvailable, Integration::StencilBufferAvailable stencilBufferAvailable, Vector& boundTextures, - const RenderInstruction& instruction + const RenderInstruction& instruction, + const Rect& rootClippingRect ) { DALI_PRINT_RENDER_LIST( renderList ); @@ -411,6 +412,21 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList, // Setup Scissor testing (for both viewport and per-node scissor) mScissorStack.clear(); + + // Add root clipping rect (set manually for Render function ny partial update for example) + // on the bottom of the stack + if (!rootClippingRect.IsEmpty()) + { + context.SetScissorTest( true ); + mScissorStack.push_back( rootClippingRect ); + } + // We are not performing a layer clip and no clipping rect set. Add the viewport as the root scissor rectangle. + else if (!renderList.IsClipping()) + { + context.SetScissorTest( false ); + mScissorStack.push_back( mViewportRectangle ); + } + if( renderList.IsClipping() ) { context.SetScissorTest( true ); @@ -419,12 +435,6 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList, mScissorStack.push_back( layerScissorBox ); mHasLayerScissor = true; } - else - { - // We are not performing a layer clip. Add the viewport as the root scissor rectangle. - context.SetScissorTest( false ); - mScissorStack.push_back( mViewportRectangle ); - } // Loop through all RenderList in the RenderList, set up any prerequisites to render them, then perform the render. for( uint32_t index = 0u; index < count; ++index ) @@ -466,7 +476,8 @@ void RenderAlgorithms::ProcessRenderInstruction( const RenderInstruction& instru BufferIndex bufferIndex, Integration::DepthBufferAvailable depthBufferAvailable, Integration::StencilBufferAvailable stencilBufferAvailable, - Vector& boundTextures ) + Vector& boundTextures, + const Rect& rootClippingRect ) { DALI_PRINT_RENDER_INSTRUCTION( instruction, bufferIndex ); @@ -496,8 +507,8 @@ void RenderAlgorithms::ProcessRenderInstruction( const RenderInstruction& instru depthBufferAvailable, stencilBufferAvailable, boundTextures, - instruction //added for reflection effect - ); + instruction, //added for reflection effect + rootClippingRect ); } } } diff --git a/dali/internal/render/common/render-algorithms.h b/dali/internal/render/common/render-algorithms.h index 26f4343..9d359b4 100644 --- a/dali/internal/render/common/render-algorithms.h +++ b/dali/internal/render/common/render-algorithms.h @@ -65,7 +65,8 @@ class RenderAlgorithms BufferIndex bufferIndex, Integration::DepthBufferAvailable depthBufferAvailable, Integration::StencilBufferAvailable stencilBufferAvailable, - Vector& boundTextures ); + Vector& boundTextures, + const Rect& rootClippingRect ); private: @@ -125,8 +126,8 @@ class RenderAlgorithms Integration::DepthBufferAvailable depthBufferAvailable, Integration::StencilBufferAvailable stencilBufferAvailable, Vector& boundTextures, - const Dali::Internal::SceneGraph::RenderInstruction& instruction // in the case of reflection, things like CullFace need to be adjusted for reflection world - ); + const Dali::Internal::SceneGraph::RenderInstruction& instruction, // in the case of reflection, things like CullFace need to be adjusted for reflection world + const Rect& rootClippingRect ); // Prevent copying: RenderAlgorithms( RenderAlgorithms& rhs ); diff --git a/dali/internal/render/common/render-item.cpp b/dali/internal/render/common/render-item.cpp index d47f808..d10e15e 100644 --- a/dali/internal/render/common/render-item.cpp +++ b/dali/internal/render/common/render-item.cpp @@ -50,7 +50,8 @@ RenderItem::RenderItem() mNode( NULL ), mTextureSet( NULL ), mDepthIndex( 0 ), - mIsOpaque( true ) + mIsOpaque( true ), + mIsUpdated( false ) { } @@ -59,11 +60,11 @@ RenderItem::~RenderItem() } -ClippingBox RenderItem::CalculateViewportSpaceAABB( const int viewportWidth, const int viewportHeight ) const +ClippingBox RenderItem::CalculateViewportSpaceAABB( const Vector3& size, const int viewportWidth, const int viewportHeight ) const { // Calculate extent vector of the AABB: - const float halfActorX = mSize.x * 0.5f; - const float halfActorY = mSize.y * 0.5f; + const float halfActorX = size.x * 0.5f; + const float halfActorY = size.y * 0.5f; // To transform the actor bounds to screen-space, We do a fast, 2D version of a matrix multiply optimized for 2D quads. // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3). @@ -121,7 +122,6 @@ void RenderItem::operator delete( void* ptr ) gRenderItemPool.Free( static_cast( ptr ) ); } - } // namespace SceneGraph } // namespace Internal diff --git a/dali/internal/render/common/render-item.h b/dali/internal/render/common/render-item.h index 7dbd3fb..77e1fac 100644 --- a/dali/internal/render/common/render-item.h +++ b/dali/internal/render/common/render-item.h @@ -67,7 +67,7 @@ struct RenderItem * @param[in] viewportHeight The height of the viewport to calculate for * @return The AABB coordinates in viewport-space (x, y, width, height) */ - ClippingBox CalculateViewportSpaceAABB( const int viewportWidth, const int viewportHeight ) const; + ClippingBox CalculateViewportSpaceAABB( const Vector3& size, const int viewportWidth, const int viewportHeight ) const; /** * Overriden delete operator. @@ -79,11 +79,13 @@ struct RenderItem Matrix mModelMatrix; Matrix mModelViewMatrix; Vector3 mSize; + Vector3 mUpdateSize; Render::Renderer* mRenderer; Node* mNode; const void* mTextureSet; //< Used for sorting only int mDepthIndex; bool mIsOpaque:1; + bool mIsUpdated:1; private: diff --git a/dali/internal/render/common/render-manager.cpp b/dali/internal/render/common/render-manager.cpp index 77f6088..905032a 100644 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -62,6 +62,53 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_REN } // unnamed namespace #endif +struct DirtyRect +{ + DirtyRect(Node* node, Render::Renderer* renderer, int frame, Rect& rect) + : node(node), + renderer(renderer), + frame(frame), + rect(rect), + visited(true) + { + } + + DirtyRect() + : node(nullptr), + renderer(nullptr), + frame(0), + rect(), + visited(true) + { + } + + bool operator<(const DirtyRect& rhs) const + { + if (node == rhs.node) + { + if (renderer == rhs.renderer) + { + return frame > rhs.frame; // Most recent rects come first + } + else + { + return renderer < rhs.renderer; + } + } + else + { + return node < rhs.node; + } + } + + Node* node; + Render::Renderer* renderer; + int frame; + + Rect rect; + bool visited; +}; + /** * Structure to contain internal data */ @@ -71,7 +118,8 @@ struct RenderManager::Impl Integration::GlSyncAbstraction& glSyncAbstraction, Integration::GlContextHelperAbstraction& glContextHelperAbstraction, Integration::DepthBufferAvailable depthBufferAvailableParam, - Integration::StencilBufferAvailable stencilBufferAvailableParam ) + Integration::StencilBufferAvailable stencilBufferAvailableParam, + Integration::PartialUpdateAvailable partialUpdateAvailableParam ) : context( glAbstraction, &sceneContextContainer ), currentContext( &context ), glAbstraction( glAbstraction ), @@ -89,7 +137,9 @@ struct RenderManager::Impl lastFrameWasRendered( false ), programController( glAbstraction ), depthBufferAvailable( depthBufferAvailableParam ), - stencilBufferAvailable( stencilBufferAvailableParam ) + stencilBufferAvailable( stencilBufferAvailableParam ), + partialUpdateAvailable( partialUpdateAvailableParam ), + itemsCheckSum(0) { // Create thread pool with just one thread ( there may be a need to create more threads in the future ). threadPool = std::unique_ptr( new Dali::ThreadPool() ); @@ -176,24 +226,29 @@ struct RenderManager::Impl Integration::DepthBufferAvailable depthBufferAvailable; ///< Whether the depth buffer is available Integration::StencilBufferAvailable stencilBufferAvailable; ///< Whether the stencil buffer is available + Integration::PartialUpdateAvailable partialUpdateAvailable; ///< Whether the partial update is available std::unique_ptr threadPool; ///< The thread pool Vector boundTextures; ///< The textures bound for rendering Vector textureDependencyList; ///< The dependency list of binded textures + std::size_t itemsCheckSum; ///< The damaged render items checksum from previous prerender phase. + std::vector itemsDirtyRects; }; RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction, Integration::GlSyncAbstraction& glSyncAbstraction, Integration::GlContextHelperAbstraction& glContextHelperAbstraction, Integration::DepthBufferAvailable depthBufferAvailable, - Integration::StencilBufferAvailable stencilBufferAvailable ) + Integration::StencilBufferAvailable stencilBufferAvailable, + Integration::PartialUpdateAvailable partialUpdateAvailable ) { RenderManager* manager = new RenderManager; manager->mImpl = new Impl( glAbstraction, glSyncAbstraction, glContextHelperAbstraction, depthBufferAvailable, - stencilBufferAvailable ); + stencilBufferAvailable, + partialUpdateAvailable ); return manager; } @@ -563,9 +618,233 @@ void RenderManager::PreRender( Integration::RenderStatus& status, bool forceClea } } +void RenderManager::PreRender( Integration::Scene& scene, std::vector>& damagedRects ) +{ + if (mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE) + { + return; + } + + class DamagedRectsCleaner + { + public: + DamagedRectsCleaner(std::vector>& damagedRects) + : mDamagedRects(damagedRects), + mCleanOnReturn(true) + { + } + + void SetCleanOnReturn(bool cleanOnReturn) + { + mCleanOnReturn = cleanOnReturn; + } + + ~DamagedRectsCleaner() + { + if (mCleanOnReturn) + { + mDamagedRects.clear(); + } + } + + private: + std::vector>& mDamagedRects; + bool mCleanOnReturn; + }; + + Rect surfaceRect = Rect(0, 0, static_cast( scene.GetSize().width ), static_cast( scene.GetSize().height )); + + // Clean collected dirty/damaged rects on exit if 3d layer or 3d node or other conditions. + DamagedRectsCleaner damagedRectCleaner(damagedRects); + + // Mark previous dirty rects in the sorted array. The array is already sorted by node and renderer, frame number. + // so you don't need to sort: std::stable_sort(mImpl->itemsDirtyRects.begin(), mImpl->itemsDirtyRects.end()); + for (DirtyRect& dirtyRect : mImpl->itemsDirtyRects) + { + dirtyRect.visited = false; + } + + Internal::Scene& sceneInternal = GetImplementation(scene); + SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); + uint32_t count = sceneObject->GetRenderInstructions().Count( mImpl->renderBufferIndex ); + for (uint32_t i = 0; i < count; ++i) + { + RenderInstruction& instruction = sceneObject->GetRenderInstructions().At( mImpl->renderBufferIndex, i ); + + if (instruction.mFrameBuffer) + { + return; // TODO: reset, we don't deal with render tasks with framebuffers (for now) + } + + const Camera* camera = instruction.GetCamera(); + if (camera->mType == Camera::DEFAULT_TYPE && camera->mTargetPosition == Camera::DEFAULT_TARGET_POSITION) + { + const Node* node = instruction.GetCamera()->GetNode(); + if (node) + { + Vector3 position; + Vector3 scale; + Quaternion orientation; + node->GetWorldMatrix(mImpl->renderBufferIndex).GetTransformComponents(position, orientation, scale); + + Vector3 orientationAxis; + Radian orientationAngle; + orientation.ToAxisAngle( orientationAxis, orientationAngle ); + + if (position.x > Math::MACHINE_EPSILON_10000 || + position.y > Math::MACHINE_EPSILON_10000 || + orientationAxis != Vector3(0.0f, 1.0f, 0.0f) || + orientationAngle != ANGLE_180 || + scale != Vector3(1.0f, 1.0f, 1.0f)) + { + return; + } + } + } + else + { + return; + } + + Rect viewportRect; + if (instruction.mIsViewportSet) + { + const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y; + viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height); + if (viewportRect.IsEmpty() || !viewportRect.IsValid()) + { + return; // just skip funny use cases for now, empty viewport means it is set somewhere else + } + } + else + { + viewportRect = surfaceRect; + } + + const Matrix* viewMatrix = instruction.GetViewMatrix(mImpl->renderBufferIndex); + const Matrix* projectionMatrix = instruction.GetProjectionMatrix(mImpl->renderBufferIndex); + if (viewMatrix && projectionMatrix) + { + const RenderListContainer::SizeType count = instruction.RenderListCount(); + for (RenderListContainer::SizeType index = 0u; index < count; ++index) + { + const RenderList* renderList = instruction.GetRenderList( index ); + if (renderList && !renderList->IsEmpty()) + { + const std::size_t count = renderList->Count(); + for (uint32_t index = 0u; index < count; ++index) + { + RenderItem& item = renderList->GetItem( index ); + // If the item does 3D transformation, do early exit and clean the damaged rect array + if (item.mUpdateSize == Vector3::ZERO) + { + return; + } + + Rect rect; + DirtyRect dirtyRect(item.mNode, item.mRenderer, mImpl->frameCount, rect); + // If the item refers to updated node or renderer. + if (item.mIsUpdated || + (item.mNode && + (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated(mImpl->renderBufferIndex, item.mNode))))) + { + item.mIsUpdated = false; + item.mNode->SetUpdated(false); + + rect = item.CalculateViewportSpaceAABB(item.mUpdateSize, viewportRect.width, viewportRect.height); + if (rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty()) + { + const int left = rect.x; + const int top = rect.y; + const int right = rect.x + rect.width; + const int bottom = rect.y + rect.height; + rect.x = (left / 16) * 16; + rect.y = (top / 16) * 16; + rect.width = ((right + 16) / 16) * 16 - rect.x; + rect.height = ((bottom + 16) / 16) * 16 - rect.y; + + // Found valid dirty rect. + // 1. Insert it in the sorted array of the dirty rects. + // 2. Mark the related dirty rects as visited so they will not be removed below. + // 3. Keep only last 3 dirty rects for the same node and renderer (Tizen uses 3 back buffers, Ubuntu 1). + dirtyRect.rect = rect; + auto dirtyRectPos = std::lower_bound(mImpl->itemsDirtyRects.begin(), mImpl->itemsDirtyRects.end(), dirtyRect); + dirtyRectPos = mImpl->itemsDirtyRects.insert(dirtyRectPos, dirtyRect); + + int c = 1; + while (++dirtyRectPos != mImpl->itemsDirtyRects.end()) + { + if (dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer) + { + break; + } + + dirtyRectPos->visited = true; + Rect& dirtRect = dirtyRectPos->rect; + rect.Merge(dirtRect); + + c++; + if (c > 3) // no more then 3 previous rects + { + mImpl->itemsDirtyRects.erase(dirtyRectPos); + break; + } + } + + damagedRects.push_back(rect); + } + } + else + { + // 1. The item is not dirty, the node and renderer referenced by the item are still exist. + // 2. Mark the related dirty rects as visited so they will not be removed below. + auto dirtyRectPos = std::lower_bound(mImpl->itemsDirtyRects.begin(), mImpl->itemsDirtyRects.end(), dirtyRect); + while (dirtyRectPos != mImpl->itemsDirtyRects.end()) + { + if (dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer) + { + break; + } + + dirtyRectPos->visited = true; + dirtyRectPos++; + } + } + } + } + } + } + } + + // Check removed nodes or removed renderers dirty rects + auto i = mImpl->itemsDirtyRects.begin(); + auto j = mImpl->itemsDirtyRects.begin(); + while (i != mImpl->itemsDirtyRects.end()) + { + if (i->visited) + { + *j++ = *i; + } + else + { + Rect& dirtRect = i->rect; + damagedRects.push_back(dirtRect); + } + i++; + } + + mImpl->itemsDirtyRects.resize(j - mImpl->itemsDirtyRects.begin()); + damagedRectCleaner.SetCleanOnReturn(false); +} void RenderManager::RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo ) { + Rect clippingRect; + RenderScene( status, scene, renderToFbo, clippingRect); +} + +void RenderManager::RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect ) +{ Internal::Scene& sceneInternal = GetImplementation( scene ); SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); @@ -723,26 +1002,45 @@ void RenderManager::RenderScene( Integration::RenderStatus& status, Integration: clearFullFrameRect = ( surfaceRect == viewportRect ); } + if (!clippingRect.IsEmpty()) + { + if (!clippingRect.Intersect(viewportRect)) + { + DALI_LOG_ERROR("Invalid clipping rect %d %d %d %d\n", clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height); + clippingRect = Rect(); + } + clearFullFrameRect = false; + } + mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); - if( instruction.mIsClearColorSet ) + if (instruction.mIsClearColorSet) { - mImpl->currentContext->ClearColor( clearColor.r, - clearColor.g, - clearColor.b, - clearColor.a ); - - if( !clearFullFrameRect ) + mImpl->currentContext->ClearColor(clearColor.r, + clearColor.g, + clearColor.b, + clearColor.a); + if (!clearFullFrameRect) { - mImpl->currentContext->SetScissorTest( true ); - mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height ); - mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR ); - mImpl->currentContext->SetScissorTest( false ); + if (!clippingRect.IsEmpty()) + { + mImpl->currentContext->SetScissorTest(true); + mImpl->currentContext->Scissor(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height); + mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR); + mImpl->currentContext->SetScissorTest(false); + } + else + { + mImpl->currentContext->SetScissorTest(true); + mImpl->currentContext->Scissor(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); + mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR); + mImpl->currentContext->SetScissorTest(false); + } } else { - mImpl->currentContext->SetScissorTest( false ); - mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR ); + mImpl->currentContext->SetScissorTest(false); + mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR); } } @@ -755,7 +1053,8 @@ void RenderManager::RenderScene( Integration::RenderStatus& status, Integration: mImpl->renderBufferIndex, depthBufferAvailable, stencilBufferAvailable, - mImpl->boundTextures ); + mImpl->boundTextures, + clippingRect ); // Synchronise the FBO/Texture access when there are multiple contexts if ( mImpl->currentContext->IsSurfacelessContextSupported() ) diff --git a/dali/internal/render/common/render-manager.h b/dali/internal/render/common/render-manager.h index 5ed4296..abc3c12 100644 --- a/dali/internal/render/common/render-manager.h +++ b/dali/internal/render/common/render-manager.h @@ -85,7 +85,8 @@ public: Integration::GlSyncAbstraction& glSyncAbstraction, Integration::GlContextHelperAbstraction& glContextHelperAbstraction, Integration::DepthBufferAvailable depthBufferAvailable, - Integration::StencilBufferAvailable stencilBufferAvailable ); + Integration::StencilBufferAvailable stencilBufferAvailable, + Integration::PartialUpdateAvailable partialUpdateAvailable ); /** * Non-virtual destructor; not intended as a base class @@ -359,6 +360,18 @@ public: */ void PreRender( Integration::RenderStatus& status, bool forceClear, bool uploadOnly ); + // This method should be called from Core::PreRender() + + /** + * This is called before rendering any scene in the next frame. This method should be preceded + * by a call up Update. + * Multi-threading note: this method should be called from a dedicated rendering thread. + * @pre The GL context must have been created, and made current. + * @param[in] scene The scene to be rendered. + * @param[out] damagedRects The list of damaged rects for the current render pass. + */ + void PreRender( Integration::Scene& scene, std::vector>& damagedRects ); + // This method should be called from Core::RenderScene() /** @@ -373,6 +386,19 @@ public: */ void RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo ); + /** + * Render a scene in the next frame. This method should be preceded by a call up PreRender. + * This method should be called twice. The first pass to render off-screen frame buffers if any, + * and the second pass to render the surface. + * Multi-threading note: this method should be called from a dedicated rendering thread. + * @pre The GL context must have been created, and made current. + * @param[out] status contains the rendering flags. + * @param[in] scene The scene to be rendered. + * @param[in] renderToFbo True to render off-screen frame buffers only if any, and False to render the surface only. + * @param[in] clippingRect The clipping rect for the rendered scene. + */ + void RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect ); + // This method should be called from Core::PostRender() /** diff --git a/dali/internal/render/renderers/render-renderer.cpp b/dali/internal/render/renderers/render-renderer.cpp index eea391a..7456616 100644 --- a/dali/internal/render/renderers/render-renderer.cpp +++ b/dali/internal/render/renderers/render-renderer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include namespace Dali @@ -137,6 +138,7 @@ Renderer::Renderer( SceneGraph::RenderDataProvider* dataProvider, mGeometry( geometry ), mUniformIndexMap(), mAttributesLocation(), + mUniformsHash(), mStencilParameters( stencilParameters ), mBlendingOptions(), mIndexedDrawFirstElement( 0 ), @@ -147,7 +149,8 @@ Renderer::Renderer( SceneGraph::RenderDataProvider* dataProvider, mDepthTestMode( depthTestMode ), mUpdateAttributesLocation( true ), mPremultipledAlphaEnabled( preMultipliedAlphaEnabled ), - mShaderChanged( false ) + mShaderChanged( false ), + mUpdated( true ) { if( blendingBitmask != 0u ) { @@ -198,6 +201,8 @@ void Renderer::SetBlending( Context& context, bool blend ) context.BlendEquationSeparate( mBlendingOptions.GetBlendEquationRgb(), mBlendingOptions.GetBlendEquationAlpha() ); } + + mUpdated = true; } void Renderer::GlContextDestroyed() @@ -376,41 +381,49 @@ bool Renderer::BindTextures( Context& context, Program& program, Vector& void Renderer::SetFaceCullingMode( FaceCullingMode::Type mode ) { mFaceCullingMode = mode; + mUpdated = true; } void Renderer::SetBlendingBitMask( uint32_t bitmask ) { mBlendingOptions.SetBitmask( bitmask ); + mUpdated = true; } void Renderer::SetBlendColor( const Vector4& color ) { mBlendingOptions.SetBlendColor( color ); + mUpdated = true; } void Renderer::SetIndexedDrawFirstElement( uint32_t firstElement ) { mIndexedDrawFirstElement = firstElement; + mUpdated = true; } void Renderer::SetIndexedDrawElementsCount( uint32_t elementsCount ) { mIndexedDrawElementsCount = elementsCount; + mUpdated = true; } void Renderer::EnablePreMultipliedAlpha( bool enable ) { mPremultipledAlphaEnabled = enable; + mUpdated = true; } void Renderer::SetDepthWriteMode( DepthWriteMode::Type depthWriteMode ) { mDepthWriteMode = depthWriteMode; + mUpdated = true; } void Renderer::SetDepthTestMode( DepthTestMode::Type depthTestMode ) { mDepthTestMode = depthTestMode; + mUpdated = true; } DepthWriteMode::Type Renderer::GetDepthWriteMode() const @@ -426,6 +439,7 @@ DepthTestMode::Type Renderer::GetDepthTestMode() const void Renderer::SetDepthFunction( DepthFunction::Type depthFunction ) { mDepthFunction = depthFunction; + mUpdated = true; } DepthFunction::Type Renderer::GetDepthFunction() const @@ -436,6 +450,7 @@ DepthFunction::Type Renderer::GetDepthFunction() const void Renderer::SetRenderMode( RenderMode::Type renderMode ) { mStencilParameters.renderMode = renderMode; + mUpdated = true; } RenderMode::Type Renderer::GetRenderMode() const @@ -446,6 +461,7 @@ RenderMode::Type Renderer::GetRenderMode() const void Renderer::SetStencilFunction( StencilFunction::Type stencilFunction ) { mStencilParameters.stencilFunction = stencilFunction; + mUpdated = true; } StencilFunction::Type Renderer::GetStencilFunction() const @@ -456,6 +472,7 @@ StencilFunction::Type Renderer::GetStencilFunction() const void Renderer::SetStencilFunctionMask( int stencilFunctionMask ) { mStencilParameters.stencilFunctionMask = stencilFunctionMask; + mUpdated = true; } int Renderer::GetStencilFunctionMask() const @@ -466,6 +483,7 @@ int Renderer::GetStencilFunctionMask() const void Renderer::SetStencilFunctionReference( int stencilFunctionReference ) { mStencilParameters.stencilFunctionReference = stencilFunctionReference; + mUpdated = true; } int Renderer::GetStencilFunctionReference() const @@ -476,6 +494,7 @@ int Renderer::GetStencilFunctionReference() const void Renderer::SetStencilMask( int stencilMask ) { mStencilParameters.stencilMask = stencilMask; + mUpdated = true; } int Renderer::GetStencilMask() const @@ -486,6 +505,7 @@ int Renderer::GetStencilMask() const void Renderer::SetStencilOperationOnFail( StencilOperation::Type stencilOperationOnFail ) { mStencilParameters.stencilOperationOnFail = stencilOperationOnFail; + mUpdated = true; } StencilOperation::Type Renderer::GetStencilOperationOnFail() const @@ -496,6 +516,7 @@ StencilOperation::Type Renderer::GetStencilOperationOnFail() const void Renderer::SetStencilOperationOnZFail( StencilOperation::Type stencilOperationOnZFail ) { mStencilParameters.stencilOperationOnZFail = stencilOperationOnZFail; + mUpdated = true; } StencilOperation::Type Renderer::GetStencilOperationOnZFail() const @@ -506,6 +527,7 @@ StencilOperation::Type Renderer::GetStencilOperationOnZFail() const void Renderer::SetStencilOperationOnZPass( StencilOperation::Type stencilOperationOnZPass ) { mStencilParameters.stencilOperationOnZPass = stencilOperationOnZPass; + mUpdated = true; } StencilOperation::Type Renderer::GetStencilOperationOnZPass() const @@ -609,6 +631,8 @@ void Renderer::Render( Context& context, mAttributesLocation, mIndexedDrawFirstElement, mIndexedDrawElementsCount ); + + mUpdated = false; } } @@ -624,6 +648,51 @@ void Renderer::SetShaderChanged( bool value ) mShaderChanged = value; } +bool Renderer::Updated(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider* node) +{ + if (mUpdated) + { + mUpdated = false; + return true; + } + + if (mShaderChanged || mUpdateAttributesLocation || mGeometry->AttributesChanged()) + { + return true; + } + + std::vector textures = mRenderDataProvider->GetTextures(); + for (Render::Texture* texture : textures) + { + if (texture && texture->IsNativeImage()) + { + return true; + } + } + + uint64_t hash = 0xc70f6907UL; + const SceneGraph::CollectedUniformMap& uniformMapNode = node->GetUniformMap( bufferIndex ); + for (const auto* uniformProperty : uniformMapNode) + { + hash = uniformProperty->propertyPtr->Hash(bufferIndex, hash); + } + + const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMap(); + const SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetUniformMap( bufferIndex ); + for (const auto* uniformProperty : uniformMap) + { + hash = uniformProperty->propertyPtr->Hash(bufferIndex, hash); + } + + if (mUniformsHash != hash) + { + mUniformsHash = hash; + return true; + } + + return false; +} + } // namespace SceneGraph } // namespace Internal diff --git a/dali/internal/render/renderers/render-renderer.h b/dali/internal/render/renderers/render-renderer.h index a544883..fccf372 100755 --- a/dali/internal/render/renderers/render-renderer.h +++ b/dali/internal/render/renderers/render-renderer.h @@ -384,6 +384,14 @@ public: */ void SetShaderChanged( bool value ); + /** + * Check if the renderer attributes/uniforms are updated and returns the flag + * + * @param[in] bufferIndex The current update buffer index. + * @param[in] node The node using this renderer + */ + bool Updated(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider* node); + private: struct UniformIndexMap; @@ -445,6 +453,8 @@ private: UniformIndexMappings mUniformIndexMap; Vector mAttributesLocation; + uint64_t mUniformsHash; + StencilParameters mStencilParameters; ///< Struct containing all stencil related options BlendingOptions mBlendingOptions; ///< Blending options including blend color, blend func and blend equation @@ -458,6 +468,7 @@ private: bool mUpdateAttributesLocation:1; ///< Indicates attribute locations have changed bool mPremultipledAlphaEnabled:1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required bool mShaderChanged:1; ///< Flag indicating the shader changed and uniform maps have to be updated + bool mUpdated:1; }; diff --git a/dali/internal/update/animation/scene-graph-animator.h b/dali/internal/update/animation/scene-graph-animator.h index 0b3ff50..2de0fd7 100644 --- a/dali/internal/update/animation/scene-graph-animator.h +++ b/dali/internal/update/animation/scene-graph-animator.h @@ -519,6 +519,11 @@ public: progress = SetProgress( progress ); } + if( mPropertyOwner ) + { + mPropertyOwner->SetUpdated( true ); + } + float alpha = ApplyAlphaFunction( progress ); // PropertyType specific part diff --git a/dali/internal/update/common/property-owner.h b/dali/internal/update/common/property-owner.h index 843a19b..d9523e8 100644 --- a/dali/internal/update/common/property-owner.h +++ b/dali/internal/update/common/property-owner.h @@ -160,6 +160,23 @@ public: return mCustomProperties; } + /** + * Mark an property owner with the updated flag. + * @param[in] updated The updated flag + */ + virtual void SetUpdated(bool updated) + { + mUpdated = updated; + } + + /** + * Retrieve if the property owner is updated due to the property is being animating. + * @return An updated flag + */ + bool Updated() + { + return mUpdated; + } // Constraints @@ -226,6 +243,7 @@ protected: OwnedPropertyContainer mCustomProperties; ///< Properties provided with InstallCustomProperty() UniformMap mUniformMaps; ///< Container of owned uniform maps + bool mUpdated; private: diff --git a/dali/internal/update/manager/render-instruction-processor.cpp b/dali/internal/update/manager/render-instruction-processor.cpp index 1e41c12..37f9236 100644 --- a/dali/internal/update/manager/render-instruction-processor.cpp +++ b/dali/internal/update/manager/render-instruction-processor.cpp @@ -151,45 +151,53 @@ bool CompareItems3DWithClipping( const RenderInstructionProcessor::SortAttribute * @param isLayer3d Whether we are processing a 3D layer or not * @param cull Whether frustum culling is enabled or not */ -inline void AddRendererToRenderList( BufferIndex updateBufferIndex, - RenderList& renderList, - Renderable& renderable, - const Matrix& viewMatrix, - SceneGraph::Camera& camera, - bool isLayer3d, - bool cull ) +inline void AddRendererToRenderList(BufferIndex updateBufferIndex, + RenderList& renderList, + Renderable& renderable, + const Matrix& viewMatrix, + SceneGraph::Camera& camera, + bool isLayer3d, + bool cull) { - bool inside( true ); + bool inside(true); Node* node = renderable.mNode; - if( cull && renderable.mRenderer && !renderable.mRenderer->GetShader().HintEnabled( Dali::Shader::Hint::MODIFIES_GEOMETRY ) ) + if (cull && renderable.mRenderer && !renderable.mRenderer->GetShader().HintEnabled(Dali::Shader::Hint::MODIFIES_GEOMETRY)) { const Vector4& boundingSphere = node->GetBoundingSphere(); - inside = ( boundingSphere.w > Math::MACHINE_EPSILON_1000 ) && - ( camera.CheckSphereInFrustum( updateBufferIndex, Vector3( boundingSphere ), boundingSphere.w ) ); + inside = (boundingSphere.w > Math::MACHINE_EPSILON_1000) && + (camera.CheckSphereInFrustum(updateBufferIndex, Vector3(boundingSphere), boundingSphere.w)); } - if( inside ) + if (inside) { Renderer::OpacityType opacityType = renderable.mRenderer ? renderable.mRenderer->GetOpacityType( updateBufferIndex, *renderable.mNode ) : Renderer::OPAQUE; - if( opacityType != Renderer::TRANSPARENT || node->GetClippingMode() == ClippingMode::CLIP_CHILDREN ) + if (opacityType != Renderer::TRANSPARENT || node->GetClippingMode() == ClippingMode::CLIP_CHILDREN) { // Get the next free RenderItem. RenderItem& item = renderList.GetNextFreeItem(); + item.mIsUpdated = (item.mNode != renderable.mNode); item.mNode = renderable.mNode; - item.mIsOpaque = ( opacityType == Renderer::OPAQUE ); - item.mDepthIndex = 0; - if(!isLayer3d) + bool prevIsOpaque = item.mIsOpaque; + item.mIsOpaque = (opacityType == Renderer::OPAQUE); + item.mIsUpdated |= (prevIsOpaque != item.mIsOpaque); + + int prevDepthIndex = item.mDepthIndex; + item.mDepthIndex = 0; + if (!isLayer3d) { item.mDepthIndex = renderable.mNode->GetDepthIndex(); } - if( DALI_LIKELY( renderable.mRenderer ) ) + Render::Renderer* prevRenderer = item.mRenderer; + if (DALI_LIKELY(renderable.mRenderer)) { - item.mRenderer = &renderable.mRenderer->GetRenderer(); - item.mTextureSet = renderable.mRenderer->GetTextures(); + item.mRenderer = &renderable.mRenderer->GetRenderer(); + const void* prevTextureSet = item.mTextureSet; + item.mTextureSet = renderable.mRenderer->GetTextures(); + item.mIsUpdated |= (prevTextureSet != item.mTextureSet); item.mDepthIndex += renderable.mRenderer->GetDepthIndex(); } else @@ -197,17 +205,45 @@ inline void AddRendererToRenderList( BufferIndex updateBufferIndex, item.mRenderer = nullptr; } - // Save ModelView matrix onto the item. - node->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize ); + item.mIsUpdated |= (prevDepthIndex != item.mDepthIndex); + item.mIsUpdated |= (prevRenderer != item.mRenderer); + item.mIsUpdated |= isLayer3d; - Matrix::Multiply( item.mModelViewMatrix, item.mModelMatrix, viewMatrix ); + if (!item.mIsUpdated) + { + Matrix prevModelViewMatrix = item.mModelViewMatrix; + Vector3 prevSize = item.mSize; + + // Save ModelView matrix onto the item. + node->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize ); + Matrix::Multiply( item.mModelViewMatrix, item.mModelMatrix, viewMatrix ); + + item.mIsUpdated = ((prevSize != item.mSize) || (item.mModelViewMatrix != prevModelViewMatrix)); + } + else + { + // Save ModelView matrix onto the item. + node->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize ); + Matrix::Multiply( item.mModelViewMatrix, item.mModelMatrix, viewMatrix ); + } + + item.mUpdateSize = node->GetUpdateSizeHint(); + if (item.mUpdateSize == Vector3::ZERO) + { + // RenderItem::CalculateViewportSpaceAABB cannot cope with z transform + // I don't use item.mModelMatrix.GetTransformComponents() for z transform, would be to slow + if (!isLayer3d && item.mModelMatrix.GetZAxis() == Vector3(0.0f, 0.0f, 1.0f)) + { + item.mUpdateSize = item.mSize; + } + } } - node->SetCulled( updateBufferIndex, false ); + node->SetCulled( updateBufferIndex, false ); } else { - node->SetCulled( updateBufferIndex, true ); + node->SetCulled( updateBufferIndex, true ); } } @@ -240,7 +276,7 @@ inline void AddRenderersToRenderList( BufferIndex updateBufferIndex, viewMatrix, camera, isLayer3d, - cull ); + cull); } } @@ -280,6 +316,7 @@ inline bool TryReuseCachedRenderers( Layer& layer, retValue = true; } } + return retValue; } diff --git a/dali/internal/update/nodes/node.cpp b/dali/internal/update/nodes/node.cpp index d80d7c4..32f6dee 100755 --- a/dali/internal/update/nodes/node.cpp +++ b/dali/internal/update/nodes/node.cpp @@ -90,6 +90,7 @@ Node::Node() mVisible( true ), mCulled( false ), mColor( Color::WHITE ), + mUpdateSizeHint( Vector3::ZERO ), mWorldPosition( TRANSFORM_PROPERTY_WORLD_POSITION, Vector3( 0.0f,0.0f,0.0f ) ), // Zero initialized by default mWorldScale( TRANSFORM_PROPERTY_WORLD_SCALE, Vector3( 1.0f,1.0f,1.0f ) ), mWorldOrientation(), // Initialized to identity by default diff --git a/dali/internal/update/nodes/node.h b/dali/internal/update/nodes/node.h index 5cd6073..6d24979 100755 --- a/dali/internal/update/nodes/node.h +++ b/dali/internal/update/nodes/node.h @@ -117,6 +117,21 @@ public: } /** + * Mark an node and its sub tree according to the updated flag. + * @param[in] updated The updated flag + * (used for partial rendering to mark an animating sub tree for example). + */ + virtual void SetUpdated(bool updated) + { + mUpdated = updated; + + for (Node* child : mChildren) + { + child->SetUpdated(updated); + } + } + + /** * This method sets clipping information on the node based on its hierarchy in the scene-graph. * A value is calculated that can be used during sorting to increase sort speed. * @param[in] clippingId The Clipping ID of the node to set @@ -614,6 +629,20 @@ public: } /** + * Retrieve the update size hint of the node. + * @return The update size hint. + */ + const Vector3& GetUpdateSizeHint() const + { + if( mTransformId != INVALID_TRANSFORM_ID ) + { + return mUpdateSizeHint.Get(0); + } + + return Vector3::ZERO; + } + + /** * Retrieve the bounding sphere of the node * @return A vector4 describing the bounding sphere. XYZ is the center and W is the radius */ @@ -881,6 +910,8 @@ public: // Default properties AnimatableProperty mVisible; ///< Visibility can be inherited from the Node hierachy AnimatableProperty mCulled; ///< True if the node is culled. This is not animatable. It is just double-buffered. AnimatableProperty mColor; ///< Color can be inherited from the Node hierarchy + AnimatableProperty mUpdateSizeHint; ///< Update size hint is provided for damaged area calculation. This is not animatable. It is just double-buffered. (Because all these bloody properties are). + // Inherited properties; read-only from public API diff --git a/dali/internal/update/render-tasks/scene-graph-camera.cpp b/dali/internal/update/render-tasks/scene-graph-camera.cpp index 71a2d52..aa44bd3 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.cpp +++ b/dali/internal/update/render-tasks/scene-graph-camera.cpp @@ -194,6 +194,11 @@ void Camera::SetNode( const Node* node ) mNode = node; } +const Node* Camera::GetNode() const +{ + return mNode; +} + void Camera::SetType( Dali::Camera::Type type ) { mType = type; diff --git a/dali/internal/update/render-tasks/scene-graph-camera.h b/dali/internal/update/render-tasks/scene-graph-camera.h index a3bc173..f75f81b 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.h +++ b/dali/internal/update/render-tasks/scene-graph-camera.h @@ -100,6 +100,12 @@ public: void SetNode( const Node* node ); /** + * Get the node this scene graph camera belongs to. + * @return node The owning node. + */ + const Node* GetNode() const; + + /** * @copydoc Dali::Internal::CameraActor::SetType */ void SetType( Dali::Camera::Type type ); diff --git a/dali/public-api/common/list-wrapper.h b/dali/public-api/common/list-wrapper.h new file mode 100644 index 0000000..a63e6c8 --- /dev/null +++ b/dali/public-api/common/list-wrapper.h @@ -0,0 +1,64 @@ +#ifndef DALI_LIST_WRAPPER_H +#define DALI_LIST_WRAPPER_H + +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef HIDE_DALI_INTERNALS + +#include + +#else + +// Ensure that default visibility is used with any class that is used as an exception type +#include +#include +#include + +#if defined(__clang__) + +#undef _LIBCPP_INLINE_VISIBILITY +#define _LIBCPP_INLINE_VISIBILITY +#undef _LIBCPP_EXTERN_TEMPLATE +#define _LIBCPP_EXTERN_TEMPLATE(...) + +#include + +#undef _LIBCPP_INLINE_VISIBILITY +#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__)) +#undef _LIBCPP_EXTERN_TEMPLATE +#define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__; + +#else + +#include +#include +#undef _GLIBCXX_VISIBILITY_ATTR +#undef _GLIBCXX_VISIBILITY +#define _GLIBCXX_VISIBILITY_ATTR(V) __attribute__ ((__visibility__ ("hidden"))) +#define _GLIBCXX_VISIBILITY(V) __attribute__ ((__visibility__ ("hidden"))) +#include +#undef _GLIBCXX_VISIBILITY_ATTR +#undef _GLIBCXX_VISIBILITY +#define _GLIBCXX_VISIBILITY_ATTR(V) __attribute__ ((__visibility__ (#V))) // restore `_GLIBCXX_VISIBILITY_ATTR` +#define _GLIBCXX_VISIBILITY(V) __attribute__ ((__visibility__ (#V))) // restore `_GLIBCXX_VISIBILITY` + +#endif // #ifdef __clang__ + +#endif // #ifndef HIDE_DALI_INTERNALS + +#endif // DALI_LISt_WRAPPER_H diff --git a/dali/public-api/file.list b/dali/public-api/file.list index eadaa1f..12c49bd 100644 --- a/dali/public-api/file.list +++ b/dali/public-api/file.list @@ -127,6 +127,7 @@ SET( public_api_core_common_header_files ${public_api_src_dir}/common/loading-state.h ${public_api_src_dir}/common/stage.h ${public_api_src_dir}/common/type-traits.h + ${public_api_src_dir}/common/list-wrapper.h ${public_api_src_dir}/common/vector-wrapper.h ${public_api_src_dir}/common/view-mode.h ) diff --git a/dali/public-api/math/rect.h b/dali/public-api/math/rect.h index b8b64cf..8c4f616 100644 --- a/dali/public-api/math/rect.h +++ b/dali/public-api/math/rect.h @@ -166,6 +166,16 @@ struct Rect } /** + * @brief Determines whether or not this Rectangle is valid. + * + * @return True if width and height are not negative + */ + bool IsValid() const + { + return !(width < 0 || height < 0); + } + + /** * @brief Gets the left of the rectangle. * * @SINCE_1_0.0 @@ -228,10 +238,70 @@ struct Rect */ bool Intersects(const Rect& other) const { - return (other.x + other.width) > x && - other.x < (x + width) && - (other.y + other.height) > y && - other.y < (y + height); + return (other.x + other.width) > x && other.x < (x + width) && + (other.y + other.height) > y && other.y < (y + height); + } + + /** + * @brief Intersects this rectangle and the specified rectangle. + * The result of the intersection is stored in this rectangle. + * + * @param[in] rect The other rectangle to intersect with + */ + bool Intersect(const Rect& rect) + { + const int left = std::max(rect.x, x); + const int top = std::max(rect.y, y); + const int right = std::min(rect.x + rect.width, x + width); + const int bottom = std::min(rect.y + rect.height, y + height); + + const int width = right - left; + const int height = bottom - top; + if (!(width < 0 || height < 0)) + { + x = left; + y = top; + this->width = width; + this->height = height; + return true; + } + + return false; + } + + /** + * @brief Merges this rectangle and the specified rectangle. + * The result of the merge is stored in this rectangle. + * + * @param[in] rect The other rectangle to merge with + */ + void Merge(const Rect& rect) + { + const int left = std::min(rect.x, x); + const int top = std::min(rect.y, y); + const int right = std::max(rect.x + rect.width, x + width); + const int bottom = std::max(rect.y + rect.height, y + height); + x = left; + y = top; + width = right - left; + height = bottom - top; + } + + /** + * @brief Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards. + * If dx is negative, then the sides are moved outwards. + * The result of the inset is stored in this rectangle. + */ + void Inset(T dx, T dy) + { + const int left = x - dx; + const int top = y - dy; + const int right = x + width + dx; + const int bottom = y + height + dy; + x = left; + y = top; + width = right - left; + height = bottom - top; } /** @@ -243,10 +313,8 @@ struct Rect */ bool Contains(const Rect& other) const { - return other.x >= x && - (other.x + other.width) <= (x + width) && - other.y >= y && - (other.y + other.height) <= (y + height); + return other.x >= x && (other.x + other.width) <= (x + width) && + other.y >= y && (other.y + other.height) <= (y + height); } public: // Data -- 2.7.4