mDataRetentionPolicy,
Integration::RenderToFrameBuffer::FALSE,
Integration::DepthBufferAvailable::TRUE,
- Integration::StencilBufferAvailable::TRUE );
+ Integration::StencilBufferAvailable::TRUE,
+ Integration::PartialUpdateAvailable::FALSE );
mCore->ContextCreated();
return mBackgroundColor;
}
+void TestRenderSurface::SetDamagedRect( const Dali::DamagedRect& damagedRect, Dali::DamagedRect& mergedRect )
+{
+}
+
+int32_t TestRenderSurface::GetBufferAge()
+{
+ return 0;
+}
+
} // Namespace dali
*/
virtual Vector4 GetBackgroundColor();
+ /**
+ * @copydoc Dali::Integration::RenderSurface::SetDamagedRect
+ */
+ virtual void SetDamagedRect( const Dali::DamagedRect& damagedRect, Dali::DamagedRect& mergedRect );
+
+ /**
+ * @copydoc Dali::Integration::RenderSurface::GetBufferAge
+ */
+ virtual int32_t GetBufferAge();
+
private:
/**
{ "inheritPosition", Actor::Property::INHERIT_POSITION, Property::BOOLEAN },
{ "clippingMode", Actor::Property::CLIPPING_MODE, Property::STRING },
{ "opacity", DevelActor::Property::OPACITY, Property::FLOAT },
+ { "updateSizeHint", DevelActor::Property::UPDATE_SIZE_HINT, Property::VECTOR2 },
};
const unsigned int PROPERTY_TABLE_COUNT = sizeof( PROPERTY_TABLE ) / sizeof( PROPERTY_TABLE[0] );
} // unnamed namespace
END_TEST;
}
+int UtcDaliActorUpdateSizeHint(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Vector3 vector(100.0f, 100.0f, 0.0f);
+
+ DALI_TEST_CHECK(vector != actor.GetCurrentSize());
+
+ actor.SetSize(vector.x, vector.y);
+
+
+ Vector2 updateSizeHint = Vector2(150.f, 150.f);
+ actor.SetProperty(Dali::DevelActor::Property::UPDATE_SIZE_HINT, updateSizeHint);
+
+ // Flush the queue and render once
+ application.SendNotification();
+ application.Render();
+
+
+ Vector2 currentSizeHint = actor.GetProperty( Dali::DevelActor::Property::UPDATE_SIZE_HINT ).Get< Vector2 >();
+ DALI_TEST_EQUALS( currentSizeHint, updateSizeHint, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+ // Flush the queue and render once
+ application.SendNotification();
+ application.Render();
+
+ END_TEST;
+}
+
int utcDaliEnsureRenderWhenRemovingLastRenderableActor(void)
{
TestApplication application;
* @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 When this value is set, the update area is determined by this value when a partial update.
+ * By default, render item size is used for partial update.
+ * It is scaled but not animated.
+ */
+ UPDATE_SIZE_HINT = INHERIT_LAYOUT_DIRECTION + 6,
};
} // namespace Property
TRUE
};
+/**
+ * @brief Enumerations to specify whether the partial update is available.
+ */
+enum class PartialUpdateAvailable
+{
+ FALSE = 0,
+ TRUE
+};
+
} // namespace Integration
} // namespace Dali
ResourcePolicy::DataRetention policy,
RenderToFrameBuffer renderToFboEnabled,
DepthBufferAvailable depthBufferAvailable,
- StencilBufferAvailable stencilBufferAvailable )
+ StencilBufferAvailable stencilBufferAvailable,
+ PartialUpdateAvailable partialUpdateAvailable )
{
Core* instance = new Core;
instance->mImpl = new Internal::Core( renderController,
policy,
renderToFboEnabled,
depthBufferAvailable,
- stencilBufferAvailable );
+ stencilBufferAvailable,
+ partialUpdateAvailable );
return instance;
}
* @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] partialUpdateAvailble whether the partial update is available
* @return A newly allocated Core.
*/
static Core* New( RenderController& renderController,
ResourcePolicy::DataRetention policy,
RenderToFrameBuffer renderToFboEnabled,
DepthBufferAvailable depthBufferAvailable,
- StencilBufferAvailable stencilBufferAvailable );
+ StencilBufferAvailable stencilBufferAvailable,
+ PartialUpdateAvailable partialUpdateAvailable );
/**
* Non-virtual destructor. Core is not intended as a base class.
*/
typedef Dali::Rect<int> PositionSize;
+/**
+ * @brief The Rect of partial updated area
+ */
+typedef Dali::Rect<int32_t> DamagedRect;
+
+
namespace Integration
{
*/
virtual Integration::StencilBufferAvailable GetStencilBufferRequired() = 0;
+ /**
+ * @brief Sets currentframe updated/damaged rects
+ * @return The Rect of partial updated area
+ */
+ virtual void SetDamagedRect( const DamagedRect& damagedRect, DamagedRect& mergedRect ) = 0;
+
+ /**
+ * @brief Gets buffer age
+ * @return current buffer age
+ */
+ virtual int32_t GetBufferAge() = 0;
+
private:
/**
ResourcePolicy::DataRetention dataRetentionPolicy,
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();
renderController,
*mRenderManager,
renderQueue,
- *mRenderTaskProcessor );
+ *mRenderTaskProcessor,
+ partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE );
mRenderManager->SetShaderSaver( *mUpdateManager );
ResourcePolicy::DataRetention dataRetentionPolicy,
Integration::RenderToFrameBuffer renderToFboEnabled,
Integration::DepthBufferAvailable depthBufferAvailable,
- Integration::StencilBufferAvailable stencilBufferAvailable );
+ Integration::StencilBufferAvailable stencilBufferAvailable,
+ Integration::PartialUpdateAvailable partialUpdateAvailable );
/**
* Destructor
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, true, 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
return FLT_MAX; // Default
}
+void Actor::SetUpdateSizeHint( const Vector2& updateSizeHint )
+{
+ // node is being used in a separate thread; queue a message to set the value & base value
+ SceneGraph::NodeTransformPropertyMessage<Vector3>::Send( GetEventThreadServices(), &GetNode(), &GetNode().mUpdateSizeHint, &SceneGraph::TransformManagerPropertyHandler<Vector3>::Bake, Vector3(updateSizeHint.width, updateSizeHint.height, 0.f ) );
+}
+
+Vector2 Actor::GetUpdateSizeHint() const
+{
+ // node is being used in a separate thread; copy the value from the previous update
+ Vector3 updateSizeHint = Vector3::ZERO;
+ GetNode().GetUpdateSizeHint( GetEventThreadServices().GetEventBufferIndex(), updateSizeHint );
+ return Vector2( updateSizeHint.width, updateSizeHint.height );
+}
+
Object* Actor::GetParentObject() const
{
return mParent;
float GetMaximumSize( Dimension::Type dimension ) const;
/**
+ * @brief Sets the update size hint of an actor for partial update.
+ * @param [in] updateSizeHint The new updateSizeHint.
+ */
+ void SetUpdateSizeHint( const Vector2& updateSizeHint );
+
+ /**
+ * @brief Return the update size hint of actor
+ * @return Return the update size hint
+ */
+ Vector2 GetUpdateSizeHint() const;
+
+ /**
* @copydoc Dali::Actor::AddRenderer()
*/
uint32_t AddRenderer( Renderer& renderer );
void Scene::Remove(Actor& actor)
{
mRootLayer->Remove( actor );
+ if( mSurface )
+ {
+ mRenderTaskList->GetTask( 0u )->GetFrameBuffer()->SetPartialUpdateEnabled( false );
+ }
}
Size Scene::GetSize() const
}
}
+void FrameBuffer::SetPartialUpdateEnabled( bool value )
+{
+ if( mRenderObject->IsSurfaceBacked() )
+ {
+ SetFrameBufferPartialUpdateMessage( mEventThreadServices.GetUpdateManager(), static_cast<Render::SurfaceFrameBuffer*>( mRenderObject ), value );
+ }
+}
+
+
FrameBuffer::~FrameBuffer()
{
if( EventThreadServices::IsCoreRunning() && mRenderObject )
*/
void MarkSurfaceAsInvalid();
+ /**
+ * @brief Sets whether to enable partial update.
+ * @param[in] value whether partial update or not
+ */
+ void SetPartialUpdateEnabled( bool value );
+
private: // implementation
/**
Integration::DepthBufferAvailable depthBufferAvailable,
Integration::StencilBufferAvailable stencilBufferAvailable,
Vector<GLuint>& boundTextures,
- int orientation )
+ int orientation,
+ Dali::ClippingBox& scissorBox )
{
DALI_PRINT_RENDER_LIST( renderList );
mScissorStack.push_back( layerScissorBox );
mHasLayerScissor = true;
}
+ else if ( !scissorBox.IsEmpty() )
+ {
+ context.SetScissorTest( true );
+ context.Scissor( scissorBox.x, scissorBox.y, scissorBox.width, scissorBox.height );
+ mScissorStack.push_back( scissorBox );
+ }
else
{
// We are not performing a layer clip. Add the viewport as the root scissor rectangle.
Integration::DepthBufferAvailable depthBufferAvailable,
Integration::StencilBufferAvailable stencilBufferAvailable,
Vector<GLuint>& boundTextures,
- int orientation )
+ int orientation,
+ Dali::ClippingBox& scissorBox )
{
DALI_PRINT_RENDER_INSTRUCTION( instruction, bufferIndex );
depthBufferAvailable,
stencilBufferAvailable,
boundTextures,
- orientation );
+ orientation,
+ scissorBox );
}
}
}
* @param[in] depthBufferAvailable Whether the depth buffer is available
* @param[in] stencilBufferAvailable Whether the stencil buffer is available
* @param[in] boundTextures The textures bound for rendering
+ * @param[in] scissorBox The damaged rect for partial update
*/
void ProcessRenderInstruction( const SceneGraph::RenderInstruction& instruction,
Context& context,
Integration::DepthBufferAvailable depthBufferAvailable,
Integration::StencilBufferAvailable stencilBufferAvailable,
Vector<GLuint>& boundTextures,
- int orientation);
+ int orientation,
+ Dali::ClippingBox& scissorBox );
private:
* @param[in] depthBufferAvailable Whether the depth buffer is available
* @param[in] stencilBufferAvailable Whether the stencil buffer is available
* @param[in] boundTextures The textures bound for rendering
+ * @param[in] scissorBox The damaged rect for partial update
*/
inline void ProcessRenderList( const Dali::Internal::SceneGraph::RenderList& renderList,
Context& context,
Integration::DepthBufferAvailable depthBufferAvailable,
Integration::StencilBufferAvailable stencilBufferAvailable,
Vector<GLuint>& boundTextures,
- int orientation );
+ int orientation,
+ Dali::ClippingBox& scissorBox );
// Prevent copying:
RenderAlgorithms( RenderAlgorithms& rhs );
: mModelMatrix( false ),
mModelViewMatrix( false ),
mSize(),
+ mUpdateSizeHint(),
mRenderer( NULL ),
mNode( NULL ),
mTextureSet( NULL ),
mDepthIndex( 0 ),
- mIsOpaque( true )
+ mIsOpaque( true ),
+ mPartialUpdateEnabled( false )
{
}
}
-ClippingBox RenderItem::CalculateViewportSpaceAABB( const int viewportWidth, const int viewportHeight ) const
+ClippingBox RenderItem::CalculateViewportSpaceAABB( const int viewportWidth, const int viewportHeight, const bool useUpdateSizeHint ) const
{
// Calculate extent vector of the AABB:
- const float halfActorX = mSize.x * 0.5f;
- const float halfActorY = mSize.y * 0.5f;
+ float halfActorX;
+ float halfActorY;
+ if( useUpdateSizeHint )
+ {
+ halfActorX = mUpdateSizeHint.x * 0.5f;
+ halfActorY = mUpdateSizeHint.y * 0.5f;
+ }
+ else
+ {
+ halfActorX = mSize.x * 0.5f;
+ halfActorY = mSize.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).
*
* @param[in] viewportWidth The width of the viewport to calculate for
* @param[in] viewportHeight The height of the viewport to calculate for
+ * @param[in] useUpdateSizeHint Set to true if you want to use update size hint instead of item size
* @return The AABB coordinates in viewport-space (x, y, width, height)
*/
- ClippingBox CalculateViewportSpaceAABB( const int viewportWidth, const int viewportHeight ) const;
+ ClippingBox CalculateViewportSpaceAABB( const int viewportWidth, const int viewportHeight, const bool useUpdateSizeHint = false ) const;
/**
* Overriden delete operator.
Matrix mModelMatrix;
Matrix mModelViewMatrix;
Vector3 mSize;
+ Vector3 mUpdateSizeHint;
Render::Renderer* mRenderer;
Node* mNode;
const void* mTextureSet; //< Used for sorting only
int mDepthIndex;
bool mIsOpaque:1;
+ bool mPartialUpdateEnabled:1;
private:
: mNextFree( 0 ),
mClippingBox( NULL ),
mSourceLayer( NULL ),
- mHasColorRenderItems( false )
+ mHasColorRenderItems( false ),
+ mPartialUpdateEnabled( false )
{
}
return mHasColorRenderItems;
}
+ /**
+ * Enable/Disable Partial update dirty flag
+ * @param[in] true to mark dirty else false
+ */
+ void SetPartialUpdateEnabled( bool value )
+ {
+ mPartialUpdateEnabled = value;
+ }
+
+ /**
+ * Get Partial update dirty flag
+ * @return true if dirty else false
+ */
+ bool IsPartialUpdateEnabled() const
+ {
+ return mPartialUpdateEnabled;
+ }
+
private:
/*
ClippingBox* mClippingBox; ///< The clipping box, in window coordinates, when clipping is enabled
Layer* mSourceLayer; ///< The originating layer where the renderers are from
bool mHasColorRenderItems : 1; ///< True if list contains color render items
+ bool mPartialUpdateEnabled : 1; //< True if partial update is needed.
};
} // unnamed namespace
#endif
+namespace
+{
+const float partialUpdateRatio = 0.8f; // If the partial update area exceeds 80%, change to full update.
+
+/**
+ * @brief Find the intersection of two AABB rectangles.
+ * This is a logical AND operation. IE. The intersection is the area overlapped by both rectangles.
+ * @param[in] aabbA Rectangle A
+ * @param[in] aabbB Rectangle B
+ * @return The intersection of rectangle A & B (result is a rectangle)
+ */
+inline ClippingBox IntersectAABB( const ClippingBox& aabbA, const ClippingBox& aabbB )
+{
+ ClippingBox intersectionBox;
+
+ // First calculate the largest starting positions in X and Y.
+ intersectionBox.x = std::max( aabbA.x, aabbB.x );
+ intersectionBox.y = std::max( aabbA.y, aabbB.y );
+
+ // Now calculate the smallest ending positions, and take the largest starting
+ // positions from the result, to get the width and height respectively.
+ // If the two boxes do not intersect at all, then we need a 0 width and height clipping area.
+ // We use max here to clamp both width and height to >= 0 for this use-case.
+ intersectionBox.width = std::max( std::min( aabbA.x + aabbA.width, aabbB.x + aabbB.width ) - intersectionBox.x, 0 );
+ intersectionBox.height = std::max( std::min( aabbA.y + aabbA.height, aabbB.y + aabbB.height ) - intersectionBox.y, 0 );
+
+ return intersectionBox;
+}
+
+}
+
/**
* 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, &surfaceContextContainer ),
currentContext( &context ),
glAbstraction( glAbstraction ),
programController( glAbstraction ),
depthBufferAvailable( depthBufferAvailableParam ),
stencilBufferAvailable( stencilBufferAvailableParam ),
+ partialUpdateAvailable( partialUpdateAvailableParam ),
defaultSurfaceOrientation( 0 )
{
// Create thread pool with just one thread ( there may be a need to create more threads in the future ).
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
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;
}
DALI_PRINT_RENDER_END();
}
+bool GetDamagedRect( Rect<int32_t> &viewportRect, RenderInstruction& instruction, Rect<int32_t> &damagedRect )
+{
+ // merge bounding
+ int dx1 = viewportRect.width, dx2 = 0, dy1 = viewportRect.height, dy2 = 0;
+ int checkWidth = static_cast<int>( static_cast<float>( viewportRect.width ) * partialUpdateRatio );
+ int checkHeight = static_cast<int>( static_cast<float>( viewportRect.height ) * partialUpdateRatio );
+ Rect<int32_t> screenRect;
+
+ bool isPartialUpdate = false;
+
+ const RenderListContainer::SizeType renderListCount = instruction.RenderListCount();
+ // Iterate through each render list.
+
+ for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index )
+ {
+ const RenderList* renderList = instruction.GetRenderList( index );
+
+ if( renderList && !renderList->IsEmpty() && renderList->IsPartialUpdateEnabled() )
+ {
+ const std::size_t itemCount = renderList->Count();
+ for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex )
+ {
+ const RenderItem& item = renderList->GetItem( itemIndex );
+
+ if( item.mPartialUpdateEnabled )
+ {
+ isPartialUpdate = true;
+
+ screenRect = item.CalculateViewportSpaceAABB( viewportRect.width, viewportRect.height, true );
+
+ dx1 = std::min( screenRect.x, dx1 );
+ dx2 = std::max( screenRect.x + screenRect.width, dx2);
+ dy1 = std::min( screenRect.y, dy1 );
+ dy2 = std::max( screenRect.y + screenRect.height, dy2 );
+
+ if( ( dx2 - dx1 ) > checkWidth && ( dy2 - dy1 ) > checkHeight )
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if( isPartialUpdate )
+ {
+ if( dx1 < 0.0f )
+ {
+ dx1 = 0.0f;
+ }
+ if( dy1 < 0.0f )
+ {
+ dy1 = 0.0f;
+ }
+ if( dx2 > viewportRect.width )
+ {
+ dx2 = viewportRect.width;
+ }
+ if( dy2 > viewportRect.height )
+ {
+ dy2 = viewportRect.height;
+ }
+
+ damagedRect.x = dx1;
+ damagedRect.y = dy1;
+ damagedRect.width = dx2 - dx1;
+ damagedRect.height = dy2 - dy1;
+ }
+
+ return isPartialUpdate;
+}
+
void RenderManager::DoRender( RenderInstruction& instruction )
{
Rect<int32_t> viewportRect;
Vector4 clearColor;
+ bool isPartialUpdate = false;
+ Dali::DamagedRect damagedRect;
+ Dali::DamagedRect mergedRect;
+ Dali::ClippingBox scissorBox;
+ Dali::ClippingBox intersectRect;
if ( instruction.mIsClearColorSet )
{
int surfaceOrientation = mImpl->defaultSurfaceOrientation;
Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable;
Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
+ Integration::PartialUpdateAvailable partialUpdateAvailable = mImpl->partialUpdateAvailable;
Render::SurfaceFrameBuffer* surfaceFrameBuffer = nullptr;
if ( instruction.mFrameBuffer != 0 )
mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u );
}
+
+ if( surfaceFrameBuffer &&
+ partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE )
+ {
+ // Iterate through each render list.
+ if( surfaceFrameBuffer->IsPartialUpdateEnabled() )
+ {
+ isPartialUpdate = GetDamagedRect( surfaceRect, instruction, damagedRect ) ;
+ }
+
+ if( !isPartialUpdate )
+ {
+ damagedRect = surfaceRect;
+ }
+
+ surfaceFrameBuffer->SetDamagedRect( damagedRect, mergedRect );
+
+ if( mergedRect.IsEmpty() )
+ {
+ isPartialUpdate = false;
+ }
+ else
+ {
+ scissorBox.x = mergedRect.x;
+ scissorBox.y = mergedRect.y;
+ scissorBox.width = mergedRect.width;
+ scissorBox.height = mergedRect.height;
+ }
+ }
+
if ( surfaceFrameBuffer )
{
mImpl->currentContext->Viewport( surfaceRect.x,
if( !clearFullFrameRect )
{
mImpl->currentContext->SetScissorTest( true );
- mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height );
+ if( isPartialUpdate )
+ {
+ intersectRect = IntersectAABB( scissorBox, viewportRect );
+ mImpl->currentContext->Scissor( intersectRect.x, intersectRect.y, intersectRect.width, intersectRect.height );
+ }
+ else
+ {
+ mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height );
+ }
mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR );
mImpl->currentContext->SetScissorTest( false );
}
depthBufferAvailable,
stencilBufferAvailable,
mImpl->boundTextures,
- surfaceOrientation );
+ surfaceOrientation,
+ scissorBox );
// 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
mWidth( mSurface->GetPositionSize().width ),
mHeight( mSurface->GetPositionSize().height ),
mSizeChanged( false ),
- mIsSurfaceInvalid( false )
+ mIsSurfaceInvalid( false ),
+ mPartialUpdateEnabled( true )
{
}
}
mSizeChanged = false;
+ mPartialUpdateEnabled = true;
+}
+
+void SurfaceFrameBuffer::SetDamagedRect( const Dali::DamagedRect& damagedRect, Dali::DamagedRect& mergedRect )
+{
+ if ( IsSurfaceValid() )
+ {
+ mSurface->SetDamagedRect( damagedRect, mergedRect );
+ }
}
Context* SurfaceFrameBuffer::GetContext()
return mSurface && !mIsSurfaceInvalid;
}
+bool SurfaceFrameBuffer::IsPartialUpdateEnabled() const
+{
+ bool ret = false;
+ if ( IsSurfaceValid() )
+ {
+ ret = mSurface->GetBufferAge() && ( mPartialUpdateEnabled && !mSizeChanged );
+ }
+ return ret;
+}
+
+void SurfaceFrameBuffer::SetPartialUpdateEnabled( bool value )
+{
+ mPartialUpdateEnabled = value;
+}
+
} //Render
} //Internal
*/
void MakeContextCurrent();
+ /**
+ * @brief Sets currentframe damaged rects
+ * @param[in] Sets currentframe damaged rects
+ * @param[out] return merged rect
+ */
+ void SetDamagedRect( const Dali::DamagedRect& damagedRect, Dali::DamagedRect& mergedRect );
+
+ /**
+ * @brief Gets whether partial update is required for partial update
+ * @return whether partial update or not
+ */
+ bool IsPartialUpdateEnabled() const;
+
+ /**
+ * @brief Sets whether partial update is required for partial update
+ * @param[in] value whether partial update or not
+ */
+ void SetPartialUpdateEnabled( bool value );
+
private:
Integration::RenderSurface* mSurface; ///< The render surface
uint32_t mHeight;
bool mSizeChanged;
std::atomic<bool> mIsSurfaceInvalid; ///< This is set only from the event thread and read only from the render thread
+ bool mPartialUpdateEnabled; ///< This value is whether partial update is required
};
// Messages for FrameBuffer
new (slot) LocalType( surfaceFrameBuffer, &SurfaceFrameBuffer::SetSize, width, height );
}
+inline void SetFrameBufferPartialUpdateMessage( SceneGraph::UpdateManager& updateManager, SurfaceFrameBuffer* surfaceFrameBuffer, bool value )
+{
+ typedef MessageValue1< SurfaceFrameBuffer, bool > LocalType;
+
+ // Reserve some memory inside the message queue
+ uint32_t* slot = updateManager.ReserveMessageSlot( sizeof( LocalType ) );
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new (slot) LocalType( surfaceFrameBuffer, &SurfaceFrameBuffer::SetPartialUpdateEnabled, value );
+}
+
} // namespace Render
} // namespace Internal
progress = SetProgress( progress );
}
+ if( mPropertyOwner )
+ {
+ mPropertyOwner->SetPropertyDirty( true );
+ }
+
float alpha = ApplyAlphaFunction( progress );
// PropertyType specific part
*/
virtual void Process( BufferIndex updateBufferIndex )
{
+ mSceneObject->SetPropertyDirty( true );
(mProperty->*mMemberFunction)( updateBufferIndex, mParam );
}
*/
virtual void Process( BufferIndex updateBufferIndex )
{
+ mSceneObject->SetPropertyDirty( true );
(mProperty->*mMemberFunction)( updateBufferIndex, mParam );
}
}
PropertyOwner::PropertyOwner()
+:mPropertyDirty( false )
{
}
mUniformMaps.RemoveObserver( observer );
}
+void PropertyOwner::SetPropertyDirty( bool value )
+{
+ mPropertyDirty = value;
+}
+bool PropertyOwner::IsPropertyDirty() const
+{
+ return mPropertyDirty;
+}
} // namespace SceneGraph
*/
void RemoveUniformMapObserver( UniformMap::Observer& observer );
+ /**
+ * Set whether property has changed to run following a render.
+ * @param[in] value Set to true if the property has changed
+ */
+ virtual void SetPropertyDirty( bool value );
+
+ /**
+ * Query the property status following rendering of a frame.
+ * @return True if the property has changed
+ */
+ virtual bool IsPropertyDirty() const;
+
protected:
OwnedPropertyContainer mCustomProperties; ///< Properties provided with InstallCustomProperty()
UniformMap mUniformMaps; ///< Container of owned uniform maps
+ bool mPropertyDirty:1; ///< Required for marking it dirty in case of partial update.
private:
#include <dali/internal/render/renderers/render-renderer.h>
#include <dali/internal/render/renderers/render-property-buffer.h>
#include <dali/internal/update/nodes/scene-graph-layer.h>
+#include <dali/internal/common/math.h>
namespace
{
{
bool inside( true );
Node* node = renderable.mNode;
-
- if( cull && renderable.mRenderer && !renderable.mRenderer->GetShader().HintEnabled( Dali::Shader::Hint::MODIFIES_GEOMETRY ) )
+ bool geomertryModified = false;
+ if( cull && renderable.mRenderer && !( geomertryModified = renderable.mRenderer->GetShader().HintEnabled( Dali::Shader::Hint::MODIFIES_GEOMETRY ) ) )
{
const Vector4& boundingSphere = node->GetBoundingSphere();
inside = ( boundingSphere.w > Math::MACHINE_EPSILON_1000 ) &&
item.mNode = renderable.mNode;
item.mIsOpaque = ( opacityType == Renderer::OPAQUE );
item.mDepthIndex = 0;
+ item.mPartialUpdateEnabled = false;
- if(!isLayer3d)
+ if( !isLayer3d )
{
item.mDepthIndex = renderable.mNode->GetDepthIndex();
}
+ if( isLayer3d || geomertryModified )
+ {
+ renderList.SetPartialUpdateEnabled( false );
+ }
if( DALI_LIKELY( renderable.mRenderer ) )
{
item.mRenderer = &renderable.mRenderer->GetRenderer();
item.mTextureSet = renderable.mRenderer->GetTextures();
item.mDepthIndex += renderable.mRenderer->GetDepthIndex();
+
+ if( FaceCullingMode::NONE != renderable.mRenderer->GetFaceCullingMode() )
+ {
+ renderList.SetPartialUpdateEnabled( false );
+ }
}
else
{
node->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize );
Matrix::Multiply( item.mModelViewMatrix, item.mModelMatrix, viewMatrix );
- }
- node->SetCulled( updateBufferIndex, false );
+ if( node->IsPartialUpdateAvailable() && DALI_LIKELY( item.mRenderer ) && renderList.IsPartialUpdateEnabled() )
+ {
+ if( node->IsComponentChanged() || node->IsPropertyDirty() )
+ {
+ item.mPartialUpdateEnabled = true;
+
+ item.mUpdateSizeHint = item.mSize;
+ Vector3 updateSizeHint = Vector3::ZERO;
+ node->GetUpdateSizeHint( updateBufferIndex, updateSizeHint );
+ if( updateSizeHint != Vector3::ZERO )
+ {
+ item.mUpdateSizeHint = updateSizeHint;
+ }
+ }
+ }
+ }
+ node->SetCulled( updateBufferIndex, false );
}
else
{
- node->SetCulled( updateBufferIndex, true );
+ node->SetCulled( updateBufferIndex, true );
}
}
if( !SetupRenderList( renderables, layer, instruction, tryReuseRenderList, &renderList ) )
{
renderList->SetHasColorRenderItems( true );
+ if( !isLayer3D )
+ {
+ renderList->SetPartialUpdateEnabled( true );
+ }
AddRenderersToRenderList( updateBufferIndex,
*renderList,
renderables,
if( !SetupRenderList( renderables, layer, instruction, tryReuseRenderList, &renderList ) )
{
renderList->SetHasColorRenderItems( false );
+ if( !isLayer3D )
+ {
+ renderList->SetPartialUpdateEnabled( true );
+ }
AddRenderersToRenderList( updateBufferIndex,
*renderList,
renderables,
mSizeBase.PushBack(Vector3(0.0f,0.0f,0.0f));
mComponentDirty.PushBack(false);
mLocalMatrixDirty.PushBack(false);
+ mComponentChanged.PushBack(false);
+ mPrevWorld.PushBack(Matrix::IDENTITY);
+ mUpdateSizeHint.PushBack(Vector3(0.0f,0.0f,0.0f));
+ mUpdateSizeHintBase.PushBack(Vector3(0.0f,0.0f,0.0f));
}
else
{
mSizeBase[mComponentCount] = Vector3(0.0f,0.0f,0.0f);
mComponentDirty[mComponentCount] = false;
mLocalMatrixDirty[mComponentCount] = false;
+ mComponentChanged[mComponentCount] = false;
+ mPrevWorld[mComponentCount].SetIdentity();
+ mUpdateSizeHint[mComponentCount] = Vector3(0.0f,0.0f,0.0f);
+ mUpdateSizeHintBase[mComponentCount] = Vector3(0.0f,0.0f,0.0f);
}
mComponentCount++;
mComponentDirty[index] = mComponentDirty[mComponentCount];
mLocalMatrixDirty[index] = mLocalMatrixDirty[mComponentCount];
mBoundingSpheres[index] = mBoundingSpheres[mComponentCount];
+ mComponentChanged[index] = mComponentChanged[mComponentCount];
+ mPrevWorld[index] = mPrevWorld[mComponentCount];
+ mUpdateSizeHint[index] = mUpdateSizeHint[mComponentCount];
+ mUpdateSizeHintBase[index] = mUpdateSizeHintBase[mComponentCount];
TransformId lastItemId = mComponentId[mComponentCount];
mIds[ lastItemId ] = index;
{
mInheritanceMode[ index ] &= ~INHERIT_ORIENTATION;
}
-
mComponentDirty[index] = true;
}
memcpy( &mTxComponentAnimatable[0], &mTxComponentAnimatableBaseValue[0], sizeof(TransformComponentAnimatable)*mComponentCount );
memcpy( &mSize[0], &mSizeBase[0], sizeof(Vector3)*mComponentCount );
memset( &mLocalMatrixDirty[0], false, sizeof(bool)*mComponentCount );
+ memcpy( &mUpdateSizeHint[0], &mUpdateSizeHintBase[0], sizeof(Vector3)*mComponentCount );
}
}
const Vector3 topLeft( 0.0f, 0.0f, 0.5f );
for( unsigned int i(0); i<mComponentCount; ++i )
{
+ mPrevWorld[i] = mWorld[i];
+
if( DALI_LIKELY( mInheritanceMode[i] != DONT_INHERIT_TRANSFORM && mParent[i] != INVALID_TRANSFORM_ID ) )
{
const TransformId& parentIndex = mIds[mParent[i] ];
mBoundingSpheres[i] = mWorld[i].GetTranslation();
mBoundingSpheres[i].w = Length( centerToEdgeWorldSpace );
+ mComponentChanged[i] = false;
+
+ // Due to parent transformation child transformation could be changed
+ if( mComponentDirty[i] ||
+ mPrevWorld[i] != mWorld[i] )
+ {
+ mComponentChanged[i] = true;
+ }
+
mComponentDirty[i] = false;
+
}
}
std::swap( mComponentDirty[i], mComponentDirty[j] );
std::swap( mBoundingSpheres[i], mBoundingSpheres[j] );
std::swap( mWorld[i], mWorld[j] );
+ std::swap( mComponentChanged[i], mComponentChanged[j] );
+ std::swap( mPrevWorld[i], mPrevWorld[j] );
+ std::swap( mUpdateSizeHint[i], mUpdateSizeHint[j] );
+ std::swap( mUpdateSizeHintBase[i], mUpdateSizeHintBase[j] );
mIds[ mComponentId[i] ] = i;
mIds[ mComponentId[j] ] = j;
mComponentDirty[ index ] = true;
return mSize[ index ];
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ TransformId index( mIds[id] );
+ mComponentDirty[ index ] = true;
+ return mUpdateSizeHint[ index ];
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
{
return mSize[ mIds[id] ];
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ return mUpdateSizeHint[ mIds[id] ];
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
{
return mSize[ mIds[id] ][component];
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ return mUpdateSizeHint[ mIds[id] ][component];
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ] = value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ] = value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ][component] = value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ][component] = value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ] = mSizeBase[index] = value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ] = mUpdateSizeHintBase[index] = value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ] = mSizeBase[index] = mSize[ index ] + value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ] = mUpdateSizeHintBase[index] = mUpdateSizeHint[ index ] + value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ] = mSizeBase[index] = mSize[ index ] * value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ] = mUpdateSizeHintBase[index] = mUpdateSizeHint[ index ] * value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ][component] = mSizeBase[index][component] = value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ][component] = mUpdateSizeHintBase[index][component] = value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ].x = mSizeBase[index].x = value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ].x = mUpdateSizeHintBase[index].x = value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ].y = mSizeBase[index].y = value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ].y = mUpdateSizeHintBase[index].y = value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
mSize[ index ].z = mSizeBase[index].z = value;
break;
}
+ case TRANSFORM_PROPERTY_UPDATE_SIZE_HINT:
+ {
+ mUpdateSizeHint[ index ].z = mUpdateSizeHintBase[index].z = value;
+ break;
+ }
default:
{
DALI_ASSERT_ALWAYS(false);
return mBoundingSpheres[ mIds[id] ];
}
+bool TransformManager::IsComponentChanged( TransformId id ) const
+{
+ return mComponentChanged[ mIds[id]];
+}
+
void TransformManager::GetWorldMatrixAndSize( TransformId id, Matrix& worldMatrix, Vector3& size ) const
{
TransformId index = mIds[id];
size = mSize[index];
}
+void TransformManager::GetUpdateSizeHint( TransformId id, Vector3& updateSizeHint ) const
+{
+ updateSizeHint = mUpdateSizeHint[ mIds[id] ] * mTxComponentAnimatable[mIds[ id ] ].mScale;
+}
+
void TransformManager::SetPositionUsesAnchorPoint( TransformId id, bool value )
{
TransformId index( mIds[ id ] );
TRANSFORM_PROPERTY_WORLD_SCALE,
TRANSFORM_PROPERTY_WORLD_ORIENTATION,
TRANSFORM_PROPERTY_WORLD_MATRIX,
+ TRANSFORM_PROPERTY_UPDATE_SIZE_HINT,
TRANSFORM_PROPERTY_COUNT,
};
const Vector4& GetBoundingSphere( TransformId id ) const;
/**
+ * Component of node is changed or not
+ * @param[in] id Id of the transform component
+ * @return true if Component box is changed else false.
+ */
+ bool IsComponentChanged( TransformId id ) const;
+
+ /**
* Get the world matrix and size of a given component
* @param[in] id Id of the transform component
* @param[out] The world matrix of the component
void GetWorldMatrixAndSize( TransformId id, Matrix& worldMatrix, Vector3& size ) const;
/**
+ * Get the update size hint,
+ * @param[in] id Id of the transform component
+ * @param[out] The update size hint of the component
+ */
+ void GetUpdateSizeHint( TransformId id, Vector3& updateSizeHint ) const;
+
+
+ /**
* @brief Sets the boolean which states whether the position should use the anchor-point on the given transform component.
* @param[in] id Id of the transform component
* @param[in] value True if the position should use the anchor-point
Vector< Vector3 > mSize; ///< Size of the components
Vector< TransformId > mParent; ///< Parent of the components
Vector< Matrix > mWorld; ///< Local to world transform of the components
+ Vector< Matrix > mPrevWorld; ///< Local to world transform of the components in last frame
Vector< Matrix > mLocal; ///< Local to parent space transform of the components
Vector< Vector4 > mBoundingSpheres; ///< Bounding spheres. xyz is the center and w is the radius
Vector< TransformComponentAnimatable > mTxComponentAnimatableBaseValue; ///< Base values for the animatable part of the components
Vector< bool > mComponentDirty; ///< 1u if some of the parts of the component has changed in this frame, 0 otherwise
Vector< bool > mLocalMatrixDirty; ///< 1u if the local matrix has been updated in this frame, 0 otherwise
Vector< SOrderItem > mOrderedComponents; ///< Used to reorder components when hierarchy changes
+ Vector< bool> mComponentChanged; ///< Component is changed or not
+ Vector< Vector3 > mUpdateSizeHint; ///< BoundingBox of the components
+ Vector< Vector3 > mUpdateSizeHintBase; ///< Base value for the boundingBox of the components
bool mReorder; ///< Flag to determine if the components have to reordered in the next Update
};
RenderManager& renderManager,
RenderQueue& renderQueue,
SceneGraphBuffers& sceneGraphBuffers,
- RenderTaskProcessor& renderTaskProcessor )
+ RenderTaskProcessor& renderTaskProcessor,
+ bool partialUpdateAvailable )
: renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
notificationManager( notificationManager ),
transformManager(),
previousUpdateScene( false ),
renderTaskWaiting( false ),
renderersAdded( false ),
- surfaceRectChanged( false )
+ surfaceRectChanged( false ),
+ partialUpdateAvailable( partialUpdateAvailable )
{
sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue );
bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered
bool renderersAdded; ///< Flag to keep track when renderers have been added to avoid unnecessary processing
bool surfaceRectChanged; ///< True if the default surface rect is changed
+ bool partialUpdateAvailable; ///< Whether the partial update is available
private:
RenderController& controller,
RenderManager& renderManager,
RenderQueue& renderQueue,
- RenderTaskProcessor& renderTaskProcessor )
+ RenderTaskProcessor& renderTaskProcessor,
+ bool partialUpdateAvailable )
: mImpl(NULL)
{
mImpl = new Impl( notificationManager,
renderManager,
renderQueue,
mSceneGraphBuffers,
- renderTaskProcessor );
+ renderTaskProcessor,
+ partialUpdateAvailable );
}
{
mImpl->nodes.Insert((iter+1), rawNode );
rawNode->CreateTransform( &mImpl->transformManager );
+ rawNode->SetPartialUpdateAvailable( mImpl->partialUpdateAvailable );
return;
}
}
parent->ConnectChild( node );
+ parent->SetPropertyDirty( true );
+
// Inform the frame-callback-processor, if set, about the node-hierarchy changing
if( mImpl->frameCallbackProcessor )
{
* @param[in] renderManager This is responsible for rendering the results of each "update".
* @param[in] renderQueue Used to queue messages for the next render.
* @param[in] renderTaskProcessor Handles RenderTasks and RenderInstrucitons.
+ * @param[in] partialUpdateAvailble whether the partial update is available
*/
UpdateManager( NotificationManager& notificationManager,
CompleteNotificationInterface& animationPlaylist,
Integration::RenderController& controller,
RenderManager& renderManager,
RenderQueue& renderQueue,
- RenderTaskProcessor& renderTaskProcessor );
+ RenderTaskProcessor& renderTaskProcessor,
+ bool partialUpdateAvailable );
/**
* Destructor.
*/
virtual void Process( BufferIndex updateBufferIndex )
{
+ mNode->SetPropertyDirty( true );
(mProperty->*mMemberFunction)( updateBufferIndex, mParam );
}
*/
virtual void Process( BufferIndex updateBufferIndex )
{
+ mNode->SetPropertyDirty( true );
(mProperty->*mMemberFunction)( updateBufferIndex, mParam );
}
*/
virtual void Process( BufferIndex updateBufferIndex )
{
+ mNode->SetPropertyDirty( true );
(mProperty->*mMemberFunction)( updateBufferIndex, mParam );
}
*/
virtual void Process( BufferIndex updateBufferIndex )
{
+ mNode->SetPropertyDirty( true );
(mProperty->*mMemberFunction)( updateBufferIndex, mParam );
}
mPosition( TRANSFORM_PROPERTY_POSITION ), // Zero initialized by default
mOrientation(), // Initialized to identity by default
mScale( TRANSFORM_PROPERTY_SCALE ),
+ mUpdateSizeHint( TRANSFORM_PROPERTY_UPDATE_SIZE_HINT ),
mVisible( true ),
mCulled( false ),
mColor( Color::WHITE ),
mClippingMode( ClippingMode::DISABLED ),
mIsRoot( false ),
mIsLayer( false ),
- mPositionUsesAnchorPoint( true )
+ mPositionUsesAnchorPoint( true ),
+ mPartialUpdateAvailable( false )
{
mUniformMapChanged[0] = 0u;
mUniformMapChanged[1] = 0u;
+ mPropertyDirty = true;
#ifdef DEBUG_ENABLED
gNodeCount++;
//Initialize all the animatable properties
mPosition.Initialize( transformManager, mTransformId );
mScale.Initialize( transformManager, mTransformId );
+ mUpdateSizeHint.Initialize( transformManager, mTransformId );
mOrientation.Initialize( transformManager, mTransformId );
mSize.Initialize( transformManager, mTransformId );
mParentOrigin.Initialize( transformManager, mTransformId );
}
mRenderer.PushBack( renderer );
+ SetPropertyDirty( true );
}
+
void Node::RemoveRenderer( const Renderer* renderer )
{
+ Node *parent = mIsRoot ? NULL : GetParent();
RendererContainer::SizeType rendererCount( mRenderer.Size() );
for( RendererContainer::SizeType i = 0; i < rendererCount; ++i )
{
if( mRenderer[i] == renderer )
{
+ if( parent != NULL )
+ {
+ parent->mPropertyDirty = true;
+ }
+ SetPropertyDirty( true );
mRenderer.Erase( mRenderer.Begin()+i);
return;
}
void Node::ResetDirtyFlags( BufferIndex updateBufferIndex )
{
mDirtyFlags = NodePropertyFlags::NOTHING;
+
+ SetPropertyDirty( false );
+
}
void Node::SetParent( Node& parentNode )
mTransformManager->SetParent( mTransformId, INVALID_TRANSFORM_ID );
}
}
+void Node::SetPartialUpdateAvailable( bool value )
+{
+ mPartialUpdateAvailable = value;
+}
+
+bool Node::IsPartialUpdateAvailable() const
+{
+ return mPartialUpdateAvailable;
+}
+
+void Node::SetPropertyDirty( bool value )
+{
+ if( mPartialUpdateAvailable )
+ {
+ mPropertyDirty = value;
+
+ const NodeIter endIter = mChildren.End();
+ for ( NodeIter iter = mChildren.Begin(); iter != endIter; ++iter )
+ {
+ Node* current = *iter;
+ current->SetPropertyDirty( value );
+ }
+ }
+}
+
+bool Node::IsPropertyDirty() const
+{
+ if( mPartialUpdateAvailable )
+ {
+ if( !mPropertyDirty )
+ {
+ for( auto&& existingRenderer : mRenderer )
+ {
+ if( existingRenderer->IsDirty() )
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return mPropertyDirty;
+}
} // namespace SceneGraph
*/
void SetClippingMode( const ClippingMode::Type clippingMode )
{
+ SetPropertyDirty( true );
mClippingMode = clippingMode;
}
*/
void SetDirtyFlag( NodePropertyFlags flag )
{
+ SetPropertyDirty( true );
mDirtyFlags |= flag;
}
*/
void SetDrawMode( const DrawMode::Type& drawMode )
{
+ SetPropertyDirty( true );
mDrawMode = drawMode;
}
*/
void SetDepthIndex( uint32_t depthIndex )
{
+ SetPropertyDirty( true );
mDepthIndex = depthIndex;
}
return mCulled[bufferIndex];
}
+ /**
+ * @Is component changed
+ * @Return true if component is changed else false
+ */
+ bool IsComponentChanged() const
+ {
+ return (mTransformId != INVALID_TRANSFORM_ID) &&
+ (mTransformManager->IsComponentChanged( mTransformId ));
+ }
+
+ /**
+ * Retrieve the update size hint of the node
+ * @return A vector3 describing the update size hint
+ */
+ void GetUpdateSizeHint( BufferIndex bufferIndex, Vector3& updateSizeHint ) const
+ {
+ if( mTransformId != INVALID_TRANSFORM_ID )
+ {
+ mTransformManager->GetUpdateSizeHint( mTransformId, updateSizeHint );
+ }
+ }
+
+ /**
+ * Set Whether the partial update is available
+ * @param[in] partialUpdateAvailable value Set to true if the partial update is available
+ */
+ void SetPartialUpdateAvailable( bool value );
+
+ /**
+ * Retrieve the whether the partial update is available
+ * @return true if the partial update is available
+ */
+ bool IsPartialUpdateAvailable() const;
+
+ /**
+ * Set whether partial update needs to run following a render.
+ * @param[in] value Set to true if an partial update is required to be run
+ */
+ virtual void SetPropertyDirty( bool value );
+
+ /**
+ * Query the property status following rendering of a frame.
+ * @return True if the property has changed
+ */
+ virtual bool IsPropertyDirty() const;
+
public:
/**
* @copydoc UniformMap::Add
TransformManagerPropertyVector3 mPosition; ///< Local transform; distance between parent-origin & anchor-point
TransformManagerPropertyQuaternion mOrientation; ///< Local transform; rotation relative to parent node
TransformManagerPropertyVector3 mScale; ///< Local transform; scale relative to parent node
+ TransformManagerPropertyVector3 mUpdateSizeHint; ///< Local transform; update size hint is provided for partial update
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.
bool mIsLayer:1; ///< True if the node is a layer
bool mPositionUsesAnchorPoint:1; ///< True if the node should use the anchor-point when calculating the position
+ bool mPartialUpdateAvailable; ///< True if the partial update is available
+
// Changes scope, should be at end of class
DALI_LOG_OBJECT_STRING_DECLARATION;
};
{
if( mSortFunction != function )
{
+ SetPropertyDirty( true );
// is a custom sort function used
if( function != Internal::Layer::ZValue )
{
void Layer::SetClipping(bool enabled)
{
mIsClipping = enabled;
+ SetPropertyDirty( true );
}
void Layer::SetClippingBox(const Dali::ClippingBox& box)
{
mClippingBox.Set(box.x, box.y, box.width, box.height);
+ SetPropertyDirty( true );
}
void Layer::SetBehavior( Dali::Layer::Behavior behavior )
{
mBehavior = behavior;
+ SetPropertyDirty( true );
}
void Layer::SetDepthTestDisabled( bool disable )
{
mDepthTestDisabled = disable;
+ SetPropertyDirty( true );
}
bool Layer::IsDepthTestDisabled() const
mDepthTestMode( DepthTestMode::AUTO ),
mRenderingBehavior( DevelRenderer::Rendering::IF_REQUIRED ),
mPremultipledAlphaEnabled( false ),
+ mDirty( false ),
mOpacity( 1.0f ),
mDepthIndex( 0 )
{
void Renderer::PrepareRender( BufferIndex updateBufferIndex )
{
+ SetDirty( false );
if( mRegenerateUniformMap == UNIFORM_MAP_READY )
{
mUniformMapChanged[updateBufferIndex] = false;
}
else
{
+ mDirty = true;
if( mRegenerateUniformMap == REGENERATE_UNIFORM_MAP)
{
CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
if( mResendFlag != 0 )
{
+ mDirty = true;
if( mResendFlag & RESEND_GEOMETRY )
{
typedef MessageValue1< Render::Renderer, Render::Geometry* > DerivedType;
void Renderer::SetDepthIndex( int depthIndex )
{
mDepthIndex = depthIndex;
+ mDirty = true;
}
void Renderer::SetFaceCullingMode( FaceCullingMode::Type faceCullingMode )
void Renderer::SetBlendMode( BlendMode::Type blendingMode )
{
mBlendMode = blendingMode;
+ mDirty = true;
}
BlendMode::Type Renderer::GetBlendMode() const
void Renderer::BakeOpacity( BufferIndex updateBufferIndex, float opacity )
{
+ mDirty = true;
mOpacity.Bake( updateBufferIndex, opacity );
}
void Renderer::SetRenderingBehavior( DevelRenderer::Rendering::Type renderingBehavior )
{
mRenderingBehavior = renderingBehavior;
+ mDirty = true;
}
DevelRenderer::Rendering::Type Renderer::GetRenderingBehavior() const
mRenderer = Render::Renderer::New( mRenderDataProvider, mGeometry, mBlendBitmask, GetBlendColor(), static_cast< FaceCullingMode::Type >( mFaceCullingMode ),
mPremultipledAlphaEnabled, mDepthWriteMode, mDepthTestMode, mDepthFunction, mStencilParameters );
-
OwnerPointer< Render::Renderer > transferOwnership( mRenderer );
mSceneController->GetRenderMessageDispatcher().AddRenderer( transferOwnership );
}
mRenderDataProvider->mTextures.clear();
mRenderDataProvider->mSamplers.clear();
}
+ mDirty = true;
}
}
}
}
+void Renderer::SetDirty( bool value )
+{
+ mDirty = value;
+ if( mShader )
+ {
+ mShader->SetPropertyDirty( value );
+ }
+}
+
+bool Renderer::IsDirty() const
+{
+ bool ret = false;
+
+ if( !mDirty )
+ {
+ if( mShader )
+ {
+ ret = mShader->IsPropertyDirty();
+ }
+
+ // check native image
+ if( !ret && mTextureSet )
+ {
+ uint32_t textureCount = mTextureSet->GetTextureCount();
+
+ if(textureCount > 0)
+ {
+ Dali::Internal::Render::Texture* texture;
+ for( uint32_t i = 0; i<textureCount; ++i )
+ {
+ texture = const_cast<Dali::Internal::SceneGraph::TextureSet *>(mTextureSet)->GetTexture(i);
+ if( texture && texture->IsNativeImage() )
+ {
+ ret = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return ret | mDirty;
+}
+
} // namespace SceneGraph
} // namespace Internal
} // namespace Dali
*/
void DisconnectFromSceneGraph( SceneController& sceneController, BufferIndex bufferIndex );
+ /**
+ * Enable/Disable Partial update dirty flag
+ * @param[in] true to mark dirty else false
+ */
+ void SetDirty( bool value );
+
+ /**
+ * Get Partial update dirty flag
+ * @return true if dirty else false
+ */
+ bool IsDirty() const;
+
public: // Implementation of ConnectionChangePropagator
/**
* @copydoc ConnectionChangePropagator::AddObserver
DevelRenderer::Rendering::Type mRenderingBehavior:2; ///< The rendering behavior
bool mUniformMapChanged[2]; ///< Records if the uniform map has been altered this frame
bool mPremultipledAlphaEnabled:1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
+ bool mDirty:1; ///< Required for marking it dirty in case of partial update.
public: