Commit b305a615 authored by Kevin Ellis's avatar Kevin Ellis Committed by Commit Bot

Implement asynchronous mutation of animation worklets.

* Adds MutateAynchronously method to the mutator dispatcher.
* Adds tests for ansynchronous mutation.
* Stubs in API for notification of mutation state (pending/complete).

Note async mutations are not used outside of testing with the patch pending completion of the notification plumbing in a separate CL.

Bug: 791280
Change-Id: I91545306c71899945f797a641831257247849b86
Reviewed-on: https://chromium-review.googlesource.com/c/1409600Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Reviewed-by: default avatarMajid Valipour <majidvp@chromium.org>
Commit-Queue: Kevin Ellis <kevers@chromium.org>
Cr-Commit-Position: refs/heads/master@{#625199}
parent eda64695
...@@ -139,7 +139,8 @@ void WorkletAnimationController::MutateAnimations() { ...@@ -139,7 +139,8 @@ void WorkletAnimationController::MutateAnimations() {
if (!main_thread_mutator_client_) if (!main_thread_mutator_client_)
return; return;
main_thread_mutator_client_->Mutator()->Mutate(CollectAnimationStates()); main_thread_mutator_client_->Mutator()->MutateSynchronously(
CollectAnimationStates());
} }
std::unique_ptr<AnimationWorkletDispatcherInput> std::unique_ptr<AnimationWorkletDispatcherInput>
......
...@@ -58,6 +58,8 @@ class CORE_EXPORT WorkletAnimationController ...@@ -58,6 +58,8 @@ class CORE_EXPORT WorkletAnimationController
void SetMutationUpdate( void SetMutationUpdate(
std::unique_ptr<AnimationWorkletOutput> output) override; std::unique_ptr<AnimationWorkletOutput> output) override;
void NotifyAnimationsPending() override {}
void NotifyAnimationsReady() override {}
void SynchronizeAnimatorName(const String& animator_name) override; void SynchronizeAnimatorName(const String& animator_name) override;
// Returns true if the animator with given name is registered in // Returns true if the animator with given name is registered in
......
...@@ -15,7 +15,11 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcher { ...@@ -15,7 +15,11 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcher {
virtual ~AnimationWorkletMutatorDispatcher() = default; virtual ~AnimationWorkletMutatorDispatcher() = default;
// Run the animation frame callbacks from all connected AnimationWorklets. // Run the animation frame callbacks from all connected AnimationWorklets.
virtual void Mutate(std::unique_ptr<AnimationWorkletDispatcherInput>) = 0; virtual void MutateSynchronously(
std::unique_ptr<AnimationWorkletDispatcherInput>) = 0;
virtual void MutateAsynchronously(
std::unique_ptr<AnimationWorkletDispatcherInput>) = 0;
// Returns true if Mutate may do something if called 'now'. // Returns true if Mutate may do something if called 'now'.
virtual bool HasMutators() = 0; virtual bool HasMutators() = 0;
}; };
......
...@@ -19,6 +19,15 @@ ...@@ -19,6 +19,15 @@
namespace blink { namespace blink {
namespace {
int next_async_mutation_id = 0;
int GetNextAsyncMutationId() {
return next_async_mutation_id++;
}
} // end namespace
// Wrap output vector in a thread safe and ref-counted object since it is // Wrap output vector in a thread safe and ref-counted object since it is
// accessed from animation worklet threads and its lifetime must be guaranteed // accessed from animation worklet threads and its lifetime must be guaranteed
// to outlive the mutation update cycle. // to outlive the mutation update cycle.
...@@ -84,13 +93,14 @@ AnimationWorkletMutatorDispatcherImpl::CreateMainThreadClient( ...@@ -84,13 +93,14 @@ AnimationWorkletMutatorDispatcherImpl::CreateMainThreadClient(
return CreateClient<MainThreadMutatorClient>(weak_interface, queue, true); return CreateClient<MainThreadMutatorClient>(weak_interface, queue, true);
} }
void AnimationWorkletMutatorDispatcherImpl::Mutate( void AnimationWorkletMutatorDispatcherImpl::MutateSynchronously(
std::unique_ptr<AnimationWorkletDispatcherInput> mutator_input) { std::unique_ptr<AnimationWorkletDispatcherInput> mutator_input) {
TRACE_EVENT0("cc", "AnimationWorkletMutatorDispatcherImpl::mutate"); TRACE_EVENT0("cc", "AnimationWorkletMutatorDispatcherImpl::mutate");
if (mutator_map_.IsEmpty() || !mutator_input) if (mutator_map_.IsEmpty() || !mutator_input)
return; return;
base::ElapsedTimer timer; base::ElapsedTimer timer;
DCHECK(client_); DCHECK(client_);
DCHECK(host_queue_->BelongsToCurrentThread());
DCHECK(mutator_input_map_.IsEmpty()); DCHECK(mutator_input_map_.IsEmpty());
DCHECK(outputs_->get().IsEmpty()); DCHECK(outputs_->get().IsEmpty());
...@@ -104,15 +114,7 @@ void AnimationWorkletMutatorDispatcherImpl::Mutate( ...@@ -104,15 +114,7 @@ void AnimationWorkletMutatorDispatcherImpl::Mutate(
RequestMutations(std::move(on_done)); RequestMutations(std::move(on_done));
event.Wait(); event.Wait();
for (auto& output : outputs_->get()) { ApplyMutationsOnHostThread();
// Animator that has no input does not produce any output.
if (!output)
continue;
client_->SetMutationUpdate(std::move(output));
}
mutator_input_map_.clear();
outputs_->get().clear();
UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
"Animation.AnimationWorklet.Dispatcher.SynchronousMutateDuration", "Animation.AnimationWorklet.Dispatcher.SynchronousMutateDuration",
...@@ -120,6 +122,58 @@ void AnimationWorkletMutatorDispatcherImpl::Mutate( ...@@ -120,6 +122,58 @@ void AnimationWorkletMutatorDispatcherImpl::Mutate(
base::TimeDelta::FromMilliseconds(100), 50); base::TimeDelta::FromMilliseconds(100), 50);
} }
void AnimationWorkletMutatorDispatcherImpl::MutateAsynchronously(
std::unique_ptr<AnimationWorkletDispatcherInput> mutator_input) {
if (mutator_map_.IsEmpty() || !mutator_input)
return;
DCHECK(client_);
DCHECK(host_queue_->BelongsToCurrentThread());
if (!mutator_input_map_.IsEmpty()) {
// Still running mutations from a previous frame. Skip this frame to avoid
// lagging behind.
// TODO(kevers): Consider queuing pending mutation cycle. A pending tree
// mutation should likely be queued an active tree mutation cycle is still
// running.
return;
}
mutator_input_map_ = CreateInputMap(*mutator_input);
if (mutator_input_map_.IsEmpty())
return;
int next_async_mutation_id = GetNextAsyncMutationId();
TRACE_EVENT_ASYNC_BEGIN0("cc",
"AnimationWorkletMutatorDispatcherImpl::MutateAsync",
next_async_mutation_id);
WTF::CrossThreadClosure on_done = CrossThreadBind(
[](scoped_refptr<base::SingleThreadTaskRunner> host_queue,
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> dispatcher,
int next_async_mutation_id) {
PostCrossThreadTask(
*host_queue, FROM_HERE,
CrossThreadBind(
&AnimationWorkletMutatorDispatcherImpl::AsyncMutationsDone,
dispatcher, next_async_mutation_id));
},
host_queue_, weak_factory_.GetWeakPtr(), next_async_mutation_id);
client_->NotifyAnimationsPending();
RequestMutations(std::move(on_done));
}
void AnimationWorkletMutatorDispatcherImpl::AsyncMutationsDone(
int async_mutation_id) {
DCHECK(client_);
DCHECK(host_queue_->BelongsToCurrentThread());
ApplyMutationsOnHostThread();
client_->NotifyAnimationsReady();
TRACE_EVENT_ASYNC_END0("cc",
"AnimationWorkletMutatorDispatcherImpl::MutateAsync",
async_mutation_id);
// TODO(kevers): Add UMA metric to track the asynchronous mutate duration.
}
void AnimationWorkletMutatorDispatcherImpl::RegisterAnimationWorkletMutator( void AnimationWorkletMutatorDispatcherImpl::RegisterAnimationWorkletMutator(
CrossThreadPersistent<AnimationWorkletMutator> mutator, CrossThreadPersistent<AnimationWorkletMutator> mutator,
scoped_refptr<base::SingleThreadTaskRunner> mutator_runner) { scoped_refptr<base::SingleThreadTaskRunner> mutator_runner) {
...@@ -171,6 +225,7 @@ AnimationWorkletMutatorDispatcherImpl::CreateInputMap( ...@@ -171,6 +225,7 @@ AnimationWorkletMutatorDispatcherImpl::CreateInputMap(
void AnimationWorkletMutatorDispatcherImpl::RequestMutations( void AnimationWorkletMutatorDispatcherImpl::RequestMutations(
WTF::CrossThreadClosure done_callback) { WTF::CrossThreadClosure done_callback) {
DCHECK(client_);
DCHECK(outputs_->get().IsEmpty()); DCHECK(outputs_->get().IsEmpty());
int num_requests = mutator_map_.size(); int num_requests = mutator_map_.size();
...@@ -214,4 +269,15 @@ void AnimationWorkletMutatorDispatcherImpl::RequestMutations( ...@@ -214,4 +269,15 @@ void AnimationWorkletMutatorDispatcherImpl::RequestMutations(
} }
} }
void AnimationWorkletMutatorDispatcherImpl::ApplyMutationsOnHostThread() {
DCHECK(client_);
DCHECK(host_queue_->BelongsToCurrentThread());
for (auto& output : outputs_->get()) {
if (output)
client_->SetMutationUpdate(std::move(output));
}
mutator_input_map_.clear();
outputs_->get().clear();
}
} // namespace blink } // namespace blink
...@@ -48,7 +48,12 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final ...@@ -48,7 +48,12 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
~AnimationWorkletMutatorDispatcherImpl() override; ~AnimationWorkletMutatorDispatcherImpl() override;
// AnimationWorkletMutatorDispatcher implementation. // AnimationWorkletMutatorDispatcher implementation.
void Mutate(std::unique_ptr<AnimationWorkletDispatcherInput>) override; void MutateSynchronously(
std::unique_ptr<AnimationWorkletDispatcherInput>) override;
void MutateAsynchronously(
std::unique_ptr<AnimationWorkletDispatcherInput>) override;
// TODO(majidvp): Remove when timeline inputs are known. // TODO(majidvp): Remove when timeline inputs are known.
bool HasMutators() override; bool HasMutators() override;
...@@ -65,6 +70,8 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final ...@@ -65,6 +70,8 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
void SynchronizeAnimatorName(const String& animator_name); void SynchronizeAnimatorName(const String& animator_name);
MutatorClient* client() { return client_; }
private: private:
class OutputVectorRef; class OutputVectorRef;
...@@ -81,6 +88,10 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final ...@@ -81,6 +88,10 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final
// associated with the last mutation to complete. // associated with the last mutation to complete.
void RequestMutations(WTF::CrossThreadClosure done_callback); void RequestMutations(WTF::CrossThreadClosure done_callback);
void AsyncMutationsDone(int async_mutation_id);
void ApplyMutationsOnHostThread();
// The AnimationWorkletProxyClients are also owned by the WorkerClients // The AnimationWorkletProxyClients are also owned by the WorkerClients
// dictionary. // dictionary.
AnimationWorkletMutatorToTaskRunnerMap mutator_map_; AnimationWorkletMutatorToTaskRunnerMap mutator_map_;
......
...@@ -26,7 +26,9 @@ CompositorMutatorClient::~CompositorMutatorClient() { ...@@ -26,7 +26,9 @@ CompositorMutatorClient::~CompositorMutatorClient() {
void CompositorMutatorClient::Mutate( void CompositorMutatorClient::Mutate(
std::unique_ptr<cc::MutatorInputState> input_state) { std::unique_ptr<cc::MutatorInputState> input_state) {
TRACE_EVENT0("cc", "CompositorMutatorClient::Mutate"); TRACE_EVENT0("cc", "CompositorMutatorClient::Mutate");
mutator_->Mutate(std::move(input_state)); // TODO(http://crbug.com/791280): Switch to asynchronous once plumbing is
// complete.
mutator_->MutateSynchronously(std::move(input_state));
} }
void CompositorMutatorClient::SetMutationUpdate( void CompositorMutatorClient::SetMutationUpdate(
......
...@@ -23,6 +23,9 @@ class PLATFORM_EXPORT CompositorMutatorClient : public cc::LayerTreeMutator, ...@@ -23,6 +23,9 @@ class PLATFORM_EXPORT CompositorMutatorClient : public cc::LayerTreeMutator,
void SynchronizeAnimatorName(const String& animator_name) override {} void SynchronizeAnimatorName(const String& animator_name) override {}
void SetMutationUpdate(std::unique_ptr<cc::MutatorOutputState>) override; void SetMutationUpdate(std::unique_ptr<cc::MutatorOutputState>) override;
// TODO(http://crbug.com/791280): Plumb notifications through to cc scheduler.
void NotifyAnimationsPending() override {}
void NotifyAnimationsReady() override {}
// cc::LayerTreeMutator // cc::LayerTreeMutator
void SetClient(cc::LayerTreeMutatorClient*) override; void SetClient(cc::LayerTreeMutatorClient*) override;
......
...@@ -22,6 +22,8 @@ class PLATFORM_EXPORT MainThreadMutatorClient : public MutatorClient { ...@@ -22,6 +22,8 @@ class PLATFORM_EXPORT MainThreadMutatorClient : public MutatorClient {
void SynchronizeAnimatorName(const String& animator_name) override; void SynchronizeAnimatorName(const String& animator_name) override;
void SetMutationUpdate(std::unique_ptr<AnimationWorkletOutput>) override; void SetMutationUpdate(std::unique_ptr<AnimationWorkletOutput>) override;
void NotifyAnimationsPending() override {}
void NotifyAnimationsReady() override {}
void SetDelegate(MutatorClient* client); void SetDelegate(MutatorClient* client);
AnimationWorkletMutatorDispatcherImpl* Mutator() { return mutator_.get(); } AnimationWorkletMutatorDispatcherImpl* Mutator() { return mutator_.get(); }
......
...@@ -17,6 +17,10 @@ class PLATFORM_EXPORT MutatorClient { ...@@ -17,6 +17,10 @@ class PLATFORM_EXPORT MutatorClient {
virtual void SynchronizeAnimatorName(const String& animator_name) = 0; virtual void SynchronizeAnimatorName(const String& animator_name) = 0;
virtual void SetMutationUpdate(std::unique_ptr<AnimationWorkletOutput>) = 0; virtual void SetMutationUpdate(std::unique_ptr<AnimationWorkletOutput>) = 0;
virtual void NotifyAnimationsPending() = 0;
virtual void NotifyAnimationsReady() = 0;
}; };
} // namespace blink } // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment