From c99b916b9708aa161c5d736964d5a8eadf235636 Mon Sep 17 00:00:00 2001 From: David Steele Date: Wed, 24 Jan 2018 13:59:55 +0000 Subject: [PATCH] [4.0] Changed Update to reset only target properties each frame Currently all default and custom animated properties are reset each frame. This is wasteful, as unnecessary time is spent setting the same value again and again. Instead, have added a new PropertyResetter, which is created when a property is being animated or constrained. This is responsible for resetting the double buffered values of that property. Transform Manager properties are unaffected, as the reset is a single memset/memcpy that handles all such properties at once, and is much faster than resetting properties individually. Added a PropertyResetter to animators. Removed property reset from everything except transform manager. Ensured property resetters die with animators Added lifecycle observer to scene graph animators Hooked up property resetter to observe animator destruction Added aging to property resetter to ensure it resets for another frame after animator death Added constraint resetters Changing connection to disconnection tracking fixes constraint velocity issue Also changed Property::Bake to write to both buffer indexed values. Ensured property resetters destroyed after animations ( animators have a resetter observing destruction; order matters ). Change-Id: Ia11f0e45744b09859ce1b87f306e1829efbb8fac Signed-off-by: David Steele (cherry picked from commit 39093bc48ee4ed2b4956c183faf59c36f3e9746c) --- dali/internal/event/animation/animator-connector.h | 57 +++-- dali/internal/event/animation/constraint-impl.h | 49 ++++- dali/internal/update/animation/property-accessor.h | 2 +- .../update/animation/scene-graph-animator.h | 39 +++- .../animation/scene-graph-constraint-base.cpp | 15 +- .../update/animation/scene-graph-constraint-base.h | 43 +++- dali/internal/update/common/animatable-property.h | 32 ++- dali/internal/update/common/property-owner.cpp | 14 +- dali/internal/update/common/property-owner.h | 14 +- dali/internal/update/common/property-resetter.h | 234 +++++++++++++++++++++ dali/internal/update/manager/update-algorithms.cpp | 5 +- dali/internal/update/manager/update-manager.cpp | 50 ++--- dali/internal/update/manager/update-manager.h | 22 +- dali/internal/update/nodes/node.cpp | 7 +- dali/internal/update/nodes/node.h | 12 +- .../render-tasks/scene-graph-render-task.cpp | 9 +- .../update/render-tasks/scene-graph-render-task.h | 5 +- 17 files changed, 490 insertions(+), 119 deletions(-) create mode 100644 dali/internal/update/common/property-resetter.h diff --git a/dali/internal/event/animation/animator-connector.h b/dali/internal/event/animation/animator-connector.h index d672329..8119063 100644 --- a/dali/internal/event/animation/animator-connector.h +++ b/dali/internal/event/animation/animator-connector.h @@ -2,7 +2,7 @@ #define __DALI_INTERNAL_ANIMATOR_CONNECTOR_H__ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace Dali @@ -33,7 +34,8 @@ namespace Internal { /** - * AnimatorConnector is used to connect SceneGraph::Animators for newly created scene-graph objects. + * AnimatorConnector is used to connect SceneGraph::Animators and + * PropertyResetters for newly created scene-graph objects. * * SceneGraph::Animators weakly reference scene objects, and are automatically deleted when orphaned. * Therefore the AnimatorConnector is NOT responsible for disconnecting animators. @@ -81,8 +83,8 @@ public: mObject->RemoveObserver( *this ); } - //If there is not a SceneGraph::Animator, the AnimatorConnector is responsible for deleting the mAnimatorFunction - //otherwise, the animator function ownership is transferred to the SceneGraph::Animator + // If there is not a SceneGraph::Animator, the AnimatorConnector is responsible for deleting the mAnimatorFunction + // otherwise, the animator function ownership is transferred to the SceneGraph::Animator if( !mAnimator ) { delete mAnimatorFunction; @@ -141,7 +143,9 @@ private: } /** - * Helper function to create a Scenegraph::Animator and add it to its correspondent SceneGraph::Animation. + * Helper function to create a Scenegraph::Animator and PropertyResetter and add it to its correspondent + * SceneGraph::Animation. + * * @note This function will only be called the first time the object is added to the scene or at creation time if * the object was already in the scene */ @@ -154,10 +158,12 @@ private: //Get the PropertyOwner the animator is going to animate const SceneGraph::PropertyOwner* propertyOwner = mObject->GetSceneObject(); - //Get SceneGraph::BaseProperty + // Get SceneGraph::BaseProperty const SceneGraph::PropertyBase* baseProperty = mObject->GetSceneObjectAnimatableProperty( mPropertyIndex ); - //Check if property is a component of another property + OwnerPointer resetter; + + // Check if property is a component of another property const int componentIndex = mObject->GetPropertyComponentIndex( mPropertyIndex ); if( componentIndex != Property::INVALID_COMPONENT_INDEX ) { @@ -166,9 +172,9 @@ private: if( mComponentIndex == Property::INVALID_COMPONENT_INDEX ) { - ///Animating the whole property + // Animating the whole property - //Cast to AnimatableProperty + // Cast to AnimatableProperty const PropertyInterfaceType* animatableProperty = dynamic_cast< const PropertyInterfaceType* >( baseProperty ); if( animatableProperty == NULL ) @@ -176,6 +182,7 @@ private: if( baseProperty->IsTransformManagerProperty() ) { mAnimator = SceneGraph::AnimatorTransformProperty< PropertyType,TransformManagerPropertyAccessor >::New( *propertyOwner, *baseProperty, mAnimatorFunction, mAlphaFunction, mTimePeriod ); + // Don't reset transform manager properties - TransformManager will do it more efficiently } else { @@ -185,15 +192,16 @@ private: } else { - //Create the animator - mAnimator = AnimatorType::New( *propertyOwner, *animatableProperty, mAnimatorFunction, mAlphaFunction, mTimePeriod ); + // Create the animator and resetter + mAnimator = AnimatorType::New( *propertyOwner, *animatableProperty, mAnimatorFunction, + mAlphaFunction, mTimePeriod ); + resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator ); } - } else { { - ///Animating a component of the property + // Animating a component of the property if ( PropertyTypes::Get< Vector2 >() == baseProperty->GetType() ) { // Animate float component of Vector2 property @@ -227,6 +235,11 @@ private: break; } } + + if( mAnimator != nullptr ) + { + resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator ); + } } else if ( PropertyTypes::Get< Vector3 >() == baseProperty->GetType() ) @@ -256,10 +269,11 @@ private: { DALI_ASSERT_DEBUG( animatableProperty != NULL && "Animating non-animatable property" ); } + // Don't manually reset transform property - TransformManager will do it more efficiently } else { - //Dynamic cast will fail if BaseProperty is not a Vector3 AnimatableProperty + // Dynamic cast will fail if BaseProperty is not a Vector3 AnimatableProperty DALI_ASSERT_DEBUG( animatableProperty != NULL && "Animating non-animatable property" ); switch( mComponentIndex ) @@ -296,6 +310,11 @@ private: break; } } + + if( mAnimator != nullptr ) + { + resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator ); + } } } else if ( PropertyTypes::Get< Vector4 >() == baseProperty->GetType() ) @@ -352,6 +371,10 @@ private: break; } } + if( mAnimator != nullptr ) + { + resetter = SceneGraph::AnimatorResetter::New( *propertyOwner, *baseProperty, *mAnimator ); + } } } } @@ -362,6 +385,12 @@ private: const SceneGraph::Animation* animation = mParent->GetSceneObject(); DALI_ASSERT_DEBUG( NULL != animation ); AddAnimatorMessage( mParent->GetEventThreadServices(), *animation, *mAnimator ); + + // Add the new SceneGraph::PropertyResetter to the update manager via message + if( resetter != nullptr ) + { + AddResetterMessage( mParent->GetEventThreadServices().GetUpdateManager(), resetter ); + } } protected: diff --git a/dali/internal/event/animation/constraint-impl.h b/dali/internal/event/animation/constraint-impl.h index 2f9d65f..0fc820d 100644 --- a/dali/internal/event/animation/constraint-impl.h +++ b/dali/internal/event/animation/constraint-impl.h @@ -2,7 +2,7 @@ #define __DALI_INTERNAL_ACTIVE_CONSTRAINT_H__ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,9 +30,11 @@ #include #include #include +#include #include #include #include +#include namespace Dali { @@ -137,11 +139,11 @@ private: Constraint& operator=( const Constraint& rhs ); /** - * Create and connect a constraint for a scene-object. + * Create and connect a constraint and property resetter for a scene-graph property */ void ConnectConstraint() { - // Should not come here if target-object has been destroyed + // Should not come here if target object has been destroyed DALI_ASSERT_DEBUG( NULL != mTargetObject ); // Guard against double connections @@ -163,9 +165,10 @@ private: if ( func ) { - // Create the SceneGraphConstraint, and connect to the scene-graph + // Create the SceneGraphConstraint and PropertyResetter, and connect them to the scene-graph const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetIndex ); + OwnerPointer resetter; // The targetProperty should exist, when targetObject exists DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" ); @@ -173,10 +176,12 @@ private: if( targetProperty->IsTransformManagerProperty() ) //It is a property managed by the transform manager { // Connect the constraint - mSceneGraphConstraint = SceneGraph::Constraint >::New( *targetProperty, - propertyOwners, - func, - mRemoveAction ); + mSceneGraphConstraint = + SceneGraph::Constraint >::New( *targetProperty, + propertyOwners, + func, + mRemoveAction ); + // Don't create a resetter for transform manager property, it's less efficient } else //SceneGraph property { @@ -185,9 +190,17 @@ private: propertyOwners, func, mRemoveAction ); + // Connect the resetter + resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint ); + } OwnerPointer< SceneGraph::ConstraintBase > transferOwnership( const_cast< SceneGraph::ConstraintBase* >( mSceneGraphConstraint ) ); ApplyConstraintMessage( GetEventThreadServices(), *targetObject, transferOwnership ); + + if( resetter != nullptr ) + { + AddResetterMessage( GetEventThreadServices().GetUpdateManager(), resetter ); + } } } @@ -390,6 +403,7 @@ private: // Create the SceneGraphConstraint, and connect to the scene-graph const SceneGraph::PropertyBase* targetProperty = mTargetObject->GetSceneObjectAnimatableProperty( mTargetIndex ); + OwnerPointer resetter; // The targetProperty should exist, when targetObject exists DALI_ASSERT_ALWAYS( NULL != targetProperty && "Constraint target property does not exist" ); @@ -404,6 +418,7 @@ private: typedef SceneGraph::Constraint< float, PropertyAccessor > SceneGraphConstraint; mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction ); + resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint ); } else { @@ -423,6 +438,10 @@ private: typedef SceneGraph::Constraint< float, PropertyComponentAccessorY > SceneGraphConstraint; mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction ); } + if( mSceneGraphConstraint ) + { + resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint ); + } } else if ( PropertyTypes::Get< Vector3 >() == targetProperty->GetType() ) { @@ -444,6 +463,7 @@ private: typedef SceneGraph::Constraint< float, TransformManagerPropertyComponentAccessor > SceneGraphConstraint; mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction ); } + // Do not create a resetter for transform manager property } else { @@ -462,6 +482,10 @@ private: typedef SceneGraph::Constraint< float, PropertyComponentAccessorZ > SceneGraphConstraint; mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction ); } + if( mSceneGraphConstraint ) + { + resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint ); + } } } else if ( PropertyTypes::Get< Vector4 >() == targetProperty->GetType() ) @@ -488,6 +512,11 @@ private: typedef SceneGraph::Constraint< float, PropertyComponentAccessorW > SceneGraphConstraint; mSceneGraphConstraint = SceneGraphConstraint::New( *targetProperty, propertyOwners, func, mRemoveAction ); } + + if( mSceneGraphConstraint ) + { + resetter = SceneGraph::ConstraintResetter::New( *targetObject, *targetProperty, *mSceneGraphConstraint ); + } } } @@ -496,6 +525,10 @@ private: OwnerPointer< SceneGraph::ConstraintBase > transferOwnership( const_cast< SceneGraph::ConstraintBase* >( mSceneGraphConstraint ) ); ApplyConstraintMessage( GetEventThreadServices(), *targetObject, transferOwnership ); } + if( resetter != nullptr ) + { + AddResetterMessage( GetEventThreadServices().GetUpdateManager(), resetter ); + } } } diff --git a/dali/internal/update/animation/property-accessor.h b/dali/internal/update/animation/property-accessor.h index 31364cd..f745112 100644 --- a/dali/internal/update/animation/property-accessor.h +++ b/dali/internal/update/animation/property-accessor.h @@ -2,7 +2,7 @@ #define __DALI_INTERNAL_SCENE_GRAPH_PROPERTY_ACCESSOR_H__ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. diff --git a/dali/internal/update/animation/scene-graph-animator.h b/dali/internal/update/animation/scene-graph-animator.h index aff2b2c..b8da716 100644 --- a/dali/internal/update/animation/scene-graph-animator.h +++ b/dali/internal/update/animation/scene-graph-animator.h @@ -2,7 +2,7 @@ #define __DALI_INTERNAL_SCENE_GRAPH_ANIMATOR_H__ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -65,10 +65,30 @@ public: typedef float (*AlphaFunc)(float progress); ///< Definition of an alpha function /** + * Observer to determine when the animator is no longer present + */ + class LifecycleObserver + { + public: + /** + * Called shortly before the animator is destroyed. + */ + virtual void ObjectDestroyed() = 0; + + protected: + /** + * Virtual destructor, no deletion through this interface + */ + virtual ~LifecycleObserver() = default; + }; + + + /** * Constructor. */ AnimatorBase() - : mDurationSeconds(1.0f), + : mLifecycleObserver(nullptr), + mDurationSeconds(1.0f), mIntervalDelaySeconds(0.0f), mSpeedFactor(1.0f), mLoopCount(1), @@ -86,6 +106,20 @@ public: */ virtual ~AnimatorBase() { + if( mLifecycleObserver != nullptr ) + { + mLifecycleObserver->ObjectDestroyed(); + } + } + + void AddLifecycleObserver( LifecycleObserver& observer ) + { + mLifecycleObserver = &observer; + } + + void RemoveLifecycleObserver( LifecycleObserver& observer ) + { + mLifecycleObserver = nullptr; } /** @@ -403,6 +437,7 @@ protected: return 3.0f*(1.0f-t)*(1.0f-t)*t*p0 + 3.0f*(1.0f-t)*tSquare*p1 + tSquare*t; } + LifecycleObserver* mLifecycleObserver; float mDurationSeconds; float mIntervalDelaySeconds; float mSpeedFactor; diff --git a/dali/internal/update/animation/scene-graph-constraint-base.cpp b/dali/internal/update/animation/scene-graph-constraint-base.cpp index 9a692dd..7c39de9 100644 --- a/dali/internal/update/animation/scene-graph-constraint-base.cpp +++ b/dali/internal/update/animation/scene-graph-constraint-base.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -36,7 +36,8 @@ ConstraintBase::ConstraintBase( PropertyOwnerContainer& ownerSet, RemoveAction r : mRemoveAction( removeAction ), mFirstApply( true ), mDisconnected( true ), - mObservedOwners( ownerSet ) + mObservedOwners( ownerSet ), + mLifecycleObserver( nullptr ) { #ifdef DEBUG_ENABLED ++mCurrentInstanceCount; @@ -51,16 +52,16 @@ ConstraintBase::~ConstraintBase() StopObservation(); } + if( mLifecycleObserver != nullptr ) + { + mLifecycleObserver->ObjectDestroyed(); + } + #ifdef DEBUG_ENABLED --mCurrentInstanceCount; #endif } -void ConstraintBase::ResetDefaultProperties( BufferIndex updateBufferIndex ) -{ - DALI_ASSERT_DEBUG( false ); -} - unsigned int ConstraintBase::GetCurrentInstanceCount() { #ifdef DEBUG_ENABLED diff --git a/dali/internal/update/animation/scene-graph-constraint-base.h b/dali/internal/update/animation/scene-graph-constraint-base.h index a55bd2e..c816bcc 100644 --- a/dali/internal/update/animation/scene-graph-constraint-base.h +++ b/dali/internal/update/animation/scene-graph-constraint-base.h @@ -2,7 +2,7 @@ #define __DALI_INTERNAL_SCENE_GRAPH_CONSTRAINT_BASE_H__ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -51,6 +51,25 @@ typedef PropertyOwnerContainer::Iterator PropertyOwnerIter; class ConstraintBase : public PropertyOwner::Observer { public: + /** + * Observer to determine when the constraint is no longer present + */ + class LifecycleObserver + { + public: + /** + * Called shortly before the constraint is destroyed. + */ + virtual void ObjectDestroyed() = 0; + + protected: + /** + * Virtual destructor, no deletion through this interface + */ + virtual ~LifecycleObserver() = default; + }; + +public: typedef Dali::Constraint::RemoveAction RemoveAction; @@ -67,6 +86,22 @@ public: virtual ~ConstraintBase(); /** + * Property resetter observes the lifecycle of this object + */ + void AddLifecycleObserver( LifecycleObserver& observer ) + { + mLifecycleObserver = &observer; + } + + /** + * Property resetter observers the lifecycle of this object + */ + void RemoveLifecycleObserver( LifecycleObserver& observer ) + { + mLifecycleObserver = nullptr; + } + + /** * Initialize the constraint. * This should by called by a scene-object, when the constraint is connected. */ @@ -190,11 +225,6 @@ private: } /** - * @copydoc Dali::Internal::SceneGraph::PropertyOwner::ResetDefaultProperties() - */ - virtual void ResetDefaultProperties( BufferIndex updateBufferIndex ); - - /** * Notify the derived class to disconnect from property owners */ virtual void OnDisconnect() = 0; @@ -209,6 +239,7 @@ protected: private: PropertyOwnerContainer mObservedOwners; ///< A set of pointers to each observed object. Not owned. + LifecycleObserver* mLifecycleObserver; ///< Resetter observers this object #ifdef DEBUG_ENABLED static unsigned int mCurrentInstanceCount; ///< The current number of Constraint instances in existence. diff --git a/dali/internal/update/common/animatable-property.h b/dali/internal/update/common/animatable-property.h index a05d545..f82ed88 100644 --- a/dali/internal/update/common/animatable-property.h +++ b/dali/internal/update/common/animatable-property.h @@ -2,7 +2,7 @@ #define __DALI_INTERNAL_SCENE_GRAPH_ANIMATABLE_PROPERTY_H__ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -258,7 +258,10 @@ public: if( mBaseValue != value ) { mBaseValue = value; + // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side + // has never been atomically safe. mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; OnBake(); } @@ -416,6 +419,7 @@ public: void Bake(BufferIndex bufferIndex, int value) { mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; mBaseValue = mValue[bufferIndex]; OnBake(); @@ -595,7 +599,10 @@ public: */ void Bake(BufferIndex bufferIndex, float value) { + // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side + // has never been atomically safe. mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; mBaseValue = mValue[bufferIndex]; OnBake(); @@ -824,7 +831,10 @@ public: */ void Bake(BufferIndex bufferIndex, const Vector2& value) { + // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side + // has never been atomically safe. mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; mBaseValue = value; OnBake(); @@ -838,6 +848,7 @@ public: void BakeX(BufferIndex bufferIndex, float value) { mValue[bufferIndex].x = value; + mValue[1-bufferIndex].x = value; mBaseValue.x = value; OnBake(); @@ -851,6 +862,7 @@ public: void BakeY(BufferIndex bufferIndex, float value) { mValue[bufferIndex].y = value; + mValue[1-bufferIndex].y = value; mBaseValue.y = value; OnBake(); @@ -1117,6 +1129,7 @@ public: void Bake(BufferIndex bufferIndex, const Vector3& value) { mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; mBaseValue = value; OnBake(); @@ -1130,6 +1143,7 @@ public: void BakeX(BufferIndex bufferIndex, float value) { mValue[bufferIndex].x = value; + mValue[1-bufferIndex].x = value; mBaseValue.x = value; OnBake(); @@ -1143,6 +1157,7 @@ public: void BakeY(BufferIndex bufferIndex, float value) { mValue[bufferIndex].y = value; + mValue[1-bufferIndex].y = value; mBaseValue.y = value; OnBake(); @@ -1156,6 +1171,7 @@ public: void BakeZ(BufferIndex bufferIndex, float value) { mValue[bufferIndex].z = value; + mValue[1-bufferIndex].z = value; mBaseValue.z = value; OnBake(); @@ -1464,6 +1480,7 @@ public: void Bake(BufferIndex bufferIndex, const Vector4& value) { mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; mBaseValue = mValue[bufferIndex]; OnBake(); @@ -1477,6 +1494,7 @@ public: void BakeX(BufferIndex bufferIndex, float value) { mValue[bufferIndex].x = value; + mValue[1-bufferIndex].x = value; mBaseValue.x = mValue[bufferIndex].x; OnBake(); @@ -1490,6 +1508,7 @@ public: void BakeY(BufferIndex bufferIndex, float value) { mValue[bufferIndex].y = value; + mValue[1-bufferIndex].y = value; mBaseValue.y = mValue[bufferIndex].y; OnBake(); @@ -1503,6 +1522,7 @@ public: void BakeZ(BufferIndex bufferIndex, float value) { mValue[bufferIndex].z = value; + mValue[1-bufferIndex].z = value; mBaseValue.z = mValue[bufferIndex].z; OnBake(); @@ -1516,6 +1536,7 @@ public: void BakeW(BufferIndex bufferIndex, float value) { mValue[bufferIndex].w = value; + mValue[1-bufferIndex].w = value; mBaseValue.w = mValue[bufferIndex].w; OnBake(); @@ -1743,7 +1764,10 @@ public: */ void Bake(BufferIndex bufferIndex, const Quaternion& value) { + // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side + // has never been atomically safe. mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; mBaseValue = value; OnBake(); @@ -1901,7 +1925,10 @@ public: */ void Bake(BufferIndex bufferIndex, const Matrix& value) { + // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side + // has never been atomically safe. mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; mBaseValue = mValue[bufferIndex]; OnBake(); @@ -2059,7 +2086,10 @@ public: */ void Bake(BufferIndex bufferIndex, const Matrix3& value) { + // It's ok to bake both buffers as render is performed in same thread as update. Reading from event side + // has never been atomically safe. mValue[bufferIndex] = value; + mValue[1-bufferIndex] = value; mBaseValue = mValue[bufferIndex]; OnBake(); diff --git a/dali/internal/update/common/property-owner.cpp b/dali/internal/update/common/property-owner.cpp index aa666ef..fb655e3 100644 --- a/dali/internal/update/common/property-owner.cpp +++ b/dali/internal/update/common/property-owner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -115,18 +115,6 @@ void PropertyOwner::InstallCustomProperty( OwnerPointer& property mCustomProperties.PushBack( property.Release() ); } -void PropertyOwner::ResetToBaseValues( BufferIndex updateBufferIndex ) -{ - // Reset custom properties - const OwnedPropertyIter endIter = mCustomProperties.End(); - for ( OwnedPropertyIter iter = mCustomProperties.Begin(); endIter != iter; ++iter ) - { - (*iter)->ResetToBaseValue( updateBufferIndex ); - } - - // Notification for derived classes, to reset default properties - ResetDefaultProperties( updateBufferIndex ); -} ConstraintOwnerContainer& PropertyOwner::GetConstraints() { diff --git a/dali/internal/update/common/property-owner.h b/dali/internal/update/common/property-owner.h index 51d3664..ec5a862 100644 --- a/dali/internal/update/common/property-owner.h +++ b/dali/internal/update/common/property-owner.h @@ -2,7 +2,7 @@ #define __DALI_INTERNAL_SCENE_GRAPH_PROPERTY_OWNER_H__ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -162,12 +162,6 @@ public: return mCustomProperties; } - /** - * Reset animatable properties to the corresponding base values. - * @param[in] currentBufferIndex The buffer to reset. - * @post The ResetDefaultProperties method is called, during which derived classes can reset default properties. - */ - void ResetToBaseValues( BufferIndex updateBufferIndex ); // Constraints @@ -230,12 +224,6 @@ private: // Undefined PropertyOwner& operator=(const PropertyOwner& rhs); - /** - * Called after ResetToBaseValues; derived classes should reset any default properties. - * @param[in] currentBufferIndex The buffer to reset. - */ - virtual void ResetDefaultProperties( BufferIndex updateBufferIndex ) {} - protected: OwnedPropertyContainer mCustomProperties; ///< Properties provided with InstallCustomProperty() diff --git a/dali/internal/update/common/property-resetter.h b/dali/internal/update/common/property-resetter.h new file mode 100644 index 0000000..c28322f --- /dev/null +++ b/dali/internal/update/common/property-resetter.h @@ -0,0 +1,234 @@ +#ifndef DALI_INTERNAL_SCENEGRAPH_PROPERTY_RESETTER_H +#define DALI_INTERNAL_SCENEGRAPH_PROPERTY_RESETTER_H + +/* + * Copyright (c) 2018 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. + */ + +#include +#include +#include +#include +#include + +namespace Dali +{ +namespace Internal +{ +namespace SceneGraph +{ + +/** + * Class to reset the watched property to it's base value. Used by UpdateManager to + * reset animating and constrained properties. The derived classes AnimatorResetter and + * ConstraintResetter are designed to match the lifecycle of the SceneGraph::Animator + * and SceneGraph::Constraint respectively. + */ +class PropertyResetterBase : public PropertyOwner::Observer +{ +public: + /** + * Virtual Destructor + */ + virtual ~PropertyResetterBase() + { + if( mPropertyOwner != nullptr ) + { + mPropertyOwner->RemoveObserver(*this); + } + } + + /** + * Initialize. + * + * Watches the property owner to track if it's disconnected or not. + */ + void Initialize() + { + mPropertyOwner->AddObserver(*this); + } + + /** + * Reset the property to it's base value if the property owner is still alive and on stage + * @param[in] updateBufferIndex the current buffer index + */ + void ResetToBaseValue( BufferIndex updateBufferIndex ) + { + if( mPropertyOwner != nullptr && !mDisconnected ) + { + mBaseProperty->ResetToBaseValue( updateBufferIndex ); + } + }; + + /** + * Called when mPropertyOwner is connected to the scene graph. + * + * Note, this resetter object may be created after the property owner has been connected + * to the stage, so we track disconnection and re-connection instead of connection + * + * @param[in] owner The property owner + */ + virtual void PropertyOwnerConnected( PropertyOwner& owner ) override + { + mDisconnected = false; + } + + /** + * Called when mPropertyOwner is disconnected from the scene graph. + * @param[in] bufferIndex the current buffer index + * @param[in] owner The property owner + */ + virtual void PropertyOwnerDisconnected( BufferIndex bufferIndex, PropertyOwner& owner ) override + { + mDisconnected = true; + } + + /** + * Called shortly before the propertyOwner is destroyed + * @param[in] owner The property owner + */ + virtual void PropertyOwnerDestroyed( PropertyOwner& owner ) override + { + mDisconnected = true; + mPropertyOwner = nullptr; + + // Don't need to wait another frame as the property is being destroyed + mRunning = 0; + } + + /** + * Determine if the resetter has finished. + * + * If an animation or constraint stops, then we need to reset the + * property in the next frame as well to ensure both property values + * are set appropriately. + * + * @return true if the resetter has finished. + */ + virtual bool IsFinished() + { + bool finished = mRunning <= 0; + if( mRunning == 1 ) + { + mRunning = 0; + } + return finished; + } + +protected: + + /** + * Constructor + * + * @param[in] propertyOwner The property owner storing the base property + * @param[in] baseProperty The base property + */ + PropertyResetterBase( PropertyOwner* propertyOwner, + PropertyBase* baseProperty ) + : mPropertyOwner( propertyOwner ), + mBaseProperty( baseProperty ), + mRunning( 2 ), + mDisconnected( false ) + { + } + + PropertyOwner* mPropertyOwner; ///< The property owner + PropertyBase* mBaseProperty; ///< The base property being animated or constrained + int mRunning; ///< 2 if running, 1 if aging, 0 if stopped + bool mDisconnected; ///< True if the property owner has been disconnected +}; + + +/** + * Specialization of Resetter based on templated modifier type (either Constraint or Animator) + */ +template< typename ModifierType> +class Resetter : public PropertyResetterBase, public ModifierType::LifecycleObserver +{ +public: + + /** + * New method. + * @param[in] propertyOwner The owner of the property + * @param[in] baseProperty The property being animated + * @param[in] modifier The scene-graph animator/constraint of the property + * @return the new property resetter + */ + static PropertyResetterBase* New( const PropertyOwner& propertyOwner, + const PropertyBase& baseProperty, + const ModifierType& modifier ) + { + return new Resetter( const_cast( &propertyOwner ), + const_cast( &baseProperty ), + const_cast( &modifier ) ); + } + + /** + * Virtual destructor. + */ + virtual ~Resetter() + { + // Disconnect from modifier object. Although this resetter should match the lifecycle of the modifier object, + // there are situations where it is deleted first (e.g. if the property owner is destroyed) + if( mModifier ) + { + mModifier->RemoveLifecycleObserver(*this); + } + } + +private: + /** + * Constructor + * @param[in] propertyOwner The owner of the property + * @param[in] baseProperty The property being animated + * @param[in] modifier The scene-graph animator/constraint of the property + */ + Resetter( PropertyOwner* propertyOwner, + PropertyBase* baseProperty, + ModifierType* modifier ) + : PropertyResetterBase( propertyOwner, baseProperty ), + mModifier( modifier ) + { + // Track the lifecycle of the modifying object + mModifier->AddLifecycleObserver(*this); + } + + /** + * The Animator or Constraint is destroyed + */ + virtual void ObjectDestroyed() override + { + // When the modifier is destroyed, reduce the running value to ensure we stay alive for + // another frame to reset the other buffer. + --mRunning; + mModifier = nullptr; + } + + ModifierType* mModifier; +}; + + +typedef Resetter AnimatorResetter; +typedef Resetter ConstraintResetter; + + + +} // namespace SceneGraph + +} // namespace Internal + +} // namespace Dali + +#endif //DALI_INTERNAL_SCENEGRAPH_PROPERTY_RESETTER_H diff --git a/dali/internal/update/manager/update-algorithms.cpp b/dali/internal/update/manager/update-algorithms.cpp index d7f9759..ead7154 100644 --- a/dali/internal/update/manager/update-algorithms.cpp +++ b/dali/internal/update/manager/update-algorithms.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -54,7 +54,6 @@ Debug::Filter* gUpdateFilter = Debug::Filter::New(Debug::Concise, false, "LOG_UP * Constrain the local properties of the PropertyOwner. * @param propertyOwner to constrain * @param updateBufferIndex buffer index to use - * @return The number of constraints that are still being applied */ void ConstrainPropertyOwner( PropertyOwner& propertyOwner, BufferIndex updateBufferIndex ) { @@ -109,7 +108,7 @@ inline int UpdateNodes( Node& node, Layer& currentLayer, int inheritedDrawMode ) { - //Apply constraints to the node + // Apply constraints to the node ConstrainPropertyOwner( node, updateBufferIndex ); // Short-circuit for invisible nodes diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index c509ec6..6ef46be 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -285,9 +285,9 @@ struct UpdateManager::Impl OwnerContainer< Camera* > cameras; ///< A container of cameras OwnerContainer< PropertyOwner* > customObjects; ///< A container of owned objects (with custom properties) + OwnerContainer< PropertyResetterBase* > propertyResetters; ///< A container of property resetters AnimationContainer animations; ///< A container of owned animations PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications. - OwnerContainer< Renderer* > renderers; ///< A container of owned renderers OwnerContainer< TextureSet* > textureSets; ///< A container of owned texture sets OwnerContainer< Shader* > shaders; ///< A container of owned shaders @@ -481,6 +481,12 @@ bool UpdateManager::IsAnimationRunning() const return false; } +void UpdateManager::AddPropertyResetter( OwnerPointer& propertyResetter ) +{ + propertyResetter->Initialize(); + mImpl->propertyResetters.PushBack( propertyResetter.Release() ); +} + void UpdateManager::AddPropertyNotification( OwnerPointer< PropertyNotification >& propertyNotification ) { mImpl->propertyNotifications.PushBack( propertyNotification.Release() ); @@ -606,40 +612,30 @@ void UpdateManager::ResetProperties( BufferIndex bufferIndex ) // Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped mImpl->animationFinishedDuringUpdate = false; - // Animated properties have to be reset to their original value each frame - - // Reset root properties - if ( mImpl->root ) + // Reset all animating / constrained properties + std::vectortoDelete; + for( auto&& element : mImpl->propertyResetters ) { - mImpl->root->ResetToBaseValues( bufferIndex ); + element->ResetToBaseValue( bufferIndex ); + if( element->IsFinished() ) + { + toDelete.push_back( element ); + } } - if ( mImpl->systemLevelRoot ) + + // If a resetter is no longer required (the animator or constraint has been removed), delete it. + for( auto&& elementPtr : toDelete ) { - mImpl->systemLevelRoot->ResetToBaseValues( bufferIndex ); + mImpl->propertyResetters.EraseObject( elementPtr ); } - // Reset all the nodes + // Clear node dirty flags Vector::Iterator iter = mImpl->nodes.Begin()+1; Vector::Iterator endIter = mImpl->nodes.End(); for( ;iter != endIter; ++iter ) { - (*iter)->ResetToBaseValues( bufferIndex ); + (*iter)->ResetDirtyFlags( bufferIndex ); } - - // Reset system-level render-task list properties to base values - ResetToBaseValues( mImpl->systemLevelTaskList.GetTasks(), bufferIndex ); - - // Reset render-task list properties to base values. - ResetToBaseValues( mImpl->taskList.GetTasks(), bufferIndex ); - - // Reset custom object properties to base values - ResetToBaseValues( mImpl->customObjects, bufferIndex ); - - // Reset animatable renderer properties to base values - ResetToBaseValues( mImpl->renderers, bufferIndex ); - - // Reset animatable shader properties to base values - ResetToBaseValues( mImpl->shaders, bufferIndex ); } bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds ) @@ -875,7 +871,7 @@ unsigned int UpdateManager::Update( float elapsedSeconds, //Update renderers and apply constraints UpdateRenderers( bufferIndex ); - //Update the trnasformations of all the nodes + //Update the transformations of all the nodes mImpl->transformManager.Update(); //Process Property Notifications diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index d603eb6..ccecef8 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_SCENE_GRAPH_UPDATE_MANAGER_H /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -238,6 +239,13 @@ public: */ bool IsAnimationRunning() const; + /** + * Add a property resetter. UpdateManager takes ownership of the object. + * It will be killed by UpdateManager when the associated animator or + * constraint has finished; or the property owner of the property is destroyed. + */ + void AddPropertyResetter( OwnerPointer& propertyResetter ); + // Property Notification /** @@ -1294,6 +1302,18 @@ inline void SetDepthIndicesMessage( UpdateManager& manager, OwnerPointer< NodeDe new (slot) LocalType( &manager, &UpdateManager::SetDepthIndices, nodeDepths ); } +inline void AddResetterMessage( UpdateManager& manager, OwnerPointer resetter ) +{ + typedef MessageValue1< UpdateManager, OwnerPointer > LocalType; + + // Reserve some memory inside the message queue + unsigned int* slot = manager.ReserveMessageSlot( sizeof( LocalType ) ); + + // Construct message in the message queue memory; note that delete should not be called on the return value + new (slot) LocalType( &manager, &UpdateManager::AddPropertyResetter, resetter ); +} + + } // namespace SceneGraph } // namespace Internal diff --git a/dali/internal/update/nodes/node.cpp b/dali/internal/update/nodes/node.cpp index 5030a03..aa7f777 100644 --- a/dali/internal/update/nodes/node.cpp +++ b/dali/internal/update/nodes/node.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -310,11 +310,8 @@ int Node::GetDirtyFlags() const return flags; } -void Node::ResetDefaultProperties( BufferIndex updateBufferIndex ) +void Node::ResetDirtyFlags( BufferIndex updateBufferIndex ) { - mVisible.ResetToBaseValue( updateBufferIndex ); - mColor.ResetToBaseValue( updateBufferIndex ); - mDirtyFlags = NothingFlag; } diff --git a/dali/internal/update/nodes/node.h b/dali/internal/update/nodes/node.h index 93e6a3f..71102fb 100644 --- a/dali/internal/update/nodes/node.h +++ b/dali/internal/update/nodes/node.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_SCENE_GRAPH_NODE_H /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -768,6 +768,11 @@ public: */ void CreateTransform( SceneGraph::TransformManager* transformManager ); + /** + * Reset dirty flags + */ + void ResetDirtyFlags( BufferIndex updateBufferIndex ); + protected: /** @@ -833,11 +838,6 @@ private: Node& operator=(const Node& rhs); /** - * @copydoc Dali::Internal::SceneGraph::PropertyOwner::ResetDefaultProperties() - */ - virtual void ResetDefaultProperties( BufferIndex updateBufferIndex ); - - /** * Recursive helper to disconnect a Node and its children. * Disconnected Nodes have no parent or children. * @param[in] updateBufferIndex The current update buffer index. diff --git a/dali/internal/update/render-tasks/scene-graph-render-task.cpp b/dali/internal/update/render-tasks/scene-graph-render-task.cpp index 007d341..7d2ced8 100644 --- a/dali/internal/update/render-tasks/scene-graph-render-task.cpp +++ b/dali/internal/update/render-tasks/scene-graph-render-task.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -451,13 +451,6 @@ void RenderTask::SetSyncRequired( bool requiresSync ) mRequiresSync = requiresSync; } -void RenderTask::ResetDefaultProperties( BufferIndex updateBufferIndex ) -{ - // Reset default properties - mViewportPosition.ResetToBaseValue( updateBufferIndex ); - mViewportSize.ResetToBaseValue( updateBufferIndex ); - mClearColor.ResetToBaseValue( updateBufferIndex ); -} RenderTask::RenderTask() : mViewportPosition( Vector2::ZERO), diff --git a/dali/internal/update/render-tasks/scene-graph-render-task.h b/dali/internal/update/render-tasks/scene-graph-render-task.h index 0797dd3..b66077e 100644 --- a/dali/internal/update/render-tasks/scene-graph-render-task.h +++ b/dali/internal/update/render-tasks/scene-graph-render-task.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_SCENE_GRAPH_RENDER_TASK_H /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -339,9 +339,6 @@ private: // Undefined RenderTask& operator=(const RenderTask&); -private: // PropertyOwner - - virtual void ResetDefaultProperties( BufferIndex currentBufferIndex ); public: // Animatable Properties AnimatableProperty< Vector2 > mViewportPosition; ///< viewportPosition -- 2.7.4