Partial update implementation, first phase. 90/236790/2
authorAnton Obzhirov <a.obzhirov@samsung.com>
Tue, 14 Apr 2020 14:59:45 +0000 (15:59 +0100)
committerSunghyun Kim <scholb.kim@samsung.com>
Mon, 22 Jun 2020 07:45:10 +0000 (16:45 +0900)
Change-Id: I7d2a70c747247c057af6d00d8c147594bf6c7a3d

31 files changed:
automated-tests/src/dali/dali-test-suite-utils/test-application.cpp
automated-tests/src/dali/dali-test-suite-utils/test-application.h
automated-tests/src/dali/utc-Dali-Actor.cpp
dali/devel-api/actors/actor-devel.h
dali/integration-api/core-enumerations.h
dali/integration-api/core.cpp
dali/integration-api/core.h
dali/internal/common/core-impl.cpp
dali/internal/common/core-impl.h
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h
dali/internal/event/common/property-buffer-impl.cpp
dali/internal/event/common/property-input-impl.h
dali/internal/render/common/render-algorithms.cpp
dali/internal/render/common/render-algorithms.h
dali/internal/render/common/render-item.cpp
dali/internal/render/common/render-item.h
dali/internal/render/common/render-manager.cpp
dali/internal/render/common/render-manager.h
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/renderers/render-renderer.h
dali/internal/update/animation/scene-graph-animator.h
dali/internal/update/common/property-owner.h
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/nodes/node.cpp
dali/internal/update/nodes/node.h
dali/internal/update/render-tasks/scene-graph-camera.cpp
dali/internal/update/render-tasks/scene-graph-camera.h
dali/public-api/common/list-wrapper.h [new file with mode: 0644]
dali/public-api/file.list
dali/public-api/math/rect.h

index e8c0d12..b2a3fb9 100644 (file)
@@ -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<Rect<int>>& 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<Rect<int>>& damagedRects, Rect<int>& 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++;
index e96f759..1df0743 100644 (file)
@@ -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<Rect<int>>& damagedRects);
+  bool RenderWithPartialUpdate(std::vector<Rect<int>>& damagedRects, Rect<int>& 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;
 };
 
index e96ab7a..1550098 100644 (file)
@@ -7500,3 +7500,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<Rect<int>> damagedRects;
+  Rect<int> 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<int>(16, 768, 32, 32); // in screen coordinates, includes 3 last frames updates
+  DALI_TEST_EQUALS<Rect<int>>(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<int>(16, 752, 48, 48); // in screen coordinates, includes 3 last frames updates
+  DALI_TEST_EQUALS<Rect<int>>(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<int>(16, 736, 64, 64); // in screen coordinates, includes 3 last frames updates
+  DALI_TEST_EQUALS<Rect<int>>(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<Rect<int>>(clippingRect, Rect<int>(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<Rect<int>> damagedRects;
+  Rect<int> 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<int>(16, 768, 32, 32); // in screen coordinates, includes 3 last frames updates
+  DALI_TEST_EQUALS<Rect<int>>(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<int>(16, 768, 32, 32); // in screen coordinates, includes 3 last frames updates
+  DALI_TEST_EQUALS<Rect<int>>(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<Rect<int>> damagedRects;
+  Rect<int> 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<int>(16, 768, 32, 32); // in screen coordinates, includes 3 last frames updates
+  DALI_TEST_EQUALS<Rect<int>>(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<Rect<int>>(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<Rect<int>>(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<Rect<int>> damagedRects;
+  application.PreRenderWithPartialUpdate(TestApplication::DEFAULT_RENDER_INTERVAL, nullptr, damagedRects);
+
+  DALI_TEST_EQUALS(damagedRects.size(), 2, TEST_LOCATION);
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(64, 672, 64, 64), damagedRects[0], TEST_LOCATION);
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(96, 592, 112, 112), damagedRects[1], TEST_LOCATION);
+
+  // in screen coordinates, adaptor would calculate it using previous frames information
+  Rect<int> clippingRect = Rect<int>(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<Rect<int>> damagedRects;
+  application.PreRenderWithPartialUpdate(TestApplication::DEFAULT_RENDER_INTERVAL, nullptr, damagedRects);
+
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+  Rect<int> clippingRect = Rect<int>(0, 496, 160, 320);
+  DALI_TEST_EQUALS<Rect<int>>(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;
+}
+
index ff521de..1e4e049 100644 (file)
@@ -128,6 +128,13 @@ enum Type
    * @note True means that the actor is out of the view frustum.
    */
   CULLED = INHERIT_LAYOUT_DIRECTION + 5,
+
+  /**
+   * @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 = INHERIT_LAYOUT_DIRECTION + 6,
 };
 
 } // namespace Property
index e11dc63..ff6153c 100644 (file)
@@ -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
index 47eb713..ee0b608 100644 (file)
@@ -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<Rect<int>>& 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<int>& clippingRect )
+{
+  mImpl->RenderScene( status, scene, renderToFbo, clippingRect );
+}
+
 void Core::PostRender( bool uploadOnly )
 {
   mImpl->PostRender( uploadOnly );
index f1a7e63..a897631 100644 (file)
@@ -23,6 +23,8 @@
 
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/rect.h>
 #include <dali/integration-api/context-notifier.h>
 #include <dali/integration-api/core-enumerations.h>
 
@@ -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<Rect<int>>& 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<int>& clippingRect );
 
   /**
    * This is called after rendering all the scenes in the next frame. This method should be
index 5da52a4..fd17bd2 100644 (file)
@@ -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<Rect<int>>& 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<int>& clippingRect )
+{
+  mRenderManager->RenderScene( status, scene, renderToFbo, clippingRect );
+}
+
 void Core::PostRender( bool uploadOnly )
 {
   mRenderManager->PostRender( uploadOnly );
index cbe41a4..f2b6b62 100644 (file)
@@ -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<Rect<int>>& 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<int>& clippingRect );
+
+  /**
    * @copydoc Dali::Integration::Core::Render()
    */
   void PostRender( bool uploadOnly );
index 7710dc5..b45c7e9 100644 (file)
@@ -214,6 +214,7 @@ DALI_PROPERTY( "opacity",                   FLOAT,    true,  true,  true,  Dali:
 DALI_PROPERTY( "screenPosition",            VECTOR2,  false, false, false, Dali::DevelActor::Property::SCREEN_POSITION )
 DALI_PROPERTY( "positionUsesAnchorPoint",   BOOLEAN,  true,  false, false, Dali::DevelActor::Property::POSITION_USES_ANCHOR_POINT )
 DALI_PROPERTY( "culled",                    BOOLEAN,  false, false, true, Dali::DevelActor::Property::CULLED )
+DALI_PROPERTY( "updateSizeHint",            VECTOR2,  true,  false, false, Dali::DevelActor::Property::UPDATE_SIZE_HINT )
 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX, ActorDefaultProperties )
 
 // Signals
@@ -2759,6 +2760,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
@@ -4041,6 +4048,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
@@ -5110,6 +5123,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<Vector3>::Send( GetEventThreadServices(), &GetNode(), &GetNode().mUpdateSizeHint, &AnimatableProperty<Vector3>::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
index bf58f23..4e57518 100755 (executable)
@@ -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
index c44df2c..242aa67 100644 (file)
 #include <dali/public-api/rendering/property-buffer.h>
 #include <dali/internal/update/manager/update-manager.h>
 
+#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<const unsigned char*>(bytes)[i];
+    }
+
+    return seed;
+  }
+}
+#endif
+
 namespace Dali
 {
 namespace Internal
index ca46246..297332f 100644 (file)
 #include <dali/public-api/math/matrix.h>
 #include <dali/internal/common/buffer-index.h>
 
+#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.
index 01bba05..cfd1f92 100644 (file)
@@ -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<GLuint>& boundTextures,
-                                                 const RenderInstruction& instruction
+                                                 const RenderInstruction& instruction,
+                                                 const Rect<int>& 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<GLuint>& boundTextures )
+                                                 Vector<GLuint>& boundTextures,
+                                                 const Rect<int>& 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 );
       }
     }
   }
index 26f4343..9d359b4 100644 (file)
@@ -65,7 +65,8 @@ class RenderAlgorithms
                                    BufferIndex bufferIndex,
                                    Integration::DepthBufferAvailable depthBufferAvailable,
                                    Integration::StencilBufferAvailable stencilBufferAvailable,
-                                   Vector<GLuint>& boundTextures );
+                                   Vector<GLuint>& boundTextures,
+                                   const Rect<int>& rootClippingRect );
 
   private:
 
@@ -125,8 +126,8 @@ class RenderAlgorithms
                                    Integration::DepthBufferAvailable depthBufferAvailable,
                                    Integration::StencilBufferAvailable stencilBufferAvailable,
                                    Vector<GLuint>& 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<int>& rootClippingRect );
 
     // Prevent copying:
     RenderAlgorithms( RenderAlgorithms& rhs );
index d47f808..d10e15e 100644 (file)
@@ -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<RenderItem*>( ptr ) );
 }
 
-
 } // namespace SceneGraph
 
 } // namespace Internal
index 7dbd3fb..77e1fac 100644 (file)
@@ -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:
 
