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 )
{
mGlContextHelperAbstraction,
Integration::RenderToFrameBuffer::FALSE,
Integration::DepthBufferAvailable::TRUE,
- Integration::StencilBufferAvailable::TRUE );
+ Integration::StencilBufferAvailable::TRUE,
+ mPartialUpdateEnabled ? Integration::PartialUpdateAvailable::TRUE : Integration::PartialUpdateAvailable::FALSE );
mCore->ContextCreated();
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++;
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();
{
// 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++;
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();
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( );
struct { uint32_t x; uint32_t y; } mDpi;
uint32_t mLastVSyncTime;
+ bool mPartialUpdateEnabled;
static bool mLoggingEnabled;
};
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;
+}
+
* @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
TRUE
};
+/**
+ * @brief Enumerations to specify whether the stencil buffer is available.
+ */
+enum class PartialUpdateAvailable
+{
+ FALSE = 0,
+ TRUE
+};
+
} // namespace Integration
} // namespace Dali
GlContextHelperAbstraction& glContextHelperAbstraction,
RenderToFrameBuffer renderToFboEnabled,
DepthBufferAvailable depthBufferAvailable,
- StencilBufferAvailable stencilBufferAvailable )
+ StencilBufferAvailable stencilBufferAvailable,
+ PartialUpdateAvailable partialUpdateAvailable )
{
Core* instance = new Core;
instance->mImpl = new Internal::Core( renderController,
glContextHelperAbstraction,
renderToFboEnabled,
depthBufferAvailable,
- stencilBufferAvailable );
+ stencilBufferAvailable,
+ partialUpdateAvailable );
return instance;
}
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 );
// 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>
* @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,
GlContextHelperAbstraction& glContextHelperAbstraction,
RenderToFrameBuffer renderToFboEnabled,
DepthBufferAvailable depthBufferAvailable,
- StencilBufferAvailable stencilBufferAvailable );
+ StencilBufferAvailable stencilBufferAvailable,
+ PartialUpdateAvailable partialUpdateAvailable);
/**
* Non-virtual destructor. Core is not intended as a base class.
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.
*/
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
GlContextHelperAbstraction& glContextHelperAbstraction,
Integration::RenderToFrameBuffer renderToFboEnabled,
Integration::DepthBufferAvailable depthBufferAvailable,
- Integration::StencilBufferAvailable stencilBufferAvailable )
+ Integration::StencilBufferAvailable stencilBufferAvailable,
+ Integration::PartialUpdateAvailable partialUpdateAvailable )
: mRenderController( renderController ),
mPlatform(platform),
mProcessingEvent(false),
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();
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 );
Integration::GlContextHelperAbstraction& glContextHelperAbstraction,
Integration::RenderToFrameBuffer renderToFboEnabled,
Integration::DepthBufferAvailable depthBufferAvailable,
- Integration::StencilBufferAvailable stencilBufferAvailable );
+ Integration::StencilBufferAvailable stencilBufferAvailable,
+ Integration::PartialUpdateAvailable partialUpdateAvailable );
/**
* Destructor
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 );
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
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
break;
}
+ case Dali::DevelActor::Property::UPDATE_SIZE_HINT:
+ {
+ value = GetUpdateSizeHint();
+ break;
+ }
+
default:
{
// Must be an event-side only property
}
}
+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
*/
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
#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
#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
{
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.
// 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() );
Integration::DepthBufferAvailable depthBufferAvailable,
Integration::StencilBufferAvailable stencilBufferAvailable,
Vector<GLuint>& boundTextures,
- const RenderInstruction& instruction
+ const RenderInstruction& instruction,
+ const Rect<int>& rootClippingRect
)
{
DALI_PRINT_RENDER_LIST( 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 );
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 )
BufferIndex bufferIndex,
Integration::DepthBufferAvailable depthBufferAvailable,
Integration::StencilBufferAvailable stencilBufferAvailable,
- Vector<GLuint>& boundTextures )
+ Vector<GLuint>& boundTextures,
+ const Rect<int>& rootClippingRect )
{
DALI_PRINT_RENDER_INSTRUCTION( instruction, bufferIndex );
depthBufferAvailable,
stencilBufferAvailable,
boundTextures,
- instruction //added for reflection effect
- );
+ instruction, //added for reflection effect
+ rootClippingRect );
}
}
}
BufferIndex bufferIndex,
Integration::DepthBufferAvailable depthBufferAvailable,
Integration::StencilBufferAvailable stencilBufferAvailable,
- Vector<GLuint>& boundTextures );
+ Vector<GLuint>& boundTextures,
+ const Rect<int>& rootClippingRect );
private:
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 );
mNode( NULL ),
mTextureSet( NULL ),
mDepthIndex( 0 ),
- mIsOpaque( true )
+ mIsOpaque( true ),
+ mIsUpdated( false )
{
}
}
-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).
gRenderItemPool.Free( static_cast<RenderItem*>( ptr ) );
}
-
} // namespace SceneGraph
} // namespace Internal
* @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.
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:
} // 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
*/
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 ),
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() );
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;
}
}
}
+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();
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);
}
}
mImpl->renderBufferIndex,
depthBufferAvailable,
stencilBufferAvailable,
- mImpl->boundTextures );
+ mImpl->boundTextures,
+ clippingRect );
// Synchronise the FBO/Texture access when there are multiple contexts
if ( mImpl->currentContext->IsSurfacelessContextSupported() )
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
*/
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()
/**
*/
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()
/**
#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
mGeometry( geometry ),
mUniformIndexMap(),
mAttributesLocation(),
+ mUniformsHash(),
mStencilParameters( stencilParameters ),
mBlendingOptions(),
mIndexedDrawFirstElement( 0 ),
mDepthTestMode( depthTestMode ),
mUpdateAttributesLocation( true ),
mPremultipledAlphaEnabled( preMultipliedAlphaEnabled ),
- mShaderChanged( false )
+ mShaderChanged( false ),
+ mUpdated( true )
{
if( blendingBitmask != 0u )
{
context.BlendEquationSeparate( mBlendingOptions.GetBlendEquationRgb(),
mBlendingOptions.GetBlendEquationAlpha() );
}
+
+ mUpdated = true;
}
void Renderer::GlContextDestroyed()
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
void Renderer::SetDepthFunction( DepthFunction::Type depthFunction )
{
mDepthFunction = depthFunction;
+ mUpdated = true;
}
DepthFunction::Type Renderer::GetDepthFunction() const
void Renderer::SetRenderMode( RenderMode::Type renderMode )
{
mStencilParameters.renderMode = renderMode;
+ mUpdated = true;
}
RenderMode::Type Renderer::GetRenderMode() const
void Renderer::SetStencilFunction( StencilFunction::Type stencilFunction )
{
mStencilParameters.stencilFunction = stencilFunction;
+ mUpdated = true;
}
StencilFunction::Type Renderer::GetStencilFunction() const
void Renderer::SetStencilFunctionMask( int stencilFunctionMask )
{
mStencilParameters.stencilFunctionMask = stencilFunctionMask;
+ mUpdated = true;
}
int Renderer::GetStencilFunctionMask() const
void Renderer::SetStencilFunctionReference( int stencilFunctionReference )
{
mStencilParameters.stencilFunctionReference = stencilFunctionReference;
+ mUpdated = true;
}
int Renderer::GetStencilFunctionReference() const
void Renderer::SetStencilMask( int stencilMask )
{
mStencilParameters.stencilMask = stencilMask;
+ mUpdated = true;
}
int Renderer::GetStencilMask() const
void Renderer::SetStencilOperationOnFail( StencilOperation::Type stencilOperationOnFail )
{
mStencilParameters.stencilOperationOnFail = stencilOperationOnFail;
+ mUpdated = true;
}
StencilOperation::Type Renderer::GetStencilOperationOnFail() const
void Renderer::SetStencilOperationOnZFail( StencilOperation::Type stencilOperationOnZFail )
{
mStencilParameters.stencilOperationOnZFail = stencilOperationOnZFail;
+ mUpdated = true;
}
StencilOperation::Type Renderer::GetStencilOperationOnZFail() const
void Renderer::SetStencilOperationOnZPass( StencilOperation::Type stencilOperationOnZPass )
{
mStencilParameters.stencilOperationOnZPass = stencilOperationOnZPass;
+ mUpdated = true;
}
StencilOperation::Type Renderer::GetStencilOperationOnZPass() const
mAttributesLocation,
mIndexedDrawFirstElement,
mIndexedDrawElementsCount );
+
+ mUpdated = false;
}
}
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
*/
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;
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
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;
};
progress = SetProgress( progress );
}
+ if( mPropertyOwner )
+ {
+ mPropertyOwner->SetUpdated( true );
+ }
+
float alpha = ApplyAlphaFunction( progress );
// PropertyType specific part
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
OwnedPropertyContainer mCustomProperties; ///< Properties provided with InstallCustomProperty()
UniformMap mUniformMaps; ///< Container of owned uniform maps
+ bool mUpdated;
private:
* @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
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 );
}
}
viewMatrix,
camera,
isLayer3d,
- cull );
+ cull);
}
}
retValue = true;
}
}
+
return retValue;
}
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
}
/**
+ * 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
}
/**
+ * 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
*/
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
mNode = node;
}
+const Node* Camera::GetNode() const
+{
+ return mNode;
+}
+
void Camera::SetType( Dali::Camera::Type type )
{
mType = type;
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 );
--- /dev/null
+#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
${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
)
}
/**
+ * @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
*/
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;
}
/**
*/
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