[problem] Animation-finished and property-notifications can be fired off too soon.
[cause] We queue the message from update straight away, even before the scene has been
updated.
[solution] Create another buffer in the notification-manager which is only swapped at the end
of the update.
Change-Id: I7b72fa2485ed9faa606b52a3925e111df2931776
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
extern int UtcDaliAnimationAnimateBetweenActorColorFunctionTimePeriod(void);
extern int UtcDaliAnimationAnimateVector3Func(void);
extern int UtcDaliAnimationCreateDestroy(void);
+extern int UtcDaliAnimationUpdateManager(void);
extern int UtcDaliAnyConstructors(void);
extern int UtcDaliAnyAssignmentOperators(void);
extern int UtcDaliAnyNegativeAssignmentOperators(void);
{"UtcDaliAnimationAnimateBetweenActorColorFunctionTimePeriod", UtcDaliAnimationAnimateBetweenActorColorFunctionTimePeriod, utc_dali_animation_startup, utc_dali_animation_cleanup},
{"UtcDaliAnimationAnimateVector3Func", UtcDaliAnimationAnimateVector3Func, utc_dali_animation_startup, utc_dali_animation_cleanup},
{"UtcDaliAnimationCreateDestroy", UtcDaliAnimationCreateDestroy, utc_dali_animation_startup, utc_dali_animation_cleanup},
+ {"UtcDaliAnimationUpdateManager", UtcDaliAnimationUpdateManager, utc_dali_animation_startup, utc_dali_animation_cleanup},
{"UtcDaliAnyConstructors", UtcDaliAnyConstructors, utc_dali_any_startup, utc_dali_any_cleanup},
{"UtcDaliAnyAssignmentOperators", UtcDaliAnyAssignmentOperators, utc_dali_any_startup, utc_dali_any_cleanup},
{"UtcDaliAnyNegativeAssignmentOperators", UtcDaliAnyNegativeAssignmentOperators, utc_dali_any_startup, utc_dali_any_cleanup},
delete animation;
END_TEST;
}
+
+struct UpdateManagerTestConstraint
+{
+ UpdateManagerTestConstraint(TestApplication& application)
+ : mApplication(application)
+ {
+ }
+
+ Vector3 operator()(const Vector3& current)
+ {
+ mApplication.SendNotification(); // Process events
+ return current;
+ }
+
+ TestApplication& mApplication;
+};
+
+int UtcDaliAnimationUpdateManager(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add( actor );
+
+ // Build the animation
+ Animation animation = Animation::New( 0.0f );
+
+ bool signalReceived = false;
+ AnimationFinishCheck finishCheck( signalReceived );
+ animation.FinishedSignal().Connect( &application, finishCheck );
+
+ Vector3 startValue(1.0f, 1.0f, 1.0f);
+ Property::Index index = actor.RegisterProperty( "test-property", startValue );
+ Constraint constraint = Constraint::New<Vector3>( index, UpdateManagerTestConstraint( application ) );
+ actor.ApplyConstraint( constraint );
+
+ // Apply animation to actor
+ BounceFunc func(0.0f, 0.0f, -100.0f);
+ animation.Animate<Vector3>( Property(actor, Actor::POSITION), func, AlphaFunctions::Linear );
+
+ animation.Play();
+
+ application.SendNotification();
+ application.UpdateOnly( 16 );
+
+ finishCheck.CheckSignalNotReceived();
+
+ application.SendNotification(); // Process events
+
+ finishCheck.CheckSignalReceived();
+
+ END_TEST;
+}
+
+
// queueMutex must be locked whilst accessing queue
MessageQueueMutex queueMutex;
- MessageContainer updateQueue;
+ MessageContainer updateCompletedQueue;
+ MessageContainer updateWorkingQueue;
MessageContainer eventQueue;
};
// queueMutex must be locked whilst accessing queue
MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
- mImpl->updateQueue.PushBack( message );
+ mImpl->updateWorkingQueue.PushBack( message );
+}
+
+void NotificationManager::UpdateCompleted()
+{
+ // queueMutex must be locked whilst accessing queue
+ MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+ // Swap the queue, original queue ends up empty, then release the lock
+ mImpl->updateCompletedQueue.Swap( mImpl->updateWorkingQueue );
}
bool NotificationManager::MessagesToProcess()
// queueMutex must be locked whilst accessing queue
MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
- return ( false == mImpl->updateQueue.IsEmpty() );
+ return ( false == mImpl->updateCompletedQueue.IsEmpty() );
}
void NotificationManager::ProcessMessages()
MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
// Swap the queue, original queue ends up empty, then release the lock
- mImpl->updateQueue.Swap( mImpl->eventQueue );
+ mImpl->updateCompletedQueue.Swap( mImpl->eventQueue );
}
// end of scope, lock is released
public:
/**
- * Create an NotificationManager.
+ * Create an NotificationManager. Owned by Core in event thread side.
*/
NotificationManager();
*/
virtual ~NotificationManager();
+/// Update side interface, can only be called from Update-thread
+
/**
* Queue a scene message. This method is thread-safe.
* @param[in] message A newly allocated message; NotificationManager takes ownership.
void QueueMessage( MessageBase* message );
/**
+ * Signal Notification Manager that update frame is completed so it can let event thread process the notifications
+ */
+ void UpdateCompleted();
+
+/// Event side interface, can only be called from Update-thread
+
+ /**
* Query whether the NotificationManager has messages to process.
* @return True if there are messages to process.
*/
}
}
+ if ( mImpl->animationFinishedDuringUpdate )
+ {
+ // The application should be notified by NotificationManager, in another thread
+ mImpl->notificationManager.QueueMessage( AnimationFinishedMessage( mImpl->animationFinishedNotifier ) );
+ }
+
PERF_MONITOR_END(PerformanceMonitor::ANIMATE_NODES);
}
keepUpdating |= KeepUpdating::MONITORING_PERFORMANCE;
#endif
- // Only queue the message at the end of the update so that animation finished notifications are
- // not fired off before the scene has actually been updated.
- // TODO: implement better queueing mechanism from update-to-event thread.
- if ( mImpl->animationFinishedDuringUpdate )
- {
- // The application should be notified by NotificationManager, in another thread
- mImpl->notificationManager.QueueMessage( AnimationFinishedMessage( mImpl->animationFinishedNotifier ) );
- }
-
// The update has finished; swap the double-buffering indices
mSceneGraphBuffers.Swap();
+ // tell the update manager that we're done so the queue can be given to event thread
+ mImpl->notificationManager.UpdateCompleted();
+
PERF_MONITOR_END(PerformanceMonitor::UPDATE);
return keepUpdating;