index 77f6088..905032a 100644 (file)
@@ -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<int>& 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<int> 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<Dali::ThreadPool>( 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<Dali::ThreadPool>         threadPool;               ///< The thread pool
   Vector<GLuint>                            boundTextures;            ///< The textures bound for rendering
   Vector<GLuint>                            textureDependencyList;    ///< The dependency list of binded textures
+  std::size_t                               itemsCheckSum;            ///< The damaged render items checksum from previous prerender phase.
+  std::vector<DirtyRect>                    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<Rect<int>>& damagedRects )
+{
+  if (mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE)
+  {
+    return;
+  }
+
+  class DamagedRectsCleaner
+  {
+  public:
+    DamagedRectsCleaner(std::vector<Rect<int>>& damagedRects)
+    : mDamagedRects(damagedRects),
+      mCleanOnReturn(true)
+    {
+    }
+
+    void SetCleanOnReturn(bool cleanOnReturn)
+    {
+      mCleanOnReturn = cleanOnReturn;
+    }
+
+    ~DamagedRectsCleaner()
+    {
+      if (mCleanOnReturn)
+      {
+        mDamagedRects.clear();
+      }
+    }
+
+  private:
+    std::vector<Rect<int>>& mDamagedRects;
+    bool mCleanOnReturn;
+  };
+
+  Rect<int32_t> surfaceRect = Rect<int32_t>(0, 0, static_cast<int32_t>( scene.GetSize().width ), static_cast<int32_t>( 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<int32_t> 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<int> 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<int>& 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<int>& 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<int> clippingRect;
+  RenderScene( status, scene, renderToFbo, clippingRect);
+}
+
+void RenderManager::RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect<int>& 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<int>();
+      }
+      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() )
index 5ed4296..abc3c12 100644 (file)
@@ -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<Rect<int>>& 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<int>& clippingRect );
+
   // This method should be called from Core::PostRender()
 
   /**
index eea391a..7456616 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/internal/render/shaders/scene-graph-shader.h>
 #include <dali/internal/render/shaders/program.h>
 #include <dali/internal/render/data-providers/node-data-provider.h>
+#include <dali/internal/render/data-providers/uniform-map-data-provider.h>
 #include <dali/internal/render/common/render-instruction.h>
 
 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<GLuint>&
 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<Render::Texture*> 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
index a544883..fccf372 100755 (executable)
@@ -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<GLint>                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;
 
 
 };
index 0b3ff50..2de0fd7 100644 (file)
@@ -519,6 +519,11 @@ public:
       progress = SetProgress( progress );
     }
 
+    if( mPropertyOwner )
+    {
+      mPropertyOwner->SetUpdated( true );
+    }
+
     float alpha = ApplyAlphaFunction( progress );
 
     // PropertyType specific part
index 843a19b..d9523e8 100644 (file)
@@ -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:
 
index 1e41c12..37f9236 100644 (file)
@@ -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;
 }
 
index d80d7c4..32f6dee 100755 (executable)
@@ -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
index 5cd6073..6d24979 100755 (executable)
@@ -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<bool>           mVisible;                ///< Visibility can be inherited from the Node hierachy
   AnimatableProperty<bool>           mCulled;                 ///< True if the node is culled. This is not animatable. It is just double-buffered.
   AnimatableProperty<Vector4>        mColor;                  ///< Color can be inherited from the Node hierarchy
+  AnimatableProperty<Vector3>        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
 
index 71a2d52..aa44bd3 100644 (file)
@@ -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;
index a3bc173..f75f81b 100644 (file)
@@ -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 (file)
index 0000000..a63e6c8
--- /dev/null
@@ -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 <list>
+
+#else
+
+// Ensure that default visibility is used with any class that is used as an exception type
+#include <memory>
+#include <new>
+#include <stdexcept>
+
+#if defined(__clang__)
+
+#undef _LIBCPP_INLINE_VISIBILITY
+#define _LIBCPP_INLINE_VISIBILITY
+#undef _LIBCPP_EXTERN_TEMPLATE
+#define _LIBCPP_EXTERN_TEMPLATE(...)
+
+#include <list>
+
+#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 <bits/c++config.h>
+#include <bits/stl_list.h>
+#undef _GLIBCXX_VISIBILITY_ATTR
+#undef _GLIBCXX_VISIBILITY
+#define _GLIBCXX_VISIBILITY_ATTR(V) __attribute__ ((__visibility__ ("hidden")))
+#define _GLIBCXX_VISIBILITY(V) __attribute__ ((__visibility__ ("hidden")))
+#include <list>
+#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
index 01d7a75..d73e282 100644 (file)
@@ -133,6 +133,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
 )
index 5560a8a..4569a98 100644 (file)
@@ -135,6 +135,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
@@ -197,10 +207,70 @@ struct Rect
    */
   bool Intersects(const Rect<T>& 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<T>& 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<T>& 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;
   }
 
   /**
@@ -212,10 +282,8 @@ struct Rect
    */
   bool Contains(const Rect<T>& 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