diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 16:23:34 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:37:21 +0000 |
commit | 38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch) | |
tree | c4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/third_party/blink/renderer/platform/graphics | |
parent | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff) | |
download | qtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz |
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/graphics')
111 files changed, 2248 insertions, 1741 deletions
diff --git a/chromium/third_party/blink/renderer/platform/graphics/DEPS b/chromium/third_party/blink/renderer/platform/graphics/DEPS index 4a56a8d8607..e3412554492 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/DEPS +++ b/chromium/third_party/blink/renderer/platform/graphics/DEPS @@ -8,6 +8,7 @@ include_rules = [ # Dependencies. "+base/threading/sequenced_task_runner_handle.h", "+base/threading/thread_restrictions.h", + "+base/barrier_closure.h", "+cc", "+components/viz/client", "+components/viz/common", @@ -21,6 +22,7 @@ include_rules = [ "+gpu/ipc/common/mailbox.mojom-blink.h", "+media/base/media_switches.h", "+media/base/video_frame.h", + "+media/base/video_types.h", "+media/renderers/video_resource_updater.h", "+services/viz/public/interfaces", "+services/ws/public/cpp/gpu/context_provider_command_buffer.h", diff --git a/chromium/third_party/blink/renderer/platform/graphics/OWNERS b/chromium/third_party/blink/renderer/platform/graphics/OWNERS index 78c0ada3f1e..28d1c1091e5 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/OWNERS +++ b/chromium/third_party/blink/renderer/platform/graphics/OWNERS @@ -19,3 +19,11 @@ mcasas@chromium.org # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Paint + +# Video SurfaceLayer functionality. +per-file video_frame*=file://media/OWNERS +per-file video_frame*=mlamouri@chromium.org +per-file video_frame*=lethalantidote@chromium.org +per-file surface_layer_bridge*=file://media/OWNERS +per-file surface_layer_bridge*=mlamouri@chromium.org +per-file surface_layer_bridge*=lethalantidote@chromium.org diff --git a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc index 3214da58c82..851be76f139 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc @@ -289,9 +289,5 @@ bool AcceleratedStaticBitmapImage::CurrentFrameKnownToBeOpaque() { return texture_holder_->CurrentFrameKnownToBeOpaque(); } -void AcceleratedStaticBitmapImage::Abandon() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - texture_holder_->Abandon(); -} } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h index fa769532993..7fc90d2a08f 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h +++ b/chromium/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h @@ -88,8 +88,6 @@ class PLATFORM_EXPORT AcceleratedStaticBitmapImage final PaintImage PaintImageForCurrentFrame() override; - void Abandon() final; - TextureHolder* TextureHolderForTesting() { return texture_holder_.get(); } private: diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h index a8d19eda503..a35b7834192 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h +++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h @@ -15,7 +15,7 @@ class PLATFORM_EXPORT AnimationWorkletMutator : public GarbageCollectedMixin { public: virtual ~AnimationWorkletMutator() = default; - virtual int GetScopeId() const = 0; + virtual int GetWorkletId() const = 0; // Runs the animation frame callback. virtual std::unique_ptr<AnimationWorkletOutput> Mutate( std::unique_ptr<AnimationWorkletInput>) = 0; diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h index 441c38143e5..a7db4f11508 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h +++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher.h @@ -15,7 +15,11 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcher { virtual ~AnimationWorkletMutatorDispatcher() = default; // 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'. virtual bool HasMutators() = 0; }; diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc index 5fb4c57c500..a76626e1f0c 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.cc @@ -3,6 +3,8 @@ // found in the LICENSE file. #include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h" + +#include "base/barrier_closure.h" #include "base/metrics/histogram_macros.h" #include "base/timer/elapsed_timer.h" #include "third_party/blink/public/platform/platform.h" @@ -17,10 +19,39 @@ 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 +// accessed from animation worklet threads and its lifetime must be guaranteed +// to outlive the mutation update cycle. +class AnimationWorkletMutatorDispatcherImpl::OutputVectorRef + : public ThreadSafeRefCounted<OutputVectorRef> { + public: + static scoped_refptr<OutputVectorRef> Create() { + return base::AdoptRef(new OutputVectorRef()); + } + Vector<std::unique_ptr<AnimationWorkletDispatcherOutput>>& get() { + return vector_; + } + + private: + OutputVectorRef() = default; + Vector<std::unique_ptr<AnimationWorkletDispatcherOutput>> vector_; +}; + AnimationWorkletMutatorDispatcherImpl::AnimationWorkletMutatorDispatcherImpl( bool main_thread_task_runner) - : client_(nullptr), weak_factory_(this) { - // By default layout tests run without threaded compositing. See + : client_(nullptr), + outputs_(OutputVectorRef::Create()), + weak_factory_(this) { + // By default web tests run without threaded compositing. See // https://crbug.com/770028 For these situations we run on the Main thread. host_queue_ = main_thread_task_runner || !Thread::CompositorThread() ? Thread::MainThread()->GetTaskRunner() @@ -62,63 +93,85 @@ AnimationWorkletMutatorDispatcherImpl::CreateMainThreadClient( return CreateClient<MainThreadMutatorClient>(weak_interface, queue, true); } -void AnimationWorkletMutatorDispatcherImpl::Mutate( +void AnimationWorkletMutatorDispatcherImpl::MutateSynchronously( std::unique_ptr<AnimationWorkletDispatcherInput> mutator_input) { TRACE_EVENT0("cc", "AnimationWorkletMutatorDispatcherImpl::mutate"); - if (mutator_map_.IsEmpty()) + if (mutator_map_.IsEmpty() || !mutator_input) return; base::ElapsedTimer timer; DCHECK(client_); + DCHECK(host_queue_->BelongsToCurrentThread()); + DCHECK(mutator_input_map_.IsEmpty()); + DCHECK(outputs_->get().IsEmpty()); - Vector<std::unique_ptr<AnimationWorkletDispatcherOutput>> outputs( - mutator_map_.size()); - Vector<WaitableEvent> done_events(mutator_map_.size()); + mutator_input_map_ = CreateInputMap(*mutator_input); + if (mutator_input_map_.IsEmpty()) + return; - int index = 0; - for (auto& pair : mutator_map_) { - AnimationWorkletMutator* mutator = pair.key; - scoped_refptr<base::SingleThreadTaskRunner> worklet_queue = pair.value; + WaitableEvent event; + WTF::CrossThreadClosure on_done = CrossThreadBind( + &WaitableEvent::Signal, WTF::CrossThreadUnretained(&event)); + RequestMutations(std::move(on_done)); + event.Wait(); - std::unique_ptr<AnimationWorkletInput> input = - mutator_input->TakeWorkletState(mutator->GetScopeId()); + ApplyMutationsOnHostThread(); - DCHECK(!worklet_queue->BelongsToCurrentThread()); - std::unique_ptr<AutoSignal> done = - std::make_unique<AutoSignal>(&done_events[index]); - std::unique_ptr<AnimationWorkletDispatcherOutput>& output = outputs[index]; + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Animation.AnimationWorklet.Dispatcher.SynchronousMutateDuration", + timer.Elapsed(), base::TimeDelta::FromMicroseconds(1), + base::TimeDelta::FromMilliseconds(100), 50); +} - if (input) { - PostCrossThreadTask( - *worklet_queue, FROM_HERE, - CrossThreadBind( - [](AnimationWorkletMutator* mutator, - std::unique_ptr<AnimationWorkletInput> input, - std::unique_ptr<AutoSignal> completion, - std::unique_ptr<AnimationWorkletDispatcherOutput>* output) { - *output = mutator->Mutate(std::move(input)); - }, - WrapCrossThreadWeakPersistent(mutator), - WTF::Passed(std::move(input)), WTF::Passed(std::move(done)), - CrossThreadUnretained(&output))); - } - index++; +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; } - for (WaitableEvent& event : done_events) { - event.Wait(); - } + mutator_input_map_ = CreateInputMap(*mutator_input); + if (mutator_input_map_.IsEmpty()) + return; - for (auto& output : outputs) { - // Animator that has no input does not produce any output. - if (!output) - continue; - client_->SetMutationUpdate(std::move(output)); - } + int next_async_mutation_id = GetNextAsyncMutationId(); + TRACE_EVENT_ASYNC_BEGIN0("cc", + "AnimationWorkletMutatorDispatcherImpl::MutateAsync", + next_async_mutation_id); - UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( - "Animation.AnimationWorklet.Dispatcher.SynchronousMutateDuration", - timer.Elapsed(), base::TimeDelta::FromMicroseconds(1), - base::TimeDelta::FromMilliseconds(100), 50); + 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( @@ -145,18 +198,86 @@ void AnimationWorkletMutatorDispatcherImpl::UnregisterAnimationWorkletMutator( mutator_map_.erase(mutator); } +void AnimationWorkletMutatorDispatcherImpl::SynchronizeAnimatorName( + const String& animator_name) { + client_->SynchronizeAnimatorName(animator_name); +} + bool AnimationWorkletMutatorDispatcherImpl::HasMutators() { return !mutator_map_.IsEmpty(); } -AnimationWorkletMutatorDispatcherImpl::AutoSignal::AutoSignal( - WaitableEvent* event) - : event_(event) { - DCHECK(event); +AnimationWorkletMutatorDispatcherImpl::InputMap +AnimationWorkletMutatorDispatcherImpl::CreateInputMap( + AnimationWorkletDispatcherInput& mutator_input) const { + InputMap input_map; + for (const auto& pair : mutator_map_) { + AnimationWorkletMutator* mutator = pair.key; + const int worklet_id = mutator->GetWorkletId(); + std::unique_ptr<AnimationWorkletInput> input = + mutator_input.TakeWorkletState(worklet_id); + if (input) { + input_map.insert(worklet_id, std::move(input)); + } + } + return input_map; +} + +void AnimationWorkletMutatorDispatcherImpl::RequestMutations( + WTF::CrossThreadClosure done_callback) { + DCHECK(client_); + DCHECK(outputs_->get().IsEmpty()); + + int num_requests = mutator_map_.size(); + int next_request_index = 0; + outputs_->get().Grow(num_requests); + base::RepeatingClosure on_mutator_done = base::BarrierClosure( + num_requests, ConvertToBaseCallback(std::move(done_callback))); + + for (const auto& pair : mutator_map_) { + AnimationWorkletMutator* mutator = pair.key; + scoped_refptr<base::SingleThreadTaskRunner> worklet_queue = pair.value; + int worklet_id = mutator->GetWorkletId(); + DCHECK(!worklet_queue->BelongsToCurrentThread()); + auto it = mutator_input_map_.find(worklet_id); + if (it == mutator_input_map_.end()) { + // No input to process. + on_mutator_done.Run(); + continue; + } + PostCrossThreadTask( + *worklet_queue, FROM_HERE, + CrossThreadBind( + [](AnimationWorkletMutator* mutator, + std::unique_ptr<AnimationWorkletInput> input, + scoped_refptr<OutputVectorRef> outputs, int index, + WTF::CrossThreadClosure on_mutator_done) { + std::unique_ptr<AnimationWorkletOutput> output = + mutator ? mutator->Mutate(std::move(input)) : nullptr; + outputs->get()[index] = std::move(output); + on_mutator_done.Run(); + }, + // The mutator is created and destroyed on the worklet thread. + WrapCrossThreadWeakPersistent(mutator), + // The worklet input is not required after the Mutate call. + WTF::Passed(std::move(it->value)), + // The vector of outputs is wrapped in a scoped_refptr initialized + // on the host thread. It can outlive the dispatcher during shutdown + // of a process with a running animation. + outputs_, next_request_index++, + WTF::Passed(WTF::CrossThreadClosure(on_mutator_done)))); + } } -AnimationWorkletMutatorDispatcherImpl::AutoSignal::~AutoSignal() { - event_->Signal(); +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 diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h index 27509cdea3e..4aa67917413 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h +++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h @@ -16,13 +16,14 @@ #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/heap/visitor.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" +#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" namespace blink { class CompositorMutatorClient; class MainThreadMutatorClient; -class WaitableEvent; // Fans out requests to all of the registered AnimationWorkletMutators which can // then run worklet animations to produce mutation updates. Requests for @@ -47,7 +48,12 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final ~AnimationWorkletMutatorDispatcherImpl() override; // 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. bool HasMutators() override; @@ -62,21 +68,29 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final void SetClient(MutatorClient* client) { client_ = client; } + void SynchronizeAnimatorName(const String& animator_name); + + MutatorClient* client() { return client_; } + private: + class OutputVectorRef; + + using InputMap = HashMap<int, std::unique_ptr<AnimationWorkletInput>>; + using AnimationWorkletMutatorToTaskRunnerMap = HashMap<CrossThreadPersistent<AnimationWorkletMutator>, scoped_refptr<base::SingleThreadTaskRunner>>; - class AutoSignal { - public: - explicit AutoSignal(WaitableEvent*); - ~AutoSignal(); + InputMap CreateInputMap(AnimationWorkletDispatcherInput& mutator_input) const; - private: - WaitableEvent* event_; + // Dispatches mutation update requests. The callback is triggered once + // all mutation updates have been computed on the animation worklet thread + // associated with the last mutation to complete. + void RequestMutations(WTF::CrossThreadClosure done_callback); - DISALLOW_COPY_AND_ASSIGN(AutoSignal); - }; + void AsyncMutationsDone(int async_mutation_id); + + void ApplyMutationsOnHostThread(); // The AnimationWorkletProxyClients are also owned by the WorkerClients // dictionary. @@ -98,6 +112,21 @@ class PLATFORM_EXPORT AnimationWorkletMutatorDispatcherImpl final // valid as long as this class exists. MutatorClient* client_; + // Map of mutator scope IDs to mutator input. The Mutate methods safeguards + // against concurrent calls (important once async mutations are introduced) by + // checking that the map has been reset on entry. For this reason, it is + // important to reset the map at the end of the mutation cycle. + InputMap mutator_input_map_; + + // Reference to a vector for collecting mutation output. The vector is + // accessed across threads, thus it must be guaranteed to persist until the + // last mutation update is complete, and updates must be done in a thread-safe + // manner. The Mutate method guards against concurrent calls (important once + // async mutations are introduced) by checking that the output vector is + // empty. For this reason, it is important to clear the output at the end of + // the mutation cycle. + scoped_refptr<OutputVectorRef> outputs_; + base::WeakPtrFactory<AnimationWorkletMutatorDispatcherImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(AnimationWorkletMutatorDispatcherImpl); diff --git a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc index 383fe843619..87b8dcd769c 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl_test.cc @@ -9,18 +9,24 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_thread_type.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" #include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator.h" #include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" #include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" +#include "third_party/blink/renderer/platform/waitable_event.h" #include <memory> using ::testing::_; +using ::testing::AtLeast; using ::testing::Mock; -using ::testing::StrictMock; using ::testing::Return; +using ::testing::Sequence; +using ::testing::StrictMock; using ::testing::Truly; // This test uses actual threads since mutator logic requires it. This means we @@ -52,7 +58,7 @@ class MockAnimationWorkletMutator return std::unique_ptr<AnimationWorkletOutput>(MutateRef(*input)); } - MOCK_CONST_METHOD0(GetScopeId, int()); + MOCK_CONST_METHOD0(GetWorkletId, int()); MOCK_METHOD1(MutateRef, AnimationWorkletOutput*(const AnimationWorkletInput&)); @@ -63,7 +69,7 @@ class MockCompositorMutatorClient : public CompositorMutatorClient { public: MockCompositorMutatorClient( std::unique_ptr<AnimationWorkletMutatorDispatcherImpl> mutator) - : CompositorMutatorClient(std::move(mutator)) {} + : CompositorMutatorClient(std::move(mutator)), done_event_(nullptr) {} ~MockCompositorMutatorClient() override {} // gmock cannot mock methods with move-only args so we forward it to ourself. void SetMutationUpdate( @@ -71,8 +77,26 @@ class MockCompositorMutatorClient : public CompositorMutatorClient { SetMutationUpdateRef(output_state.get()); } + MOCK_METHOD0(NotifyAnimationsPending, void()); + + void NotifyAnimationsReady() override { + NotifyAnimationsReadyRef(); + if (done_event_) { + done_event_->Signal(); + } + } + + MOCK_METHOD0(NotifyAnimationsReadyRef, void()); + + void SignalWhenComplete(WaitableEvent* done_event) { + done_event_ = done_event; + } + MOCK_METHOD1(SetMutationUpdateRef, void(cc::MutatorOutputState* output_state)); + + private: + WaitableEvent* done_event_; // not owned. }; class AnimationWorkletMutatorDispatcherImplTest : public ::testing::Test { @@ -116,32 +140,35 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, RegisteredAnimatorShouldOnlyReceiveInputForItself) { std::unique_ptr<Thread> first_thread = CreateThread("FirstThread"); MockAnimationWorkletMutator* first_mutator = - new ::testing::StrictMock<MockAnimationWorkletMutator>( + MakeGarbageCollected<MockAnimationWorkletMutator>( first_thread->GetTaskRunner()); mutator_->RegisterAnimationWorkletMutator(first_mutator, first_thread->GetTaskRunner()); - EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11)); + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); EXPECT_CALL(*first_mutator, MutateRef(Truly(OnlyIncludesAnimation1))) .Times(1) .WillOnce(Return(new AnimationWorkletOutput())); EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1); - - mutator_->Mutate(CreateTestMutatorInput()); + mutator_->MutateSynchronously(CreateTestMutatorInput()); } TEST_F(AnimationWorkletMutatorDispatcherImplTest, RegisteredAnimatorShouldNotBeMutatedWhenNoInput) { std::unique_ptr<Thread> first_thread = CreateThread("FirstThread"); MockAnimationWorkletMutator* first_mutator = - new ::testing::StrictMock<MockAnimationWorkletMutator>( + MakeGarbageCollected<MockAnimationWorkletMutator>( first_thread->GetTaskRunner()); mutator_->RegisterAnimationWorkletMutator(first_mutator, first_thread->GetTaskRunner()); - EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11)); + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0); EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0); @@ -151,7 +178,7 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, auto input = std::make_unique<AnimationWorkletDispatcherInput>(); input->Add(std::move(state2)); - mutator_->Mutate(std::move(input)); + mutator_->MutateSynchronously(std::move(input)); } TEST_F(AnimationWorkletMutatorDispatcherImplTest, @@ -159,7 +186,7 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0); std::unique_ptr<AnimationWorkletDispatcherInput> input = std::make_unique<AnimationWorkletDispatcherInput>(); - mutator_->Mutate(std::move(input)); + mutator_->MutateSynchronously(std::move(input)); } TEST_F(AnimationWorkletMutatorDispatcherImplTest, @@ -167,15 +194,18 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, // Create a thread to run mutator tasks. std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread"); MockAnimationWorkletMutator* first_mutator = - new ::testing::StrictMock<MockAnimationWorkletMutator>( + MakeGarbageCollected<MockAnimationWorkletMutator>( first_thread->GetTaskRunner()); mutator_->RegisterAnimationWorkletMutator(first_mutator, first_thread->GetTaskRunner()); - EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11)); + + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); EXPECT_CALL(*first_mutator, MutateRef(_)).Times(1).WillOnce(Return(nullptr)); EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0); - mutator_->Mutate(CreateTestMutatorInput()); + mutator_->MutateSynchronously(CreateTestMutatorInput()); } TEST_F(AnimationWorkletMutatorDispatcherImplTest, @@ -183,17 +213,20 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, // Create a thread to run mutator tasks. std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread"); MockAnimationWorkletMutator* first_mutator = - new ::testing::StrictMock<MockAnimationWorkletMutator>( + MakeGarbageCollected<MockAnimationWorkletMutator>( first_thread->GetTaskRunner()); mutator_->RegisterAnimationWorkletMutator(first_mutator, first_thread->GetTaskRunner()); - EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11)); + + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); EXPECT_CALL(*first_mutator, MutateRef(_)) .Times(1) .WillOnce(Return(new AnimationWorkletOutput())); EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1); - mutator_->Mutate(CreateTestMutatorInput()); + mutator_->MutateSynchronously(CreateTestMutatorInput()); // The above call blocks on mutator threads running their tasks so we can // safely verify here. @@ -201,10 +234,12 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, // Ensure mutator is not invoked after unregistration. EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0); + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(0); EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0); + EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(0); mutator_->UnregisterAnimationWorkletMutator(first_mutator); - mutator_->Mutate(CreateTestMutatorInput()); + mutator_->MutateSynchronously(CreateTestMutatorInput()); Mock::VerifyAndClearExpectations(client_.get()); } @@ -212,10 +247,10 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnSameThread) { std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread"); MockAnimationWorkletMutator* first_mutator = - new ::testing::StrictMock<MockAnimationWorkletMutator>( + MakeGarbageCollected<MockAnimationWorkletMutator>( first_thread->GetTaskRunner()); MockAnimationWorkletMutator* second_mutator = - new ::testing::StrictMock<MockAnimationWorkletMutator>( + MakeGarbageCollected<MockAnimationWorkletMutator>( first_thread->GetTaskRunner()); mutator_->RegisterAnimationWorkletMutator(first_mutator, @@ -223,17 +258,20 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, mutator_->RegisterAnimationWorkletMutator(second_mutator, first_thread->GetTaskRunner()); - EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11)); + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); EXPECT_CALL(*first_mutator, MutateRef(_)) .Times(1) .WillOnce(Return(new AnimationWorkletOutput())); - EXPECT_CALL(*second_mutator, GetScopeId()).Times(1).WillOnce(Return(22)); + EXPECT_CALL(*second_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(22)); EXPECT_CALL(*second_mutator, MutateRef(_)) .Times(1) .WillOnce(Return(new AnimationWorkletOutput())); - EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2); - mutator_->Mutate(CreateTestMutatorInput()); + mutator_->MutateSynchronously(CreateTestMutatorInput()); } TEST_F( @@ -241,12 +279,12 @@ TEST_F( MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnDifferentThreads) { std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread"); MockAnimationWorkletMutator* first_mutator = - new ::testing::StrictMock<MockAnimationWorkletMutator>( + MakeGarbageCollected<MockAnimationWorkletMutator>( first_thread->GetTaskRunner()); std::unique_ptr<Thread> second_thread = CreateThread("SecondAnimationThread"); MockAnimationWorkletMutator* second_mutator = - new ::testing::StrictMock<MockAnimationWorkletMutator>( + MakeGarbageCollected<MockAnimationWorkletMutator>( second_thread->GetTaskRunner()); mutator_->RegisterAnimationWorkletMutator(first_mutator, @@ -254,35 +292,364 @@ TEST_F( mutator_->RegisterAnimationWorkletMutator(second_mutator, second_thread->GetTaskRunner()); - EXPECT_CALL(*first_mutator, GetScopeId()).Times(1).WillOnce(Return(11)); + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); EXPECT_CALL(*first_mutator, MutateRef(_)) .Times(1) .WillOnce(Return(new AnimationWorkletOutput())); - EXPECT_CALL(*second_mutator, GetScopeId()).Times(1).WillOnce(Return(22)); + EXPECT_CALL(*second_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(22)); EXPECT_CALL(*second_mutator, MutateRef(_)) .Times(1) .WillOnce(Return(new AnimationWorkletOutput())); EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2); - mutator_->Mutate(CreateTestMutatorInput()); + mutator_->MutateSynchronously(CreateTestMutatorInput()); // The above call blocks on mutator threads running their tasks so we can // safely verify here. Mock::VerifyAndClearExpectations(client_.get()); - // Ensure mutator is not invoked after unregistration. + // Ensure first_mutator is not invoked after unregistration. mutator_->UnregisterAnimationWorkletMutator(first_mutator); - EXPECT_CALL(*first_mutator, GetScopeId()).Times(0); + EXPECT_CALL(*first_mutator, GetWorkletId()).Times(0); EXPECT_CALL(*first_mutator, MutateRef(_)).Times(0); - EXPECT_CALL(*second_mutator, GetScopeId()).Times(1).WillOnce(Return(22)); + EXPECT_CALL(*second_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(22)); EXPECT_CALL(*second_mutator, MutateRef(_)) .Times(1) .WillOnce(Return(new AnimationWorkletOutput())); EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1); - mutator_->Mutate(CreateTestMutatorInput()); + mutator_->MutateSynchronously(CreateTestMutatorInput()); + Mock::VerifyAndClearExpectations(client_.get()); } +// ----------------------------------------------------------------------- +// Asynchronous version of tests. + +// Callback wrapping portion of the async test that is required to run on the +// compositor thread. +using MutateAsyncCallback = WTF::CrossThreadFunction<void()>; + +using MutatorDispatcherRef = + scoped_refptr<AnimationWorkletMutatorDispatcherImpl>; + +class AnimationWorkletMutatorDispatcherImplAsyncTest + : public AnimationWorkletMutatorDispatcherImplTest { + public: + void SetUp() override { + if (!Thread::CompositorThread()) { + Thread::CreateAndSetCompositorThread(); + } + AnimationWorkletMutatorDispatcherImplTest::SetUp(); + } + + // Call this version of mutate and wait if expecting a mutate completion + // notification from the client. + void CallMutateAndWaitForClientCompletion( + MutateAsyncCallback mutate_callback) { + WaitableEvent done_event; + client_->SignalWhenComplete(&done_event); + PostCrossThreadTask(*Thread::CompositorThread()->GetTaskRunner(), FROM_HERE, + std::move(mutate_callback)); + done_event.Wait(); + } + + // Call this version of mutate and wait if there is no expectation of client + // notifications. There are no notificaitons if the mutate call is a no-op + // such as when there are no inputs. + void CallMutateAndWaitForCallbackCompletion( + MutateAsyncCallback mutate_callback) { + WaitableEvent done_event; + PostCrossThreadTask( + *Thread::CompositorThread()->GetTaskRunner(), FROM_HERE, + CrossThreadBind( + [](MutateAsyncCallback mutate_callback, WaitableEvent* done_event) { + mutate_callback.Run(); + done_event->Signal(); + }, + WTF::Passed(std::move(mutate_callback)), + WTF::CrossThreadUnretained(&done_event))); + done_event.Wait(); + } +}; + +TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest, + RegisteredAnimatorShouldOnlyReceiveInputForItself) { + std::unique_ptr<Thread> first_thread = CreateThread("FirstThread"); + MockAnimationWorkletMutator* first_mutator = + MakeGarbageCollected<MockAnimationWorkletMutator>( + first_thread->GetTaskRunner()); + + // Call MutateAsynchronously from the compositor thread. + MutateAsyncCallback mutate_callback = CrossThreadBind( + [](std::unique_ptr<Thread> first_thread, + MockAnimationWorkletMutator* first_mutator, + AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) { + async_test->mutator_->RegisterAnimationWorkletMutator( + first_mutator, first_thread->GetTaskRunner()); + async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput()); + }, + WTF::Passed(std::move(first_thread)), + WrapCrossThreadWeakPersistent(first_mutator), + WTF::CrossThreadUnretained(this)); + + Sequence s; + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); + EXPECT_CALL(*first_mutator, MutateRef(_)) + .Times(1) + .WillOnce(Return(new AnimationWorkletOutput())); + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s); + EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1).InSequence(s); + EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s); + CallMutateAndWaitForClientCompletion(std::move(mutate_callback)); +} + +TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest, + RegisteredAnimatorShouldNotBeMutatedWhenNoInput) { + std::unique_ptr<Thread> first_thread = CreateThread("FirstThread"); + MockAnimationWorkletMutator* first_mutator = + MakeGarbageCollected<MockAnimationWorkletMutator>( + first_thread->GetTaskRunner()); + + // Call MutateAsynchronously from the compositor thread. + MutateAsyncCallback mutate_callback = CrossThreadBind( + [](std::unique_ptr<Thread> first_thread, + MockAnimationWorkletMutator* first_mutator, + AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) { + async_test->mutator_->RegisterAnimationWorkletMutator( + first_mutator, first_thread->GetTaskRunner()); + + AnimationWorkletInput::AddAndUpdateState state2{ + {22, 2}, "test2", 5000, nullptr, 1}; + + auto input = std::make_unique<AnimationWorkletDispatcherInput>(); + input->Add(std::move(state2)); + + async_test->mutator_->MutateAsynchronously(std::move(input)); + }, + WTF::Passed(std::move(first_thread)), + WrapCrossThreadWeakPersistent(first_mutator), + WTF::CrossThreadUnretained(this)); + + // The start of the mutation process will be synchronous. If a pending + // notification is not received by the time the callback returns, it will not + // be triggered later. + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(0); + CallMutateAndWaitForCallbackCompletion(std::move(mutate_callback)); +} + +TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest, + MutationUpdateIsNotInvokedWithNoRegisteredAnimators) { + // Call MutateAsynchronously from the compositor thread. + MutateAsyncCallback mutate_callback = CrossThreadBind( + [](AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) { + std::unique_ptr<AnimationWorkletDispatcherInput> input = + std::make_unique<AnimationWorkletDispatcherInput>(); + async_test->mutator_->MutateAsynchronously(std::move(input)); + }, + WTF::CrossThreadUnretained(this)); + + // The start of the mutation process will be synchronous. If a pending + // notification is not received by the time the callback returns, it will not + // be triggered later. + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(0); + CallMutateAndWaitForCallbackCompletion(std::move(mutate_callback)); +} + +TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest, + MutationUpdateIsNotInvokedWithNullOutput) { + // Create a thread to run mutator tasks. + std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread"); + MockAnimationWorkletMutator* first_mutator = + MakeGarbageCollected<MockAnimationWorkletMutator>( + first_thread->GetTaskRunner()); + + // Call MutateAsynchronously from the compositor thread. + MutateAsyncCallback mutate_callback = CrossThreadBind( + [](std::unique_ptr<Thread> first_thread, + MockAnimationWorkletMutator* first_mutator, + AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) { + async_test->mutator_->RegisterAnimationWorkletMutator( + first_mutator, first_thread->GetTaskRunner()); + async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput()); + }, + WTF::Passed(std::move(first_thread)), + WrapCrossThreadWeakPersistent(first_mutator), + WTF::CrossThreadUnretained(this)); + + Sequence s; + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); + EXPECT_CALL(*first_mutator, MutateRef(_)).Times(1).WillOnce(Return(nullptr)); + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s); + EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0); + EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s); + CallMutateAndWaitForClientCompletion(std::move(mutate_callback)); +} + +TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest, + MutationUpdateIsInvokedCorrectlyWithSingleRegisteredAnimator) { + // Create a thread to run mutator tasks. + std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread"); + MockAnimationWorkletMutator* first_mutator = + MakeGarbageCollected<MockAnimationWorkletMutator>( + first_thread->GetTaskRunner()); + + // Call MutateAsynchronously from the compositor thread. + MutateAsyncCallback mutate_callback = CrossThreadBind( + [](std::unique_ptr<Thread> first_thread, + MockAnimationWorkletMutator* first_mutator, + AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) { + async_test->mutator_->RegisterAnimationWorkletMutator( + first_mutator, first_thread->GetTaskRunner()); + async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput()); + }, + WTF::Passed(std::move(first_thread)), + WrapCrossThreadWeakPersistent(first_mutator), + WTF::CrossThreadUnretained(this)); + + Sequence s; + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); + EXPECT_CALL(*first_mutator, MutateRef(_)) + .Times(1) + .WillOnce(Return(new AnimationWorkletOutput())); + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s); + EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1).InSequence(s); + EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s); + CallMutateAndWaitForClientCompletion(std::move(mutate_callback)); + + // Above call blocks until complete signal is received. + Mock::VerifyAndClearExpectations(client_.get()); + + // Call MutateAsynchronously from the compositor thread. + MutateAsyncCallback mutate_callback2 = CrossThreadBind( + [](MockAnimationWorkletMutator* first_mutator, + AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) { + // Ensure mutator is not invoked after unregistration. + async_test->mutator_->UnregisterAnimationWorkletMutator(first_mutator); + async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput()); + }, + WrapCrossThreadWeakPersistent(first_mutator), + WTF::CrossThreadUnretained(this)); + + // The start of the mutation process will be synchronous. If a pending + // notification is not received by the time the callback returns, it will not + // be triggered later. + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(0); + CallMutateAndWaitForCallbackCompletion(std::move(mutate_callback2)); + Mock::VerifyAndClearExpectations(client_.get()); +} + +TEST_F(AnimationWorkletMutatorDispatcherImplAsyncTest, + MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnSameThread) { + std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread"); + MockAnimationWorkletMutator* first_mutator = + MakeGarbageCollected<MockAnimationWorkletMutator>( + first_thread->GetTaskRunner()); + MockAnimationWorkletMutator* second_mutator = + MakeGarbageCollected<MockAnimationWorkletMutator>( + first_thread->GetTaskRunner()); + + // Call MutateAsynchronously from the compositor thread. + MutateAsyncCallback mutate_callback = CrossThreadBind( + [](std::unique_ptr<Thread> first_thread, + MockAnimationWorkletMutator* first_mutator, + MockAnimationWorkletMutator* second_mutator, + AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) { + async_test->mutator_->RegisterAnimationWorkletMutator( + first_mutator, first_thread->GetTaskRunner()); + async_test->mutator_->RegisterAnimationWorkletMutator( + second_mutator, first_thread->GetTaskRunner()); + async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput()); + }, + WTF::Passed(std::move(first_thread)), + WrapCrossThreadWeakPersistent(first_mutator), + WrapCrossThreadWeakPersistent(second_mutator), + WTF::CrossThreadUnretained(this)); + + Sequence s; + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); + EXPECT_CALL(*first_mutator, MutateRef(_)) + .Times(1) + .WillOnce(Return(new AnimationWorkletOutput())); + EXPECT_CALL(*second_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(22)); + EXPECT_CALL(*second_mutator, MutateRef(_)) + .Times(1) + .WillOnce(Return(new AnimationWorkletOutput())); + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s); + EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2).InSequence(s); + EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s); + CallMutateAndWaitForClientCompletion(std::move(mutate_callback)); +} + +TEST_F( + AnimationWorkletMutatorDispatcherImplAsyncTest, + MutationUpdateInvokedCorrectlyWithTwoRegisteredAnimatorsOnDifferentThreads) { + std::unique_ptr<Thread> first_thread = CreateThread("FirstAnimationThread"); + MockAnimationWorkletMutator* first_mutator = + MakeGarbageCollected<MockAnimationWorkletMutator>( + first_thread->GetTaskRunner()); + + std::unique_ptr<Thread> second_thread = CreateThread("SecondAnimationThread"); + MockAnimationWorkletMutator* second_mutator = + MakeGarbageCollected<MockAnimationWorkletMutator>( + second_thread->GetTaskRunner()); + + // Call MutateAsynchronously from the compositor thread. + MutateAsyncCallback mutate_callback = CrossThreadBind( + [](std::unique_ptr<Thread> first_thread, + std::unique_ptr<Thread> second_thread, + MockAnimationWorkletMutator* first_mutator, + MockAnimationWorkletMutator* second_mutator, + AnimationWorkletMutatorDispatcherImplAsyncTest* async_test) { + async_test->mutator_->RegisterAnimationWorkletMutator( + first_mutator, first_thread->GetTaskRunner()); + async_test->mutator_->RegisterAnimationWorkletMutator( + second_mutator, second_thread->GetTaskRunner()); + async_test->mutator_->MutateAsynchronously(CreateTestMutatorInput()); + }, + WTF::Passed(std::move(first_thread)), + WTF::Passed(std::move(second_thread)), + WrapCrossThreadWeakPersistent(first_mutator), + WrapCrossThreadWeakPersistent(second_mutator), + WTF::CrossThreadUnretained(this)); + + Sequence s; + EXPECT_CALL(*first_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(11)); + EXPECT_CALL(*first_mutator, MutateRef(_)) + .Times(1) + .WillOnce(Return(new AnimationWorkletOutput())); + EXPECT_CALL(*second_mutator, GetWorkletId()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(22)); + EXPECT_CALL(*second_mutator, MutateRef(_)) + .Times(1) + .WillOnce(Return(new AnimationWorkletOutput())); + EXPECT_CALL(*client_, NotifyAnimationsPending()).Times(1).InSequence(s); + EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(2).InSequence(s); + EXPECT_CALL(*client_, NotifyAnimationsReadyRef()).Times(1).InSequence(s); + CallMutateAndWaitForClientCompletion(std::move(mutate_callback)); +} + } // namespace } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc index 0fdd3dd61b2..8a56e382d36 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image.cc @@ -99,7 +99,7 @@ void BitmapImage::NotifyMemoryChanged() { size_t BitmapImage::TotalFrameBytes() { if (cached_frame_) - return Size().Area() * sizeof(ImageFrame::PixelData); + return static_cast<size_t>(Size().Area()) * sizeof(ImageFrame::PixelData); return 0u; } @@ -182,8 +182,8 @@ Image::SizeAvailability BitmapImage::SetData(scoped_refptr<SharedBuffer> data, // Return the image density in 0.01 "bits per pixel" rounded to the nearest // integer. -static inline int ImageDensityInCentiBpp(IntSize size, - size_t image_size_bytes) { +static inline uint64_t ImageDensityInCentiBpp(IntSize size, + size_t image_size_bytes) { uint64_t image_area = static_cast<uint64_t>(size.Width()) * size.Height(); return (static_cast<uint64_t>(image_size_bytes) * 100 * 8 + image_area / 2) / image_area; diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc index 3158dc5f284..965892c862e 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc @@ -46,24 +46,27 @@ void BitmapImageMetrics::CountImageOrientation( } void BitmapImageMetrics::CountImageJpegDensity(int image_min_side, - int64_t density_centi_bpp) { + uint64_t density_centi_bpp) { // Values are reported in the range 0.01 to 10 bpp, in different metrics // depending on the image category (small, medium, large). if (image_min_side >= 1000) { DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, density_histogram, ("Blink.DecodedImage.JpegDensity.1000px", 1, 1000, 100)); - density_histogram.Count(density_centi_bpp); + density_histogram.Count( + base::saturated_cast<base::Histogram::Sample>(density_centi_bpp)); } else if (image_min_side >= 400) { DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, density_histogram, ("Blink.DecodedImage.JpegDensity.400px", 1, 1000, 100)); - density_histogram.Count(density_centi_bpp); + density_histogram.Count( + base::saturated_cast<base::Histogram::Sample>(density_centi_bpp)); } else if (image_min_side >= 100) { DEFINE_THREAD_SAFE_STATIC_LOCAL( CustomCountHistogram, density_histogram, ("Blink.DecodedImage.JpegDensity.100px", 1, 1000, 100)); - density_histogram.Count(density_centi_bpp); + density_histogram.Count( + base::saturated_cast<base::Histogram::Sample>(density_centi_bpp)); } else { // We don't report for images with 0 to 99px on the smallest dimension. } diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h index 3479690b4e5..ab67d76ca28 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h +++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h @@ -77,7 +77,7 @@ class PLATFORM_EXPORT BitmapImageMetrics { // Report the JPEG compression density in 0.01 bits per pixel for an image // with a smallest side (width or length) of |image_min_side|. static void CountImageJpegDensity(int image_min_side, - int64_t density_centi_bpp); + uint64_t density_centi_bpp); static void CountImageGammaAndGamut(const skcms_ICCProfile*); static void CountJpegArea(const IntSize& size); static void CountJpegColorSpace(JpegColorSpace color_space); diff --git a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc index 616b61d76b9..618a32a8f91 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/bitmap_image_test.cc @@ -31,6 +31,7 @@ #include "third_party/blink/renderer/platform/graphics/bitmap_image.h" #include "base/test/simple_test_tick_clock.h" +#include "cc/paint/image_provider.h" #include "cc/paint/skia_paint_canvas.h" #include "cc/tiles/mipmap_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -233,7 +234,7 @@ class BitmapImageTest : public testing::Test { protected: void SetUp() override { - image_observer_ = new FakeImageObserver; + image_observer_ = MakeGarbageCollected<FakeImageObserver>(); image_ = BitmapImage::Create(image_observer_.Get()); } diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc index ca6a5261754..594dd36935a 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc @@ -33,6 +33,7 @@ #include "cc/layers/texture_layer.h" #include "components/viz/common/resources/transferable_resource.h" #include "gpu/command_buffer/client/gles2_interface.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/graphics/canvas_heuristic_parameters.h" #include "third_party/blink/renderer/platform/graphics/canvas_resource.h" @@ -141,6 +142,9 @@ void Canvas2DLayerBridge::ResetResourceProvider() { } bool Canvas2DLayerBridge::ShouldAccelerate(AccelerationHint hint) const { + if (base::FeatureList::IsEnabled(features::kAlwaysAccelerateCanvas)) { + return true; + } bool accelerate; if (software_rendering_while_hidden_) { accelerate = false; @@ -601,13 +605,12 @@ bool Canvas2DLayerBridge::PrepareTransferableResource( return false; scoped_refptr<CanvasResource> frame = ResourceProvider()->ProduceFrame(); - if (frame && frame->IsValid()) { - // Note frame is kept alive via a reference kept in out_release_callback. - bool success = frame->PrepareTransferableResource( - out_resource, out_release_callback, kUnverifiedSyncToken); - return success; - } - return false; + if (!frame || !frame->IsValid()) + return false; + + // Note frame is kept alive via a reference kept in out_release_callback. + return frame->PrepareTransferableResource(out_resource, out_release_callback, + kUnverifiedSyncToken); } cc::Layer* Canvas2DLayerBridge::Layer() { diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h index 326c4f6727f..02c3c1c3528 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h +++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h @@ -193,7 +193,7 @@ class PLATFORM_EXPORT Canvas2DLayerBridge : public cc::TextureLayerClient { friend class Canvas2DLayerBridgeTest; friend class CanvasRenderingContext2DTest; - friend class HTMLCanvasPainterTestForSPv2; + friend class HTMLCanvasPainterTestForCAP; AccelerationMode acceleration_mode_; CanvasColorParams color_params_; diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc index e3079a828ba..cdcba06eaa4 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_color_params.cc @@ -140,24 +140,24 @@ sk_sp<SkColorSpace> CanvasColorParams::GetSkColorSpace() const { sk_sp<SkColorSpace> CanvasColorParams::CanvasColorSpaceToSkColorSpace( CanvasColorSpace color_space) { - SkColorSpace::Gamut gamut = SkColorSpace::kSRGB_Gamut; - SkColorSpace::RenderTargetGamma gamma = SkColorSpace::kSRGB_RenderTargetGamma; + skcms_Matrix3x3 gamut = SkNamedGamut::kSRGB; + skcms_TransferFunction transferFn = SkNamedTransferFn::kSRGB; switch (color_space) { case kSRGBCanvasColorSpace: break; case kLinearRGBCanvasColorSpace: - gamma = SkColorSpace::kLinear_RenderTargetGamma; + transferFn = SkNamedTransferFn::kLinear; break; case kRec2020CanvasColorSpace: - gamut = SkColorSpace::kRec2020_Gamut; - gamma = SkColorSpace::kLinear_RenderTargetGamma; + gamut = SkNamedGamut::kRec2020; + transferFn = SkNamedTransferFn::kLinear; break; case kP3CanvasColorSpace: - gamut = SkColorSpace::kDCIP3_D65_Gamut; - gamma = SkColorSpace::kLinear_RenderTargetGamma; + gamut = SkNamedGamut::kDCIP3; + transferFn = SkNamedTransferFn::kLinear; break; } - return SkColorSpace::MakeRGB(gamma, gamut); + return SkColorSpace::MakeRGB(transferFn, gamut); } gfx::BufferFormat CanvasColorParams::GetBufferFormat() const { @@ -240,14 +240,14 @@ CanvasColorParams::CanvasColorParams(const sk_sp<SkColorSpace> color_space, color_space_ = kLinearRGBCanvasColorSpace; } else if (SkColorSpace::Equals( color_space.get(), - SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kRec2020_Gamut) + SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, + SkNamedGamut::kRec2020) .get())) { color_space_ = kRec2020CanvasColorSpace; } else if (SkColorSpace::Equals( color_space.get(), - SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kDCIP3_D65_Gamut) + SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, + SkNamedGamut::kDCIP3) .get())) { color_space_ = kP3CanvasColorSpace; } diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc index 69d5a9a547f..46bb27f2346 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource.cc @@ -82,12 +82,10 @@ static void ReleaseFrameResources( const gpu::SyncToken& sync_token, bool lost_resource) { resource->WaitSyncToken(sync_token); - if (lost_resource) { + if (lost_resource) resource->Abandon(); - } - if (resource_provider && !lost_resource && resource->IsRecycleable()) { + if (resource_provider && !lost_resource && resource->IsRecycleable()) resource_provider->RecycleResource(std::move(resource)); - } } bool CanvasResource::PrepareTransferableResource( @@ -116,7 +114,8 @@ bool CanvasResource::PrepareAcceleratedTransferableResource( // Gpu compositing is a prerequisite for compositing an accelerated resource DCHECK(SharedGpuContext::IsGpuCompositingEnabled()); auto* gl = ContextGL(); - DCHECK(gl); + if (!gl) + return false; const gpu::Mailbox& mailbox = GetOrCreateGpuMailbox(sync_mode); if (mailbox.IsZero()) return false; @@ -413,7 +412,6 @@ void CanvasResourceGpuMemoryBuffer::Abandon() { const gpu::Mailbox& CanvasResourceGpuMemoryBuffer::GetOrCreateGpuMailbox( MailboxSyncMode sync_mode) { auto* gl = ContextGL(); - DCHECK(gl); // caller should already have early exited if !gl. if (gpu_mailbox_.IsZero() && gl) { gl->ProduceTextureDirectCHROMIUM(texture_id_, gpu_mailbox_.name); mailbox_needs_new_sync_token_ = true; @@ -431,16 +429,17 @@ GLuint CanvasResourceGpuMemoryBuffer::GetBackingTextureHandleForOverwrite() { } const gpu::SyncToken CanvasResourceGpuMemoryBuffer::GetSyncToken() { - if (mailbox_needs_new_sync_token_) { - auto* gl = ContextGL(); - DCHECK(gl); // caller should already have early exited if !gl. - mailbox_needs_new_sync_token_ = false; - if (mailbox_sync_mode_ == kVerifiedSyncToken) { - gl->GenSyncTokenCHROMIUM(sync_token_.GetData()); - } else { - gl->GenUnverifiedSyncTokenCHROMIUM(sync_token_.GetData()); - } - } + if (!mailbox_needs_new_sync_token_) + return sync_token_; + auto* gl = ContextGL(); + if (!gl) + return sync_token_; + mailbox_needs_new_sync_token_ = false; + if (mailbox_sync_mode_ == kVerifiedSyncToken) + gl->GenSyncTokenCHROMIUM(sync_token_.GetData()); + else + gl->GenUnverifiedSyncTokenCHROMIUM(sync_token_.GetData()); + return sync_token_; } diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc index d66820e97e0..75731e65285 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc @@ -60,7 +60,7 @@ CanvasResourceDispatcher::CanvasResourceDispatcher( num_unreclaimed_frames_posted_(0), client_(client), enable_surface_synchronization_( - features::IsSurfaceSynchronizationEnabled()), + ::features::IsSurfaceSynchronizationEnabled()), weak_ptr_factory_(this) { // Frameless canvas pass an invalid |frame_sink_id_|; don't create mojo // channel for this special case. @@ -75,8 +75,9 @@ CanvasResourceDispatcher::CanvasResourceDispatcher( DCHECK(provider); binding_.Bind(mojo::MakeRequest(&client_ptr_)); provider->CreateCompositorFrameSink(frame_sink_id_, std::move(client_ptr_), - mojo::MakeRequest(&sink_), - mojo::MakeRequest(&surface_embedder_)); + mojo::MakeRequest(&sink_)); + provider->ConnectToEmbedder(frame_sink_id_, + mojo::MakeRequest(&surface_embedder_)); } CanvasResourceDispatcher::~CanvasResourceDispatcher() = default; @@ -218,6 +219,8 @@ bool CanvasResourceDispatcher::PrepareFrame( } frame->metadata.begin_frame_ack = current_begin_frame_ack_; + frame->metadata.frame_token = ++next_frame_token_; + const gfx::Rect bounds(size_.Width(), size_.Height()); constexpr int kRenderPassId = 1; constexpr bool is_clipped = false; diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h index 299818c4434..cee6b36546f 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h +++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h @@ -120,6 +120,8 @@ class PLATFORM_EXPORT CanvasResourceDispatcher unsigned next_resource_id_ = 0; ResourceMap resources_; + viz::FrameTokenGenerator next_frame_token_; + // The latest_unposted_resource_id_ always refers to the Id of the frame // resource used by the latest_unposted_image_. scoped_refptr<CanvasResource> latest_unposted_image_; diff --git a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index d04b01988af..e282da6a595 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h" #include "base/metrics/histogram_functions.h" +#include "base/stl_util.h" #include "cc/paint/decode_stashing_image_provider.h" #include "cc/tiles/software_image_decode_cache.h" #include "components/viz/common/resources/resource_format_utils.h" @@ -435,53 +436,84 @@ class CanvasResourceProviderDirectGpuMemoryBuffer final scoped_refptr<CanvasResource> resource_; }; -enum CanvasResourceType { - kDirectGpuMemoryBufferResourceType, - kTextureGpuMemoryBufferResourceType, - kBitmapGpuMemoryBufferResourceType, - kSharedBitmapResourceType, - kTextureResourceType, - kBitmapResourceType, -}; - -constexpr CanvasResourceType kSoftwareCompositedFallbackList[] = { - kBitmapGpuMemoryBufferResourceType, - kSharedBitmapResourceType, - // Fallback to no direct compositing support - kBitmapResourceType, -}; +namespace { -constexpr CanvasResourceType kSoftwareFallbackList[] = { - kBitmapResourceType, +enum class CanvasResourceType { + kDirectGpuMemoryBuffer, + kTextureGpuMemoryBuffer, + kBitmapGpuMemoryBuffer, + kSharedBitmap, + kTexture, + kBitmap, }; -constexpr CanvasResourceType kAcceleratedFallbackList[] = { - kTextureResourceType, - // Fallback to software - kBitmapResourceType, -}; +const std::vector<CanvasResourceType>& GetResourceTypeFallbackList( + CanvasResourceProvider::ResourceUsage usage) { + static const std::vector<CanvasResourceType> kSoftwareFallbackList({ + CanvasResourceType::kBitmap, + }); + + static const std::vector<CanvasResourceType> kAcceleratedFallbackList({ + CanvasResourceType::kTexture, + // Fallback to software + CanvasResourceType::kBitmap, + }); + + static const std::vector<CanvasResourceType> kSoftwareCompositedFallbackList({ + CanvasResourceType::kBitmapGpuMemoryBuffer, + CanvasResourceType::kSharedBitmap, + // Fallback to no direct compositing support + CanvasResourceType::kBitmap, + }); + + static const std::vector<CanvasResourceType> + kAcceleratedCompositedFallbackList({ + CanvasResourceType::kTextureGpuMemoryBuffer, + CanvasResourceType::kTexture, + // Fallback to software composited + // (|kSoftwareCompositedFallbackList|). + CanvasResourceType::kBitmapGpuMemoryBuffer, + CanvasResourceType::kSharedBitmap, + // Fallback to no direct compositing support + CanvasResourceType::kBitmap, + }); + DCHECK(std::equal(kAcceleratedCompositedFallbackList.begin() + 2, + kAcceleratedCompositedFallbackList.end(), + kSoftwareCompositedFallbackList.begin(), + kSoftwareCompositedFallbackList.end())); + + static const std::vector<CanvasResourceType> kAcceleratedDirectFallbackList({ + CanvasResourceType::kDirectGpuMemoryBuffer, + // The rest is equal to |kAcceleratedCompositedFallbackList|. + CanvasResourceType::kTextureGpuMemoryBuffer, + CanvasResourceType::kTexture, + // Fallback to software composited + CanvasResourceType::kBitmapGpuMemoryBuffer, + CanvasResourceType::kSharedBitmap, + // Fallback to no direct compositing support + CanvasResourceType::kBitmap, + }); + DCHECK(std::equal(kAcceleratedDirectFallbackList.begin() + 1, + kAcceleratedDirectFallbackList.end(), + kAcceleratedCompositedFallbackList.begin(), + kAcceleratedCompositedFallbackList.end())); -constexpr CanvasResourceType kAcceleratedCompositedFallbackList[] = { - kTextureGpuMemoryBufferResourceType, - kTextureResourceType, - // Fallback to software composited - kBitmapGpuMemoryBufferResourceType, - kSharedBitmapResourceType, - // Fallback to no direct compositing support - kBitmapResourceType, -}; + switch (usage) { + case CanvasResourceProvider::kSoftwareResourceUsage: + return kSoftwareFallbackList; + case CanvasResourceProvider::kSoftwareCompositedResourceUsage: + return kSoftwareCompositedFallbackList; + case CanvasResourceProvider::kAcceleratedResourceUsage: + return kAcceleratedFallbackList; + case CanvasResourceProvider::kAcceleratedCompositedResourceUsage: + return kAcceleratedCompositedFallbackList; + case CanvasResourceProvider::kAcceleratedDirectResourceUsage: + return kAcceleratedDirectFallbackList; + } + NOTREACHED(); +} -constexpr CanvasResourceType kAcceleratedDirectFallbackList[] = { - kDirectGpuMemoryBufferResourceType, - // The rest is equal to |kAcceleratedCompositedFallbackList|. - kTextureGpuMemoryBufferResourceType, - kTextureResourceType, - // Fallback to software composited - kBitmapGpuMemoryBufferResourceType, - kSharedBitmapResourceType, - // Fallback to no direct compositing support - kBitmapResourceType, -}; +} // unnamed namespace std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create( const IntSize& size, @@ -492,41 +524,17 @@ std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create( PresentationMode presentation_mode, base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher, bool is_origin_top_left) { - const CanvasResourceType* resource_type_fallback_list = nullptr; - size_t list_length = 0; - - switch (usage) { - case kSoftwareResourceUsage: - resource_type_fallback_list = kSoftwareFallbackList; - list_length = arraysize(kSoftwareFallbackList); - break; - case kSoftwareCompositedResourceUsage: - resource_type_fallback_list = kSoftwareCompositedFallbackList; - list_length = arraysize(kSoftwareCompositedFallbackList); - break; - case kAcceleratedResourceUsage: - resource_type_fallback_list = kAcceleratedFallbackList; - list_length = arraysize(kAcceleratedFallbackList); - break; - case kAcceleratedCompositedResourceUsage: - resource_type_fallback_list = kAcceleratedCompositedFallbackList; - list_length = arraysize(kAcceleratedCompositedFallbackList); - break; - case kAcceleratedDirectResourceUsage: - resource_type_fallback_list = kAcceleratedDirectFallbackList; - list_length = arraysize(kAcceleratedDirectFallbackList); - break; - } - std::unique_ptr<CanvasResourceProvider> provider; - for (size_t i = 0; i < list_length; ++i) { + const std::vector<CanvasResourceType>& fallback_list = + GetResourceTypeFallbackList(usage); + for (CanvasResourceType resource_type : fallback_list) { // Note: We are deliberately not using std::move() on // |context_provider_wrapper| and |resource_dispatcher| to ensure that the // pointers remain valid for the next iteration of this loop if necessary. - switch (resource_type_fallback_list[i]) { - case kTextureGpuMemoryBufferResourceType: + switch (resource_type) { + case CanvasResourceType::kTextureGpuMemoryBuffer: FALLTHROUGH; - case kDirectGpuMemoryBufferResourceType: + case CanvasResourceType::kDirectGpuMemoryBuffer: if (!SharedGpuContext::IsGpuCompositingEnabled()) continue; if (presentation_mode != kAllowImageChromiumPresentationMode) @@ -546,8 +554,7 @@ std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create( DCHECK_EQ(color_params.GLUnsizedInternalFormat(), gpu::InternalFormatForGpuMemoryBufferFormat( color_params.GetBufferFormat())); - if (resource_type_fallback_list[i] == - kDirectGpuMemoryBufferResourceType) { + if (resource_type == CanvasResourceType::kDirectGpuMemoryBuffer) { provider = std::make_unique<CanvasResourceProviderDirectGpuMemoryBuffer>( size, msaa_sample_count, color_params, @@ -561,7 +568,7 @@ std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create( is_origin_top_left); } break; - case kBitmapGpuMemoryBufferResourceType: + case CanvasResourceType::kBitmapGpuMemoryBuffer: if (!SharedGpuContext::IsGpuCompositingEnabled()) continue; if (presentation_mode != kAllowImageChromiumPresentationMode) @@ -579,20 +586,20 @@ std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create( size, color_params, context_provider_wrapper, resource_dispatcher); break; - case kSharedBitmapResourceType: + case CanvasResourceType::kSharedBitmap: if (!resource_dispatcher) continue; provider = std::make_unique<CanvasResourceProviderSharedBitmap>( size, color_params, resource_dispatcher); break; - case kTextureResourceType: + case CanvasResourceType::kTexture: if (!context_provider_wrapper) continue; provider = std::make_unique<CanvasResourceProviderTexture>( size, msaa_sample_count, color_params, context_provider_wrapper, resource_dispatcher, is_origin_top_left); break; - case kBitmapResourceType: + case CanvasResourceType::kBitmap: provider = std::make_unique<CanvasResourceProviderBitmap>( size, color_params, context_provider_wrapper, resource_dispatcher); break; diff --git a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc index 25fdcaa6f59..9fa1a526ebe 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc @@ -77,12 +77,12 @@ ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace( if (conversion == kColorSpaceConversion_LinearRGB) return SkColorSpace::MakeSRGBLinear(); if (conversion == kColorSpaceConversion_P3) { - return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kDCIP3_D65_Gamut); + return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, + SkNamedGamut::kDCIP3); } if (conversion == kColorSpaceConversion_Rec2020) { - return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kRec2020_Gamut); + return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, + SkNamedGamut::kRec2020); } return nullptr; } @@ -286,9 +286,12 @@ bool ColorCorrectionTestUtils::MatchSkImages(sk_sp<SkImage> src_image, return false; // Color type is not checked since the decoded image does not have a specific // color type, unless it is drawn onto a surface or readPixels() is called. - if (!MatchColorSpace(src_image->refColorSpace(), - dst_image->refColorSpace())) { - return false; + // Only compare color spaces if both are non-null + if (src_image->refColorSpace() && dst_image->refColorSpace()) { + if (!MatchColorSpace(src_image->refColorSpace(), + dst_image->refColorSpace())) { + return false; + } } bool test_passed = true; diff --git a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h index 4ce10d0025a..f052b58fdd8 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h +++ b/chromium/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h @@ -73,6 +73,9 @@ class ColorCorrectionTestUtils { static bool MatchColorSpace(sk_sp<SkColorSpace> src_color_space, sk_sp<SkColorSpace> dst_color_space); + // Compares size, colorspace and pixel values of two images + // If the colorspace of either image is null the colorspaces are assumed + // to be equal static bool MatchSkImages(sk_sp<SkImage> src_image, sk_sp<SkImage> dst_image, unsigned uint8_tolerance, diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/README.md b/chromium/third_party/blink/renderer/platform/graphics/compositing/README.md index 274707ffec5..f8334d739ce 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/README.md +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/README.md @@ -5,7 +5,7 @@ This directory contains the implementation of the "Blink compositing algorithm". This code is owned by the [paint team][paint-team-site]. [paint-team-site]: https://www.chromium.org/teams/paint-team -This document explains the SPv2 world as it develops, not the SPv1 world it +This document explains the CAP world as it develops, not the SPv1 world it replaces. ## Blink compositing algorithm diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc index a1b314914fd..c9c643ff9ef 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc @@ -37,7 +37,8 @@ class ChunkToLayerMapperTest : public testing::Test { e0(), EffectPaintPropertyNode::State{ layer_transform_.get(), layer_clip_.get(), kColorFilterLuminanceToAlpha, CompositorFilterOperations(), - 0.789f, CompositorFilterOperations(), SkBlendMode::kSrcIn}); + 0.789f, CompositorFilterOperations(), gfx::RectF(), + SkBlendMode::kSrcIn}); } return PropertyTreeState(layer_transform_.get(), layer_clip_.get(), layer_effect_.get()); diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc index 374222bd712..dc6ed8d6271 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.cc @@ -32,7 +32,9 @@ ContentLayerClientImpl::ContentLayerClientImpl() cc_picture_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr()); } -ContentLayerClientImpl::~ContentLayerClientImpl() = default; +ContentLayerClientImpl::~ContentLayerClientImpl() { + cc_picture_layer_->ClearClient(); +} static int GetTransformId(const TransformPaintPropertyNode* transform, ContentLayerClientImpl::LayerAsJSONContext& context) { @@ -84,7 +86,7 @@ static int GetTransformId(const TransformPaintPropertyNode* transform, return transform_id; } -// This is the SPv2 version of GraphicsLayer::LayerAsJSONInternal(). +// This is the CAP version of GraphicsLayer::LayerAsJSONInternal(). std::unique_ptr<JSONObject> ContentLayerClientImpl::LayerAsJSON( LayerAsJSONContext& context) const { std::unique_ptr<JSONObject> json = JSONObject::Create(); diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc index 43aeb50ebdd..4d20e8dc113 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc @@ -10,6 +10,7 @@ #include "cc/layers/layer.h" #include "cc/layers/picture_layer.h" #include "cc/paint/display_item_list.h" +#include "cc/trees/effect_node.h" #include "cc/trees/layer_tree_host.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h" @@ -67,8 +68,9 @@ PaintArtifactCompositor::PaintArtifactCompositor( base::RepeatingCallback<void(const gfx::ScrollOffset&, const cc::ElementId&)> scroll_callback) : scroll_callback_(std::move(scroll_callback)), - tracks_raster_invalidations_(false) { - if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && + tracks_raster_invalidations_(false), + needs_update_(true) { + if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) return; root_layer_ = cc::Layer::Create(); @@ -86,6 +88,8 @@ PaintArtifactCompositor::~PaintArtifactCompositor() { } void PaintArtifactCompositor::EnableExtraDataForTesting() { + if (!extra_data_for_testing_enabled_) + SetNeedsUpdate(true); extra_data_for_testing_enabled_ = true; extra_data_for_testing_ = std::make_unique<ExtraDataForTesting>(); } @@ -205,7 +209,7 @@ PaintArtifactCompositor::ScrollHitTestLayerForPendingLayer( // match (see: crbug.com/753124). auto bounds = scroll_node.ContainerRect().Size(); // Mark the layer as scrollable. - // TODO(pdr): When SPV2 launches this parameter for bounds will not be needed. + // TODO(pdr): When CAP launches this parameter for bounds will not be needed. scroll_layer->SetScrollable(static_cast<gfx::Size>(bounds)); // Set the layer's bounds equal to the container because the scroll layer // does not scroll. @@ -412,11 +416,13 @@ static bool CanUpcastTo(const PropertyTreeState& guest, guest.Transform()->IsBackfaceHidden()) return false; - auto* home_clip = home.Clip()->Unalias(); - for (const ClipPaintPropertyNode* current_clip = guest.Clip()->Unalias(); + // TODO(crbug.com/923729): Note that SafeUnalias() is a speculative fix for + // the referenced bug. The home and guest Clips should always exist, so we can + // just call Unalias on them. + auto* home_clip = SafeUnalias(home.Clip()); + for (const ClipPaintPropertyNode* current_clip = SafeUnalias(guest.Clip()); current_clip != home_clip; - current_clip = current_clip->Parent() ? current_clip->Parent()->Unalias() - : nullptr) { + current_clip = SafeUnalias(current_clip->Parent())) { if (!current_clip || current_clip->HasDirectCompositingReasons()) return false; if (!IsNonCompositingAncestorOf( @@ -518,6 +524,7 @@ static bool SkipGroupIfEffectivelyInvisible( void PaintArtifactCompositor::LayerizeGroup( const PaintArtifact& paint_artifact, + const Settings& settings, Vector<PendingLayer>& pending_layers, const EffectPaintPropertyNode& current_group, Vector<PaintChunk>::const_iterator& chunk_it) { @@ -578,8 +585,8 @@ void PaintArtifactCompositor::LayerizeGroup( // Case C: The following chunks belong to a subgroup. Process them by // a recursion call. wtf_size_t first_layer_in_subgroup = pending_layers.size(); - LayerizeGroup(paint_artifact, pending_layers, *unaliased_subgroup, - chunk_it); + LayerizeGroup(paint_artifact, settings, pending_layers, + *unaliased_subgroup, chunk_it); // Now the chunk iterator stepped over the subgroup we just saw. // If the subgroup generated 2 or more layers then the subgroup must be // composited to satisfy grouping requirement. @@ -624,11 +631,12 @@ void PaintArtifactCompositor::LayerizeGroup( void PaintArtifactCompositor::CollectPendingLayers( const PaintArtifact& paint_artifact, + const Settings& settings, Vector<PendingLayer>& pending_layers) { Vector<PaintChunk>::const_iterator cursor = paint_artifact.PaintChunks().begin(); - LayerizeGroup(paint_artifact, pending_layers, EffectPaintPropertyNode::Root(), - cursor); + LayerizeGroup(paint_artifact, settings, pending_layers, + EffectPaintPropertyNode::Root(), cursor); DCHECK_EQ(paint_artifact.PaintChunks().end(), cursor); } @@ -651,6 +659,7 @@ class SynthesizedClip : private cc::ContentLayerClient { CompositorElementIdFromUniqueObjectId(NewUniqueObjectId()); layer_->SetIsDrawable(true); } + ~SynthesizedClip() override { layer_->ClearClient(); } void Update(const FloatRoundedRect& rrect, scoped_refptr<const RefCountedPath> path) { @@ -749,10 +758,32 @@ cc::Layer* PaintArtifactCompositor::CreateOrReuseSynthesizedClipLayer( return synthesized_clip.GetLayer(); } +static void UpdateCompositorViewportProperties( + const PaintArtifactCompositor::ViewportProperties& properties, + PropertyTreeManager& property_tree_manager, + cc::LayerTreeHost* layer_tree_host) { + cc::LayerTreeHost::ViewportPropertyIds ids; + // This is also needed by pre-CompositeAfterPaint, so is not guarded by + // CompositeAfterPaintEnabled(). + if (properties.page_scale) { + ids.page_scale_transform = + property_tree_manager.EnsureCompositorPageScaleTransformNode( + properties.page_scale); + } + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { + if (properties.inner_scroll_translation) { + ids.inner_scroll = property_tree_manager.EnsureCompositorScrollNode( + properties.inner_scroll_translation); + } + layer_tree_host->RegisterViewportPropertyIds(ids); + } +} + void PaintArtifactCompositor::Update( scoped_refptr<const PaintArtifact> paint_artifact, CompositorElementIdSet& composited_element_ids, - TransformPaintPropertyNode* viewport_scale_node) { + const ViewportProperties& viewport_properties, + const Settings& settings) { DCHECK(root_layer_); // The tree will be null after detaching and this update can be ignored. @@ -761,6 +792,11 @@ void PaintArtifactCompositor::Update( if (!host) return; + // Skip updating property trees, pushing cc::Layers, and issuing raster + // invalidations if possible. + if (!NeedsUpdate()) + return; + // When using BlinkGenPropertyTrees, the compositor accepts a list of layers // and property trees instead of building property trees. This DCHECK ensures // we have not forgotten to set |use_layer_lists|. @@ -778,16 +814,10 @@ void PaintArtifactCompositor::Update( PropertyTreeManager property_tree_manager( *this, *host->property_trees(), root_layer_.get(), &layer_list_builder); Vector<PendingLayer, 0> pending_layers; - CollectPendingLayers(*paint_artifact, pending_layers); + CollectPendingLayers(*paint_artifact, settings, pending_layers); - cc::LayerTreeHost::ViewportPropertyIds viewport_property_ids; - if (viewport_scale_node) { - viewport_property_ids.page_scale_transform = - property_tree_manager.EnsureCompositorPageScaleTransformNode( - viewport_scale_node); - } - if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) - host->RegisterViewportPropertyIds(viewport_property_ids); + UpdateCompositorViewportProperties(viewport_properties, property_tree_manager, + host); Vector<std::unique_ptr<ContentLayerClientImpl>> new_content_layer_clients; new_content_layer_clients.ReserveCapacity(pending_layers.size()); @@ -796,6 +826,8 @@ void PaintArtifactCompositor::Update( for (auto& entry : synthesized_clip_cache_) entry.in_use = false; + // Clear prior frame ids before inserting new ones. + composited_element_ids.clear(); for (auto& pending_layer : pending_layers) { const auto& property_state = pending_layer.property_tree_state; const auto* transform = property_state.Transform(); @@ -817,9 +849,9 @@ void PaintArtifactCompositor::Update( paint_artifact, pending_layer, layer_offset, new_content_layer_clients, new_scroll_hit_test_layers); - // Pre-SPV2, touch action rects are updated through + // Pre-CompositeAfterPaint, touch action rects are updated through // ScrollingCoordinator::UpdateLayerTouchActionRects. - if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { auto paint_chunks = paint_artifact->GetPaintChunkSubset( pending_layer.paint_chunk_indices); UpdateTouchActionRects(layer.get(), layer_offset, property_state, @@ -866,8 +898,10 @@ void PaintArtifactCompositor::Update( // Calling |PropertyTreeStateChanged| for every pending layer is // O(|property nodes|^2) and could be optimized by caching the lookup of // nodes known to be changed/unchanged. - if (PropertyTreeStateChanged(property_state)) + if (PropertyTreeStateChanged(property_state)) { layer->SetSubtreePropertyChanged(); + root_layer_->SetNeedsCommit(); + } } property_tree_manager.Finalize(); content_layer_clients_.swap(new_content_layer_clients); @@ -885,15 +919,21 @@ void PaintArtifactCompositor::Update( } } - root_layer_->SetChildLayerList(layer_list_builder.Finalize()); + // This should be done before UpdateRenderSurfaceForEffects() for which to + // get property tree node ids from the layers. + host->property_trees()->sequence_number = g_s_property_tree_sequence_number; + + auto layers = layer_list_builder.Finalize(); + UpdateRenderSurfaceForEffects(*host, layers); + root_layer_->SetChildLayerList(std::move(layers)); // Update the host's active registered element ids. host->SetActiveRegisteredElementIds(composited_element_ids); // Mark the property trees as having been rebuilt. - host->property_trees()->sequence_number = g_s_property_tree_sequence_number; host->property_trees()->needs_rebuild = false; host->property_trees()->ResetCachedData(); + SetNeedsUpdate(false); g_s_property_tree_sequence_number++; @@ -912,6 +952,33 @@ void PaintArtifactCompositor::Update( #endif } +// Every effect is supposed to have render surface enabled for grouping, but we +// can omit one if the effect is opacity-only, render surface is not forced, +// and the effect has only one compositing child. This is both for optimization +// and not introducing sub-pixel differences in web tests. +// TODO(crbug.com/504464): There is ongoing work in cc to delay render surface +// decision until later phase of the pipeline. Remove premature optimization +// here once the work is ready. +void PaintArtifactCompositor::UpdateRenderSurfaceForEffects( + cc::LayerTreeHost& host, + const cc::LayerList& layers) { + HashSet<int> pending_render_surfaces; + auto& effect_tree = host.property_trees()->effect_tree; + for (const auto& layer : layers) { + for (auto* effect = effect_tree.Node(layer->effect_tree_index()); + !effect->has_render_surface; + effect = effect_tree.Node(effect->parent_id)) { + if (effect->opacity != 1.f && + !pending_render_surfaces.insert(effect->id).is_new_entry) { + // The opacity-only effect is seen the second time, which means that it + // has more than one compositing child and needs a render surface. + effect->has_render_surface = true; + break; + } + } + } +} + void LayerListBuilder::Add(scoped_refptr<cc::Layer> layer) { DCHECK(list_valid_); list_.push_back(layer); diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h index 1b04c0b9d04..26a8f15ebe3 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h @@ -21,6 +21,7 @@ namespace cc { struct ElementId; class Layer; +class LayerTreeHost; } namespace gfx { @@ -53,7 +54,7 @@ class LayerListBuilder { // changes in the paint artifact. // // PaintArtifactCompositor is the successor to PaintLayerCompositor, reflecting -// the new home of compositing decisions after paint in Slimming Paint v2. +// the new home of compositing decisions after paint with CompositeAfterPaint. class PLATFORM_EXPORT PaintArtifactCompositor final : private PropertyTreeManagerClient { USING_FAST_MALLOC(PaintArtifactCompositor); @@ -68,13 +69,25 @@ class PLATFORM_EXPORT PaintArtifactCompositor final new PaintArtifactCompositor(std::move(scroll_callback))); } + struct ViewportProperties { + const TransformPaintPropertyNode* page_scale = nullptr; + const TransformPaintPropertyNode* inner_scroll_translation = nullptr; + // TODO(crbug.com/909750): Add other viewport properties, e.g. + // outer_scroll_translation. + }; + + struct Settings { + bool prefer_compositing_to_lcd_text = false; + }; + // Updates the layer tree to match the provided paint artifact. // // Populates |composited_element_ids| with the CompositorElementId of all // animations for which we saw a paint chunk and created a layer. void Update(scoped_refptr<const PaintArtifact>, CompositorElementIdSet& composited_element_ids, - TransformPaintPropertyNode* viewport_scale_node); + const ViewportProperties& viewport_properties, + const Settings& settings); // The root layer of the tree managed by this object. cc::Layer* RootLayer() const { return root_layer_.get(); } @@ -119,6 +132,9 @@ class PLATFORM_EXPORT PaintArtifactCompositor final const PropertyTreeState& layer_state, const PaintChunkSubset& paint_chunks); + void SetNeedsUpdate(bool needs_update) { needs_update_ = needs_update; } + bool NeedsUpdate() const { return needs_update_; } + private: // A pending layer is a collection of paint chunks that will end up in // the same cc::Layer. @@ -153,7 +169,9 @@ class PLATFORM_EXPORT PaintArtifactCompositor final // Collects the PaintChunks into groups which will end up in the same // cc layer. This is the entry point of the layerization algorithm. void CollectPendingLayers(const PaintArtifact&, + const Settings& settings, Vector<PendingLayer>& pending_layers); + // This is the internal recursion of collectPendingLayers. This function // loops over the list of paint chunks, scoped by an isolated group // (i.e. effect node). Inside of the loop, chunks are tested for overlap @@ -172,6 +190,7 @@ class PLATFORM_EXPORT PaintArtifactCompositor final // overlap with other chunks in the parent group, if grouping requirement // can be satisfied (and the effect node has no direct reason). static void LayerizeGroup(const PaintArtifact&, + const Settings& settings, Vector<PendingLayer>& pending_layers, const EffectPaintPropertyNode&, Vector<PaintChunk>::const_iterator& chunk_cursor); @@ -222,11 +241,15 @@ class PLATFORM_EXPORT PaintArtifactCompositor final CompositorElementId& mask_isolation_id, CompositorElementId& mask_effect_id) final; + static void UpdateRenderSurfaceForEffects(cc::LayerTreeHost&, + const cc::LayerList&); + // Provides a callback for notifying blink of composited scrolling. base::RepeatingCallback<void(const gfx::ScrollOffset&, const cc::ElementId&)> scroll_callback_; bool tracks_raster_invalidations_; + bool needs_update_; scoped_refptr<cc::Layer> root_layer_; Vector<std::unique_ptr<ContentLayerClientImpl>> content_layer_clients_; @@ -242,7 +265,7 @@ class PLATFORM_EXPORT PaintArtifactCompositor final bool extra_data_for_testing_enabled_ = false; std::unique_ptr<ExtraDataForTesting> extra_data_for_testing_; - friend class StubChromeClientForSPv2; + friend class StubChromeClientForCAP; friend class PaintArtifactCompositorTest; DISALLOW_COPY_AND_ASSIGN(PaintArtifactCompositor); diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc index 1855e61bdf5..a601fe254bc 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc @@ -24,6 +24,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h" +#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h" #include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h" #include "third_party/blink/renderer/platform/testing/fake_display_item_client.h" @@ -130,18 +131,17 @@ class PaintArtifactCompositorTest : public testing::Test, Update(artifact, element_ids); } - void Update(scoped_refptr<const PaintArtifact> artifact, - CompositorElementIdSet& element_ids) { - // Pass nullptr for the visual viewport paint property nodes since we're - // really just checking the internals of PaintArtifactCompositor. - Update(artifact, element_ids, nullptr); - } + using ViewportProperties = PaintArtifactCompositor::ViewportProperties; + using Settings = PaintArtifactCompositor::Settings; - void Update(scoped_refptr<const PaintArtifact> artifact, - CompositorElementIdSet& element_ids, - TransformPaintPropertyNode* viewport_scale_transform_node) { + void Update( + scoped_refptr<const PaintArtifact> artifact, + CompositorElementIdSet& element_ids, + const ViewportProperties& viewport_properties = ViewportProperties(), + const Settings& settings = Settings()) { + paint_artifact_compositor_->SetNeedsUpdate(true); paint_artifact_compositor_->Update(artifact, element_ids, - viewport_scale_transform_node); + viewport_properties, settings); layer_tree_->layer_tree_host()->LayoutAndUpdateLayers(); } @@ -151,8 +151,8 @@ class PaintArtifactCompositorTest : public testing::Test, cc::Layer* RootLayer() { return paint_artifact_compositor_->RootLayer(); } - // SlimmingPaintV2 creates scroll hit test display items (which create scroll - // hit test layers in PaintArtifactCompositor) whereas in + // CompositeAfterPaint creates scroll hit test display items (which create + // scroll hit test layers in PaintArtifactCompositor) whereas in // BlinkGenPropertyTrees, scrollable foreign layers are created in // ScrollingCoordinator and passed to PaintArtifactCompositor. This function // is used to create a chunk representing the scrollable layer in either of @@ -182,8 +182,8 @@ class PaintArtifactCompositorTest : public testing::Test, .ScrollHitTest(scroll_offset); } - // Returns the |num|th scrollable layer. In SlimmingPaintV2, this will be a - // scroll hit test layer, whereas in BlinkGenPropertyTrees this will be a + // Returns the |num|th scrollable layer. In CompositeAfterPaint, this will be + // a scroll hit test layer, whereas in BlinkGenPropertyTrees this will be a // content layer. cc::Layer* ScrollableLayerAt(size_t num) { if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { @@ -203,7 +203,7 @@ class PaintArtifactCompositorTest : public testing::Test, .get(); } - // Returns the |num|th non-scrollable layer. In SlimmingPaintV2, content + // Returns the |num|th non-scrollable layer. In CompositeAfterPaint, content // layers are not scrollable so this is the |num|th content layer. In // BlinkGenPropertyTrees, content layers are scrollable and non-scrollable, so // this will return the |num|th content layer that is not scrollable. @@ -3254,8 +3254,10 @@ TEST_P(PaintArtifactCompositorTest, CreatesViewportNodes) { TransformPaintPropertyNode::Root(), std::move(transform_state)); TestPaintArtifact artifact; + ViewportProperties viewport_properties; + viewport_properties.page_scale = scale_transform_node.get(); CompositorElementIdSet element_ids; - Update(artifact.Build(), element_ids, scale_transform_node.get()); + Update(artifact.Build(), element_ids, viewport_properties); cc::TransformTree& transform_tree = GetPropertyTrees().transform_tree; cc::TransformNode* cc_transform_node = transform_tree.FindNodeFromElementId( @@ -3267,4 +3269,169 @@ TEST_P(PaintArtifactCompositorTest, CreatesViewportNodes) { EXPECT_TRUE(cc_transform_node->pre_local.IsIdentity()); } +enum { kNoRenderSurface, kHasRenderSurface }; + +#define EXPECT_OPACITY(effect_id, expected_opacity, expected_render_surface) \ + do { \ + const auto* effect = GetPropertyTrees().effect_tree.Node(effect_id); \ + EXPECT_EQ(expected_opacity, effect->opacity); \ + EXPECT_EQ(expected_render_surface == kHasRenderSurface, \ + effect->has_render_surface); \ + } while (false) + +TEST_P(PaintArtifactCompositorTest, OpacityRenderSurfaces) { + // e + // / | \ + // a b c -- L4 + // / \ / \ \ + // aa ab L2 L3 ca (L = layer) + // | | | + // L0 L1 L5 + auto e = CreateOpacityEffect(e0(), 0.1f); + auto a = CreateOpacityEffect(*e, 0.2f); + auto b = + CreateOpacityEffect(*e, 0.3f, CompositingReason::kActiveOpacityAnimation); + auto c = + CreateOpacityEffect(*e, 0.4f, CompositingReason::kActiveOpacityAnimation); + auto aa = + CreateOpacityEffect(*a, 0.5f, CompositingReason::kActiveOpacityAnimation); + auto ab = + CreateOpacityEffect(*a, 0.6f, CompositingReason::kActiveOpacityAnimation); + auto ca = + CreateOpacityEffect(*c, 0.7f, CompositingReason::kActiveOpacityAnimation); + auto t = CreateTransform(t0(), TransformationMatrix().Rotate(90), + FloatPoint3D(), CompositingReason::k3DTransform); + + TestPaintArtifact artifact; + FloatRect r(150, 150, 100, 100); + artifact.Chunk(t0(), c0(), *aa).RectDrawing(r, Color::kWhite); + artifact.Chunk(t0(), c0(), *ab).RectDrawing(r, Color::kWhite); + artifact.Chunk(t0(), c0(), *b).RectDrawing(r, Color::kWhite); + artifact.Chunk(*t, c0(), *b).RectDrawing(r, Color::kWhite); + artifact.Chunk(t0(), c0(), *c).RectDrawing(r, Color::kWhite); + artifact.Chunk(t0(), c0(), *ca).RectDrawing(r, Color::kWhite); + Update(artifact.Build()); + ASSERT_EQ(6u, ContentLayerCount()); + + int effect_ids[6]; + for (size_t i = 0; i < ContentLayerCount(); i++) + effect_ids[i] = ContentLayerAt(i)->effect_tree_index(); + + // Effects of layer 0, 1, 5 each has one compositing layer, so don't have + // render surface. + EXPECT_OPACITY(effect_ids[0], 0.5f, kNoRenderSurface); + EXPECT_OPACITY(effect_ids[1], 0.6f, kNoRenderSurface); + EXPECT_OPACITY(effect_ids[5], 0.7f, kNoRenderSurface); + + // Layer 2 and 3 have the same effect state. The effect has render surface + // because it has two compositing layers. + EXPECT_EQ(effect_ids[2], effect_ids[3]); + EXPECT_OPACITY(effect_ids[2], 0.3f, kHasRenderSurface); + + // Effect |a| has two indirect compositing layers, so has render surface. + const auto& effect_tree = GetPropertyTrees().effect_tree; + int id_a = effect_tree.Node(effect_ids[0])->parent_id; + EXPECT_EQ(id_a, effect_tree.Node(effect_ids[1])->parent_id); + EXPECT_OPACITY(id_a, 0.2f, kHasRenderSurface); + + // Effect |c| has one direct and one indirect compositing layers, so has + // render surface. + EXPECT_OPACITY(effect_ids[4], 0.4f, kHasRenderSurface); + + // Though all children of effect |e| have render surfaces and |e| doesn't + // control any compositing layer, we still give it a render surface for + // simplicity of the algorithm. + EXPECT_OPACITY(effect_tree.Node(effect_ids[4])->parent_id, 0.1f, + kHasRenderSurface); +} + +TEST_P(PaintArtifactCompositorTest, OpacityIndirectlyAffectingTwoLayers) { + auto opacity = CreateOpacityEffect(e0(), 0.5f); + auto child_composited_effect = CreateOpacityEffect( + *opacity, 1.f, CompositingReason::kActiveOpacityAnimation); + auto grandchild_composited_effect = + CreateOpacityEffect(*child_composited_effect, 1.f, + CompositingReason::kActiveOpacityAnimation); + + TestPaintArtifact artifact; + artifact.Chunk(t0(), c0(), *child_composited_effect) + .RectDrawing(FloatRect(150, 150, 100, 100), Color::kWhite); + artifact.Chunk(t0(), c0(), *grandchild_composited_effect) + .RectDrawing(FloatRect(150, 150, 100, 100), Color::kGray); + Update(artifact.Build()); + ASSERT_EQ(2u, ContentLayerCount()); + + const auto& effect_tree = GetPropertyTrees().effect_tree; + int layer0_effect_id = ContentLayerAt(0)->effect_tree_index(); + EXPECT_OPACITY(layer0_effect_id, 1.f, kNoRenderSurface); + int layer1_effect_id = ContentLayerAt(1)->effect_tree_index(); + EXPECT_OPACITY(layer1_effect_id, 1.f, kNoRenderSurface); + int opacity_id = effect_tree.Node(layer0_effect_id)->parent_id; + EXPECT_OPACITY(opacity_id, 0.5f, kHasRenderSurface); +} + +TEST_P(PaintArtifactCompositorTest, Non2dAxisAlignedClip) { + auto rotate = CreateTransform(t0(), TransformationMatrix().Rotate(45)); + auto clip = CreateClip(c0(), rotate.get(), FloatRoundedRect(50, 50, 50, 50)); + auto opacity = CreateOpacityEffect( + e0(), 0.5f, CompositingReason::kActiveOpacityAnimation); + + TestPaintArtifact artifact; + artifact.Chunk(t0(), *clip, *opacity) + .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite); + Update(artifact.Build()); + ASSERT_EQ(1u, ContentLayerCount()); + + // We should create a synthetic effect node for the non-2d-axis-aligned clip. + int clip_id = ContentLayerAt(0)->clip_tree_index(); + const auto* cc_clip = GetPropertyTrees().clip_tree.Node(clip_id); + int effect_id = ContentLayerAt(0)->effect_tree_index(); + const auto* cc_effect = GetPropertyTrees().effect_tree.Node(effect_id); + EXPECT_OPACITY(effect_id, 1.f, kHasRenderSurface); + EXPECT_OPACITY(cc_effect->parent_id, 0.5f, kNoRenderSurface); + EXPECT_EQ(cc_effect->clip_id, cc_clip->parent_id); +} + +TEST_P(PaintArtifactCompositorTest, + Non2dAxisAlignedClipUnderLaterRenderSurface) { + auto rotate1 = + CreateTransform(t0(), TransformationMatrix().Rotate(45), FloatPoint3D(), + CompositingReason::k3DTransform); + auto rotate2 = + CreateTransform(*rotate1, TransformationMatrix().Rotate(-45), + FloatPoint3D(), CompositingReason::k3DTransform); + auto clip = CreateClip(c0(), rotate2.get(), FloatRoundedRect(50, 50, 50, 50)); + auto opacity = + CreateOpacityEffect(e0(), rotate1.get(), &c0(), 0.5f, + CompositingReason::kActiveOpacityAnimation); + + // This assert ensures the test actually tests the situation. If it fails + // due to floating-point errors, we should choose other transformation values + // to make it succeed. + ASSERT_TRUE( + GeometryMapper::SourceToDestinationProjection(&t0(), rotate2.get()) + .Preserves2dAxisAlignment()); + + TestPaintArtifact artifact; + artifact.Chunk(t0(), c0(), *opacity) + .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite); + artifact.Chunk(*rotate1, c0(), *opacity) + .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite); + artifact.Chunk(*rotate2, *clip, *opacity) + .RectDrawing(FloatRect(50, 50, 50, 50), Color::kWhite); + Update(artifact.Build()); + ASSERT_EQ(3u, ContentLayerCount()); + + // We should create a synthetic effect node for the non-2d-axis-aligned clip, + // though the accumulated transform to the known render surface was identity + // when the cc clip node was created. + int clip_id = ContentLayerAt(2)->clip_tree_index(); + const auto* cc_clip = GetPropertyTrees().clip_tree.Node(clip_id); + int effect_id = ContentLayerAt(2)->effect_tree_index(); + const auto* cc_effect = GetPropertyTrees().effect_tree.Node(effect_id); + EXPECT_OPACITY(effect_id, 1.f, kHasRenderSurface); + EXPECT_OPACITY(cc_effect->parent_id, 0.5f, kHasRenderSurface); + EXPECT_EQ(cc_effect->clip_id, cc_clip->parent_id); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc index c14f863846a..9982f86778c 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc @@ -341,8 +341,8 @@ void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) { #endif // This bug is known to happen in SPv1 due to some clip-escaping corner // cases that are very difficult to fix in legacy architecture. - // In SPv2 this should never happen. - if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) + // In CAP this should never happen. + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) NOTREACHED(); break; } @@ -515,9 +515,7 @@ void ConversionContext::StartEffect(const EffectPaintPropertyNode* effect) { effect->GetColorFilter())); save_layer_id = cc_list_.push<cc::SaveLayerOp>(nullptr, &flags); } else { - constexpr bool preserve_lcd_text_requests = false; - save_layer_id = cc_list_.push<cc::SaveLayerAlphaOp>( - nullptr, alpha, preserve_lcd_text_requests); + save_layer_id = cc_list_.push<cc::SaveLayerAlphaOp>(nullptr, alpha); } saved_count++; } else { diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc index 6bfb15050c0..eeaae7ecc63 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc @@ -51,9 +51,9 @@ namespace blink { namespace { class PaintChunksToCcLayerTest : public testing::Test, - private ScopedSlimmingPaintV2ForTest { + private ScopedCompositeAfterPaintForTest { protected: - PaintChunksToCcLayerTest() : ScopedSlimmingPaintV2ForTest(true) {} + PaintChunksToCcLayerTest() : ScopedCompositeAfterPaintForTest(true) {} }; // Matches PaintOpTypes in a PaintRecord. @@ -1190,7 +1190,7 @@ TEST_F(PaintChunksToCcLayerTest, StartWithAliasClip) { // release builds. A DCHECK'd build will trap instead. #if !DCHECK_IS_ON() TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipFailSafe) { - ScopedSlimmingPaintV2ForTest spv2_disabler(false); + ScopedCompositeAfterPaintForTest cap_disabler(false); // This test verifies the fail-safe path correctly recovers from a malformed // chunk that escaped its layer's clip. FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f); @@ -1210,7 +1210,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipFailSafe) { } TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeEffectClipFailSafe) { - ScopedSlimmingPaintV2ForTest spv2_disabler(false); + ScopedCompositeAfterPaintForTest cap_disabler(false); // This test verifies the fail-safe path correctly recovers from a malformed // chunk that escaped its effect's clip. FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f); @@ -1234,7 +1234,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeEffectClipFailSafe) { } TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipDoubleFault) { - ScopedSlimmingPaintV2ForTest spv2_disabler(false); + ScopedCompositeAfterPaintForTest cap_disabler(false); // This test verifies the fail-safe path correctly recovers from a series of // malformed chunks that escaped their layer's clip. FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f); diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc index 83635ef9c2a..c521cf05576 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc @@ -32,6 +32,12 @@ static constexpr int kSecondaryRootNodeId = 1; } // namespace +inline const TransformPaintPropertyNode* +PropertyTreeManager::EffectState::Transform() const { + return effect_type == CcEffectType::kEffect ? effect->LocalTransformSpace() + : clip->LocalTransformSpace(); +} + PropertyTreeManager::PropertyTreeManager(PropertyTreeManagerClient& client, cc::PropertyTrees& property_trees, cc::Layer* root_layer, @@ -154,26 +160,39 @@ void PropertyTreeManager::SetupRootScrollNode() { root_layer_->SetScrollTreeIndex(scroll_node.id); } +static bool TransformsAre2dAxisAligned(const TransformPaintPropertyNode* a, + const TransformPaintPropertyNode* b) { + return a == b || GeometryMapper::SourceToDestinationProjection(a, b) + .Preserves2dAxisAlignment(); +} + void PropertyTreeManager::SetCurrentEffectState( const cc::EffectNode& cc_effect_node, CcEffectType effect_type, const EffectPaintPropertyNode* effect, const ClipPaintPropertyNode* clip) { + const auto* previous_transform = + effect->IsRoot() ? nullptr : current_.Transform(); current_.effect_id = cc_effect_node.id; current_.effect_type = effect_type; DCHECK(!effect->IsParentAlias() || !effect->Parent()); current_.effect = effect; DCHECK(!clip->IsParentAlias() || !clip->Parent()); current_.clip = clip; - if (cc_effect_node.has_render_surface) - current_.render_surface_transform = effect->LocalTransformSpace(); + + if (cc_effect_node.has_render_surface) { + current_.may_be_2d_axis_misaligned_to_render_surface = false; + } else if (previous_transform && + !current_.may_be_2d_axis_misaligned_to_render_surface) { + current_.may_be_2d_axis_misaligned_to_render_surface = + !TransformsAre2dAxisAligned(current_.Transform(), previous_transform); + } } // TODO(crbug.com/504464): Remove this when move render surface decision logic // into cc compositor thread. void PropertyTreeManager::SetCurrentEffectHasRenderSurface() { GetEffectTree().Node(current_.effect_id)->has_render_surface = true; - current_.render_surface_transform = current_.effect->LocalTransformSpace(); } int PropertyTreeManager::EnsureCompositorTransformNode( @@ -458,12 +477,6 @@ void PropertyTreeManager::CloseCcEffect() { } } -static bool TransformsAre2dAxisAligned(const TransformPaintPropertyNode* a, - const TransformPaintPropertyNode* b) { - return a == b || GeometryMapper::SourceToDestinationProjection(a, b) - .Preserves2dAxisAlignment(); -} - int PropertyTreeManager::SwitchToEffectNodeWithSynthesizedClip( const EffectPaintPropertyNode& next_effect, const ClipPaintPropertyNode& next_clip) { @@ -519,9 +532,8 @@ int PropertyTreeManager::SwitchToEffectNodeWithSynthesizedClip( while (current_.effect != &ancestor) CloseCcEffect(); - bool newly_built = BuildEffectNodesRecursively(&next_effect); - SynthesizeCcEffectsForClipsIfNeeded(&next_clip, SkBlendMode::kSrcOver, - newly_built); + BuildEffectNodesRecursively(&next_effect); + SynthesizeCcEffectsForClipsIfNeeded(&next_clip, SkBlendMode::kSrcOver); return current_.effect_id; } @@ -549,8 +561,9 @@ PropertyTreeManager::NeedsSyntheticEffect( // Cc requires that a rectangluar clip is 2d-axis-aligned with the render // surface to correctly apply the clip. - if (!TransformsAre2dAxisAligned(clip.LocalTransformSpace(), - current_.render_surface_transform)) + if (current_.may_be_2d_axis_misaligned_to_render_surface || + !TransformsAre2dAxisAligned(clip.LocalTransformSpace(), + current_.Transform())) return CcEffectType::kSyntheticFor2dAxisAlignment; return base::nullopt; @@ -558,8 +571,7 @@ PropertyTreeManager::NeedsSyntheticEffect( SkBlendMode PropertyTreeManager::SynthesizeCcEffectsForClipsIfNeeded( const ClipPaintPropertyNode* target_clip, - SkBlendMode delegated_blend, - bool effect_is_newly_built) { + SkBlendMode delegated_blend) { auto* unaliased_target_clip = target_clip->Unalias(); if (delegated_blend != SkBlendMode::kSrcOver) { // Exit all synthetic effect node if the next child has exotic blending mode @@ -585,16 +597,6 @@ SkBlendMode PropertyTreeManager::SynthesizeCcEffectsForClipsIfNeeded( if (IsNodeOnAncestorChain(lca, *pre_exit_clip, *current_.clip)) break; } - - // If the effect is an existing node, i.e. already has at least one paint - // chunk or child effect, and by reaching here it implies we are going to - // attach either another paint chunk or child effect to it. We can no longer - // omit render surface for it even for opacity-only node. - // See comments in PropertyTreeManager::BuildEffectNodesRecursively(). - // TODO(crbug.com/504464): Remove premature optimization here. - if (!effect_is_newly_built && !IsCurrentCcEffectSynthetic() && - current_.effect->Opacity() != 1.f) - SetCurrentEffectHasRenderSurface(); } DCHECK(current_.clip->IsAncestorOf(*unaliased_target_clip)); @@ -649,21 +651,19 @@ SkBlendMode PropertyTreeManager::SynthesizeCcEffectsForClipsIfNeeded( effect_stack_.emplace_back(current_); SetCurrentEffectState(synthetic_effect, pending_clip.type, current_.effect, pending_clip.clip); - current_.render_surface_transform = - pending_clip.clip->LocalTransformSpace(); } return delegated_blend; } -bool PropertyTreeManager::BuildEffectNodesRecursively( +void PropertyTreeManager::BuildEffectNodesRecursively( const EffectPaintPropertyNode* next_effect) { next_effect = SafeUnalias(next_effect); if (next_effect == current_.effect) - return false; + return; DCHECK(next_effect); - bool newly_built = BuildEffectNodesRecursively(next_effect->Parent()); + BuildEffectNodesRecursively(next_effect->Parent()); DCHECK_EQ(next_effect->Parent()->Unalias(), current_.effect); #if DCHECK_IS_ON() @@ -678,16 +678,15 @@ bool PropertyTreeManager::BuildEffectNodesRecursively( const auto* output_clip = SafeUnalias(next_effect->OutputClip()); if (output_clip) { used_blend_mode = SynthesizeCcEffectsForClipsIfNeeded( - output_clip, next_effect->BlendMode(), newly_built); + output_clip, next_effect->BlendMode()); output_clip_id = EnsureCompositorClipNode(output_clip); } else { while (IsCurrentCcEffectSynthetic()) CloseCcEffect(); // An effect node can't omit render surface if it has child with exotic - // blending mode, nor being opacity-only node with more than one child. + // blending mode. // TODO(crbug.com/504464): Remove premature optimization here. - if (next_effect->BlendMode() != SkBlendMode::kSrcOver || - (!newly_built && current_.effect->Opacity() != 1.f)) + if (next_effect->BlendMode() != SkBlendMode::kSrcOver) SetCurrentEffectHasRenderSurface(); used_blend_mode = next_effect->BlendMode(); @@ -701,16 +700,10 @@ bool PropertyTreeManager::BuildEffectNodesRecursively( effect_node.stable_id = next_effect->GetCompositorElementId().GetInternalValue(); effect_node.clip_id = output_clip_id; - // Every effect is supposed to have render surface enabled for grouping, - // but we can get away without one if the effect is opacity-only and has only - // one compositing child with kSrcOver blend mode. This is both for - // optimization and not introducing sub-pixel differences in layout tests. - // See PropertyTreeManager::switchToEffectNode() and above where we - // retrospectively enable render surface when more than one compositing child - // or a child with exotic blend mode is detected. - // TODO(crbug.com/504464): There is ongoing work in cc to delay render surface - // decision until later phase of the pipeline. Remove premature optimization - // here once the work is ready. + + // An effect with filters, backdrop filters or non-kSrcOver blend mode needs + // a render surface. The render surface status of opacity-only effects will be + // updated in PaintArtifactCompositor::UpdateRenderSurfaceForEffects(). if (!next_effect->Filter().IsEmpty() || !next_effect->BackdropFilter().IsEmpty() || used_blend_mode != SkBlendMode::kSrcOver) @@ -730,6 +723,7 @@ bool PropertyTreeManager::BuildEffectNodesRecursively( effect_node.filters = next_effect->Filter().AsCcFilterOperations(); effect_node.backdrop_filters = next_effect->BackdropFilter().AsCcFilterOperations(); + effect_node.backdrop_filter_bounds = next_effect->BackdropFilterBounds(); effect_node.filters_origin = next_effect->FiltersOrigin(); effect_node.transform_id = EnsureCompositorTransformNode(next_effect->LocalTransformSpace()); @@ -749,8 +743,6 @@ bool PropertyTreeManager::BuildEffectNodesRecursively( effect_stack_.emplace_back(current_); SetCurrentEffectState(effect_node, CcEffectType::kEffect, next_effect, output_clip); - - return true; } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h index 1bab20eea08..231b0411e19 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h @@ -119,11 +119,10 @@ class PropertyTreeManager { void Finalize(); private: - bool BuildEffectNodesRecursively(const EffectPaintPropertyNode* next_effect); + void BuildEffectNodesRecursively(const EffectPaintPropertyNode* next_effect); SkBlendMode SynthesizeCcEffectsForClipsIfNeeded( const ClipPaintPropertyNode* target_clip, - SkBlendMode delegated_blend, - bool effect_is_newly_built); + SkBlendMode delegated_blend); void EmitClipMaskLayer(); void CloseCcEffect(); @@ -192,19 +191,34 @@ class PropertyTreeManager { // effect and clip state from the last // SwitchToEffectNodeWithSynthesizedClip. int effect_id; + CcEffectType effect_type; + // The effect state of the cc effect node. const EffectPaintPropertyNode* effect; + // The clip state of the cc effect node. This value may be shallower than // the one passed into SwitchToEffectNodeWithSynthesizedClip because not - // every clip needs to be synthesized as cc effect. - // Is set to output clip of the effect if the type is kEffect, or set to the - // synthesized clip node if the type is kSyntheticForNonTrivialClip. + // every clip needs to be synthesized as cc effect. Is set to output clip of + // the effect if the type is kEffect, or set to the synthesized clip node. const ClipPaintPropertyNode* clip; - // The transform space of the containing render surface. - // TODO(crbug.com/504464): Remove this when move render surface decision - // logic into cc compositor thread. - const TransformPaintPropertyNode* render_surface_transform; + + // Whether the transform space of this state may be 2d axis misaligned to + // the containing render surface. As there may be new render surfaces + // created between this state and the current known ancestor render surface + // after this state is created, we must conservatively accumulate this flag + // from the known render surface instead of checking if the combined + // transform is 2d axis aligned, in case of: + // Effect1 (Current known render surface) + // Rotate(45deg) + // Effect2 (Not known now, but may become render surface later) + // Rotate(-45deg) + // Clip (Would be mistakenly treated as 2d axis aligned if we used + // accumulated transform from the clip to the known render surface.) + bool may_be_2d_axis_misaligned_to_render_surface; + + // The transform space of the state. + const TransformPaintPropertyNode* Transform() const; }; // The current effect state. Virtually it's the top of the effect stack if diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h b/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h index a9d700afff1..39a0bcff494 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h +++ b/chromium/third_party/blink/renderer/platform/graphics/compositing_reasons.h @@ -135,8 +135,7 @@ class PLATFORM_EXPORT CompositingReason { kTransformWithCompositedDescendants | kIsolateCompositedDescendants | kOpacityWithCompositedDescendants | kMaskWithCompositedDescendants | kFilterWithCompositedDescendants | kBlendingWithCompositedDescendants | - kReflectionWithCompositedDescendants | kClipsCompositingDescendants | - kPositionFixedOrStickyWithCompositedDescendants, + kReflectionWithCompositedDescendants | kClipsCompositingDescendants, kCombo3DDescendants = kPreserve3DWith3DDescendants | kPerspectiveWith3DDescendants, diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc b/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc index 434c15b3333..ea742ddd65e 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.cc @@ -26,7 +26,9 @@ CompositorMutatorClient::~CompositorMutatorClient() { void CompositorMutatorClient::Mutate( std::unique_ptr<cc::MutatorInputState> input_state) { 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( diff --git a/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h b/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h index 8823cf44e02..b6fb0b07ccf 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h +++ b/chromium/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h @@ -21,7 +21,11 @@ class PLATFORM_EXPORT CompositorMutatorClient : public cc::LayerTreeMutator, std::unique_ptr<AnimationWorkletMutatorDispatcherImpl>); ~CompositorMutatorClient() override; + void SynchronizeAnimatorName(const String& animator_name) 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 void SetClient(cc::LayerTreeMutatorClient*) override; diff --git a/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc b/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc index 45501625ff7..59c68f69182 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc @@ -63,7 +63,6 @@ void CrossfadeGeneratedImage::DrawCrossfade(cc::PaintCanvas* canvas, PaintFlags image_flags(flags); image_flags.setBlendMode(SkBlendMode::kSrcOver); image_flags.setColor(ScaleAlpha(flags.getColor(), 1 - percentage_)); - image_flags.setAntiAlias(flags.isAntiAlias()); // TODO(junov): This code should probably be propagating the // RespectImageOrientationEnum from CrossfadeGeneratedImage::draw(). Code was // written this way during refactoring to avoid modifying existing behavior, @@ -106,7 +105,6 @@ void CrossfadeGeneratedImage::DrawTile(GraphicsContext& context, PaintFlags flags = context.FillFlags(); flags.setBlendMode(SkBlendMode::kSrcOver); - flags.setAntiAlias(context.ShouldAntialias()); FloatRect dest_rect((FloatPoint()), crossfade_size_); flags.setFilterQuality( context.ComputeFilterQuality(this, dest_rect, src_rect)); diff --git a/chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc b/chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc index ca469f07a27..edb90d9d9fa 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/draw_looper_builder.cc @@ -91,7 +91,7 @@ void DrawLooperBuilder::AddShadow(const FloatSize& offset, SkPaint* paint = sk_draw_looper_builder_.addLayerOnTop(info); if (blur) { - const SkScalar sigma = SkBlurRadiusToSigma(blur); + const auto sigma = BlurRadiusToStdDev(blur); const bool respectCTM = shadow_transform_mode != kShadowIgnoresTransforms; paint->setMaskFilter( SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, respectCTM)); diff --git a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc index af4e32d69d9..6a33e1fded7 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.cc @@ -25,7 +25,10 @@ #include "third_party/blink/renderer/platform/graphics/filters/fe_component_transfer.h" #include <algorithm> + #include "SkTableColorFilter.h" + +#include "base/stl_util.h" #include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" #include "third_party/blink/renderer/platform/wtf/text/text_stream.h" @@ -161,7 +164,7 @@ void FEComponentTransfer::GetValues(unsigned char r_values[256], for (unsigned channel = 0; channel < 4; channel++) { SECURITY_DCHECK(static_cast<size_t>(transfer_function[channel].type) < - arraysize(call_effect)); + base::size(call_effect)); (*call_effect[transfer_function[channel].type])(tables[channel], transfer_function[channel]); } diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc index 2fdde120800..655e3765a3d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc @@ -31,7 +31,9 @@ #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h" #include <memory> + #include "base/memory/scoped_refptr.h" +#include "base/stl_util.h" #include "components/viz/common/resources/single_release_callback.h" #include "components/viz/common/resources/transferable_resource.h" #include "components/viz/test/test_gpu_memory_buffer_manager.h" @@ -635,7 +637,7 @@ TEST(DrawingBufferDepthStencilTest, packedDepthStencilSupported) { DepthStencilTestCase(true, true, 1, "both"), }; - for (size_t i = 0; i < arraysize(cases); i++) { + for (size_t i = 0; i < base::size(cases); i++) { SCOPED_TRACE(cases[i].test_case_name); auto gl = std::make_unique<DepthStencilTrackingGLES2Interface>(); DepthStencilTrackingGLES2Interface* tracking_gl = gl.get(); diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc index 10ff62ac177..1fc321b4251 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc @@ -155,8 +155,9 @@ bool ImageLayerBridge::PrepareTransferableResource( *out_resource = viz::TransferableResource::MakeSoftware( registered.bitmap->id(), size, resource_format); if (RuntimeEnabledFeatures::CanvasColorManagementEnabled()) { - out_resource->color_space = - SkColorSpaceToGfxColorSpace(sk_image->refColorSpace()); + out_resource->color_space = sk_image->colorSpace() + ? gfx::ColorSpace(*sk_image->colorSpace()) + : gfx::ColorSpace::CreateSRGB(); } auto func = WTF::Bind(&ImageLayerBridge::ResourceReleasedSoftware, WrapWeakPersistent(this), std::move(registered)); diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc index 6ad59bb2a61..2cc0ad8cc63 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc @@ -2721,8 +2721,8 @@ GLenum WebGLImageConversion::ComputeImageSizeInBytes( } unsigned padding = 0; - base::CheckedNumeric<uint32_t> checked_residual = - checked_value % params.alignment; + base::CheckedNumeric<uint32_t> checked_residual = checked_value; + checked_residual %= static_cast<uint32_t>(params.alignment); if (!checked_residual.IsValid()) { return GL_INVALID_VALUE; } diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc index a0ace7b10a9..158ee960343 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.cc @@ -130,15 +130,20 @@ void XRFrameTransport::FrameSubmit( // for some out-of-memory situations. // TODO(billorr): Consider whether we should just drop the frame or exit // presentation. - if (gpu_memory_buffer) { - // We decompose the cloned handle, and use it to create a - // mojo::ScopedHandle which will own cleanup of the handle, and will be - // passed over IPC. - gfx::GpuMemoryBufferHandle gpu_handle = gpu_memory_buffer->CloneHandle(); - vr_presentation_provider->SubmitFrameWithTextureHandle( - vr_frame_id, - mojo::WrapPlatformFile(gpu_handle.dxgi_handle.GetHandle())); + if (!gpu_memory_buffer) { + FrameSubmitMissing(vr_presentation_provider, gl, vr_frame_id); + // We didn't actually submit anything, so don't set + // the waiting_for_previous_frame_transfer_ and related state. + return; } + + // We decompose the cloned handle, and use it to create a + // mojo::ScopedHandle which will own cleanup of the handle, and will be + // passed over IPC. + gfx::GpuMemoryBufferHandle gpu_handle = gpu_memory_buffer->CloneHandle(); + vr_presentation_provider->SubmitFrameWithTextureHandle( + vr_frame_id, + mojo::WrapPlatformFile(gpu_handle.dxgi_handle.GetHandle())); #else NOTIMPLEMENTED(); #endif diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc index ab0754787ba..d866b64127c 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc @@ -42,8 +42,7 @@ scoped_refptr<XRWebGLDrawingBuffer> XRWebGLDrawingBuffer::Create( bool want_alpha_channel, bool want_depth_buffer, bool want_stencil_buffer, - bool want_antialiasing, - bool want_multiview) { + bool want_antialiasing) { DCHECK(drawing_buffer); // Don't proceeed if the context is already lost. @@ -83,16 +82,11 @@ scoped_refptr<XRWebGLDrawingBuffer> XRWebGLDrawingBuffer::Create( if (discard_framebuffer_supported) extensions_util->EnsureExtensionEnabled("GL_EXT_discard_framebuffer"); - // TODO(bajones): Support multiview. - bool multiview_supported = false; - scoped_refptr<XRWebGLDrawingBuffer> xr_drawing_buffer = base::AdoptRef(new XRWebGLDrawingBuffer( drawing_buffer, framebuffer, discard_framebuffer_supported, - want_alpha_channel, want_depth_buffer, want_stencil_buffer, - multiview_supported)); - if (!xr_drawing_buffer->Initialize(size, multisample_supported, - multiview_supported)) { + want_alpha_channel, want_depth_buffer, want_stencil_buffer)); + if (!xr_drawing_buffer->Initialize(size, multisample_supported)) { DLOG(ERROR) << "XRWebGLDrawingBuffer Initialization Failed"; return nullptr; } @@ -100,22 +94,83 @@ scoped_refptr<XRWebGLDrawingBuffer> XRWebGLDrawingBuffer::Create( return xr_drawing_buffer; } +void XRWebGLDrawingBuffer::MirrorClient::OnMirrorImageAvailable( + scoped_refptr<StaticBitmapImage> image, + std::unique_ptr<viz::SingleReleaseCallback> callback) { + // Replace the next image if we have one already. + if (next_image_ && next_release_callback_) { + next_release_callback_->Run(gpu::SyncToken(), false); + } + + // Set our new image. + next_image_ = image; + next_release_callback_ = std::move(callback); +} + +void XRWebGLDrawingBuffer::MirrorClient::BeginDestruction() { + // Call all callbacks we have to clean up associated resources. For + // next_release_callback_, we report the previous image as "not lost", meaning + // we can reuse the texture/image. For previous_release_callback_ + // and current_release_callback_, we report the image as lost, because we + // don't know if the consumer is still using them, so they should not be + // reused. + if (previous_release_callback_) { + previous_release_callback_->Run(gpu::SyncToken(), true); + previous_release_callback_ = nullptr; + } + + if (current_release_callback_) { + current_release_callback_->Run(gpu::SyncToken(), true); + current_release_callback_ = nullptr; + } + + if (next_release_callback_) { + next_release_callback_->Run(gpu::SyncToken(), false); + next_release_callback_ = nullptr; + } + + next_image_ = nullptr; +} + +scoped_refptr<StaticBitmapImage> +XRWebGLDrawingBuffer::MirrorClient::GetLastImage() { + if (!next_image_) + return nullptr; + + scoped_refptr<StaticBitmapImage> ret = next_image_; + next_image_ = nullptr; + DCHECK(!previous_release_callback_); + previous_release_callback_ = std::move(current_release_callback_); + DCHECK(!current_release_callback_); + current_release_callback_ = std::move(next_release_callback_); + return ret; +} + +void XRWebGLDrawingBuffer::MirrorClient::CallLastReleaseCallback() { + if (previous_release_callback_) + previous_release_callback_->Run(gpu::SyncToken(), false); + previous_release_callback_ = nullptr; +} + +XRWebGLDrawingBuffer::MirrorClient::~MirrorClient() { + BeginDestruction(); +} + XRWebGLDrawingBuffer::XRWebGLDrawingBuffer(DrawingBuffer* drawing_buffer, GLuint framebuffer, bool discard_framebuffer_supported, bool want_alpha_channel, bool want_depth_buffer, - bool want_stencil_buffer, - bool multiview_supported) + bool want_stencil_buffer) : drawing_buffer_(drawing_buffer), framebuffer_(framebuffer), discard_framebuffer_supported_(discard_framebuffer_supported), depth_(want_depth_buffer), stencil_(want_stencil_buffer), - alpha_(want_alpha_channel), - multiview_(false) {} + alpha_(want_alpha_channel) {} void XRWebGLDrawingBuffer::BeginDestruction() { + mirror_client_ = nullptr; back_color_buffer_ = nullptr; front_color_buffer_ = nullptr; recycled_color_buffer_queue_.clear(); @@ -124,8 +179,7 @@ void XRWebGLDrawingBuffer::BeginDestruction() { // TODO(bajones): The GL resources allocated in this function are leaking. Add // a way to clean up the buffers when the layer is GCed or the session ends. bool XRWebGLDrawingBuffer::Initialize(const IntSize& size, - bool use_multisampling, - bool use_multiview) { + bool use_multisampling) { gpu::gles2::GLES2Interface* gl = drawing_buffer_->ContextGL(); std::unique_ptr<Extensions3DUtil> extensions_util = @@ -179,7 +233,7 @@ gpu::gles2::GLES2Interface* XRWebGLDrawingBuffer::ContextGL() { return drawing_buffer_->ContextGL(); } -void XRWebGLDrawingBuffer::SetMirrorClient(MirrorClient* client) { +void XRWebGLDrawingBuffer::SetMirrorClient(scoped_refptr<MirrorClient> client) { mirror_client_ = client; if (mirror_client_) { // Immediately send a black 1x1 image to the mirror client to ensure that diff --git a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h index 919566a74f6..157ce76910d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h +++ b/chromium/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h @@ -29,8 +29,7 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer bool want_alpha_channel, bool want_depth_buffer, bool want_stencil_buffer, - bool want_antialiasing, - bool want_multiview); + bool want_antialiasing); gpu::gles2::GLES2Interface* ContextGL(); bool ContextLost(); @@ -41,7 +40,6 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer bool depth() const { return depth_; } bool stencil() const { return stencil_; } bool alpha() const { return alpha_; } - bool multiview() const { return multiview_; } void Resize(const IntSize&); @@ -51,14 +49,25 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage( std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback); - class MirrorClient { + class PLATFORM_EXPORT MirrorClient : public RefCounted<MirrorClient> { public: - virtual void OnMirrorImageAvailable( - scoped_refptr<StaticBitmapImage>, - std::unique_ptr<viz::SingleReleaseCallback>) = 0; + void OnMirrorImageAvailable(scoped_refptr<StaticBitmapImage>, + std::unique_ptr<viz::SingleReleaseCallback>); + + void BeginDestruction(); + scoped_refptr<StaticBitmapImage> GetLastImage(); + void CallLastReleaseCallback(); + + ~MirrorClient(); + + private: + scoped_refptr<StaticBitmapImage> next_image_; + std::unique_ptr<viz::SingleReleaseCallback> next_release_callback_; + std::unique_ptr<viz::SingleReleaseCallback> current_release_callback_; + std::unique_ptr<viz::SingleReleaseCallback> previous_release_callback_; }; - void SetMirrorClient(MirrorClient*); + void SetMirrorClient(scoped_refptr<MirrorClient> mirror_client); void UseSharedBuffer(const gpu::MailboxHolder&); void DoneWithSharedBuffer(); @@ -99,10 +108,9 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer bool discard_framebuffer_supported, bool want_alpha_channel, bool want_depth_buffer, - bool want_stencil_buffer, - bool multiview_supported); + bool want_stencil_buffer); - bool Initialize(const IntSize&, bool use_multisampling, bool use_multiview); + bool Initialize(const IntSize&, bool use_multisampling); IntSize AdjustSize(const IntSize&); @@ -151,7 +159,6 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer bool depth_; bool stencil_; bool alpha_; - bool multiview_; enum AntialiasingMode { kNone, @@ -166,7 +173,7 @@ class PLATFORM_EXPORT XRWebGLDrawingBuffer int max_texture_size_ = 0; int sample_count_ = 0; - MirrorClient* mirror_client_ = nullptr; + scoped_refptr<MirrorClient> mirror_client_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc index 0f9141b2e29..4cc66dadfbf 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.cc @@ -28,6 +28,7 @@ #include <memory> +#include "base/optional.h" #include "build/build_config.h" #include "skia/ext/platform_canvas.h" #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h" @@ -58,6 +59,34 @@ namespace blink { +class GraphicsContext::HighContrastFlags final { + STACK_ALLOCATED(); + + public: + // This helper's lifetime should never exceed |flags|'. + HighContrastFlags(const GraphicsContext* gc, const PaintFlags& flags) { + if (!gc->high_contrast_filter_) { + flags_ = &flags; + } else { + high_contrast_flags_ = flags; + if (flags.HasShader()) { + high_contrast_flags_->setColorFilter(gc->high_contrast_filter_); + } else { + high_contrast_flags_->setColor( + gc->high_contrast_filter_->filterColor(flags.getColor())); + } + + flags_ = &high_contrast_flags_.value(); + } + } + + operator const PaintFlags&() const { return *flags_; } + + private: + const PaintFlags* flags_; + base::Optional<PaintFlags> high_contrast_flags_; +}; + GraphicsContext::GraphicsContext(PaintController& paint_controller, DisabledMode disable_context_or_painting, SkMetaData* meta_data) @@ -637,7 +666,7 @@ void GraphicsContext::DrawLine(const IntPoint& point1, const IntPoint& point2) { // probably worth the speed up of no square root, which also won't be exact. FloatSize disp = p2 - p1; int length = SkScalarRoundToInt(disp.Width() + disp.Height()); - PaintFlags flags(ImmutableState()->StrokeFlags(length)); + const HighContrastFlags flags(this, ImmutableState()->StrokeFlags(length)); if (pen_style == kDottedStroke) { if (StrokeData::StrokeIsDashed(width, pen_style)) { @@ -664,8 +693,7 @@ void GraphicsContext::DrawLine(const IntPoint& point1, const IntPoint& point2) { } AdjustLineToPixelBoundaries(p1, p2, width); - canvas_->drawLine(p1.X(), p1.Y(), p2.X(), p2.Y(), - ApplyHighContrastFilter(&flags)); + canvas_->drawLine(p1.X(), p1.Y(), p2.X(), p2.Y(), flags); } void GraphicsContext::DrawLineForText(const FloatPoint& pt, float width) { @@ -743,7 +771,7 @@ void GraphicsContext::DrawTextInternal(const Font& font, return; font.DrawText(canvas_, text_info, point, device_scale_factor_, - ApplyHighContrastFilter(&flags)); + HighContrastFlags(this, flags)); } void GraphicsContext::DrawText(const Font& font, @@ -788,7 +816,7 @@ void GraphicsContext::DrawTextInternal(const Font& font, DrawTextPasses([&font, &text_info, &point, this](const PaintFlags& flags) { font.DrawText(canvas_, text_info, point, device_scale_factor_, - ApplyHighContrastFilter(&flags)); + HighContrastFlags(this, flags)); }); } @@ -816,7 +844,7 @@ void GraphicsContext::DrawEmphasisMarksInternal(const Font& font, [&font, &text_info, &mark, &point, this](const PaintFlags& flags) { font.DrawEmphasisMarks(canvas_, text_info, mark, point, device_scale_factor_, - ApplyHighContrastFilter(&flags)); + HighContrastFlags(this, flags)); }); } @@ -847,7 +875,7 @@ void GraphicsContext::DrawBidiText( this](const PaintFlags& flags) { if (font.DrawBidiText(canvas_, run_info, point, custom_font_not_ready_action, device_scale_factor_, - ApplyHighContrastFilter(&flags))) + HighContrastFlags(this, flags))) paint_controller_.SetTextPainted(); }); } @@ -882,7 +910,6 @@ void GraphicsContext::DrawImage( image_flags.setBlendMode(op); image_flags.setColor(SK_ColorBLACK); image_flags.setFilterQuality(ComputeFilterQuality(image, dest, src)); - image_flags.setAntiAlias(ShouldAntialias()); if (ShouldApplyHighContrastFilterToImage(*image)) image_flags.setColorFilter(high_contrast_filter_); image->Draw(canvas_, image_flags, dest, src, should_respect_image_orientation, @@ -918,7 +945,6 @@ void GraphicsContext::DrawImageRRect( image_flags.setColor(SK_ColorBLACK); image_flags.setFilterQuality( ComputeFilterQuality(image, dest.Rect(), src_rect)); - image_flags.setAntiAlias(ShouldAntialias()); bool use_shader = (visible_src == src_rect) && (respect_orientation == kDoNotRespectImageOrientation); @@ -1011,7 +1037,7 @@ void GraphicsContext::DrawOval(const SkRect& oval, const PaintFlags& flags) { return; DCHECK(canvas_); - canvas_->drawOval(oval, ApplyHighContrastFilter(&flags)); + canvas_->drawOval(oval, HighContrastFlags(this, flags)); } void GraphicsContext::DrawPath(const SkPath& path, const PaintFlags& flags) { @@ -1019,7 +1045,7 @@ void GraphicsContext::DrawPath(const SkPath& path, const PaintFlags& flags) { return; DCHECK(canvas_); - canvas_->drawPath(path, ApplyHighContrastFilter(&flags)); + canvas_->drawPath(path, HighContrastFlags(this, flags)); } void GraphicsContext::DrawRect(const SkRect& rect, const PaintFlags& flags) { @@ -1027,7 +1053,7 @@ void GraphicsContext::DrawRect(const SkRect& rect, const PaintFlags& flags) { return; DCHECK(canvas_); - canvas_->drawRect(rect, ApplyHighContrastFilter(&flags)); + canvas_->drawRect(rect, HighContrastFlags(this, flags)); } void GraphicsContext::DrawRRect(const SkRRect& rrect, const PaintFlags& flags) { @@ -1035,7 +1061,7 @@ void GraphicsContext::DrawRRect(const SkRRect& rrect, const PaintFlags& flags) { return; DCHECK(canvas_); - canvas_->drawRRect(rrect, ApplyHighContrastFilter(&flags)); + canvas_->drawRRect(rrect, HighContrastFlags(this, flags)); } void GraphicsContext::FillPath(const Path& path_to_fill) { @@ -1423,28 +1449,7 @@ bool GraphicsContext::ShouldApplyHighContrastFilterToImage(Image& image) { Color GraphicsContext::ApplyHighContrastFilter(const Color& input) const { if (!high_contrast_filter_) return input; - - SkColor sk_input = - SkColorSetARGB(input.Alpha(), input.Red(), input.Green(), input.Blue()); - SkColor sk_output = high_contrast_filter_->filterColor(sk_input); - return Color(MakeRGBA(SkColorGetR(sk_output), SkColorGetG(sk_output), - SkColorGetB(sk_output), SkColorGetA(sk_output))); -} - -PaintFlags GraphicsContext::ApplyHighContrastFilter( - const PaintFlags* input) const { - if (input && !high_contrast_filter_) - return *input; - - PaintFlags output; - if (input) - output = *input; - if (output.HasShader()) { - output.setColorFilter(high_contrast_filter_); - } else { - output.setColor(high_contrast_filter_->filterColor(output.getColor())); - } - return output; + return Color(high_contrast_filter_->filterColor(input.Rgb())); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h index bcde7276eff..f46176a479d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_context.h @@ -88,7 +88,7 @@ class PLATFORM_EXPORT GraphicsContext { bool ContextDisabled() const { return disabled_state_; } - const HighContrastSettings& high_contrast_settings() { + const HighContrastSettings& high_contrast_settings() const { return high_contrast_settings_; } @@ -466,9 +466,9 @@ class PLATFORM_EXPORT GraphicsContext { const SkMetaData& MetaData() const { return meta_data_; } + class HighContrastFlags; bool ShouldApplyHighContrastFilterToImage(Image&); Color ApplyHighContrastFilter(const Color& input) const; - PaintFlags ApplyHighContrastFilter(const PaintFlags* input) const; // null indicates painting is contextDisabled. Never delete this object. cc::PaintCanvas* canvas_; diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc index 5a8572622a4..589c9d31b1d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc @@ -80,6 +80,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client) : client_(client), prevent_contents_opaque_changes_(false), draws_content_(false), + paints_hit_test_(false), contents_visible_(true), hit_testable_without_draws_content_(false), needs_check_raster_invalidation_(false), @@ -90,12 +91,12 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client) parent_(nullptr), mask_layer_(nullptr), contents_clipping_mask_layer_(nullptr), - paint_count_(0), contents_layer_(nullptr), contents_layer_id_(0), rendering_context3d_(0), weak_ptr_factory_(this) { #if DCHECK_IS_ON() + DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); client.VerifyNotPainting(); #endif layer_ = cc::PictureLayer::Create(this); @@ -106,6 +107,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client) } GraphicsLayer::~GraphicsLayer() { + CcLayer()->ClearClient(); CcLayer()->SetLayerClient(nullptr); SetContentsLayer(nullptr); for (size_t i = 0; i < link_highlights_.size(); ++i) @@ -150,6 +152,18 @@ void GraphicsLayer::SetIsContainerForFixedPositionLayers(bool is_container) { CcLayer()->SetIsContainerForFixedPositionLayers(is_container); } +void GraphicsLayer::SetCompositingReasons(CompositingReasons reasons) { + CcLayer()->set_compositing_reasons(reasons); +} + +CompositingReasons GraphicsLayer::GetCompositingReasons() const { + return CcLayer()->compositing_reasons(); +} + +void GraphicsLayer::SetOwnerNodeId(int node_id) { + CcLayer()->set_owner_node_id(node_id); +} + void GraphicsLayer::SetParent(GraphicsLayer* layer) { #if DCHECK_IS_ON() DCHECK(!layer || !layer->HasAncestor(this)); @@ -244,8 +258,10 @@ void GraphicsLayer::RemoveFromParent() { // When using layer lists, cc::Layers are created and removed in // PaintArtifactCompositor. if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() && - !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { CcLayer()->RemoveFromParent(); + } else { + SetPaintArtifactCompositorNeedsUpdate(); } } @@ -287,8 +303,8 @@ void GraphicsLayer::PaintRecursively() { void GraphicsLayer::PaintRecursivelyInternal( Vector<GraphicsLayer*>& repainted_layers) { - if (DrawsContent()) { - if (Paint(nullptr)) + if (PaintsContentOrHitTest()) { + if (Paint()) repainted_layers.push_back(this); } @@ -301,8 +317,7 @@ void GraphicsLayer::PaintRecursivelyInternal( child->PaintRecursivelyInternal(repainted_layers); } -bool GraphicsLayer::Paint(const IntRect* interest_rect, - GraphicsContext::DisabledMode disabled_mode) { +bool GraphicsLayer::Paint(GraphicsContext::DisabledMode disabled_mode) { #if !DCHECK_IS_ON() // TODO(crbug.com/853096): Investigate why we can ever reach here without // a valid layer state. Seems to only happen on Android builds. @@ -310,7 +325,7 @@ bool GraphicsLayer::Paint(const IntRect* interest_rect, return false; #endif - if (PaintWithoutCommit(interest_rect, disabled_mode)) + if (PaintWithoutCommit(disabled_mode)) GetPaintController().CommitNewDisplayItems(); else if (!needs_check_raster_invalidation_) return false; @@ -330,7 +345,7 @@ bool GraphicsLayer::Paint(const IntRect* interest_rect, layer_state_->state, VisualRectSubpixelOffset(), this); if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() && - DrawsContent()) { + PaintsContentOrHitTest()) { auto& tracking = EnsureRasterInvalidator().EnsureTracking(); tracking.CheckUnderInvalidations(DebugName(), CapturePaintRecord(), InterestRect()); @@ -347,16 +362,20 @@ bool GraphicsLayer::Paint(const IntRect* interest_rect, return true; } +bool GraphicsLayer::PaintWithoutCommitForTesting( + const base::Optional<IntRect>& interest_rect) { + return PaintWithoutCommit(GraphicsContext::kNothingDisabled, + base::OptionalOrNullptr(interest_rect)); +} + bool GraphicsLayer::PaintWithoutCommit( - const IntRect* interest_rect, - GraphicsContext::DisabledMode disabled_mode) { - DCHECK(DrawsContent()); + GraphicsContext::DisabledMode disabled_mode, + const IntRect* interest_rect) { + DCHECK(PaintsContentOrHitTest()); if (client_.ShouldThrottleRendering()) return false; - IncrementPaintCount(); - IntRect new_interest_rect; if (!interest_rect) { new_interest_rect = @@ -384,7 +403,8 @@ bool GraphicsLayer::PaintWithoutCommit( void GraphicsLayer::UpdateChildList() { // When using layer lists, cc::Layers are created in PaintArtifactCompositor. if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() || - RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { + SetPaintArtifactCompositorNeedsUpdate(); return; } @@ -431,6 +451,12 @@ void GraphicsLayer::UpdateContentsRect() { if (!contents_layer) return; + if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { + const auto& offset = GetContentsOffsetFromTransformNode(); + contents_layer->SetOffsetToTransformParent( + gfx::Vector2dF(offset.X(), offset.Y())); + SetPaintArtifactCompositorNeedsUpdate(); + } contents_layer->SetPosition( FloatPoint(contents_rect_.X(), contents_rect_.Y())); if (!image_layer_) { @@ -525,16 +551,13 @@ void GraphicsLayer::SetupContentsLayer(cc::Layer* contents_layer) { // Insert the content layer first. Video elements require this, because they // have shadow content that must display in front of the video. if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() && - !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { CcLayer()->InsertChild(contents_layer_, 0); } cc::PictureLayer* border_cc_layer = contents_clipping_mask_layer_ ? contents_clipping_mask_layer_->CcLayer() : nullptr; contents_layer_->SetMaskLayer(border_cc_layer); - if (border_cc_layer) - border_cc_layer->set_is_rounded_corner_mask(true); - contents_layer_->Set3dSortingContextId(rendering_context3d_); } @@ -722,6 +745,10 @@ void GraphicsLayer::SetContentsVisible(bool contents_visible) { UpdateLayerIsDrawable(); } +void GraphicsLayer::SetPaintArtifactCompositorNeedsUpdate() const { + client_.SetPaintArtifactCompositorNeedsUpdate(); +} + void GraphicsLayer::SetClipParent(cc::Layer* parent) { has_clip_parent_ = !!parent; CcLayer()->SetClipParent(parent); @@ -751,15 +778,12 @@ void GraphicsLayer::SetContentsOpaque(bool opaque) { contents_layer_->SetContentsOpaque(opaque); } -void GraphicsLayer::SetMaskLayer(GraphicsLayer* mask_layer, - bool is_rounded_corner_mask) { +void GraphicsLayer::SetMaskLayer(GraphicsLayer* mask_layer) { if (mask_layer == mask_layer_) return; mask_layer_ = mask_layer; CcLayer()->SetMaskLayer(mask_layer_ ? mask_layer_->CcLayer() : nullptr); - if (mask_layer_) - mask_layer_->CcLayer()->set_is_rounded_corner_mask(is_rounded_corner_mask); } void GraphicsLayer::SetContentsClippingMaskLayer( @@ -775,9 +799,6 @@ void GraphicsLayer::SetContentsClippingMaskLayer( contents_clipping_mask_layer_ ? contents_clipping_mask_layer_->CcLayer() : nullptr; contents_layer->SetMaskLayer(contents_clipping_mask_cc_layer); - // Contents clipping mask layesrs (aka child clipping mask layer) is always - // a rounded corner mask. - contents_layer->set_is_rounded_corner_mask(true); UpdateContentsRect(); } @@ -829,7 +850,7 @@ void GraphicsLayer::SetContentsNeedsDisplay() { } void GraphicsLayer::SetNeedsDisplay() { - if (!DrawsContent()) + if (!PaintsContentOrHitTest()) return; CcLayer()->SetNeedsDisplay(); @@ -846,7 +867,7 @@ void GraphicsLayer::SetNeedsDisplay() { } void GraphicsLayer::SetNeedsDisplayInRect(const IntRect& rect) { - DCHECK(DrawsContent()); + DCHECK(PaintsContentOrHitTest()); CcLayer()->SetNeedsDisplayRect(rect); for (auto* link_highlight : link_highlights_) @@ -920,8 +941,11 @@ void GraphicsLayer::SetFilters(CompositorFilterOperations filters) { CcLayer()->SetFilters(filters.ReleaseCcFilterOperations()); } -void GraphicsLayer::SetBackdropFilters(CompositorFilterOperations filters) { +void GraphicsLayer::SetBackdropFilters( + CompositorFilterOperations filters, + const gfx::RectF& backdrop_filter_bounds) { CcLayer()->SetBackdropFilters(filters.ReleaseCcFilterOperations()); + CcLayer()->SetBackdropFilterBounds(backdrop_filter_bounds); } void GraphicsLayer::SetStickyPositionConstraint( @@ -962,7 +986,7 @@ std::unique_ptr<base::trace_event::TracedValue> GraphicsLayer::TakeDebugInfo( traced_value->BeginArray("compositing_reasons"); for (const char* description : - CompositingReason::Descriptions(compositing_reasons_)) + CompositingReason::Descriptions(GetCompositingReasons())) traced_value->AppendString(description); traced_value->EndArray(); @@ -972,8 +996,8 @@ std::unique_ptr<base::trace_event::TracedValue> GraphicsLayer::TakeDebugInfo( traced_value->AppendString(description); traced_value->EndArray(); - if (owner_node_id_) - traced_value->SetInteger("owner_node", owner_node_id_); + if (auto node_id = layer_->owner_node_id()) + traced_value->SetInteger("owner_node", node_id); if (auto* tracking = GetRasterInvalidationTracking()) { tracking->AddToTracedValue(*traced_value); @@ -988,7 +1012,7 @@ void GraphicsLayer::DidChangeScrollbarsHiddenIfOverlay(bool hidden) { } PaintController& GraphicsLayer::GetPaintController() const { - CHECK(DrawsContent()); + CHECK(PaintsContentOrHitTest()); if (!paint_controller_) paint_controller_ = PaintController::Create(); return *paint_controller_; @@ -1006,7 +1030,7 @@ CompositorElementId GraphicsLayer::GetElementId() const { } sk_sp<PaintRecord> GraphicsLayer::CapturePaintRecord() const { - DCHECK(DrawsContent()); + DCHECK(PaintsContentOrHitTest()); if (client_.ShouldThrottleRendering()) return sk_sp<PaintRecord>(new PaintRecord); @@ -1025,6 +1049,9 @@ void GraphicsLayer::SetLayerState(const PropertyTreeState& layer_state, DCHECK(layer_state.Transform() && layer_state.Clip() && layer_state.Effect()); if (layer_state_) { + if (layer_state_->state == layer_state && + layer_state_->offset == layer_offset) + return; layer_state_->state = layer_state; layer_state_->offset = layer_offset; } else { @@ -1036,29 +1063,25 @@ void GraphicsLayer::SetLayerState(const PropertyTreeState& layer_state, CcLayer()->SetOffsetToTransformParent( gfx::Vector2dF(layer_offset.X(), layer_offset.Y())); - if (!contents_layer_state_ && ContentsLayer()) { + if (ContentsLayer()) { + const auto& offset = GetContentsOffsetFromTransformNode(); ContentsLayer()->SetOffsetToTransformParent( - gfx::Vector2dF(layer_offset.X(), layer_offset.Y())); + gfx::Vector2dF(offset.X(), offset.Y())); } + SetPaintArtifactCompositorNeedsUpdate(); } } -void GraphicsLayer::SetContentsLayerState(const PropertyTreeState& layer_state, - const IntPoint& layer_offset) { +void GraphicsLayer::SetContentsPropertyTreeState( + const PropertyTreeState& layer_state) { DCHECK(layer_state.Transform() && layer_state.Clip() && layer_state.Effect()); DCHECK(ContentsLayer()); - if (contents_layer_state_) { - contents_layer_state_->state = layer_state; - contents_layer_state_->offset = layer_offset; + if (contents_property_tree_state_) { + *contents_property_tree_state_ = layer_state; } else { - contents_layer_state_ = - std::make_unique<LayerState>(LayerState{layer_state, layer_offset}); - } - - if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { - ContentsLayer()->SetOffsetToTransformParent( - gfx::Vector2dF(layer_offset.X(), layer_offset.Y())); + contents_property_tree_state_ = + std::make_unique<PropertyTreeState>(layer_state); } } @@ -1094,7 +1117,7 @@ scoped_refptr<cc::DisplayItemList> GraphicsLayer::PaintContentsToDisplayList( // occurs in LocalFrameView::PaintTree() which calls GraphicsLayer::Paint(); // this method merely copies the painted output to the cc::DisplayItemList. if (painting_control != PAINTING_BEHAVIOR_NORMAL) - Paint(nullptr, disabled_mode); + Paint(disabled_mode); auto display_list = base::MakeRefCounted<cc::DisplayItemList>(); diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h index 954f933c69e..71f07812a9c 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.h @@ -89,19 +89,17 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, GraphicsLayerClient& Client() const { return client_; } - void SetCompositingReasons(CompositingReasons reasons) { - compositing_reasons_ = reasons; - } - CompositingReasons GetCompositingReasons() const { - return compositing_reasons_; - } + void SetCompositingReasons(CompositingReasons reasons); + CompositingReasons GetCompositingReasons() const; + SquashingDisallowedReasons GetSquashingDisallowedReasons() const { return squashing_disallowed_reasons_; } void SetSquashingDisallowedReasons(SquashingDisallowedReasons reasons) { squashing_disallowed_reasons_ = reasons; } - void SetOwnerNodeId(int id) { owner_node_id_ = id; } + + void SetOwnerNodeId(int id); GraphicsLayer* Parent() const { return parent_; } void SetParent(GraphicsLayer*); // Internal use only. @@ -119,7 +117,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, void RemoveFromParent(); GraphicsLayer* MaskLayer() const { return mask_layer_; } - void SetMaskLayer(GraphicsLayer*, bool is_rounded_corner_mask); + void SetMaskLayer(GraphicsLayer*); GraphicsLayer* ContentsClippingMaskLayer() const { return contents_clipping_mask_layer_; @@ -159,12 +157,24 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, bool DrawsContent() const { return draws_content_; } void SetDrawsContent(bool); + // False if no hit test display items will be painted onto this GraphicsLayer. + // This is different from |DrawsContent| because hit test display items are + // internal to blink and are not copied to the cc::Layer's display list. + bool PaintsHitTest() const { return paints_hit_test_; } + void SetPaintsHitTest(bool paints) { paints_hit_test_ = paints; }; + + bool PaintsContentOrHitTest() const { + return draws_content_ || paints_hit_test_; + } + bool ContentsAreVisible() const { return contents_visible_; } void SetContentsVisible(bool); void SetScrollParent(cc::Layer*); void SetClipParent(cc::Layer*); + void SetPaintArtifactCompositorNeedsUpdate() const; + // For special cases, e.g. drawing missing tiles on Android. // The compositor should never paint this color in normal cases because the // Layer will paint the background by itself. @@ -192,7 +202,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, } void SetFilters(CompositorFilterOperations); - void SetBackdropFilters(CompositorFilterOperations); + void SetBackdropFilters(CompositorFilterOperations, const gfx::RectF&); void SetStickyPositionConstraint(const cc::LayerStickyPositionConstraint&); @@ -227,8 +237,6 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, // For hosting this GraphicsLayer in a native layer hierarchy. cc::PictureLayer* CcLayer() const; - int PaintCount() const { return paint_count_; } - // Return a string with a human readable form of the layer tree. If debug is // true, pointers for the layers and timing data will be included in the // returned string. @@ -256,8 +264,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, IntRect InterestRect(); void PaintRecursively(); // Returns true if this layer is repainted. - bool Paint(const IntRect* interest_rect, - GraphicsContext::DisabledMode = GraphicsContext::kNothingDisabled); + bool Paint(GraphicsContext::DisabledMode = GraphicsContext::kNothingDisabled); // cc::LayerClient implementation. std::unique_ptr<base::trace_event::TracedValue> TakeDebugInfo( @@ -289,15 +296,16 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, } IntPoint GetOffsetFromTransformNode() const { return layer_state_->offset; } - void SetContentsLayerState(const PropertyTreeState&, - const IntPoint& layer_offset); + void SetContentsPropertyTreeState(const PropertyTreeState&); const PropertyTreeState& GetContentsPropertyTreeState() const { - return contents_layer_state_ ? contents_layer_state_->state - : GetPropertyTreeState(); + return contents_property_tree_state_ ? *contents_property_tree_state_ + : GetPropertyTreeState(); } IntPoint GetContentsOffsetFromTransformNode() const { - return contents_layer_state_ ? contents_layer_state_->offset - : GetOffsetFromTransformNode(); + auto offset = contents_rect_.Location(); + if (layer_state_) + offset = offset + GetOffsetFromTransformNode(); + return offset; } // Capture the last painted result into a PaintRecord. This GraphicsLayer @@ -311,16 +319,18 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, bool HasScrollParent() const { return has_scroll_parent_; } bool HasClipParent() const { return has_clip_parent_; } + bool PaintWithoutCommitForTesting( + const base::Optional<IntRect>& interest_rect = base::nullopt); + protected: String DebugName(cc::Layer*) const; explicit GraphicsLayer(GraphicsLayerClient&); + private: friend class CompositedLayerMappingTest; - friend class PaintControllerPaintTestBase; friend class GraphicsLayerTest; - private: // cc::ContentLayerClient implementation. gfx::Rect PaintableRegion() final { return InterestRect(); } scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList( @@ -330,10 +340,10 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, void PaintRecursivelyInternal(Vector<GraphicsLayer*>& repainted_layers); - // Returns true if PaintController::paintArtifact() changed and needs commit. + // Returns true if PaintController::PaintArtifact() changed and needs commit. bool PaintWithoutCommit( - const IntRect* interest_rect, - GraphicsContext::DisabledMode = GraphicsContext::kNothingDisabled); + GraphicsContext::DisabledMode = GraphicsContext::kNothingDisabled, + const IntRect* interest_rect = nullptr); // Adds a child without calling updateChildList(), so that adding children // can be batched before updating. @@ -343,8 +353,6 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, bool HasAncestor(GraphicsLayer*) const; #endif - void IncrementPaintCount() { ++paint_count_; } - // Helper functions used by settors to keep layer's the state consistent. void UpdateChildList(); void UpdateLayerIsDrawable(); @@ -370,6 +378,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, bool prevent_contents_opaque_changes_ : 1; bool draws_content_ : 1; + bool paints_hit_test_ : 1; bool contents_visible_ : 1; bool hit_testable_without_draws_content_ : 1; bool needs_check_raster_invalidation_ : 1; @@ -391,8 +400,6 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, IntRect contents_rect_; - int paint_count_; - scoped_refptr<cc::PictureLayer> layer_; scoped_refptr<cc::PictureImageLayer> image_layer_; IntSize image_size_; @@ -408,10 +415,8 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, int rendering_context3d_; - CompositingReasons compositing_reasons_ = CompositingReason::kNone; SquashingDisallowedReasons squashing_disallowed_reasons_ = SquashingDisallowedReason::kNone; - int owner_node_id_ = 0; mutable std::unique_ptr<PaintController> paint_controller_; @@ -422,7 +427,7 @@ class PLATFORM_EXPORT GraphicsLayer : public cc::LayerClient, IntPoint offset; }; std::unique_ptr<LayerState> layer_state_; - std::unique_ptr<LayerState> contents_layer_state_; + std::unique_ptr<PropertyTreeState> contents_property_tree_state_; std::unique_ptr<RasterInvalidator> raster_invalidator_; diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h index 7561489f69c..f55c529d768 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_client.h @@ -97,6 +97,8 @@ class PLATFORM_EXPORT GraphicsLayerClient { virtual void SetOverlayScrollbarsHidden(bool) {} + virtual void SetPaintArtifactCompositorNeedsUpdate() const {} + virtual String DebugName(const GraphicsLayer*) const = 0; virtual const ScrollableArea* GetScrollableAreaForTesting( diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc index e79095e8fbf..ac3a7883312 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer_test.cc @@ -49,10 +49,6 @@ class GraphicsLayerTest : public testing::Test, public PaintTestConfigurations { ~GraphicsLayerTest() = default; protected: - bool PaintWithoutCommit(GraphicsLayer& layer, const IntRect* interest_rect) { - return layer.PaintWithoutCommit(interest_rect); - } - void CommitAndFinishCycle(GraphicsLayer& layer) { layer.GetPaintController().CommitNewDisplayItems(); layer.GetPaintController().FinishCycle(); @@ -82,25 +78,26 @@ INSTANTIATE_TEST_CASE_P(All, TEST_P(GraphicsLayerTest, Paint) { IntRect interest_rect(1, 2, 3, 4); - EXPECT_TRUE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect)); - CommitAndFinishCycle(layers_.graphics_layer()); + auto& layer = layers_.graphics_layer(); + EXPECT_TRUE(layer.PaintWithoutCommitForTesting(interest_rect)); + CommitAndFinishCycle(layer); layers_.graphics_layer_client().SetNeedsRepaint(true); - EXPECT_TRUE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect)); - CommitAndFinishCycle(layers_.graphics_layer()); + EXPECT_TRUE(layer.PaintWithoutCommitForTesting(interest_rect)); + CommitAndFinishCycle(layer); layers_.graphics_layer_client().SetNeedsRepaint(false); - EXPECT_FALSE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect)); + EXPECT_FALSE(layer.PaintWithoutCommitForTesting(interest_rect)); interest_rect.Move(IntSize(10, 20)); - EXPECT_TRUE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect)); - CommitAndFinishCycle(layers_.graphics_layer()); - EXPECT_FALSE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect)); + EXPECT_TRUE(layer.PaintWithoutCommitForTesting(interest_rect)); + CommitAndFinishCycle(layer); + EXPECT_FALSE(layer.PaintWithoutCommitForTesting(interest_rect)); layers_.graphics_layer().SetNeedsDisplay(); - EXPECT_TRUE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect)); - CommitAndFinishCycle(layers_.graphics_layer()); - EXPECT_FALSE(PaintWithoutCommit(layers_.graphics_layer(), &interest_rect)); + EXPECT_TRUE(layer.PaintWithoutCommitForTesting(interest_rect)); + CommitAndFinishCycle(layer); + EXPECT_FALSE(layer.PaintWithoutCommitForTesting(interest_rect)); } TEST_P(GraphicsLayerTest, PaintRecursively) { @@ -158,4 +155,21 @@ TEST_P(GraphicsLayerTest, SetDrawsContentFalse) { EXPECT_EQ(nullptr, GetInternalRasterInvalidator(layers_.graphics_layer())); } +TEST_P(GraphicsLayerTest, CcLayerClient) { + auto graphics_layer = + std::make_unique<FakeGraphicsLayer>(layers_.graphics_layer_client()); + graphics_layer->SetDrawsContent(true); + scoped_refptr<cc::PictureLayer> cc_layer = graphics_layer->CcLayer(); + ASSERT_TRUE(cc_layer); + EXPECT_TRUE(cc_layer->DrawsContent()); + EXPECT_TRUE(cc_layer->client()); + EXPECT_TRUE(cc_layer->GetLayerClientForTesting()); + + graphics_layer.reset(); + EXPECT_FALSE(cc_layer->DrawsContent()); + EXPECT_FALSE(cc_layer->client()); + EXPECT_FALSE(cc_layer->GetLayerClientForTesting()); + EXPECT_FALSE(cc_layer->GetPicture()); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/image.cc b/chromium/third_party/blink/renderer/platform/graphics/image.cc index 4b07a4b2fdc..efa5fa09313 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/image.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/image.cc @@ -303,7 +303,8 @@ namespace { sk_sp<PaintShader> CreatePatternShader(const PaintImage& image, const SkMatrix& shader_matrix, - const PaintFlags& paint, + SkFilterQuality quality_to_use, + bool should_antialias, const FloatSize& spacing, SkShader::TileMode tmx, SkShader::TileMode tmy) { @@ -318,7 +319,10 @@ sk_sp<PaintShader> CreatePatternShader(const PaintImage& image, PaintRecorder recorder; cc::PaintCanvas* canvas = recorder.beginRecording(tile_rect); - canvas->drawImage(image, 0, 0, &paint); + PaintFlags flags; + flags.setAntiAlias(should_antialias); + flags.setFilterQuality(quality_to_use); + canvas->drawImage(image, 0, 0, &flags); return PaintShader::MakePaintRecord(recorder.finishRecordingAsPicture(), tile_rect, tmx, tmy, &shader_matrix); @@ -389,22 +393,22 @@ void Image::DrawPattern(GraphicsContext& context, const auto tmy = ComputeTileMode(dest_rect.Y(), dest_rect.MaxY(), adjusted_y, adjusted_y + tile_size.Height()); - PaintFlags flags = context.FillFlags(); - flags.setColor(SK_ColorBLACK); - flags.setBlendMode(composite_op); - flags.setFilterQuality( - context.ComputeFilterQuality(this, dest_rect, FloatRect(subset_rect))); - flags.setAntiAlias(context.ShouldAntialias()); - flags.setShader(CreatePatternShader( - image, local_matrix, flags, + SkFilterQuality quality_to_use = + context.ComputeFilterQuality(this, dest_rect, FloatRect(subset_rect)); + sk_sp<PaintShader> tile_shader = CreatePatternShader( + image, local_matrix, quality_to_use, context.ShouldAntialias(), FloatSize(repeat_spacing.Width() / scale_src_to_dest.Width(), repeat_spacing.Height() / scale_src_to_dest.Height()), - tmx, tmy)); + tmx, tmy); + + PaintFlags flags = context.FillFlags(); // If the shader could not be instantiated (e.g. non-invertible matrix), // draw transparent. // Note: we can't simply bail, because of arbitrary blend mode. - if (!flags.HasShader()) - flags.setColor(SK_ColorTRANSPARENT); + flags.setColor(tile_shader ? SK_ColorBLACK : SK_ColorTRANSPARENT); + flags.setBlendMode(composite_op); + flags.setFilterQuality(quality_to_use); + flags.setShader(std::move(tile_shader)); context.DrawRect(dest_rect, flags); @@ -466,7 +470,7 @@ FloatRect Image::ComputeSubsetForBackground(const FloatRect& phase_and_size, const FloatRect& subset, const FloatSize& intrinsic_size) { // TODO(schenney): Re-enable this after determining why it fails for - // SPv2, and maybe other cases. + // CAP, and maybe other cases. // DCHECK(phase_and_size.Contains(subset)); const FloatSize scale(phase_and_size.Width() / intrinsic_size.Width(), diff --git a/chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc b/chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc index 62a2e0e25d6..7632a4e9239 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/image_pattern.cc @@ -5,11 +5,8 @@ #include "third_party/blink/renderer/platform/graphics/image_pattern.h" #include "third_party/blink/renderer/platform/graphics/image.h" -#include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_shader.h" -#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h" #include "third_party/skia/include/core/SkImage.h" -#include "third_party/skia/include/core/SkSurface.h" namespace blink { @@ -20,13 +17,6 @@ scoped_refptr<ImagePattern> ImagePattern::Create(scoped_refptr<Image> image, ImagePattern::ImagePattern(scoped_refptr<Image> image, RepeatMode repeat_mode) : Pattern(repeat_mode), tile_image_(image->PaintImageForCurrentFrame()) { - previous_local_matrix_.setIdentity(); -} - -bool ImagePattern::IsLocalMatrixChanged(const SkMatrix& local_matrix) const { - if (IsRepeatXY()) - return Pattern::IsLocalMatrixChanged(local_matrix); - return local_matrix != previous_local_matrix_; } sk_sp<PaintShader> ImagePattern::CreateShader(const SkMatrix& local_matrix) { @@ -34,45 +24,11 @@ sk_sp<PaintShader> ImagePattern::CreateShader(const SkMatrix& local_matrix) { return PaintShader::MakeColor(SK_ColorTRANSPARENT); } - if (IsRepeatXY()) { - // Fast path: for repeatXY we just return a shader from the original image. - return PaintShader::MakeImage(tile_image_, SkShader::kRepeat_TileMode, - SkShader::kRepeat_TileMode, &local_matrix); - } - - // Skia does not have a "draw the tile only once" option. Clamp_TileMode - // repeats the last line of the image after drawing one tile. To avoid - // filling the space with arbitrary pixels, this workaround forces the - // image to have a line of transparent pixels on the "repeated" edge(s), - // thus causing extra space to be transparent filled. - SkShader::TileMode tile_mode_x = - IsRepeatX() ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; - SkShader::TileMode tile_mode_y = - IsRepeatY() ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; - int border_pixel_x = IsRepeatX() ? 0 : 1; - int border_pixel_y = IsRepeatY() ? 0 : 1; - - // Create a transparent image 2 pixels wider and/or taller than the - // original, then copy the orignal into the middle of it. - const SkRect tile_bounds = - SkRect::MakeWH(tile_image_.width() + 2 * border_pixel_x, - tile_image_.height() + 2 * border_pixel_y); - PaintRecorder recorder; - auto* canvas = recorder.beginRecording(tile_bounds); - - cc::PaintFlags paint; - paint.setBlendMode(SkBlendMode::kSrc); - canvas->drawImage(tile_image_, border_pixel_x, border_pixel_y, &paint); - - previous_local_matrix_ = local_matrix; - SkMatrix adjusted_matrix(local_matrix); - adjusted_matrix.postTranslate(-border_pixel_x, -border_pixel_y); - - // Note: we specify kFixedScale to lock-in the resolution (for 1px padding in - // particular). - return PaintShader::MakePaintRecord( - recorder.finishRecordingAsPicture(), tile_bounds, tile_mode_x, - tile_mode_y, &adjusted_matrix, PaintShader::ScalingBehavior::kFixedScale); + return PaintShader::MakeImage( + tile_image_, + IsRepeatX() ? SkShader::kRepeat_TileMode : SkShader::kDecal_TileMode, + IsRepeatY() ? SkShader::kRepeat_TileMode : SkShader::kDecal_TileMode, + &local_matrix); } bool ImagePattern::IsTextureBacked() const { diff --git a/chromium/third_party/blink/renderer/platform/graphics/image_pattern.h b/chromium/third_party/blink/renderer/platform/graphics/image_pattern.h index db42125f29e..cea1b6b337d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/image_pattern.h +++ b/chromium/third_party/blink/renderer/platform/graphics/image_pattern.h @@ -20,11 +20,9 @@ class PLATFORM_EXPORT ImagePattern final : public Pattern { protected: sk_sp<PaintShader> CreateShader(const SkMatrix&) override; - bool IsLocalMatrixChanged(const SkMatrix&) const override; private: ImagePattern(scoped_refptr<Image>, RepeatMode); - SkMatrix previous_local_matrix_; PaintImage tile_image_; }; diff --git a/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h b/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h index f17b64acc09..78164e773fc 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h +++ b/chromium/third_party/blink/renderer/platform/graphics/intercepting_canvas.h @@ -116,20 +116,6 @@ class InterceptingCanvasBase : public SkCanvas { void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&) override = 0; - void onDrawText(const void* text, - size_t byte_length, - SkScalar x, - SkScalar y, - const SkPaint&) override = 0; - void onDrawPosText(const void* text, - size_t byte_length, - const SkPoint pos[], - const SkPaint&) override = 0; - void onDrawPosTextH(const void* text, - size_t byte_length, - const SkScalar xpos[], - SkScalar const_y, - const SkPaint&) override = 0; void onDrawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, @@ -258,32 +244,6 @@ class InterceptingCanvas : public InterceptingCanvasBase { this->SkCanvas::onDrawDRRect(outer, inner, paint); } - void onDrawText(const void* text, - size_t byte_length, - SkScalar x, - SkScalar y, - const SkPaint& paint) override { - Interceptor interceptor(this); - this->SkCanvas::onDrawText(text, byte_length, x, y, paint); - } - - void onDrawPosText(const void* text, - size_t byte_length, - const SkPoint pos[], - const SkPaint& paint) override { - Interceptor interceptor(this); - this->SkCanvas::onDrawPosText(text, byte_length, pos, paint); - } - - void onDrawPosTextH(const void* text, - size_t byte_length, - const SkScalar xpos[], - SkScalar const_y, - const SkPaint& paint) override { - Interceptor interceptor(this); - this->SkCanvas::onDrawPosTextH(text, byte_length, xpos, const_y, paint); - } - void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, diff --git a/chromium/third_party/blink/renderer/platform/graphics/link_highlight.h b/chromium/third_party/blink/renderer/platform/graphics/link_highlight.h index 4044ad955f3..4dfc5a27c60 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/link_highlight.h +++ b/chromium/third_party/blink/renderer/platform/graphics/link_highlight.h @@ -24,9 +24,11 @@ class PLATFORM_EXPORT LinkHighlight : public DisplayItemClient { virtual void ClearCurrentGraphicsLayer() = 0; virtual cc::Layer* Layer() = 0; - virtual const EffectPaintPropertyNode* effect() = 0; + virtual const EffectPaintPropertyNode* effect() const = 0; // DisplayItemClient methods + // TODO(wangxianzhu): This class doesn't need to be a DisplayItemClient in + // CompositeAfterPaint. String DebugName() const final { return "LinkHighlight"; } LayoutRect VisualRect() const final { return LayoutRect(); } }; diff --git a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc index 0b830191a69..849372c2853 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.cc @@ -31,6 +31,8 @@ #include "third_party/blink/renderer/platform/graphics/logging_canvas.h" #include <unicode/unistr.h> + +#include "base/stl_util.h" #include "base/sys_byteorder.h" #include "build/build_config.h" #include "third_party/blink/renderer/platform/geometry/int_size.h" @@ -39,7 +41,6 @@ #include "third_party/blink/renderer/platform/image-encoders/image_encoder.h" #include "third_party/blink/renderer/platform/wtf/hex_number.h" #include "third_party/blink/renderer/platform/wtf/text/base64.h" -#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkPaint.h" @@ -234,7 +235,7 @@ std::unique_ptr<JSONObject> ObjectForSkPath(const SkPath& path) { std::unique_ptr<JSONObject> path_point_item = JSONObject::Create(); path_point_item->SetString("verb", verb_params.name); DCHECK_LE(verb_params.point_count + verb_params.point_offset, - arraysize(points)); + base::size(points)); path_point_item->SetArray( "points", ArrayForSkPoints(verb_params.point_count, points + verb_params.point_offset)); @@ -341,18 +342,11 @@ void AppendFlagToString(String* flags_string, bool is_set, const String& name) { } String StringForSkPaintFlags(const SkPaint& paint) { - if (!paint.getFlags()) + if (!paint.isAntiAlias() && !paint.isDither()) return "none"; String flags_string = ""; AppendFlagToString(&flags_string, paint.isAntiAlias(), "AntiAlias"); AppendFlagToString(&flags_string, paint.isDither(), "Dither"); - AppendFlagToString(&flags_string, paint.isFakeBoldText(), "FakeBoldText"); - AppendFlagToString(&flags_string, paint.isLinearText(), "LinearText"); - AppendFlagToString(&flags_string, paint.isSubpixelText(), "SubpixelText"); - AppendFlagToString(&flags_string, paint.isLCDRenderText(), "LCDRenderText"); - AppendFlagToString(&flags_string, paint.isEmbeddedBitmapText(), - "EmbeddedBitmapText"); - AppendFlagToString(&flags_string, paint.isAutohinted(), "Autohinted"); return flags_string; } @@ -414,43 +408,8 @@ String StyleName(SkPaint::Style style) { }; } -String TextEncodingName(SkPaint::TextEncoding encoding) { - switch (encoding) { - case SkPaint::kUTF8_TextEncoding: - return "UTF-8"; - case SkPaint::kUTF16_TextEncoding: - return "UTF-16"; - case SkPaint::kUTF32_TextEncoding: - return "UTF-32"; - case SkPaint::kGlyphID_TextEncoding: - return "GlyphID"; - default: - NOTREACHED(); - return "?"; - }; -} - -String HintingName(SkFontHinting hinting) { - switch (hinting) { - case SkFontHinting::kNone: - return "None"; - case SkFontHinting::kSlight: - return "Slight"; - case SkFontHinting::kNormal: - return "Normal"; - case SkFontHinting::kFull: - return "Full"; - default: - NOTREACHED(); - return "?"; - }; -} - std::unique_ptr<JSONObject> ObjectForSkPaint(const SkPaint& paint) { std::unique_ptr<JSONObject> paint_item = JSONObject::Create(); - paint_item->SetDouble("textSize", paint.getTextSize()); - paint_item->SetDouble("textScaleX", paint.getTextScaleX()); - paint_item->SetDouble("textSkewX", paint.getTextSkewX()); if (SkShader* shader = paint.getShader()) paint_item->SetObject("shader", ObjectForSkShader(*shader)); paint_item->SetString("color", StringForSkColor(paint.getColor())); @@ -462,9 +421,6 @@ std::unique_ptr<JSONObject> ObjectForSkPaint(const SkPaint& paint) { paint_item->SetString("strokeCap", StrokeCapName(paint.getStrokeCap())); paint_item->SetString("strokeJoin", StrokeJoinName(paint.getStrokeJoin())); paint_item->SetString("styleName", StyleName(paint.getStyle())); - paint_item->SetString("textEncoding", - TextEncodingName(paint.getTextEncoding())); - paint_item->SetString("hinting", HintingName(paint.getHinting())); if (paint.getBlendMode() != SkBlendMode::kSrcOver) paint_item->SetString("blendMode", SkBlendMode_Name(paint.getBlendMode())); if (paint.getImageFilter()) @@ -472,14 +428,6 @@ std::unique_ptr<JSONObject> ObjectForSkPaint(const SkPaint& paint) { return paint_item; } -std::unique_ptr<JSONArray> ArrayForSkScalars(size_t n, - const SkScalar scalars[]) { - std::unique_ptr<JSONArray> scalars_array = JSONArray::Create(); - for (size_t i = 0; i < n; ++i) - scalars_array->PushDouble(scalars[i]); - return scalars_array; -} - String ClipOpName(SkClipOp op) { switch (op) { case SkClipOp::kDifference: @@ -491,58 +439,6 @@ String ClipOpName(SkClipOp op) { }; } -String SaveLayerFlagsToString(SkCanvas::SaveLayerFlags flags) { - String flags_string = ""; - if (flags & SkCanvas::kPreserveLCDText_SaveLayerFlag) - flags_string.append("kPreserveLCDText_SaveLayerFlag "); - return flags_string; -} - -String StringForUTF32LEText(const void* text, size_t byte_length) { - icu::UnicodeString utf16; -#if defined(ARCH_CPU_BIG_ENDIAN) - // Swap LE to BE - size_t char_length = length / sizeof(UChar32); - WTF::Vector<UChar32> utf32be(char_length); - const UChar32* utf32le = static_cast<const UChar32*>(text); - for (size_t i = 0; i < char_length; ++i) - utf32be[i] = base::ByteSwap(utf32le[i]); - utf16 = icu::UnicodeString::fromUTF32(utf32be.data(), - static_cast<int32_t>(byte_length)); -#else - utf16 = icu::UnicodeString::fromUTF32(reinterpret_cast<const UChar32*>(text), - static_cast<int32_t>(byte_length)); -#endif - return String(icu::toUCharPtr(utf16.getBuffer()), - static_cast<unsigned>(utf16.length())); -} - -String StringForText(const void* text, - size_t byte_length, - const SkPaint& paint) { - SkPaint::TextEncoding encoding = paint.getTextEncoding(); - switch (encoding) { - case SkPaint::kUTF8_TextEncoding: - return WTF::TextEncoding("UTF-8").Decode( - reinterpret_cast<const char*>(text), byte_length); - case SkPaint::kUTF16_TextEncoding: - return WTF::TextEncoding("UTF-16LE") - .Decode(reinterpret_cast<const char*>(text), byte_length); - case SkPaint::kUTF32_TextEncoding: - return StringForUTF32LEText(text, byte_length); - case SkPaint::kGlyphID_TextEncoding: { - WTF::Vector<SkUnichar> data_vector(byte_length / 2); - SkUnichar* text_data = data_vector.data(); - paint.glyphsToUnichars(static_cast<const uint16_t*>(text), - byte_length / 2, text_data); - return StringForUTF32LEText(text, byte_length); - } - default: - NOTREACHED(); - return "?"; - } -} - } // namespace class AutoLogger @@ -725,48 +621,6 @@ void LoggingCanvas::onDrawDRRect(const SkRRect& outer, this->SkCanvas::onDrawDRRect(outer, inner, paint); } -void LoggingCanvas::onDrawText(const void* text, - size_t byte_length, - SkScalar x, - SkScalar y, - const SkPaint& paint) { - AutoLogger logger(this); - JSONObject* params = logger.LogItemWithParams("drawText"); - params->SetString("text", StringForText(text, byte_length, paint)); - params->SetDouble("x", x); - params->SetDouble("y", y); - params->SetObject("paint", ObjectForSkPaint(paint)); - this->SkCanvas::onDrawText(text, byte_length, x, y, paint); -} - -void LoggingCanvas::onDrawPosText(const void* text, - size_t byte_length, - const SkPoint pos[], - const SkPaint& paint) { - AutoLogger logger(this); - JSONObject* params = logger.LogItemWithParams("drawPosText"); - params->SetString("text", StringForText(text, byte_length, paint)); - size_t points_count = paint.countText(text, byte_length); - params->SetArray("pos", ArrayForSkPoints(points_count, pos)); - params->SetObject("paint", ObjectForSkPaint(paint)); - this->SkCanvas::onDrawPosText(text, byte_length, pos, paint); -} - -void LoggingCanvas::onDrawPosTextH(const void* text, - size_t byte_length, - const SkScalar xpos[], - SkScalar const_y, - const SkPaint& paint) { - AutoLogger logger(this); - JSONObject* params = logger.LogItemWithParams("drawPosTextH"); - params->SetString("text", StringForText(text, byte_length, paint)); - size_t points_count = paint.countText(text, byte_length); - params->SetArray("xpos", ArrayForSkScalars(points_count, xpos)); - params->SetDouble("constY", const_y); - params->SetObject("paint", ObjectForSkPaint(paint)); - this->SkCanvas::onDrawPosTextH(text, byte_length, xpos, const_y, paint); -} - void LoggingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, @@ -870,7 +724,7 @@ SkCanvas::SaveLayerStrategy LoggingCanvas::getSaveLayerStrategy( params->SetObject("bounds", ObjectForSkRect(*rec.fBounds)); if (rec.fPaint) params->SetObject("paint", ObjectForSkPaint(*rec.fPaint)); - params->SetString("saveFlags", SaveLayerFlagsToString(rec.fSaveLayerFlags)); + params->SetInteger("saveFlags", static_cast<int>(rec.fSaveLayerFlags)); return this->SkCanvas::getSaveLayerStrategy(rec); } diff --git a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h index eceee7d8ddd..3951bbf51da 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h +++ b/chromium/third_party/blink/renderer/platform/graphics/logging_canvas.h @@ -79,20 +79,6 @@ class LoggingCanvas : public InterceptingCanvasBase { void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&) override; - void onDrawText(const void* text, - size_t byte_length, - SkScalar x, - SkScalar y, - const SkPaint&) override; - void onDrawPosText(const void* text, - size_t byte_length, - const SkPoint pos[], - const SkPaint&) override; - void onDrawPosTextH(const void* text, - size_t byte_length, - const SkScalar xpos[], - SkScalar const_y, - const SkPaint&) override; void onDrawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, diff --git a/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc b/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc index 76a59a710b6..da6cd935170 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc @@ -79,7 +79,7 @@ void MailboxTextureHolder::Sync(MailboxSyncMode mode) { return; } - if (!ContextProviderWrapper() || IsAbandoned()) + if (!ContextProviderWrapper()) return; TRACE_EVENT0("blink", "MailboxTextureHolder::Sync"); @@ -129,7 +129,7 @@ bool MailboxTextureHolder::IsValid() const { // Just assume valid. Potential problem will be detected later. return true; } - return !IsAbandoned() && !!ContextProviderWrapper(); + return !!ContextProviderWrapper(); } bool MailboxTextureHolder::IsCrossThread() const { @@ -141,20 +141,18 @@ MailboxTextureHolder::~MailboxTextureHolder() { new gpu::SyncToken(sync_token_)); std::unique_ptr<gpu::Mailbox> passed_mailbox(new gpu::Mailbox(mailbox_)); - if (!IsAbandoned()) { - if (texture_thread_task_runner_ && - thread_id_ != Thread::Current()->ThreadId()) { - PostCrossThreadTask( - *texture_thread_task_runner_, FROM_HERE, - CrossThreadBind(&ReleaseTexture, is_converted_from_skia_texture_, - texture_id_, WTF::Passed(std::move(passed_mailbox)), - WTF::Passed(ContextProviderWrapper()), - WTF::Passed(std::move(passed_sync_token)))); - } else { - ReleaseTexture(is_converted_from_skia_texture_, texture_id_, - std::move(passed_mailbox), ContextProviderWrapper(), - std::move(passed_sync_token)); - } + if (texture_thread_task_runner_ && + thread_id_ != Thread::Current()->ThreadId()) { + PostCrossThreadTask( + *texture_thread_task_runner_, FROM_HERE, + CrossThreadBind(&ReleaseTexture, is_converted_from_skia_texture_, + texture_id_, WTF::Passed(std::move(passed_mailbox)), + WTF::Passed(ContextProviderWrapper()), + WTF::Passed(std::move(passed_sync_token)))); + } else { + ReleaseTexture(is_converted_from_skia_texture_, texture_id_, + std::move(passed_mailbox), ContextProviderWrapper(), + std::move(passed_sync_token)); } texture_id_ = 0u; // invalidate the texture. diff --git a/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc b/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc index 378ec6a3fbf..37d3c6c172f 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.cc @@ -15,6 +15,11 @@ MainThreadMutatorClient::MainThreadMutatorClient( mutator_->SetClient(this); } +void MainThreadMutatorClient::SynchronizeAnimatorName( + const String& animator_name) { + delegate_->SynchronizeAnimatorName(animator_name); +} + void MainThreadMutatorClient::SetMutationUpdate( std::unique_ptr<AnimationWorkletOutput> output_state) { delegate_->SetMutationUpdate(std::move(output_state)); diff --git a/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h b/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h index 127d8f3da49..f776791ba10 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h +++ b/chromium/third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h @@ -20,7 +20,10 @@ class PLATFORM_EXPORT MainThreadMutatorClient : public MutatorClient { std::unique_ptr<AnimationWorkletMutatorDispatcherImpl>); ~MainThreadMutatorClient() override = default; + void SynchronizeAnimatorName(const String& animator_name) override; void SetMutationUpdate(std::unique_ptr<AnimationWorkletOutput>) override; + void NotifyAnimationsPending() override {} + void NotifyAnimationsReady() override {} void SetDelegate(MutatorClient* client); AnimationWorkletMutatorDispatcherImpl* Mutator() { return mutator_.get(); } diff --git a/chromium/third_party/blink/renderer/platform/graphics/mutator_client.h b/chromium/third_party/blink/renderer/platform/graphics/mutator_client.h index b4b5845034f..e83018e168d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/mutator_client.h +++ b/chromium/third_party/blink/renderer/platform/graphics/mutator_client.h @@ -7,6 +7,7 @@ #include "third_party/blink/renderer/platform/graphics/animation_worklet_mutators_state.h" #include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -14,7 +15,12 @@ class PLATFORM_EXPORT MutatorClient { public: virtual ~MutatorClient() = default; + virtual void SynchronizeAnimatorName(const String& animator_name) = 0; virtual void SetMutationUpdate(std::unique_ptr<AnimationWorkletOutput>) = 0; + + virtual void NotifyAnimationsPending() = 0; + + virtual void NotifyAnimationsReady() = 0; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/README.md b/chromium/third_party/blink/renderer/platform/graphics/paint/README.md index 26a11012dab..2f2163bceda 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/README.md +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/README.md @@ -6,18 +6,18 @@ concepts, such as DOM elements and layout objects. This code is owned by the [paint team][paint-team-site]. -Slimming Paint v2 is currently being implemented. Unlike Slimming Paint v1, SPv2 -represents its paint artifact not as a flat display list, but as a list of -drawings, and a list of paint chunks, stored together. +CompositeAfterPaint is currently being implemented. Unlike Slimming Paint v1, +CompositeAfterPaint represents its paint artifact not as a flat display list, +but as a list of drawings, and a list of paint chunks, stored together. -This document explains the SPv2 world as it develops, not the SPv1 world it -replaces. +This document explains the CompositeAfterPaint (CAP) world as it develops, not +the SPv1 world it replaces. -[paint-team-site]: https://www.chromium.org/developers/paint-team +[paint-team-site]: https://www.chromium.org/teams/paint-team ## Paint artifact -The SPv2 [paint artifact](paint_artifact.h) consists of a list of display items +The CAP [paint artifact](paint_artifact.h) consists of a list of display items in paint order (ideally mostly or all drawings), partitioned into *paint chunks* which define certain *paint properties* which affect how the content should be drawn or composited. @@ -142,7 +142,7 @@ images. *** note It is illegal for there to be two display items with the same ID in a display item list, except for display items that are marked uncacheable -(see [DisplayItemCacheSkipper](DisplayItemCacheSkipper.h)). +(see [DisplayItemCacheSkipper](display_item_cache_skipper.h)). *** Generally, clients of this code should use stack-allocated recorder classes to @@ -150,19 +150,19 @@ emit display items to a `PaintController` (using `GraphicsContext`). ### Standalone display items -#### [DrawingDisplayItem](DrawingDisplayItem.h) +#### [DrawingDisplayItem](drawing_display_item.h) Holds a `PaintRecord` which contains the paint operations required to draw some atom of content. -#### [ForeignLayerDisplayItem](ForeignLayerDisplayItem.h) +#### [ForeignLayerDisplayItem](foreign_layer_display_item.h) Draws an atom of content, but using a `cc::Layer` produced by some agent outside of the normal Blink paint system (for example, a plugin). Since they always map to a `cc::Layer`, they are always the only display item in their paint chunk, and are ineligible for squashing with other layers. -#### [ScrollHitTestDisplayItem](ScrollHitTestDisplayItem.h) +#### [ScrollHitTestDisplayItem](scroll_hit_test_display_item.h) Placeholder for creating a cc::Layer for scrolling in paint order. Hit testing in the compositor requires both property trees (scroll nodes) and a scrollable @@ -199,9 +199,9 @@ module using `PaintController` API. ## Paint artifact compositor -The [`PaintArtifactCompositor`](paint_artifact_compositor.h) is responsible for -consuming the `PaintArtifact` produced by the `PaintController`, and converting -it into a form suitable for the compositor to consume. +[`PaintArtifactCompositor`](../compositing/paint_artifact_compositor.h) is +responsible for consuming the `PaintArtifact` produced by the `PaintController`, +and converting it into a form suitable for the compositor to consume. At present, `PaintArtifactCompositor` creates a cc layer tree, with one layer for each paint chunk. In the future, it is expected that we will use heuristics diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc index a79f58d730d..44f0dd87053 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc @@ -47,7 +47,7 @@ void CullRect::Move(const IntSize& offset) { CullRect::ApplyTransformResult CullRect::ApplyTransformInternal( const TransformPaintPropertyNode* transform) { - if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { if (const auto* scroll = transform->ScrollNode()) { rect_.Intersect(scroll->ContainerRect()); if (rect_.IsEmpty()) @@ -80,7 +80,7 @@ CullRect::ApplyTransformResult CullRect::ApplyTransformInternal( void CullRect::ApplyTransforms(const TransformPaintPropertyNode* source, const TransformPaintPropertyNode* destination, const base::Optional<CullRect>& old_cull_rect) { - DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); Vector<const TransformPaintPropertyNode*> scroll_translations; for (const auto* t = destination; t != source; t = t->Parent()) { @@ -115,7 +115,7 @@ void CullRect::ApplyTransforms(const TransformPaintPropertyNode* source, } bool CullRect::ChangedEnough(const CullRect& old_cull_rect) const { - DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); const auto& new_rect = Rect(); const auto& old_rect = old_cull_rect.Rect(); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h index 73ef85de6e4..375174cf134 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect.h @@ -42,8 +42,8 @@ class PLATFORM_EXPORT CullRect { // Applies one transform to the cull rect. Before this function is called, // the cull rect is in the space of the parent the transform node. - // For SlimmingPaintV2, when the transform is a scroll translation, the cull - // rect is converted in the following steps: + // For CompositeAfterPaint, when the transform is a scroll translation, the + // cull rect is converted in the following steps: // 1. it's clipped by the container rect, // 2. transformed by inverse of the scroll translation, // 3. expanded by thousands of pixels for composited scrolling. @@ -51,13 +51,13 @@ class PLATFORM_EXPORT CullRect { ApplyTransformInternal(transform); } - // For SlimmingPaintV2 only. Applies transforms from |source| (not included) - // to |destination| (included). For each scroll translation, the cull rect is - // converted as described in ApplyTransform(). If |old_cull_rect| is provided, - // and the cull rect converted by the last scroll translation doesn't cover - // the whole scrolling contents, and the new cull rect doesn't change enough - // (by hundreds of pixels) from |old_cull_rect|, the cull rect will be set to - // |old_cull_rect| to avoid repaint on each composited scroll. + // For CompositeAfterPaint only. Applies transforms from |source| (not + // included) to |destination| (included). For each scroll translation, the + // cull rect is converted as described in ApplyTransform(). If |old_cull_rect| + // is provided, and the cull rect converted by the last scroll translation + // doesn't cover the whole scrolling contents, and the new cull rect doesn't + // change enough (by hundreds of pixels) from |old_cull_rect|, the cull rect + // will be set to |old_cull_rect| to avoid repaint on each composited scroll. void ApplyTransforms(const TransformPaintPropertyNode* source, const TransformPaintPropertyNode* destination, const base::Optional<CullRect>& old_cull_rect); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc index 40081fb82f9..bff6f12945d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc @@ -114,7 +114,7 @@ TEST_F(CullRectTest, ApplyTransformInfinite) { } TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); ScrollPaintPropertyNode::State scroll_state; scroll_state.container_rect = IntRect(20, 10, 40, 50); @@ -142,7 +142,7 @@ TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) { } TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); ScrollPaintPropertyNode::State scroll_state; scroll_state.container_rect = IntRect(200, 100, 40, 50); @@ -157,7 +157,7 @@ TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) { } TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); ScrollPaintPropertyNode::State scroll_state; scroll_state.container_rect = IntRect(20, 10, 40, 50); @@ -184,7 +184,7 @@ TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) { } TEST_F(CullRectTest, ChangedEnoughEmpty) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); EXPECT_FALSE(ChangedEnough(IntRect(), IntRect())); EXPECT_FALSE(ChangedEnough(IntRect(1, 1, 0, 0), IntRect(2, 2, 0, 0))); EXPECT_TRUE(ChangedEnough(IntRect(), IntRect(0, 0, 1, 1))); @@ -192,7 +192,7 @@ TEST_F(CullRectTest, ChangedEnoughEmpty) { } TEST_F(CullRectTest, ChangedNotEnough) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); IntRect old_rect(100, 100, 100, 100); EXPECT_FALSE(ChangedEnough(old_rect, old_rect)); EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 90, 90))); @@ -201,7 +201,7 @@ TEST_F(CullRectTest, ChangedNotEnough) { } TEST_F(CullRectTest, ChangedEnoughScrollScenarios) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); IntRect old_rect(100, 100, 100, 100); IntRect new_rect(old_rect); new_rect.Move(500, 0); @@ -215,7 +215,7 @@ TEST_F(CullRectTest, ChangedEnoughScrollScenarios) { } TEST_F(CullRectTest, ApplyTransformsSameTransform) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); auto transform = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); CullRect cull_rect1(IntRect(1, 1, 50, 50)); @@ -235,7 +235,7 @@ TEST_F(CullRectTest, ApplyTransformsSameTransform) { } TEST_F(CullRectTest, ApplyTransformsWithoutScroll) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); auto t2 = CreateTransform(*t1, TransformationMatrix().Translate(10, 20)); @@ -260,7 +260,7 @@ TEST_F(CullRectTest, ApplyTransformsWithoutScroll) { } TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); ScrollPaintPropertyNode::State scroll_state; @@ -290,7 +290,7 @@ TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) { } TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); ScrollPaintPropertyNode::State scroll_state; @@ -326,7 +326,7 @@ TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) { } TEST_F(CullRectTest, ApplyTransformsEscapingScroll) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); ScrollPaintPropertyNode::State scroll_state; @@ -352,7 +352,7 @@ TEST_F(CullRectTest, ApplyTransformsEscapingScroll) { } TEST_F(CullRectTest, ApplyTransformsSmallScrollContentsAfterBigScrollContents) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); ScrollPaintPropertyNode::State scroll_state1; @@ -387,7 +387,7 @@ TEST_F(CullRectTest, ApplyTransformsSmallScrollContentsAfterBigScrollContents) { } TEST_F(CullRectTest, ApplyTransformsBigScrollContentsAfterSmallScrollContents) { - ScopedSlimmingPaintV2ForTest spv2(true); + ScopedCompositeAfterPaintForTest cap(true); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); ScrollPaintPropertyNode::State scroll_state1; diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc index 8077c0e9b3a..9dfd70bbff2 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.cc @@ -82,7 +82,7 @@ static WTF::String SpecialDrawingTypeAsDebugString(DisplayItem::Type type) { DEBUG_STRING_CASE(LinkHighlight); DEBUG_STRING_CASE(ImageAreaFocusRing); DEBUG_STRING_CASE(OverflowControls); - DEBUG_STRING_CASE(PageOverlay); + DEBUG_STRING_CASE(FrameOverlay); DEBUG_STRING_CASE(PopupContainerBorder); DEBUG_STRING_CASE(PopupListBoxBackground); DEBUG_STRING_CASE(PopupListBoxRow); @@ -123,6 +123,7 @@ static WTF::String DrawingTypeAsDebugString(DisplayItem::Type type) { static String ForeignLayerTypeAsDebugString(DisplayItem::Type type) { switch (type) { DEBUG_STRING_CASE(ForeignLayerCanvas); + DEBUG_STRING_CASE(ForeignLayerDevToolsOverlay); DEBUG_STRING_CASE(ForeignLayerPlugin); DEBUG_STRING_CASE(ForeignLayerVideo); DEBUG_STRING_CASE(ForeignLayerWrapper); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h index e0ff93900e2..2c5c6bb2bb2 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item.h @@ -18,14 +18,8 @@ #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #endif -namespace cc { -class DisplayItemList; -} - namespace blink { -class GraphicsContext; -class FloatSize; enum class PaintPhase; class PLATFORM_EXPORT DisplayItem { @@ -75,7 +69,7 @@ class PLATFORM_EXPORT DisplayItem { kLinkHighlight, kImageAreaFocusRing, kOverflowControls, - kPageOverlay, + kFrameOverlay, kPopupContainerBorder, kPopupListBoxBackground, kPopupListBoxRow, @@ -107,6 +101,7 @@ class PLATFORM_EXPORT DisplayItem { kForeignLayerFirst, kForeignLayerCanvas = kForeignLayerFirst, + kForeignLayerDevToolsOverlay, kForeignLayerPlugin, kForeignLayerVideo, kForeignLayerWrapper, @@ -147,11 +142,15 @@ class PLATFORM_EXPORT DisplayItem { // Some fields are copied from |client|, because we need to access them in // later paint cycles when |client| may have been destroyed. - DisplayItem(const DisplayItemClient& client, Type type, size_t derived_size) + DisplayItem(const DisplayItemClient& client, + Type type, + size_t derived_size, + bool draws_content = false) : client_(&client), visual_rect_(client.VisualRect()), outset_for_raster_effects_(client.VisualRectOutsetForRasterEffects()), type_(type), + draws_content_(draws_content), fragment_(0), is_cacheable_(client.IsCacheable()), is_tombstone_(false) { @@ -181,8 +180,6 @@ class PLATFORM_EXPORT DisplayItem { Id GetId() const { return Id(*client_, GetType(), fragment_); } - virtual void Replay(GraphicsContext&) const {} - const DisplayItemClient& Client() const { DCHECK(client_); return *client_; @@ -216,13 +213,6 @@ class PLATFORM_EXPORT DisplayItem { fragment_ = fragment; } - // Appends this display item to the cc::DisplayItemList, if applicable. - // |visual_rect_offset| is the offset between the space of the GraphicsLayer - // which owns the display item and the coordinate space of VisualRect(). - // TODO(wangxianzhu): Remove the parameter for slimming paint v2. - virtual void AppendToDisplayItemList(const FloatSize& visual_rect_offset, - cc::DisplayItemList&) const {} - // See comments of enum Type for usage of the following macros. #define DEFINE_CATEGORY_METHODS(Category) \ static constexpr bool Is##Category##Type(Type type) { \ @@ -269,7 +259,7 @@ class PLATFORM_EXPORT DisplayItem { // DisplayItem. bool IsTombstone() const { return is_tombstone_; } - virtual bool DrawsContent() const { return false; } + bool DrawsContent() const { return draws_content_; } #if DCHECK_IS_ON() static WTF::String TypeAsDebugString(DisplayItem::Type); @@ -284,18 +274,19 @@ class PLATFORM_EXPORT DisplayItem { // The default DisplayItem constructor is only used by ContiguousContainer:: // AppendByMoving() where a tombstone DisplayItem is constructed at the source - // location. Only set is_tombstone_ to true, leaving other fields as-is so - // that we can get their original values. |visual_rect_| and - // |outset_for_raster_effects_| are special, see DisplayItemList:: - // AppendByMoving(). - DisplayItem() : is_tombstone_(true) {} + // location. Only set draws_content_ to false and is_tombstone_ to true, + // leaving other fields as-is so that we can get their original values. + // |visual_rect_| and |outset_for_raster_effects_| are special, see + // DisplayItemList::AppendByMoving(). + DisplayItem() : draws_content_(false), is_tombstone_(true) {} const DisplayItemClient* client_; FloatRect visual_rect_; float outset_for_raster_effects_; - static_assert(kTypeLast < (1 << 8), "DisplayItem::Type should fit in 8 bits"); - unsigned type_ : 8; + static_assert(kTypeLast < (1 << 7), "DisplayItem::Type should fit in 7 bits"); + unsigned type_ : 7; + unsigned draws_content_ : 1; unsigned derived_size_ : 8; // size of the actual derived class unsigned fragment_ : 14; unsigned is_cacheable_ : 1; diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc index 97ffe553cd1..771392a0137 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc @@ -8,13 +8,15 @@ #include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h" #include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h" #include "third_party/blink/renderer/platform/testing/test_paint_artifact.h" namespace blink { using ::testing::UnorderedElementsAre; -class DisplayItemRasterInvalidatorTest : public PaintControllerTestBase { +class DisplayItemRasterInvalidatorTest : public PaintControllerTestBase, + public PaintTestConfigurations { protected: DisplayItemRasterInvalidatorTest() : invalidator_([](const IntRect&) {}) {} @@ -26,6 +28,10 @@ class DisplayItemRasterInvalidatorTest : public PaintControllerTestBase { // invalidation rects. IntRect(0, 0, 20000, 20000), PropertyTreeState::Root()); GetPaintController().FinishCycle(); + if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { + GetPaintController().ClearPropertyTreeChangedStateTo( + PropertyTreeState::Root()); + } if (invalidator_.GetTracking()) return invalidator_.GetTracking()->Invalidations(); @@ -37,7 +43,9 @@ class DisplayItemRasterInvalidatorTest : public PaintControllerTestBase { RasterInvalidator invalidator_; }; -TEST_F(DisplayItemRasterInvalidatorTest, RemoveItemInMiddle) { +INSTANTIATE_PAINT_TEST_CASE_P(DisplayItemRasterInvalidatorTest); + +TEST_P(DisplayItemRasterInvalidatorTest, RemoveItemInMiddle) { FakeDisplayItemClient first("first", LayoutRect(100, 100, 300, 300)); FakeDisplayItemClient second("second", LayoutRect(100, 100, 200, 200)); GraphicsContext context(GetPaintController()); @@ -60,7 +68,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, RemoveItemInMiddle) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, SwapOrder) { +TEST_P(DisplayItemRasterInvalidatorTest, SwapOrder) { FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100)); FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200)); FakeDisplayItemClient unaffected("unaffected", LayoutRect(300, 300, 10, 10)); @@ -91,7 +99,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrder) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateFirst) { +TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateFirst) { FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100)); FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200)); FakeDisplayItemClient unaffected("unaffected", LayoutRect(300, 300, 10, 10)); @@ -117,7 +125,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateFirst) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateSecond) { +TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateSecond) { FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100)); FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200)); FakeDisplayItemClient unaffected("unaffected", LayoutRect(300, 300, 10, 10)); @@ -143,7 +151,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderAndInvalidateSecond) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithIncrementalInvalidation) { +TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderWithIncrementalInvalidation) { FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100)); FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200)); FakeDisplayItemClient unaffected("unaffected", LayoutRect(300, 300, 10, 10)); @@ -171,7 +179,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithIncrementalInvalidation) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, NewItemInMiddle) { +TEST_P(DisplayItemRasterInvalidatorTest, NewItemInMiddle) { FakeDisplayItemClient first("first", LayoutRect(100, 100, 100, 100)); FakeDisplayItemClient second("second", LayoutRect(100, 100, 50, 200)); FakeDisplayItemClient third("third", LayoutRect(125, 100, 200, 50)); @@ -195,7 +203,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, NewItemInMiddle) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, Incremental) { +TEST_P(DisplayItemRasterInvalidatorTest, Incremental) { LayoutRect initial_rect(100, 100, 100, 100); std::unique_ptr<FakeDisplayItemClient> clients[6]; for (size_t i = 0; i < base::size(clients); i++) { @@ -259,7 +267,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, Incremental) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, AddRemoveFirstAndInvalidateSecond) { +TEST_P(DisplayItemRasterInvalidatorTest, AddRemoveFirstAndInvalidateSecond) { FakeDisplayItemClient chunk("chunk"); FakeDisplayItemClient first("first", LayoutRect(100, 100, 150, 150)); FakeDisplayItemClient second("second", LayoutRect(200, 200, 50, 50)); @@ -304,7 +312,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, AddRemoveFirstAndInvalidateSecond) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, InvalidateFirstAndAddRemoveSecond) { +TEST_P(DisplayItemRasterInvalidatorTest, InvalidateFirstAndAddRemoveSecond) { FakeDisplayItemClient first("first", LayoutRect(100, 100, 150, 150)); FakeDisplayItemClient second("second", LayoutRect(200, 200, 50, 50)); GraphicsContext context(GetPaintController()); @@ -351,7 +359,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, InvalidateFirstAndAddRemoveSecond) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithChildren) { +TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderWithChildren) { FakeDisplayItemClient container1("container1", LayoutRect(100, 100, 100, 100)); FakeDisplayItemClient content1("content1", LayoutRect(100, 100, 50, 200)); @@ -395,7 +403,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithChildren) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithChildrenAndInvalidation) { +TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderWithChildrenAndInvalidation) { FakeDisplayItemClient container1("container1", LayoutRect(100, 100, 100, 100)); FakeDisplayItemClient content1("content1", LayoutRect(100, 100, 50, 200)); @@ -443,7 +451,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderWithChildrenAndInvalidation) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderCrossingChunks) { +TEST_P(DisplayItemRasterInvalidatorTest, SwapOrderCrossingChunks) { FakeDisplayItemClient container1("container1", LayoutRect(100, 100, 100, 100)); FakeDisplayItemClient content1("content1", LayoutRect(100, 100, 50, 200)); @@ -492,7 +500,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SwapOrderCrossingChunks) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, SkipCache) { +TEST_P(DisplayItemRasterInvalidatorTest, SkipCache) { FakeDisplayItemClient multicol("multicol", LayoutRect(100, 100, 200, 200)); FakeDisplayItemClient content("content", LayoutRect(100, 100, 100, 100)); GraphicsContext context(GetPaintController()); @@ -549,7 +557,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, SkipCache) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, PartialSkipCache) { +TEST_P(DisplayItemRasterInvalidatorTest, PartialSkipCache) { FakeDisplayItemClient content("content", LayoutRect(100, 100, 250, 250)); GraphicsContext context(GetPaintController()); @@ -581,7 +589,7 @@ TEST_F(DisplayItemRasterInvalidatorTest, PartialSkipCache) { invalidator_.SetTracksRasterInvalidations(false); } -TEST_F(DisplayItemRasterInvalidatorTest, Partial) { +TEST_P(DisplayItemRasterInvalidatorTest, Partial) { FakeDisplayItemClient client("client", LayoutRect(100, 100, 300, 300)); GraphicsContext context(GetPaintController()); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc index a9bf22f86f7..750ac8d93eb 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc @@ -13,28 +13,6 @@ namespace blink { -void DrawingDisplayItem::Replay(GraphicsContext& context) const { - if (record_) - context.DrawRecord(record_); -} - -void DrawingDisplayItem::AppendToDisplayItemList( - const FloatSize& visual_rect_offset, - cc::DisplayItemList& list) const { - if (record_) { - list.StartPaint(); - list.push<cc::DrawRecordOp>(record_); - // Convert visual rect into the GraphicsLayer's coordinate space. - auto visual_rect = VisualRect(); - visual_rect.Move(-visual_rect_offset); - list.EndPaintOfUnpaired(EnclosingIntRect(visual_rect)); - } -} - -bool DrawingDisplayItem::DrawsContent() const { - return record_.get(); -} - #if DCHECK_IS_ON() void DrawingDisplayItem::PropertiesAsJSON(JSONObject& json) const { DisplayItem::PropertiesAsJSON(json); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h index dd79922e214..9f3c691c5ff 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h @@ -33,15 +33,10 @@ class PLATFORM_EXPORT DrawingDisplayItem final : public DisplayItem { sk_sp<const PaintRecord> record, bool known_to_be_opaque = false); - void Replay(GraphicsContext&) const final; - void AppendToDisplayItemList(const FloatSize& visual_rect_offset, - cc::DisplayItemList&) const final; - bool DrawsContent() const final; - const sk_sp<const PaintRecord>& GetPaintRecord() const { return record_; } bool KnownToBeOpaque() const { - DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); return known_to_be_opaque_; } @@ -54,7 +49,7 @@ class PLATFORM_EXPORT DrawingDisplayItem final : public DisplayItem { sk_sp<const PaintRecord> record_; - // True if there are no transparent areas. Only used for SlimmingPaintV2. + // True if there are no transparent areas. Only used for CompositeAfterPaint. const bool known_to_be_opaque_; }; @@ -64,8 +59,11 @@ inline DrawingDisplayItem::DrawingDisplayItem(const DisplayItemClient& client, Type type, sk_sp<const PaintRecord> record, bool known_to_be_opaque) - : DisplayItem(client, type, sizeof(*this)), - record_(record && record->size() ? std::move(record) : nullptr), + : DisplayItem(client, + type, + sizeof(*this), + /* draws_content*/ record && record->size()), + record_(DrawsContent() ? std::move(record) : nullptr), known_to_be_opaque_(known_to_be_opaque) { DCHECK(IsDrawingType(type)); } diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc index 36d2fab5b7c..bde9029d80d 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item_test.cc @@ -45,7 +45,7 @@ static sk_sp<PaintRecord> CreateRectRecordWithTranslate( return recorder.finishRecordingAsPicture(); } -TEST_F(DrawingDisplayItemTest, VisualRectAndDrawingBounds) { +TEST_F(DrawingDisplayItemTest, DrawsContent) { FloatRect record_bounds(5.5, 6.6, 7.7, 8.8); LayoutRect drawing_bounds(record_bounds); client_.SetVisualRect(drawing_bounds); @@ -53,18 +53,19 @@ TEST_F(DrawingDisplayItemTest, VisualRectAndDrawingBounds) { DrawingDisplayItem item(client_, DisplayItem::Type::kDocumentBackground, CreateRectRecord(record_bounds)); EXPECT_EQ(FloatRect(drawing_bounds), item.VisualRect()); + EXPECT_TRUE(item.DrawsContent()); +} - auto list1 = base::MakeRefCounted<cc::DisplayItemList>(); - item.AppendToDisplayItemList(FloatSize(), *list1); - EXPECT_EQ(EnclosingIntRect(drawing_bounds), list1->VisualRectForTesting(0)); - - FloatSize offset(2.1, 3.6); - auto list2 = base::MakeRefCounted<cc::DisplayItemList>(); - item.AppendToDisplayItemList(offset, *list2); - FloatRect visual_rect_with_offset(drawing_bounds); - visual_rect_with_offset.Move(-offset); - EXPECT_EQ(EnclosingIntRect(visual_rect_with_offset), - list2->VisualRectForTesting(0)); +TEST_F(DrawingDisplayItemTest, NullPaintRecord) { + DrawingDisplayItem item(client_, DisplayItem::Type::kDocumentBackground, + nullptr); + EXPECT_FALSE(item.DrawsContent()); +} + +TEST_F(DrawingDisplayItemTest, EmptyPaintRecord) { + DrawingDisplayItem item(client_, DisplayItem::Type::kDocumentBackground, + sk_make_sp<PaintRecord>()); + EXPECT_FALSE(item.DrawsContent()); } TEST_F(DrawingDisplayItemTest, Equals) { diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h index e51a61abb9f..260e452548f 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h @@ -51,7 +51,7 @@ class PLATFORM_EXPORT DrawingRecorder final { ~DrawingRecorder(); void SetKnownToBeOpaque() { - DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); known_to_be_opaque_ = true; } @@ -60,7 +60,7 @@ class PLATFORM_EXPORT DrawingRecorder final { const DisplayItemClient& client_; const DisplayItem::Type type_; - // True if there are no transparent areas. Only used for SlimmingPaintV2. + // True if there are no transparent areas. Only used for CompositeAfterPaint. bool known_to_be_opaque_; #if DCHECK_IS_ON() diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h b/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h index 09473c1ccdc..636a087901e 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h @@ -44,6 +44,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode CompositorFilterOperations filter; float opacity = 1; CompositorFilterOperations backdrop_filter; + gfx::RectF backdrop_filter_bounds; SkBlendMode blend_mode = SkBlendMode::kSrcOver; // === End of effects === CompositingReasons direct_compositing_reasons = CompositingReason::kNone; @@ -56,6 +57,7 @@ class PLATFORM_EXPORT EffectPaintPropertyNode output_clip == o.output_clip && color_filter == o.color_filter && filter == o.filter && opacity == o.opacity && backdrop_filter == o.backdrop_filter && + backdrop_filter_bounds == o.backdrop_filter_bounds && blend_mode == o.blend_mode && direct_compositing_reasons == o.direct_compositing_reasons && compositor_element_id == o.compositor_element_id && @@ -130,6 +132,10 @@ class PLATFORM_EXPORT EffectPaintPropertyNode return state_.backdrop_filter; } + const gfx::RectF& BackdropFilterBounds() const { + return state_.backdrop_filter_bounds; + } + bool HasFilterThatMovesPixels() const { DCHECK(!Parent() || !IsParentAlias()); return state_.filter.HasFilterThatMovesPixels(); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc index 810f41d8b6c..5e57ee51738 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc @@ -18,7 +18,9 @@ namespace { class ForeignLayerDisplayItemClient final : public DisplayItemClient { public: ForeignLayerDisplayItemClient(scoped_refptr<cc::Layer> layer) - : layer_(std::move(layer)) {} + : layer_(std::move(layer)) { + Invalidate(PaintInvalidationReason::kUncacheable); + } String DebugName() const final { return "ForeignLayer"; } @@ -41,10 +43,11 @@ ForeignLayerDisplayItem::ForeignLayerDisplayItem(Type type, : DisplayItem(*new ForeignLayerDisplayItemClient(std::move(layer)), type, sizeof(*this)) { - DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled() || + DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() || RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()); DCHECK(IsForeignLayerType(type)); DCHECK(GetLayer()); + DCHECK(!IsCacheable()); } ForeignLayerDisplayItem::~ForeignLayerDisplayItem() { @@ -55,22 +58,8 @@ cc::Layer* ForeignLayerDisplayItem::GetLayer() const { return static_cast<const ForeignLayerDisplayItemClient&>(Client()).GetLayer(); } -void ForeignLayerDisplayItem::Replay(GraphicsContext&) const { - NOTREACHED(); -} - -void ForeignLayerDisplayItem::AppendToDisplayItemList( - const FloatSize&, - cc::DisplayItemList&) const { - NOTREACHED(); -} - -bool ForeignLayerDisplayItem::DrawsContent() const { - return false; -} - bool ForeignLayerDisplayItem::Equals(const DisplayItem& other) const { - return DisplayItem::Equals(other) && + return GetType() == other.GetType() && GetLayer() == static_cast<const ForeignLayerDisplayItem&>(other).GetLayer(); } @@ -84,13 +73,26 @@ void ForeignLayerDisplayItem::PropertiesAsJSON(JSONObject& json) const { void RecordForeignLayer(GraphicsContext& context, DisplayItem::Type type, - scoped_refptr<cc::Layer> layer) { + scoped_refptr<cc::Layer> layer, + const base::Optional<PropertyTreeState>& properties) { PaintController& paint_controller = context.GetPaintController(); if (paint_controller.DisplayItemConstructionIsDisabled()) return; + // This is like ScopedPaintChunkProperties but uses null id because foreign + // layer chunk doesn't need an id nor a client. + base::Optional<PropertyTreeState> previous_properties; + if (properties) { + previous_properties.emplace(paint_controller.CurrentPaintChunkProperties()); + paint_controller.UpdateCurrentPaintChunkProperties(base::nullopt, + *properties); + } paint_controller.CreateAndAppend<ForeignLayerDisplayItem>(type, std::move(layer)); + if (properties) { + paint_controller.UpdateCurrentPaintChunkProperties(base::nullopt, + *previous_properties); + } } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h index 6b42d096d78..19765ba0ce6 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h @@ -7,6 +7,7 @@ #include "cc/layers/layer.h" #include "third_party/blink/renderer/platform/graphics/paint/display_item.h" +#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h" #include "third_party/blink/renderer/platform/platform_export.h" namespace blink { @@ -17,7 +18,7 @@ class GraphicsContext; // A client supplies a layer which can be unwrapped and inserted into the full // layer tree. // -// Before SPv2, this content is not painted, but is instead inserted into the +// Before CAP, this content is not painted, but is instead inserted into the // GraphicsLayer tree. class PLATFORM_EXPORT ForeignLayerDisplayItem final : public DisplayItem { public: @@ -27,10 +28,6 @@ class PLATFORM_EXPORT ForeignLayerDisplayItem final : public DisplayItem { cc::Layer* GetLayer() const; // DisplayItem - void Replay(GraphicsContext&) const override; - void AppendToDisplayItemList(const FloatSize&, - cc::DisplayItemList&) const override; - bool DrawsContent() const override; bool Equals(const DisplayItem&) const override; #if DCHECK_IS_ON() void PropertiesAsJSON(JSONObject&) const override; @@ -39,9 +36,11 @@ class PLATFORM_EXPORT ForeignLayerDisplayItem final : public DisplayItem { // Records a foreign layer into a GraphicsContext. // Use this where you would use a recorder class. -PLATFORM_EXPORT void RecordForeignLayer(GraphicsContext&, - DisplayItem::Type, - scoped_refptr<cc::Layer>); +PLATFORM_EXPORT void RecordForeignLayer( + GraphicsContext&, + DisplayItem::Type, + scoped_refptr<cc::Layer>, + const base::Optional<PropertyTreeState>& = base::nullopt); } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc index 24bae6a33f5..914e5dbd380 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc @@ -233,10 +233,10 @@ bool GeometryMapper::LocalToAncestorVisualRectInternal( return !rect_to_map.Rect().IsEmpty(); } - if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { // On SPv1 we may fail when the paint invalidation container creates an // overflow clip (in ancestor_state) which is not in localState of an - // out-of-flow positioned descendant. See crbug.com/513108 and layout test + // out-of-flow positioned descendant. See crbug.com/513108 and web test // compositing/overflow/handle-non-ancestor-clip-parent.html (run with // --enable-prefer-compositing-to-lcd-text) for details. // Ignore it for SPv1 for now. @@ -366,7 +366,7 @@ FloatClipRect GeometryMapper::LocalToAncestorClipRectInternal( } if (!clip_node) { success = false; - if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { // On SPv1 we may fail when the paint invalidation container creates an // overflow clip (in ancestor_state) which is not in localState of an // out-of-flow positioned descendant. See crbug.com/513108 and layout diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc index 4803e356871..4111f356e8a 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_test.cc @@ -656,7 +656,7 @@ TEST_P(GeometryMapperTest, SiblingTransformsWithClip) { // Fails, because the clip of the destination state is not an ancestor of the // clip of the source state. A known bug in SPv1 would make such query, // in such case, no clips are applied. - if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { EXPECT_FALSE(success); } else { EXPECT_TRUE(success); @@ -789,8 +789,8 @@ TEST_P(GeometryMapperTest, ReflectionWithPaintOffset) { } TEST_P(GeometryMapperTest, InvertedClip) { - // This test is invalid for SPv2. - if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) + // This test is invalid for CAP. + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) return; auto clip = CreateClip(c0(), &t0(), FloatRoundedRect(10, 10, 50, 50)); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h index 51af360bd8f..9fbce5ff645 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h @@ -11,6 +11,8 @@ namespace blink { +class GraphicsContext; + // A special DisplayItem containing hit test data. class PLATFORM_EXPORT HitTestDisplayItem final : public DisplayItem { public: diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc index f4d24ceb026..450676174ee 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc @@ -30,7 +30,8 @@ void ComputeChunkDerivedData(const DisplayItemList& display_items, chunk.outset_for_raster_effects = std::max(chunk.outset_for_raster_effects, item.OutsetForRasterEffects()); - if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && item.IsDrawing()) { + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && + item.IsDrawing()) { const auto& drawing = static_cast<const DrawingDisplayItem&>(item); if (drawing.GetPaintRecord() && drawing.KnownToBeOpaque()) { known_to_be_opaque_region.op( @@ -100,7 +101,7 @@ void PaintArtifact::AppendDebugDrawing( const PropertyTreeState& property_tree_state) { DEFINE_STATIC_LOCAL(DebugDrawingClient, debug_drawing_client, ()); - DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); auto& display_item = display_item_list_.AllocateAndConstruct<DrawingDisplayItem>( debug_drawing_client, DisplayItem::kDebugDrawing, std::move(record)); @@ -121,20 +122,17 @@ void PaintArtifact::Replay(cc::PaintCanvas& canvas, const PropertyTreeState& replay_state, const IntPoint& offset) const { TRACE_EVENT0("blink,benchmark", "PaintArtifact::replay"); - scoped_refptr<cc::DisplayItemList> display_item_list = - PaintChunksToCcLayer::Convert( - PaintChunks(), replay_state, gfx::Vector2dF(offset.X(), offset.Y()), - GetDisplayItemList(), - cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer); - canvas.drawPicture(display_item_list->ReleaseAsRecord()); + canvas.drawPicture(GetPaintRecord(replay_state, offset)); } -DISABLE_CFI_PERF -void PaintArtifact::AppendToDisplayItemList(const FloatSize& visual_rect_offset, - cc::DisplayItemList& list) const { - TRACE_EVENT0("blink,benchmark", "PaintArtifact::AppendToDisplayItemList"); - for (const DisplayItem& item : display_item_list_) - item.AppendToDisplayItemList(visual_rect_offset, list); +sk_sp<PaintRecord> PaintArtifact::GetPaintRecord( + const PropertyTreeState& replay_state, + const IntPoint& offset) const { + return PaintChunksToCcLayer::Convert( + PaintChunks(), replay_state, + gfx::Vector2dF(offset.X(), offset.Y()), GetDisplayItemList(), + cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) + ->ReleaseAsRecord(); } void PaintArtifact::FinishCycle() { @@ -142,7 +140,8 @@ void PaintArtifact::FinishCycle() { // for clearing the property tree changed state at the end of paint instead of // in FinishCycle. See: LocalFrameView::RunPaintLifecyclePhase. bool clear_property_tree_changed = - !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled(); + !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() || + RuntimeEnabledFeatures::CompositeAfterPaintEnabled(); for (auto& chunk : chunks_) { chunk.client_is_just_created = false; if (clear_property_tree_changed) diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h index a4fe34d21c8..8420222bab6 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h @@ -81,9 +81,8 @@ class PLATFORM_EXPORT PaintArtifact final : public RefCounted<PaintArtifact> { const PropertyTreeState& replay_state, const IntPoint& offset = IntPoint()) const; - // Writes the paint artifact into a cc::DisplayItemList. - void AppendToDisplayItemList(const FloatSize& visual_rect_offset, - cc::DisplayItemList& display_list) const; + sk_sp<PaintRecord> GetPaintRecord(const PropertyTreeState& replay_state, + const IntPoint& offset = IntPoint()) const; // Called when the caller finishes updating a full document life cycle. // Will cleanup data (e.g. raster invalidations) that will no longer be used diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h index 4c8bb2876bc..e60c767797e 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunk.h @@ -37,7 +37,14 @@ struct PLATFORM_EXPORT PaintChunk { id(id), properties(props), is_cacheable(id.client.IsCacheable()), - client_is_just_created(id.client.IsJustCreated()) {} + client_is_just_created(id.client.IsJustCreated()) { + // PaintChunk properties should not be null. If these checks are hit, + // we may be missing a call to ScopedPaintChunkProperties, see comment in + // PaintChunker::IncrementDisplayItemIndex for more information. + CHECK(props.Transform()); + CHECK(props.Clip()); + CHECK(props.Effect()); + } size_t size() const { DCHECK_GE(end_index, begin_index); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc index a96ab6fc5fa..b1c253ed477 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_chunker_test.cc @@ -33,12 +33,6 @@ class TestChunkerDisplayItem : public DisplayItem { TestChunkerDisplayItem(const DisplayItemClient& client, DisplayItem::Type type = DisplayItem::kDrawingFirst) : DisplayItem(client, type, sizeof(*this)) {} - - void Replay(GraphicsContext&) const final { NOTREACHED(); } - void AppendToDisplayItemList(const FloatSize&, - cc::DisplayItemList&) const final { - NOTREACHED(); - } }; class TestDisplayItemRequiringSeparateChunk : public TestChunkerDisplayItem { diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc index 8af002eccdf..dc1799edeef 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc @@ -258,12 +258,12 @@ DisplayItem& PaintController::MoveItemFromCurrentListToNewList(size_t index) { } void PaintController::InvalidateAll() { - DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); InvalidateAllInternal(); } void PaintController::InvalidateAllInternal() { - // TODO(wangxianzhu): Rename this to InvalidateAllForTesting() for SPv2. + // TODO(wangxianzhu): Rename this to InvalidateAllForTesting() for CAP. // Can only be called during layout/paintInvalidation, not during painting. DCHECK(new_display_item_list_.IsEmpty()); current_paint_artifact_ = PaintArtifact::Empty(); @@ -272,7 +272,7 @@ void PaintController::InvalidateAllInternal() { } bool PaintController::CacheIsAllInvalid() const { - DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); DCHECK(!cache_is_all_invalid_ || current_paint_artifact_->IsEmpty()); return cache_is_all_invalid_; } @@ -588,7 +588,7 @@ size_t PaintController::ApproximateUnsharedMemoryUsage() const { void PaintController::AppendDebugDrawingAfterCommit( sk_sp<const PaintRecord> record, const PropertyTreeState& property_tree_state) { - DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); DCHECK(new_display_item_list_.IsEmpty()); current_paint_artifact_->AppendDebugDrawing(record, property_tree_state); } @@ -718,6 +718,9 @@ void PaintController::CheckDuplicatePaintChunkId(const PaintChunk::Id& id) { if (IsSkippingCache()) return; + if (DisplayItem::IsForeignLayerType(id.type)) + return; + auto it = new_paint_chunk_indices_by_client_.find(&id.client); if (it != new_paint_chunk_indices_by_client_.end()) { const auto& indices = it->value; diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc index ad521693437..79d6e952277 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_controller_test.cc @@ -35,10 +35,10 @@ INSTANTIATE_TEST_CASE_P( PaintControllerTest, testing::Values(0, kBlinkGenPropertyTrees, - kSlimmingPaintV2, + kCompositeAfterPaint, kUnderInvalidationChecking, kBlinkGenPropertyTrees | kUnderInvalidationChecking, - kSlimmingPaintV2 | kUnderInvalidationChecking)); + kCompositeAfterPaint | kUnderInvalidationChecking)); TEST_P(PaintControllerTest, NestedRecorders) { GraphicsContext context(GetPaintController()); @@ -1453,7 +1453,7 @@ TEST_P(PaintControllerTest, BeginAndEndFrame) { } TEST_P(PaintControllerTest, InvalidateAll) { - if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) return; EXPECT_TRUE(GetPaintController().CacheIsAllInvalid()); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h index 46899a783e8..06ec28e1666 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h @@ -12,7 +12,7 @@ #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #if DCHECK_IS_ON() -#include "third_party/blink/renderer/platform/wtf/list_hash_set.h" +#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #endif @@ -208,7 +208,7 @@ class PropertyTreePrinter { return node; } - ListHashSet<const NodeType*> nodes_; + LinkedHashSet<const NodeType*> nodes_; }; template <typename NodeType> diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc index 239f61dc8c5..2787d1ac80b 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.cc @@ -48,11 +48,9 @@ PaintRecordBuilder::~PaintRecordBuilder() = default; sk_sp<PaintRecord> PaintRecordBuilder::EndRecording( const PropertyTreeState& replay_state) { - context_->BeginRecording(FloatRect()); paint_controller_->CommitNewDisplayItems(); paint_controller_->FinishCycle(); - paint_controller_->GetPaintArtifact().Replay(*context_, replay_state); - return context_->EndRecording(); + return paint_controller_->GetPaintArtifact().GetPaintRecord(replay_state); } void PaintRecordBuilder::EndRecording(cc::PaintCanvas& canvas, diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h index 2ddaae4f2f8..22c55278198 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h @@ -37,6 +37,8 @@ class PLATFORM_EXPORT PaintRecordBuilder final : public DisplayItemClient { // transient PaintController is used for the duration of the picture building, // which therefore has no caching. It also resets paint chunk state to // PropertyTreeState::Root() before beginning to record. + // TODO(wangxianzhu): Remove the input PaintController feature for + // CompositeAfterPaint. PaintRecordBuilder(SkMetaData* metadata = nullptr, GraphicsContext* containing_context = nullptr, PaintController* = nullptr); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h index 1ba66b364d8..a80539f573f 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h @@ -31,7 +31,7 @@ struct RasterInvalidationInfo { // died. const DisplayItemClient* client = nullptr; String client_debug_name; - // For SPv2, this is set in PaintArtifactCompositor when converting chunk + // For CAP, this is set in PaintArtifactCompositor when converting chunk // raster invalidations to cc raster invalidations. IntRect rect; PaintInvalidationReason reason = PaintInvalidationReason::kFull; diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc index e33be29d177..b985689d0fe 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc @@ -160,6 +160,10 @@ void RasterInvalidator::GenerateRasterInvalidations( mapper.SwitchToChunk(new_chunk); auto& new_chunk_info = new_chunks_info.emplace_back(*this, mapper, it); + // Foreign layers take care of raster invalidation by themselves. + if (DisplayItem::IsForeignLayerType(new_chunk.id.type)) + continue; + if (!new_chunk.is_cacheable) { AddRasterInvalidation(new_chunk_info.bounds_in_layer, new_chunk.id.client, PaintInvalidationReason::kChunkUncacheable, diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc index 13cbaaab2ea..6a7e25139ad 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/raster_invalidator_test.cc @@ -8,13 +8,15 @@ #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h" #include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h" #include "third_party/blink/renderer/platform/testing/test_paint_artifact.h" namespace blink { static const IntRect kDefaultLayerBounds(-9999, -7777, 18888, 16666); -class RasterInvalidatorTest : public testing::Test { +class RasterInvalidatorTest : public testing::Test, + public PaintTestConfigurations { public: static PropertyTreeState DefaultPropertyTreeState() { return PropertyTreeState::Root(); @@ -31,6 +33,11 @@ class RasterInvalidatorTest : public testing::Test { void FinishCycle(PaintArtifact& artifact) { artifact.FinishCycle(); ClearGeometryMapperCache(); + if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { + // See PaintArtifact::FinishCycle() for the reason of doing this. + for (auto& chunk : artifact.PaintChunks()) + chunk.properties.ClearChangedToRoot(); + } } static const Vector<RasterInvalidationInfo> TrackedRasterInvalidations( @@ -54,6 +61,8 @@ class RasterInvalidatorTest : public testing::Test { [](const IntRect& rect) {}; }; +INSTANTIATE_PAINT_TEST_CASE_P(RasterInvalidatorTest); + #define EXPECT_CHUNK_INVALIDATION_CUSTOM( \ invalidations, index, chunk, expected_reason, layer_offset, mapper) \ do { \ @@ -78,7 +87,7 @@ class RasterInvalidatorTest : public testing::Test { EXPECT_EQ(PaintInvalidationReason::kIncremental, info.reason); \ } while (false) -TEST_F(RasterInvalidatorTest, ImplicitFullLayerInvalidation) { +TEST_P(RasterInvalidatorTest, ImplicitFullLayerInvalidation) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto artifact = TestPaintArtifact().Chunk(0).Build(); @@ -94,7 +103,7 @@ TEST_F(RasterInvalidatorTest, ImplicitFullLayerInvalidation) { invalidator.SetTracksRasterInvalidations(false); } -TEST_F(RasterInvalidatorTest, LayerBounds) { +TEST_P(RasterInvalidatorTest, LayerBounds) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto artifact = TestPaintArtifact().Chunk(0).Build(); @@ -122,7 +131,7 @@ TEST_F(RasterInvalidatorTest, LayerBounds) { FinishCycle(*artifact); } -TEST_F(RasterInvalidatorTest, ReorderChunks) { +TEST_P(RasterInvalidatorTest, ReorderChunks) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto artifact = TestPaintArtifact().Chunk(0).Chunk(1).Chunk(2).Build(); invalidator.Generate(artifact, kDefaultLayerBounds, @@ -150,7 +159,7 @@ TEST_F(RasterInvalidatorTest, ReorderChunks) { FinishCycle(*new_artifact); } -TEST_F(RasterInvalidatorTest, ReorderChunkSubsequences) { +TEST_P(RasterInvalidatorTest, ReorderChunkSubsequences) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto artifact = TestPaintArtifact().Chunk(0).Chunk(1).Chunk(2).Chunk(3).Chunk(4).Build(); @@ -185,7 +194,7 @@ TEST_F(RasterInvalidatorTest, ReorderChunkSubsequences) { FinishCycle(*new_artifact); } -TEST_F(RasterInvalidatorTest, ChunkAppearAndDisappear) { +TEST_P(RasterInvalidatorTest, ChunkAppearAndDisappear) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto artifact = TestPaintArtifact().Chunk(0).Chunk(1).Chunk(2).Build(); invalidator.Generate(artifact, kDefaultLayerBounds, @@ -210,7 +219,7 @@ TEST_F(RasterInvalidatorTest, ChunkAppearAndDisappear) { FinishCycle(*new_artifact); } -TEST_F(RasterInvalidatorTest, ChunkAppearAtEnd) { +TEST_P(RasterInvalidatorTest, ChunkAppearAtEnd) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto artifact = TestPaintArtifact().Chunk(0).Build(); invalidator.Generate(artifact, kDefaultLayerBounds, @@ -230,7 +239,7 @@ TEST_F(RasterInvalidatorTest, ChunkAppearAtEnd) { FinishCycle(*new_artifact); } -TEST_F(RasterInvalidatorTest, UncacheableChunks) { +TEST_P(RasterInvalidatorTest, UncacheableChunks) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto artifact = TestPaintArtifact().Chunk(0).Chunk(1).Uncacheable().Chunk(2).Build(); @@ -254,7 +263,7 @@ TEST_F(RasterInvalidatorTest, UncacheableChunks) { } // Tests the path based on ClipPaintPropertyNode::Changed(). -TEST_F(RasterInvalidatorTest, ClipPropertyChangeRounded) { +TEST_P(RasterInvalidatorTest, ClipPropertyChangeRounded) { RasterInvalidator invalidator(kNoopRasterInvalidation); FloatRoundedRect::Radii radii(FloatSize(1, 2), FloatSize(2, 3), FloatSize(3, 4), FloatSize(4, 5)); @@ -316,7 +325,7 @@ TEST_F(RasterInvalidatorTest, ClipPropertyChangeRounded) { } // Tests the path detecting change of PaintChunkInfo::chunk_to_layer_clip. -TEST_F(RasterInvalidatorTest, ClipPropertyChangeSimple) { +TEST_P(RasterInvalidatorTest, ClipPropertyChangeSimple) { RasterInvalidator invalidator(kNoopRasterInvalidation); FloatRoundedRect clip_rect(-1000, -1000, 2000, 2000); auto clip0 = CreateClip(c0(), &t0(), clip_rect); @@ -385,7 +394,7 @@ TEST_F(RasterInvalidatorTest, ClipPropertyChangeSimple) { FinishCycle(*artifact); } -TEST_F(RasterInvalidatorTest, ClipLocalTransformSpaceChange) { +TEST_P(RasterInvalidatorTest, ClipLocalTransformSpaceChange) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto t1 = CreateTransform(t0(), TransformationMatrix()); @@ -422,7 +431,7 @@ TEST_F(RasterInvalidatorTest, ClipLocalTransformSpaceChange) { // This is based on ClipLocalTransformSpaceChange, but tests the no-invalidation // path by letting the clip's LocalTransformSpace be the same as the chunk's // transform. -TEST_F(RasterInvalidatorTest, ClipLocalTransformSpaceChangeNoInvalidation) { +TEST_P(RasterInvalidatorTest, ClipLocalTransformSpaceChangeNoInvalidation) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto t1 = CreateTransform(t0(), TransformationMatrix()); @@ -453,7 +462,7 @@ TEST_F(RasterInvalidatorTest, ClipLocalTransformSpaceChangeNoInvalidation) { FinishCycle(*artifact); } -TEST_F(RasterInvalidatorTest, TransformPropertyChange) { +TEST_P(RasterInvalidatorTest, TransformPropertyChange) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto layer_transform = CreateTransform(t0(), TransformationMatrix().Scale(5)); @@ -534,7 +543,7 @@ TEST_F(RasterInvalidatorTest, TransformPropertyChange) { FinishCycle(*artifact); } -TEST_F(RasterInvalidatorTest, TransformPropertyTinyChange) { +TEST_P(RasterInvalidatorTest, TransformPropertyTinyChange) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto layer_transform = CreateTransform(t0(), TransformationMatrix().Scale(5)); @@ -580,7 +589,7 @@ TEST_F(RasterInvalidatorTest, TransformPropertyTinyChange) { EXPECT_TRUE(invalidated); } -TEST_F(RasterInvalidatorTest, TransformPropertyTinyChangeScale) { +TEST_P(RasterInvalidatorTest, TransformPropertyTinyChangeScale) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto layer_transform = CreateTransform(t0(), TransformationMatrix().Scale(5)); @@ -621,7 +630,7 @@ TEST_F(RasterInvalidatorTest, TransformPropertyTinyChangeScale) { FinishCycle(*artifact); } -TEST_F(RasterInvalidatorTest, EffectLocalTransformSpaceChange) { +TEST_P(RasterInvalidatorTest, EffectLocalTransformSpaceChange) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto t1 = CreateTransform(t0(), TransformationMatrix()); @@ -659,7 +668,7 @@ TEST_F(RasterInvalidatorTest, EffectLocalTransformSpaceChange) { // This is based on EffectLocalTransformSpaceChange, but tests the no- // invalidation path by letting the effect's LocalTransformSpace be the same as // the chunk's transform. -TEST_F(RasterInvalidatorTest, EffectLocalTransformSpaceChangeNoInvalidation) { +TEST_P(RasterInvalidatorTest, EffectLocalTransformSpaceChangeNoInvalidation) { RasterInvalidator invalidator(kNoopRasterInvalidation); auto t1 = CreateTransform(t0(), TransformationMatrix()); diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc index aa79d6d87d4..d5631ea7653 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.cc @@ -15,23 +15,13 @@ ScrollHitTestDisplayItem::ScrollHitTestDisplayItem( const TransformPaintPropertyNode& scroll_offset_node) : DisplayItem(client, kScrollHitTest, sizeof(*this)), scroll_offset_node_(scroll_offset_node) { - DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); // The scroll offset transform node should have an associated scroll node. DCHECK(scroll_offset_node_.ScrollNode()); } ScrollHitTestDisplayItem::~ScrollHitTestDisplayItem() = default; -void ScrollHitTestDisplayItem::Replay(GraphicsContext&) const { - NOTREACHED(); -} - -void ScrollHitTestDisplayItem::AppendToDisplayItemList( - const FloatSize&, - cc::DisplayItemList&) const { - NOTREACHED(); -} - bool ScrollHitTestDisplayItem::Equals(const DisplayItem& other) const { return DisplayItem::Equals(other) && &scroll_node() == diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h b/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h index 4642790e9f8..082b202de2a 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h +++ b/chromium/third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h @@ -34,9 +34,6 @@ class PLATFORM_EXPORT ScrollHitTestDisplayItem final : public DisplayItem { } // DisplayItem - void Replay(GraphicsContext&) const override; - void AppendToDisplayItemList(const FloatSize&, - cc::DisplayItemList&) const override; bool Equals(const DisplayItem&) const override; #if DCHECK_IS_ON() void PropertiesAsJSON(JSONObject&) const override; diff --git a/chromium/third_party/blink/renderer/platform/graphics/path.cc b/chromium/third_party/blink/renderer/platform/graphics/path.cc index cde993cb82c..f8c90391af9 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/path.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/path.cc @@ -353,13 +353,10 @@ void Path::AddEllipse(const FloatPoint& p, float radius_x, float radius_y, float start_angle, - float end_angle, - bool anticlockwise) { + float end_angle) { DCHECK(EllipseIsRenderable(start_angle, end_angle)); DCHECK_GE(start_angle, 0); DCHECK_LT(start_angle, kTwoPiFloat); - DCHECK((anticlockwise && (start_angle - end_angle) >= 0) || - (!anticlockwise && (end_angle - start_angle) >= 0)); SkScalar cx = WebCoreFloatToSkScalar(p.X()); SkScalar cy = WebCoreFloatToSkScalar(p.Y()); @@ -400,9 +397,8 @@ void Path::AddEllipse(const FloatPoint& p, void Path::AddArc(const FloatPoint& p, float radius, float start_angle, - float end_angle, - bool anticlockwise) { - AddEllipse(p, radius, radius, start_angle, end_angle, anticlockwise); + float end_angle) { + AddEllipse(p, radius, radius, start_angle, end_angle); } void Path::AddRect(const FloatRect& rect) { @@ -415,17 +411,14 @@ void Path::AddEllipse(const FloatPoint& p, float radius_y, float rotation, float start_angle, - float end_angle, - bool anticlockwise) { + float end_angle) { DCHECK(EllipseIsRenderable(start_angle, end_angle)); DCHECK_GE(start_angle, 0); DCHECK_LT(start_angle, kTwoPiFloat); - DCHECK((anticlockwise && (start_angle - end_angle) >= 0) || - (!anticlockwise && (end_angle - start_angle) >= 0)); if (!rotation) { AddEllipse(FloatPoint(p.X(), p.Y()), radius_x, radius_y, start_angle, - end_angle, anticlockwise); + end_angle); return; } @@ -435,8 +428,7 @@ void Path::AddEllipse(const FloatPoint& p, DCHECK(ellipse_transform.IsInvertible()); AffineTransform inverse_ellipse_transform = ellipse_transform.Inverse(); Transform(inverse_ellipse_transform); - AddEllipse(FloatPoint::Zero(), radius_x, radius_y, start_angle, end_angle, - anticlockwise); + AddEllipse(FloatPoint::Zero(), radius_x, radius_y, start_angle, end_angle); Transform(ellipse_transform); } diff --git a/chromium/third_party/blink/renderer/platform/graphics/path.h b/chromium/third_party/blink/renderer/platform/graphics/path.h index 395e02313a4..36f374597cc 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/path.h +++ b/chromium/third_party/blink/renderer/platform/graphics/path.h @@ -77,6 +77,7 @@ class PLATFORM_EXPORT Path { Path& operator=(const Path&); Path& operator=(const SkPath&); bool operator==(const Path&) const; + bool operator!=(const Path& other) const { return !(*this == other); } bool Contains(const FloatPoint&) const; bool Contains(const FloatPoint&, WindRule) const; @@ -144,16 +145,14 @@ class PLATFORM_EXPORT Path { void AddArc(const FloatPoint&, float radius, float start_angle, - float end_angle, - bool anticlockwise); + float end_angle); void AddRect(const FloatRect&); void AddEllipse(const FloatPoint&, float radius_x, float radius_y, float rotation, float start_angle, - float end_angle, - bool anticlockwise); + float end_angle); void AddEllipse(const FloatRect&); void AddRoundedRect(const FloatRect&, const FloatSize& rounding_radii); @@ -192,8 +191,7 @@ class PLATFORM_EXPORT Path { float radius_x, float radius_y, float start_angle, - float end_angle, - bool anticlockwise); + float end_angle); SkPath StrokePath(const StrokeData&) const; SkPath path_; diff --git a/chromium/third_party/blink/renderer/platform/graphics/pattern.cc b/chromium/third_party/blink/renderer/platform/graphics/pattern.cc index 45512c279b0..f38adf2831f 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/pattern.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/pattern.cc @@ -56,14 +56,10 @@ Pattern::Pattern(RepeatMode repeat_mode) : repeat_mode_(repeat_mode) {} Pattern::~Pattern() = default; void Pattern::ApplyToFlags(PaintFlags& flags, const SkMatrix& local_matrix) { - if (!cached_shader_ || IsLocalMatrixChanged(local_matrix)) + if (!cached_shader_ || local_matrix != cached_shader_->GetLocalMatrix()) cached_shader_ = CreateShader(local_matrix); flags.setShader(cached_shader_); } -bool Pattern::IsLocalMatrixChanged(const SkMatrix& local_matrix) const { - return local_matrix != cached_shader_->GetLocalMatrix(); -} - } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/pattern.h b/chromium/third_party/blink/renderer/platform/graphics/pattern.h index 821b360ebaa..2f4968c07e2 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/pattern.h +++ b/chromium/third_party/blink/renderer/platform/graphics/pattern.h @@ -71,7 +71,6 @@ class PLATFORM_EXPORT Pattern : public RefCounted<Pattern> { protected: virtual sk_sp<PaintShader> CreateShader(const SkMatrix&) = 0; - virtual bool IsLocalMatrixChanged(const SkMatrix&) const; RepeatMode repeat_mode_; diff --git a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc index 67831cef073..be09c5f451a 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/placeholder_image.cc @@ -6,6 +6,7 @@ #include <utility> +#include "base/stl_util.h" #include "third_party/blink/renderer/platform/fonts/font.h" #include "third_party/blink/renderer/platform/fonts/font_description.h" #include "third_party/blink/renderer/platform/fonts/font_family.h" @@ -126,7 +127,7 @@ String FormatOriginalResourceSizeBytes(int64_t bytes) { // Find the smallest unit that can represent |bytes| in 3 digits or less. // Round up to the next higher unit if possible when it would take 4 digits to // display the amount, e.g. 1000 KB will be rounded up to 1 MB. - for (; units < kUnitsNames + (arraysize(kUnitsNames) - 1) && + for (; units < kUnitsNames + (base::size(kUnitsNames) - 1) && bytes >= denomenator * 1000; ++units, denomenator *= 1024) { } diff --git a/chromium/third_party/blink/renderer/platform/graphics/platform_paint_worklet_input.h b/chromium/third_party/blink/renderer/platform/graphics/platform_paint_worklet_input.h deleted file mode 100644 index 7eb83bad38f..00000000000 --- a/chromium/third_party/blink/renderer/platform/graphics/platform_paint_worklet_input.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PLATFORM_PAINT_WORKLET_INPUT_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PLATFORM_PAINT_WORKLET_INPUT_H_ - -#include "cc/trees/layer_tree_painter.h" - -namespace blink { - -class PLATFORM_EXPORT PlatformPaintWorkletInput : public cc::PaintWorkletInput { - public: - PlatformPaintWorkletInput(const std::string& name, - const FloatSize& container_size, - float effective_zoom) - : name_(name), - container_size_(container_size), - effective_zoom_(effective_zoom) {} - - ~PlatformPaintWorkletInput() override = default; - - const std::string& Name() const { return name_; } - const FloatSize& ContainerSize() const { return container_size_; } - float EffectiveZoom() const { return effective_zoom_; } - - private: - std::string name_; - FloatSize container_size_; - float effective_zoom_; - // TODO(crbug.com/895579): add a cross thread style map. -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHIC_PLATFORM_PAINT_WORKLET_INPUT_H_ diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc index 38cd420db97..34559425faa 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc @@ -31,11 +31,11 @@ #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h" #include "build/build_config.h" +#include "third_party/blink/renderer/platform/geometry/layout_rect.h" #include "third_party/blink/renderer/platform/graphics/graphics_context.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h" #include "third_party/skia/include/effects/SkCornerPathEffect.h" #include "third_party/skia/third_party/skcms/skcms.h" -#include "ui/gfx/icc_profile.h" #include <algorithm> #include <cmath> @@ -319,29 +319,6 @@ SkColor ScaleAlpha(SkColor color, float alpha) { return SkColorSetA(color, rounded_alpha); } -gfx::ColorSpace SkColorSpaceToGfxColorSpace( - const sk_sp<SkColorSpace> color_space) { - if (!color_space) - return gfx::ColorSpace::CreateSRGB(); - - SkMatrix44 toXYZD50; - SkColorSpaceTransferFn transfer_fn; - if (color_space->toXYZD50(&toXYZD50) && - color_space->isNumericalTransferFn(&transfer_fn)) - return gfx::ColorSpace::CreateCustom(toXYZD50, transfer_fn); - - // Use an intermediate ICC profile to convert the color space data structure. - // If this fails, we fall back to sRGB. - sk_sp<SkData> sk_profile = color_space->serialize(); - if (sk_profile) { - gfx::ICCProfile icc_profile = - gfx::ICCProfile::FromData(sk_profile->data(), sk_profile->size()); - if (icc_profile.IsValid()) - return icc_profile.GetColorSpace(); - } - return gfx::ColorSpace::CreateSRGB(); -} - bool ApproximatelyEqualSkColorSpaces(sk_sp<SkColorSpace> src_color_space, sk_sp<SkColorSpace> dst_color_space) { if ((!src_color_space && dst_color_space) || @@ -355,6 +332,12 @@ bool ApproximatelyEqualSkColorSpaces(sk_sp<SkColorSpace> src_color_space, return skcms_ApproximatelyEqualProfiles(&src_profile, &dst_profile); } +SkRect LayoutRectToSkRect(const blink::LayoutRect& rect) { + return SkRect::MakeXYWH(SkFloatToScalar(rect.X()), SkFloatToScalar(rect.Y()), + SkFloatToScalar(rect.Width()), + SkFloatToScalar(rect.Height())); +} + template <typename PrimitiveType> void DrawFocusRingPrimitive(const PrimitiveType&, cc::PaintCanvas*, diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h index 9633ea90b44..7155983ee65 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h +++ b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils.h @@ -47,6 +47,7 @@ #include "third_party/skia/include/core/SkScalar.h" namespace blink { +class LayoutRect; /**** constants ****/ @@ -56,8 +57,8 @@ enum { // maximum dimensions, in exchange for a smaller maximum canvas size. kMaxCanvasArea = 32768 * 8192, // Maximum canvas area in CSS pixels - // In Skia, we will also limit width/height to 32767. - kMaxSkiaDim = 32767 // Maximum width/height in CSS pixels. + // In Skia, we will also limit width/height to 65535. + kMaxSkiaDim = 65535 // Maximum width/height in CSS pixels. }; bool PLATFORM_EXPORT IsValidImageSize(const IntSize&); @@ -73,14 +74,12 @@ BlendMode PLATFORM_EXPORT BlendModeFromSkBlendMode(SkBlendMode); // alpha is in the range [0, 1]. SkColor PLATFORM_EXPORT ScaleAlpha(SkColor, float); -// Convert a SkColorSpace to a gfx::ColorSpace -gfx::ColorSpace PLATFORM_EXPORT -SkColorSpaceToGfxColorSpace(const sk_sp<SkColorSpace>); - bool PLATFORM_EXPORT ApproximatelyEqualSkColorSpaces(sk_sp<SkColorSpace> src_color_space, sk_sp<SkColorSpace> dst_color_space); +SkRect PLATFORM_EXPORT LayoutRectToSkRect(const blink::LayoutRect& rect); + // Skia has problems when passed infinite, etc floats, filter them to 0. inline SkScalar WebCoreFloatToSkScalar(float f) { return SkFloatToScalar(std::isfinite(f) ? f : 0); @@ -126,13 +125,18 @@ InterpolationQuality ComputeInterpolationQuality(float src_width, float dest_height, bool is_data_complete = true); -// This replicates the old skia behavior when it used to take radius for blur. -// Now it takes sigma. -inline SkScalar SkBlurRadiusToSigma(SkScalar radius) { - SkASSERT(radius >= 0); - if (radius == 0) - return 0.0f; - return 0.288675f * radius + 0.5f; +// Technically, this is driven by the CSS/Canvas2D specs and unrelated to Skia. +// It should probably live in the CSS layer, but the notion of a "blur radius" +// leaks into platform/graphics currently (ideally we should only deal with +// sigma at this level). +// TODO(fmalita): find a better home for this helper. +inline float BlurRadiusToStdDev(float radius) { + DCHECK_GE(radius, 0); + + // Per spec, sigma is exactly half the blur radius: + // https://www.w3.org/TR/css-backgrounds-3/#shadow-blur + // https://html.spec.whatwg.org/multipage/canvas.html#when-shadows-are-drawn + return radius * 0.5f; } template <typename PrimitiveType> diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc b/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc deleted file mode 100644 index 7de98907099..00000000000 --- a/chromium/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace blink { - -class SkiaUtilsTest : public testing::Test {}; - -// Tests converting a SkColorSpace to a gfx::ColorSpace -TEST_F(SkiaUtilsTest, SkColorSpaceToGfxColorSpace) { - std::vector<sk_sp<SkColorSpace>> skia_color_spaces; - - SkColorSpace::RenderTargetGamma gammas[] = { - SkColorSpace::kLinear_RenderTargetGamma, - SkColorSpace::kSRGB_RenderTargetGamma}; - - SkColorSpace::Gamut gamuts[] = { - SkColorSpace::kSRGB_Gamut, SkColorSpace::kAdobeRGB_Gamut, - SkColorSpace::kDCIP3_D65_Gamut, SkColorSpace::kRec2020_Gamut, - }; - - skia_color_spaces.push_back((SkColorSpace::MakeSRGB())->makeColorSpin()); - - for (unsigned gamma_itr = 0; gamma_itr < 2; gamma_itr++) { - for (unsigned gamut_itr = 0; gamut_itr < 4; gamut_itr++) { - skia_color_spaces.push_back( - SkColorSpace::MakeRGB(gammas[gamma_itr], gamuts[gamut_itr])); - } - } - - std::vector<gfx::ColorSpace> gfx_color_spaces; - for (unsigned i = 0; i < skia_color_spaces.size(); i++) { - gfx::ColorSpace color_space = - SkColorSpaceToGfxColorSpace(skia_color_spaces[i]); - ASSERT_TRUE(SkColorSpace::Equals(color_space.ToSkColorSpace().get(), - skia_color_spaces[i].get())); - } -} - -} // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc b/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc index be22081f4f3..aae49942565 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc @@ -32,10 +32,6 @@ SkiaTextureHolder::SkiaTextureHolder( if (!ContextProvider()) return; - if (texture_holder->IsAbandoned()) { - Abandon(); - return; - } gpu::gles2::GLES2Interface* shared_gl = ContextProvider()->ContextGL(); GrContext* shared_gr_context = ContextProvider()->GetGrContext(); @@ -66,14 +62,8 @@ SkiaTextureHolder::~SkiaTextureHolder() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); } -void SkiaTextureHolder::Abandon() { - if (image_ && image_->getTexture()) - image_->getTexture()->abandon(); - TextureHolder::Abandon(); -} - bool SkiaTextureHolder::IsValid() const { - return !IsAbandoned() && !!ContextProviderWrapper(); + return !!ContextProviderWrapper(); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h b/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h index 9ccde9d01c5..d1c4687957a 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h +++ b/chromium/third_party/blink/renderer/platform/graphics/skia_texture_holder.h @@ -27,7 +27,6 @@ class PLATFORM_EXPORT SkiaTextureHolder final : public TextureHolder { bool IsValid() const final; bool CurrentFrameKnownToBeOpaque() final { return image_->isOpaque(); } sk_sp<SkImage> GetSkImage() final { return image_; } - void Abandon() final; // When creating a AcceleratedStaticBitmap from a texture-backed SkImage, this // function will be called to create a TextureHolder object. diff --git a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc index 034ac1332ba..8550cb7bf48 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc @@ -84,6 +84,7 @@ scoped_refptr<StaticBitmapImage> StaticBitmapImage::ConvertToColorSpace( SkColorType color_type) { DCHECK(color_space); sk_sp<SkImage> skia_image = PaintImageForCurrentFrame().GetSkImage(); + // If we don't need to change the color type, use SkImage::makeColorSpace() if (skia_image->colorType() == color_type) { skia_image = skia_image->makeColorSpace(color_space); @@ -92,23 +93,17 @@ scoped_refptr<StaticBitmapImage> StaticBitmapImage::ConvertToColorSpace( : nullptr); } - // Otherwise, create a surface and draw on that to avoid GPU readback. - sk_sp<SkColorSpace> src_color_space = skia_image->refColorSpace(); - if (!src_color_space.get()) - src_color_space = SkColorSpace::MakeSRGB(); - sk_sp<SkColorSpace> dst_color_space = color_space; - if (!dst_color_space.get()) - dst_color_space = SkColorSpace::MakeSRGB(); - + // Otherwise we need to create a surface and redraw the image as it is a + // different size in memory SkImageInfo info = SkImageInfo::Make(skia_image->width(), skia_image->height(), color_type, - skia_image->alphaType(), dst_color_space); + skia_image->alphaType(), color_space); sk_sp<SkSurface> surface = nullptr; if (skia_image->isTextureBacked()) { GrContext* gr = ContextProviderWrapper()->ContextProvider()->GetGrContext(); surface = SkSurface::MakeRenderTarget(gr, SkBudgeted::kNo, info); } else { - surface = SkSurface::MakeRaster(info); + surface = SkSurface::MakeRaster(info); } SkPaint paint; surface->getCanvas()->drawImage(skia_image, 0, 0, &paint); @@ -136,7 +131,7 @@ bool StaticBitmapImage::ConvertToArrayBufferContents( data_size.ValueOrDie() > v8::TypedArray::kMaxLength) return false; - size_t alloc_size_in_bytes = rect.Size().Area() * bytes_per_pixel; + int alloc_size_in_bytes = data_size.ValueOrDie(); if (!src_image) { auto data = WTF::ArrayBufferContents::CreateDataHandle( alloc_size_in_bytes, WTF::ArrayBufferContents::kZeroInitialize); diff --git a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h index 28b6537fc87..e52affa47ff 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h +++ b/chromium/third_party/blink/renderer/platform/graphics/static_bitmap_image.h @@ -65,7 +65,6 @@ class PLATFORM_EXPORT StaticBitmapImage : public Image { virtual bool HasMailbox() const { return false; } virtual bool IsValid() const { return true; } virtual void Transfer() {} - virtual void Abandon() {} // Creates a non-gpu copy of the image, or returns this if image is already // non-gpu. diff --git a/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc b/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc index 47a08b29157..3a641879c4b 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc @@ -34,7 +34,7 @@ SurfaceLayerBridge::SurfaceLayerBridge( binding_(this), surface_embedder_binding_(this), enable_surface_synchronization_( - features::IsSurfaceSynchronizationEnabled()), + ::features::IsSurfaceSynchronizationEnabled()), frame_sink_id_(Platform::Current()->GenerateFrameSinkId()), parent_frame_sink_id_(layer_tree_view ? layer_tree_view->GetFrameSinkId() : viz::FrameSinkId()) { @@ -126,18 +126,8 @@ const viz::FrameSinkId& SurfaceLayerBridge::GetFrameSinkId() const { return frame_sink_id_; } -void SurfaceLayerBridge::ClearSurfaceId() { - current_surface_id_ = viz::SurfaceId(); - - if (!surface_layer_) - return; - - // We reset the Ids if we lose the context_provider (case: GPU process ended) - // If we destroyed the surface_layer before that point, we need not update - // the ids. - surface_layer_->SetSurfaceId(viz::SurfaceId(), - cc::DeadlinePolicy::UseDefaultDeadline()); - surface_layer_->SetOldestAcceptableFallback(viz::SurfaceId()); +void SurfaceLayerBridge::ClearObserver() { + observer_ = nullptr; } void SurfaceLayerBridge::SetContentsOpaque(bool opaque) { diff --git a/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h b/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h index 6874555fd52..341300dba7c 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h +++ b/chromium/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h @@ -57,9 +57,9 @@ class PLATFORM_EXPORT SurfaceLayerBridge // Implementation of WebSurfaceLayerBridge. cc::Layer* GetCcLayer() const override; const viz::FrameSinkId& GetFrameSinkId() const override; - void ClearSurfaceId() override; void SetContentsOpaque(bool) override; void CreateSurfaceLayer() override; + void ClearObserver() override; const viz::SurfaceId& GetSurfaceId() const override { return current_surface_id_; diff --git a/chromium/third_party/blink/renderer/platform/graphics/texture_holder.h b/chromium/third_party/blink/renderer/platform/graphics/texture_holder.h index def091d1f44..e57624df203 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/texture_holder.h +++ b/chromium/third_party/blink/renderer/platform/graphics/texture_holder.h @@ -48,7 +48,6 @@ class PLATFORM_EXPORT TextureHolder { NOTREACHED(); return nullptr; } - virtual void Abandon() { is_abandoned_ = true; } // Overrides must call base. // Methods that have exactly the same impelmentation for all sub-classes base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper() @@ -61,7 +60,6 @@ class PLATFORM_EXPORT TextureHolder { ? context_provider_wrapper_->ContextProvider() : nullptr; } - bool IsAbandoned() const { return is_abandoned_; } protected: TextureHolder(base::WeakPtr<WebGraphicsContext3DProviderWrapper>&& @@ -75,7 +73,6 @@ class PLATFORM_EXPORT TextureHolder { // and that we need to clear the resouces associated with that // AcceleratedStaticBitmapImage on the original thread. base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_; - bool is_abandoned_ = false; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc index c20b1272045..32f6060223c 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc @@ -8,12 +8,11 @@ #include "base/threading/sequenced_task_runner_handle.h" #include "base/trace_event/trace_event.h" -#include "cc/paint/filter_operations.h" -#include "cc/scheduler/video_frame_controller.h" #include "components/viz/common/features.h" #include "components/viz/common/resources/resource_id.h" #include "components/viz/common/resources/returned_resource.h" #include "media/base/video_frame.h" +#include "media/base/video_types.h" #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom-blink.h" #include "services/ws/public/cpp/gpu/context_provider_command_buffer.h" #include "third_party/blink/public/platform/interface_provider.h" @@ -23,14 +22,6 @@ namespace blink { -namespace { - -// Delay to retry getting the context_provider. -constexpr base::TimeDelta kGetContextProviderRetryTimeout = - base::TimeDelta::FromMilliseconds(150); - -} // namespace - VideoFrameSubmitter::VideoFrameSubmitter( WebContextProviderCallback context_provider_callback, std::unique_ptr<VideoFrameResourceProvider> resource_provider) @@ -39,36 +30,90 @@ VideoFrameSubmitter::VideoFrameSubmitter( resource_provider_(std::move(resource_provider)), rotation_(media::VIDEO_ROTATION_0), enable_surface_synchronization_( - features::IsSurfaceSynchronizationEnabled()), + ::features::IsSurfaceSynchronizationEnabled()), weak_ptr_factory_(this) { - DETACH_FROM_THREAD(media_thread_checker_); + DETACH_FROM_THREAD(thread_checker_); } VideoFrameSubmitter::~VideoFrameSubmitter() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (context_provider_) context_provider_->RemoveObserver(this); + + // Release VideoFrameResourceProvider early since its destruction will make + // calls back into this class via the viz::SharedBitmapReporter interface. + resource_provider_.reset(); } -void VideoFrameSubmitter::SetRotation(media::VideoRotation rotation) { - rotation_ = rotation; +void VideoFrameSubmitter::StopUsingProvider() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (is_rendering_) + StopRendering(); + video_frame_provider_ = nullptr; } -void VideoFrameSubmitter::SetIsOpaque(bool is_opaque) { - if (is_opaque_ == is_opaque) +void VideoFrameSubmitter::StartRendering() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!is_rendering_); + is_rendering_ = true; + + if (compositor_frame_sink_) + compositor_frame_sink_->SetNeedsBeginFrame(is_rendering_ && ShouldSubmit()); +} + +void VideoFrameSubmitter::StopRendering() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(is_rendering_); + DCHECK(video_frame_provider_); + + is_rendering_ = false; + UpdateSubmissionState(); +} + +void VideoFrameSubmitter::DidReceiveFrame() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(video_frame_provider_); + + // DidReceiveFrame is called before rendering has started, as a part of + // VideoRendererSink::PaintSingleFrame. + if (!is_rendering_) + SubmitSingleFrame(); +} + +bool VideoFrameSubmitter::IsDrivingFrameUpdates() const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // We drive frame updates only when we believe that something is consuming + // them. This is different than VideoLayer, which drives updates any time + // they're in the layer tree. + return is_rendering_ && ShouldSubmit(); +} + +void VideoFrameSubmitter::Initialize(cc::VideoFrameProvider* provider) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (!provider) return; - is_opaque_ = is_opaque; - UpdateSubmissionStateInternal(); + DCHECK(!video_frame_provider_); + video_frame_provider_ = provider; + context_provider_callback_.Run( + nullptr, base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider, + weak_ptr_factory_.GetWeakPtr())); +} + +void VideoFrameSubmitter::SetRotation(media::VideoRotation rotation) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + rotation_ = rotation; } void VideoFrameSubmitter::EnableSubmission( viz::SurfaceId surface_id, - base::TimeTicks local_surface_id_allocation_time, - WebFrameSinkDestroyedCallback frame_sink_destroyed_callback) { + base::TimeTicks local_surface_id_allocation_time) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // TODO(lethalantidote): Set these fields earlier in the constructor. Will // need to construct VideoFrameSubmitter later in order to do this. frame_sink_id_ = surface_id.frame_sink_id(); - frame_sink_destroyed_callback_ = frame_sink_destroyed_callback; child_local_surface_id_allocator_.UpdateFromParent( viz::LocalSurfaceIdAllocation(surface_id.local_surface_id(), local_surface_id_allocation_time)); @@ -76,110 +121,128 @@ void VideoFrameSubmitter::EnableSubmission( StartSubmitting(); } -void VideoFrameSubmitter::UpdateSubmissionState(bool should_submit) { - should_submit_internal_ = should_submit; - UpdateSubmissionStateInternal(); +void VideoFrameSubmitter::SetIsSurfaceVisible(bool is_visible) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + is_surface_visible_ = is_visible; + UpdateSubmissionState(); +} + +void VideoFrameSubmitter::SetIsPageVisible(bool is_visible) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + is_page_visible_ = is_visible; + UpdateSubmissionState(); } void VideoFrameSubmitter::SetForceSubmit(bool force_submit) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); force_submit_ = force_submit; - UpdateSubmissionStateInternal(); + UpdateSubmissionState(); } -void VideoFrameSubmitter::UpdateSubmissionStateInternal() { - if (compositor_frame_sink_) { - compositor_frame_sink_->SetNeedsBeginFrame(IsDrivingFrameUpdates()); - if (ShouldSubmit()) - SubmitSingleFrame(); - else if (!frame_size_.IsEmpty()) - SubmitEmptyFrame(); - } +void VideoFrameSubmitter::OnContextLost() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (binding_.is_bound()) + binding_.Unbind(); + + if (context_provider_) + context_provider_->RemoveObserver(this); + + waiting_for_compositor_ack_ = false; + + resource_provider_->OnContextLost(); + + // |compositor_frame_sink_| should be reset last. + compositor_frame_sink_.reset(); + + context_provider_callback_.Run( + context_provider_, + base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider, + weak_ptr_factory_.GetWeakPtr())); } -void VideoFrameSubmitter::StopUsingProvider() { - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - if (is_rendering_) - StopRendering(); - video_frame_provider_ = nullptr; +void VideoFrameSubmitter::DidReceiveCompositorFrameAck( + const WTF::Vector<viz::ReturnedResource>& resources) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + ReclaimResources(resources); + waiting_for_compositor_ack_ = false; } -void VideoFrameSubmitter::StopRendering() { - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - DCHECK(is_rendering_); - DCHECK(video_frame_provider_); +void VideoFrameSubmitter::OnBeginFrame( + const viz::BeginFrameArgs& args, + WTF::HashMap<uint32_t, ::gfx::mojom::blink::PresentationFeedbackPtr>) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + TRACE_EVENT0("media", "VideoFrameSubmitter::OnBeginFrame"); - is_rendering_ = false; - UpdateSubmissionStateInternal(); -} + viz::BeginFrameAck current_begin_frame_ack(args, false); + if (args.type == viz::BeginFrameArgs::MISSED) { + compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack); + return; + } -void VideoFrameSubmitter::SubmitSingleFrame() { - // If we haven't gotten a valid result yet from |context_provider_callback_| - // |resource_provider_| will remain uninitalized. - // |video_frame_provider_| may be null if StopUsingProvider has been called, - // which could happen if the |video_frame_provider_| is destructing while we - // are waiting for the ContextProvider. - if (!resource_provider_->IsInitialized() || !video_frame_provider_) + // Update the current frame, even if we haven't gotten an ack for a previous + // frame yet. That probably signals a dropped frame, and this will let the + // provider know that it happened, since we won't PutCurrentFrame this one. + // Note that we should DidNotProduceFrame with or without the ack. + if (!video_frame_provider_ || !video_frame_provider_->UpdateCurrentFrame( + args.frame_time + args.interval, + args.frame_time + 2 * args.interval)) { + compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack); return; + } - viz::BeginFrameAck current_begin_frame_ack = - viz::BeginFrameAck::CreateManualAckWithDamage(); scoped_refptr<media::VideoFrame> video_frame = video_frame_provider_->GetCurrentFrame(); - if (video_frame) { - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&VideoFrameSubmitter::SubmitFrame), - weak_ptr_factory_.GetWeakPtr(), current_begin_frame_ack, - video_frame)); - video_frame_provider_->PutCurrentFrame(); + + // We do have a new frame that we could display. See if we're supposed to + // actually submit a frame or not, and try to submit one. + // + // Not submitting a frame when waiting for a previous ack saves memory by + // not building up unused remote side resources. See https://crbug.com/830828. + // + // TODO(dalecurtis): Can |is_rendering_| ever be false here? Presumably if + // StopRendering() is called above we will not have gotten a BeginFrame. + if (!is_rendering_ || waiting_for_compositor_ack_ || + !SubmitFrame(current_begin_frame_ack, std::move(video_frame))) { + compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack); + return; } -} -bool VideoFrameSubmitter::ShouldSubmit() const { - return should_submit_internal_ || force_submit_; -} + // We submitted a frame! -bool VideoFrameSubmitter::IsDrivingFrameUpdates() const { - // We drive frame updates only when we believe that something is consuming - // them. This is different than VideoLayer, which drives updates any time - // they're in the layer tree. - return is_rendering_ && ShouldSubmit(); + // We still signal PutCurrentFrame here, rather than on the ack, so that it + // lines up with the correct frame. Otherwise, any intervening calls to + // OnBeginFrame => UpdateCurrentFrame will cause the put to signal that the + // later frame was displayed. + video_frame_provider_->PutCurrentFrame(); } -void VideoFrameSubmitter::DidReceiveFrame() { - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - DCHECK(video_frame_provider_); - - // DidReceiveFrame is called before renderering has started, as a part of - // PaintSingleFrame. - if (!is_rendering_) { - SubmitSingleFrame(); - } +void VideoFrameSubmitter::ReclaimResources( + const WTF::Vector<viz::ReturnedResource>& resources) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + resource_provider_->ReceiveReturnsFromParent( + WebVector<viz::ReturnedResource>(resources).ReleaseVector()); } -void VideoFrameSubmitter::StartRendering() { - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - DCHECK(!is_rendering_); - is_rendering_ = true; - - if (compositor_frame_sink_) - compositor_frame_sink_->SetNeedsBeginFrame(is_rendering_ && ShouldSubmit()); +void VideoFrameSubmitter::DidAllocateSharedBitmap( + mojo::ScopedSharedBufferHandle buffer, + const viz::SharedBitmapId& id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(compositor_frame_sink_); + compositor_frame_sink_->DidAllocateSharedBitmap( + std::move(buffer), SharedBitmapIdToGpuMailboxPtr(id)); } -void VideoFrameSubmitter::Initialize(cc::VideoFrameProvider* provider) { - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - if (provider) { - DCHECK(!video_frame_provider_); - video_frame_provider_ = provider; - context_provider_callback_.Run( - nullptr, base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider, - weak_ptr_factory_.GetWeakPtr())); - } +void VideoFrameSubmitter::DidDeleteSharedBitmap(const viz::SharedBitmapId& id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(compositor_frame_sink_); + compositor_frame_sink_->DidDeleteSharedBitmap( + SharedBitmapIdToGpuMailboxPtr(id)); } void VideoFrameSubmitter::OnReceivedContextProvider( bool use_gpu_compositing, scoped_refptr<viz::ContextProvider> context_provider) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (!use_gpu_compositing) { resource_provider_->Initialize(nullptr, this); return; @@ -188,6 +251,10 @@ void VideoFrameSubmitter::OnReceivedContextProvider( bool has_good_context = false; while (!has_good_context) { if (!context_provider) { + // Delay to retry getting the context_provider. + constexpr base::TimeDelta kGetContextProviderRetryTimeout = + base::TimeDelta::FromMilliseconds(150); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::BindOnce( @@ -217,7 +284,7 @@ void VideoFrameSubmitter::OnReceivedContextProvider( } void VideoFrameSubmitter::StartSubmitting() { - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(frame_sink_id_.is_valid()); mojom::blink::EmbeddedFrameSinkProviderPtr provider; @@ -228,21 +295,55 @@ void VideoFrameSubmitter::StartSubmitting() { binding_.Bind(mojo::MakeRequest(&client)); provider->CreateCompositorFrameSink( frame_sink_id_, std::move(client), - mojo::MakeRequest(&compositor_frame_sink_), - mojo::MakeRequest(&surface_embedder_)); + mojo::MakeRequest(&compositor_frame_sink_)); + if (!surface_embedder_.is_bound()) { + provider->ConnectToEmbedder(frame_sink_id_, + mojo::MakeRequest(&surface_embedder_)); + } else { + GenerateNewSurfaceId(); + } compositor_frame_sink_.set_connection_error_handler(base::BindOnce( &VideoFrameSubmitter::OnContextLost, base::Unretained(this))); - UpdateSubmissionStateInternal(); + UpdateSubmissionState(); +} + +void VideoFrameSubmitter::UpdateSubmissionState() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (!compositor_frame_sink_) + return; + + compositor_frame_sink_->SetNeedsBeginFrame(IsDrivingFrameUpdates()); + + // These two calls are very important; they are responsible for significant + // memory savings when content is off-screen. + // + // While off-screen, we do not submit frames (unless |force_submit_| is true), + // which prevents GPU resource creation and accumulation on the remote side. + // During the transition to off-screen we further send an empty frame with the + // intent to evict any resources held for the previous frame. Combined these + // optimizations save 30-50% in cc:: resource memory usage. + // + // See https://crbug.com/829813 and https://crbug.com/829565. + if (ShouldSubmit()) { + // We don't want to submit when |is_rendering_| because OnBeginFrame() calls + // are already driving submissions. We should still submit the empty frame + // in the other branch for memory savings. + if (!is_rendering_) + SubmitSingleFrame(); + } else if (!frame_size_.IsEmpty()) { + SubmitEmptyFrame(); + } } bool VideoFrameSubmitter::SubmitFrame( const viz::BeginFrameAck& begin_frame_ack, scoped_refptr<media::VideoFrame> video_frame) { - TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitFrame"); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(video_frame); - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); + TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitFrame"); + if (!compositor_frame_sink_ || !ShouldSubmit()) return false; @@ -252,47 +353,23 @@ bool VideoFrameSubmitter::SubmitFrame( frame_size = gfx::Size(frame_size.height(), frame_size.width()); } if (frame_size_ != frame_size) { - if (!frame_size_.IsEmpty()) { - child_local_surface_id_allocator_.GenerateId(); - if (enable_surface_synchronization_) { - surface_embedder_->SetLocalSurfaceId( - child_local_surface_id_allocator_ - .GetCurrentLocalSurfaceIdAllocation() - .local_surface_id()); - } - } + if (!frame_size_.IsEmpty()) + GenerateNewSurfaceId(); frame_size_ = frame_size; } - viz::CompositorFrame compositor_frame; - std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create(); - - render_pass->SetNew(1, gfx::Rect(frame_size_), gfx::Rect(frame_size_), - gfx::Transform()); - render_pass->filters = cc::FilterOperations(); - resource_provider_->AppendQuads(render_pass.get(), video_frame, rotation_, - is_opaque_); - compositor_frame.metadata.begin_frame_ack = begin_frame_ack; - // We don't assume that the ack is marked as having damage. However, we're - // definitely emitting a CompositorFrame that damages the entire surface. - compositor_frame.metadata.begin_frame_ack.has_damage = true; - compositor_frame.metadata.device_scale_factor = 1; - compositor_frame.metadata.may_contain_video = true; + auto compositor_frame = + CreateCompositorFrame(begin_frame_ack, std::move(video_frame)); std::vector<viz::ResourceId> resources; - DCHECK_LE(render_pass->quad_list.size(), 1u); - if (!render_pass->quad_list.empty()) { - for (viz::ResourceId resource_id : - render_pass->quad_list.front()->resources) { - resources.push_back(resource_id); - } + const auto& quad_list = compositor_frame.render_pass_list.back()->quad_list; + if (!quad_list.empty()) { + DCHECK_EQ(quad_list.size(), 1u); + resources.assign(quad_list.front()->resources.begin(), + quad_list.front()->resources.end()); } resource_provider_->PrepareSendToParent(resources, &compositor_frame.resource_list); - compositor_frame.render_pass_list.push_back(std::move(render_pass)); - compositor_frame.metadata.local_surface_id_allocation_time = - child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() - .allocation_time(); // TODO(lethalantidote): Address third/fourth arg in SubmitCompositorFrame. compositor_frame_sink_->SubmitCompositorFrame( @@ -306,143 +383,94 @@ bool VideoFrameSubmitter::SubmitFrame( } void VideoFrameSubmitter::SubmitEmptyFrame() { - TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitEmptyFrame"); - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(compositor_frame_sink_ && !ShouldSubmit()); DCHECK(!frame_size_.IsEmpty()); - - viz::CompositorFrame compositor_frame; - - compositor_frame.metadata.begin_frame_ack = - viz::BeginFrameAck::CreateManualAckWithDamage(); - compositor_frame.metadata.device_scale_factor = 1; - compositor_frame.metadata.may_contain_video = true; - compositor_frame.metadata.local_surface_id_allocation_time = - child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() - .allocation_time(); - - std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create(); - render_pass->SetNew(1, gfx::Rect(frame_size_), gfx::Rect(frame_size_), - gfx::Transform()); - compositor_frame.render_pass_list.push_back(std::move(render_pass)); + TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitEmptyFrame"); compositor_frame_sink_->SubmitCompositorFrame( child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() .local_surface_id(), - std::move(compositor_frame), nullptr, 0); + CreateCompositorFrame(viz::BeginFrameAck::CreateManualAckWithDamage(), + nullptr), + nullptr, 0); waiting_for_compositor_ack_ = true; } -void VideoFrameSubmitter::OnBeginFrame( - const viz::BeginFrameArgs& args, - WTF::HashMap<uint32_t, ::gfx::mojom::blink::PresentationFeedbackPtr>) { - TRACE_EVENT0("media", "VideoFrameSubmitter::OnBeginFrame"); - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - viz::BeginFrameAck current_begin_frame_ack(args, false); - if (args.type == viz::BeginFrameArgs::MISSED) { - compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack); - return; - } +void VideoFrameSubmitter::SubmitSingleFrame() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - // Update the current frame, even if we haven't gotten an ack for a previous - // frame yet. That probably signals a dropped frame, and this will let the - // provider know that it happened, since we won't PutCurrentFrame this one. - // Note that we should DidNotProduceFrame with or without the ack. - if (!video_frame_provider_ || !video_frame_provider_->UpdateCurrentFrame( - args.frame_time + args.interval, - args.frame_time + 2 * args.interval)) { - compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack); + // If we haven't gotten a valid result yet from |context_provider_callback_| + // |resource_provider_| will remain uninitialized. + // |video_frame_provider_| may be null if StopUsingProvider has been called, + // which could happen if the |video_frame_provider_| is destructing while we + // are waiting for the ContextProvider. + if (!resource_provider_->IsInitialized() || !video_frame_provider_) return; - } - - scoped_refptr<media::VideoFrame> video_frame = - video_frame_provider_->GetCurrentFrame(); - // We do have a new frame that we could display. See if we're supposed to - // actually submit a frame or not, and try to submit one. - if (!is_rendering_ || waiting_for_compositor_ack_ || - !SubmitFrame(current_begin_frame_ack, std::move(video_frame))) { - compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack); + auto video_frame = video_frame_provider_->GetCurrentFrame(); + if (!video_frame) return; - } - // We submitted a frame! + // TODO(dalecurtis): This probably shouldn't be posted since it runs the risk + // of having state change out from under it. All call sites into this method + // should be from posted tasks so it should be safe to remove the post. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(base::IgnoreResult(&VideoFrameSubmitter::SubmitFrame), + weak_ptr_factory_.GetWeakPtr(), + viz::BeginFrameAck::CreateManualAckWithDamage(), + std::move(video_frame))); - // We still signal PutCurrentFrame here, rather than on the ack, so that it - // lines up with the correct frame. Otherwise, any intervening calls to - // OnBeginFrame => UpdateCurrentFrame will cause the put to signal that the - // later frame was displayed. video_frame_provider_->PutCurrentFrame(); } -void VideoFrameSubmitter::OnContextLost() { - // TODO(lethalantidote): This check will be obsolete once other TODO to move - // field initialization earlier is fulfilled. - if (frame_sink_destroyed_callback_) - frame_sink_destroyed_callback_.Run(); - - if (binding_.is_bound()) - binding_.Unbind(); - - if (context_provider_) { - context_provider_->RemoveObserver(this); - } - waiting_for_compositor_ack_ = false; - - resource_provider_->OnContextLost(); - - // |compositor_frame_sink_| should be reset last. - compositor_frame_sink_.reset(); +bool VideoFrameSubmitter::ShouldSubmit() const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return (is_surface_visible_ && is_page_visible_) || force_submit_; +} - context_provider_callback_.Run( - context_provider_, - base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider, - weak_ptr_factory_.GetWeakPtr())); +viz::CompositorFrame VideoFrameSubmitter::CreateCompositorFrame( + const viz::BeginFrameAck& begin_frame_ack, + scoped_refptr<media::VideoFrame> video_frame) { + DCHECK(!frame_size_.IsEmpty()); - // We need to trigger another submit so that surface_id's get propagated - // correctly. If we don't, we don't get any more signals to update the - // submission state. - should_submit_internal_ = true; -} + viz::CompositorFrame compositor_frame; + compositor_frame.metadata.begin_frame_ack = begin_frame_ack; + compositor_frame.metadata.frame_token = ++next_frame_token_; -void VideoFrameSubmitter::DidReceiveCompositorFrameAck( - const WTF::Vector<viz::ReturnedResource>& resources) { - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - ReclaimResources(resources); + // We don't assume that the ack is marked as having damage. However, we're + // definitely emitting a CompositorFrame that damages the entire surface. + compositor_frame.metadata.begin_frame_ack.has_damage = true; + compositor_frame.metadata.device_scale_factor = 1; + compositor_frame.metadata.may_contain_video = true; + compositor_frame.metadata.local_surface_id_allocation_time = + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() + .allocation_time(); - waiting_for_compositor_ack_ = false; -} + auto render_pass = viz::RenderPass::Create(); + render_pass->SetNew(1, gfx::Rect(frame_size_), gfx::Rect(frame_size_), + gfx::Transform()); -void VideoFrameSubmitter::ReclaimResources( - const WTF::Vector<viz::ReturnedResource>& resources) { - DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - WebVector<viz::ReturnedResource> temp_resources = resources; - std::vector<viz::ReturnedResource> std_resources = - temp_resources.ReleaseVector(); - resource_provider_->ReceiveReturnsFromParent(std_resources); -} + if (video_frame) { + const bool is_opaque = media::IsOpaque(video_frame->format()); + resource_provider_->AppendQuads(render_pass.get(), std::move(video_frame), + rotation_, is_opaque); + } -void VideoFrameSubmitter::DidAllocateSharedBitmap( - mojo::ScopedSharedBufferHandle buffer, - const viz::SharedBitmapId& id) { - DCHECK(compositor_frame_sink_); - compositor_frame_sink_->DidAllocateSharedBitmap( - std::move(buffer), SharedBitmapIdToGpuMailboxPtr(id)); + compositor_frame.render_pass_list.emplace_back(std::move(render_pass)); + return compositor_frame; } -void VideoFrameSubmitter::DidDeleteSharedBitmap(const viz::SharedBitmapId& id) { - DCHECK(compositor_frame_sink_); - compositor_frame_sink_->DidDeleteSharedBitmap( - SharedBitmapIdToGpuMailboxPtr(id)); -} +void VideoFrameSubmitter::GenerateNewSurfaceId() { + // We need a new id in the event of context loss. + child_local_surface_id_allocator_.GenerateId(); + if (!enable_surface_synchronization_) + return; -void VideoFrameSubmitter::SetSurfaceIdForTesting( - const viz::SurfaceId& surface_id, - base::TimeTicks allocation_time) { - frame_sink_id_ = surface_id.frame_sink_id(); - child_local_surface_id_allocator_.UpdateFromParent( - viz::LocalSurfaceIdAllocation(surface_id.local_surface_id(), - allocation_time)); + surface_embedder_->SetLocalSurfaceId( + child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() + .local_surface_id()); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h index 0a0f90deece..bc870137ee0 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h +++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.h @@ -28,29 +28,20 @@ namespace blink { // This single-threaded class facilitates the communication between the media // stack and browser renderer, providing compositor frames containing video -// frames and corresponding resources to the |compositor_frame_sink_|. This -// class has dependencies on classes that use the media thread's OpenGL -// ContextProvider, and thus, besides construction, should be consistently ran -// from the same media SingleThreadTaskRunner. +// frames and corresponding resources to the |compositor_frame_sink_|. +// +// This class requires and uses a viz::ContextProvider, and thus, besides +// construction, must be consistently accessed from the same thread. class PLATFORM_EXPORT VideoFrameSubmitter : public WebVideoFrameSubmitter, public viz::ContextLostObserver, public viz::SharedBitmapReporter, public viz::mojom::blink::CompositorFrameSinkClient { public: - explicit VideoFrameSubmitter(WebContextProviderCallback, - std::unique_ptr<VideoFrameResourceProvider>); - + VideoFrameSubmitter(WebContextProviderCallback, + std::unique_ptr<VideoFrameResourceProvider>); ~VideoFrameSubmitter() override; - bool Rendering() { return is_rendering_; } - cc::VideoFrameProvider* Provider() { return video_frame_provider_; } - mojo::Binding<viz::mojom::blink::CompositorFrameSinkClient>* Binding() { - return &binding_; - } - - void OnReceivedContextProvider(bool, scoped_refptr<viz::ContextProvider>); - // cc::VideoFrameProvider::Client implementation. void StopUsingProvider() override; void StartRendering() override; @@ -61,11 +52,11 @@ class PLATFORM_EXPORT VideoFrameSubmitter // WebVideoFrameSubmitter implementation. void Initialize(cc::VideoFrameProvider*) override; void SetRotation(media::VideoRotation) override; - void SetIsOpaque(bool) override; - void EnableSubmission(viz::SurfaceId, - base::TimeTicks local_surface_id_allocation_time, - WebFrameSinkDestroyedCallback) override; - void UpdateSubmissionState(bool is_visible) override; + void EnableSubmission( + viz::SurfaceId, + base::TimeTicks local_surface_id_allocation_time) override; + void SetIsSurfaceVisible(bool is_visible) override; + void SetIsPageVisible(bool is_visible) override; void SetForceSubmit(bool) override; // viz::ContextLostObserver implementation. @@ -87,43 +78,50 @@ class PLATFORM_EXPORT VideoFrameSubmitter const viz::SharedBitmapId&) override; void DidDeleteSharedBitmap(const viz::SharedBitmapId&) override; - void SetCompositorFrameSinkPtrForTesting( - viz::mojom::blink::CompositorFrameSinkPtr* sink) { - compositor_frame_sink_ = std::move(*sink); - } - void SetSurfaceEmbedderPtrForTesting( - mojom::blink::SurfaceEmbedderPtr embedder) { - surface_embedder_ = std::move(embedder); - } - void SetSurfaceIdForTesting(const viz::SurfaceId&, base::TimeTicks); - private: - FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest, ContextLostDuringSubmit); - FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest, - ShouldSubmitPreventsSubmission); - FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest, - SetForceSubmitForcesSubmission); - FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest, - FrameSizeChangeUpdatesLocalSurfaceId); - FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest, - StopUsingProviderDuringContextLost); + friend class VideoFrameSubmitterTest; + // Called during Initialize() and OnContextLost() after a new ContextGL is + // requested. + void OnReceivedContextProvider( + bool use_gpu_compositing, + scoped_refptr<viz::ContextProvider> context_provider); + + // Starts submission and calls UpdateSubmissionState(); which may submit. void StartSubmitting(); - void UpdateSubmissionStateInternal(); + + // Sets CompositorFrameSink::SetNeedsBeginFrame() state and submits a frame if + // visible or an empty frame if not. + void UpdateSubmissionState(); + // Returns whether a frame was submitted. bool SubmitFrame(const viz::BeginFrameAck&, scoped_refptr<media::VideoFrame>); + + // SubmitEmptyFrame() is used to force the remote CompositorFrameSink to + // release resources for the last submission; saving a significant amount of + // memory (~30%) when content goes off-screen. See https://crbug.com/829813. void SubmitEmptyFrame(); - // Pulls frame and submits it to compositor. - // Used in cases like PaintSingleFrame, which occurs before video rendering - // has started to post a poster image, or to submit a final frame before - // ending rendering. + // Pulls frame and submits it to compositor. Used in cases like + // DidReceiveFrame(), which occurs before video rendering has started to post + // the first frame or to submit a final frame before ending rendering. void SubmitSingleFrame(); // Return whether the submitter should submit frames based on its current - // state. + // state. It's important to only submit when this is true to save memory. See + // comments above and in UpdateSubmissionState(). bool ShouldSubmit() const; + // Generates a new surface ID using using |child_local_surface_id_allocator_|. + // Called during context loss or during a frame size change. + void GenerateNewSurfaceId(); + + // Helper method for creating viz::CompositorFrame. If |video_frame| is null + // then the frame will be empty. + viz::CompositorFrame CreateCompositorFrame( + const viz::BeginFrameAck& begin_frame_ack, + scoped_refptr<media::VideoFrame> video_frame); + cc::VideoFrameProvider* video_frame_provider_ = nullptr; scoped_refptr<viz::ContextProvider> context_provider_; viz::mojom::blink::CompositorFrameSinkPtr compositor_frame_sink_; @@ -131,18 +129,27 @@ class PLATFORM_EXPORT VideoFrameSubmitter mojo::Binding<viz::mojom::blink::CompositorFrameSinkClient> binding_; WebContextProviderCallback context_provider_callback_; std::unique_ptr<VideoFrameResourceProvider> resource_provider_; - WebFrameSinkDestroyedCallback frame_sink_destroyed_callback_; bool waiting_for_compositor_ack_ = false; + // Current rendering state. Set by StartRendering() and StopRendering(). bool is_rendering_ = false; - // If we are not on screen, we should not submit. - bool should_submit_internal_ = false; - // Whether frames should always be submitted, even if we're not visible. + + // If the surface is not visible within in the current view port, we should + // not submit. Not submitting when off-screen saves significant memory. + bool is_surface_visible_ = false; + + // Likewise, if the entire page is not visible, we should not submit. Not + // submitting in the background causes the VideoFrameProvider to enter a + // background rendering mode using lower frequency artificial BeginFrames. + bool is_page_visible_ = true; + + // Whether frames should always be submitted, even if we're not visible. Used + // by Picture-in-Picture mode to ensure submission occurs even off-screen. bool force_submit_ = false; + // Needs to be initialized in implementation because media isn't a public_dep // of blink/platform. media::VideoRotation rotation_; - bool is_opaque_ = true; viz::FrameSinkId frame_sink_id_; @@ -156,8 +163,9 @@ class PLATFORM_EXPORT VideoFrameSubmitter viz::ChildLocalSurfaceIdAllocator child_local_surface_id_allocator_; const bool enable_surface_synchronization_; + viz::FrameTokenGenerator next_frame_token_; - THREAD_CHECKER(media_thread_checker_); + THREAD_CHECKER(thread_checker_); base::WeakPtrFactory<VideoFrameSubmitter> weak_ptr_factory_; diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc index 6ec09248d5b..7f7e3924e14 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc @@ -20,6 +20,8 @@ #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom-blink.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/graphics/test/mock_compositor_frame_sink.h" +#include "third_party/blink/renderer/platform/graphics/test/mock_embedded_frame_sink_provider.h" #include "third_party/blink/renderer/platform/graphics/video_frame_resource_provider.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -47,12 +49,13 @@ class MockVideoFrameProvider : public cc::VideoFrameProvider { DISALLOW_COPY_AND_ASSIGN(MockVideoFrameProvider); }; -class MockCompositorFrameSink : public viz::mojom::blink::CompositorFrameSink { +class VideoMockCompositorFrameSink + : public viz::mojom::blink::CompositorFrameSink { public: - MockCompositorFrameSink( + VideoMockCompositorFrameSink( viz::mojom::blink::CompositorFrameSinkRequest* request) : binding_(this, std::move(*request)) {} - ~MockCompositorFrameSink() override = default; + ~VideoMockCompositorFrameSink() override = default; const viz::CompositorFrame& last_submitted_compositor_frame() const { return last_submitted_compositor_frame_; @@ -101,7 +104,7 @@ class MockCompositorFrameSink : public viz::mojom::blink::CompositorFrameSink { viz::CompositorFrame last_submitted_compositor_frame_; - DISALLOW_COPY_AND_ASSIGN(MockCompositorFrameSink); + DISALLOW_COPY_AND_ASSIGN(VideoMockCompositorFrameSink); }; class MockVideoFrameResourceProvider @@ -145,9 +148,6 @@ class VideoFrameSubmitterTest : public testing::Test { video_frame_provider_(new StrictMock<MockVideoFrameProvider>()), context_provider_(viz::TestContextProvider::Create()) { context_provider_->BindToCurrentThread(); - } - - void SetUp() override { MakeSubmitter(); scoped_task_environment_.RunUntilIdle(); } @@ -166,28 +166,55 @@ class VideoFrameSubmitterTest : public testing::Test { viz::mojom::blink::CompositorFrameSinkPtr submitter_sink; viz::mojom::blink::CompositorFrameSinkRequest request = mojo::MakeRequest(&submitter_sink); - sink_ = std::make_unique<StrictMock<MockCompositorFrameSink>>(&request); + sink_ = + std::make_unique<StrictMock<VideoMockCompositorFrameSink>>(&request); // By setting the submission state before we set the sink, we can make // testing easier without having to worry about the first sent frame. - submitter_->UpdateSubmissionState(true); - submitter_->SetCompositorFrameSinkPtrForTesting(&submitter_sink); + submitter_->SetIsSurfaceVisible(true); + submitter_->compositor_frame_sink_ = std::move(submitter_sink); mojom::blink::SurfaceEmbedderPtr embedder; mojo::MakeRequest(&embedder); - submitter_->SetSurfaceEmbedderPtrForTesting(std::move(embedder)); - submitter_->SetSurfaceIdForTesting( - viz::SurfaceId( - viz::FrameSinkId(1, 1), - viz::LocalSurfaceId( - 11, base::UnguessableToken::Deserialize(0x111111, 0))), - base::TimeTicks::Now()); + submitter_->surface_embedder_ = std::move(embedder); + auto surface_id = viz::SurfaceId( + viz::FrameSinkId(1, 1), + viz::LocalSurfaceId(11, + base::UnguessableToken::Deserialize(0x111111, 0))); + submitter_->frame_sink_id_ = surface_id.frame_sink_id(); + submitter_->child_local_surface_id_allocator_.UpdateFromParent( + viz::LocalSurfaceIdAllocation(surface_id.local_surface_id(), + base::TimeTicks::Now())); + } + + bool IsRendering() const { return submitter_->is_rendering_; } + + cc::VideoFrameProvider* GetProvider() const { + return submitter_->video_frame_provider_; + } + + bool ShouldSubmit() const { return submitter_->ShouldSubmit(); } + + void SubmitSingleFrame() { submitter_->SubmitSingleFrame(); } + + const viz::ChildLocalSurfaceIdAllocator& child_local_surface_id_allocator() + const { + return submitter_->child_local_surface_id_allocator_; + } + + gfx::Size frame_size() const { return submitter_->frame_size_; } + + void OnReceivedContextProvider( + bool use_gpu_compositing, + scoped_refptr<viz::ContextProvider> context_provider) { + submitter_->OnReceivedContextProvider(use_gpu_compositing, + std::move(context_provider)); } protected: base::test::ScopedTaskEnvironment scoped_task_environment_; std::unique_ptr<base::SimpleTestTickClock> now_src_; std::unique_ptr<viz::FakeExternalBeginFrameSource> begin_frame_source_; - std::unique_ptr<StrictMock<MockCompositorFrameSink>> sink_; + std::unique_ptr<StrictMock<VideoMockCompositorFrameSink>> sink_; std::unique_ptr<StrictMock<MockVideoFrameProvider>> video_frame_provider_; StrictMock<MockVideoFrameResourceProvider>* resource_provider_; scoped_refptr<viz::TestContextProvider> context_provider_; @@ -195,23 +222,23 @@ class VideoFrameSubmitterTest : public testing::Test { }; TEST_F(VideoFrameSubmitterTest, StatRenderingFlipsBits) { - EXPECT_FALSE(submitter_->Rendering()); + EXPECT_FALSE(IsRendering()); EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); submitter_->StartRendering(); scoped_task_environment_.RunUntilIdle(); - EXPECT_TRUE(submitter_->Rendering()); + EXPECT_TRUE(IsRendering()); } TEST_F(VideoFrameSubmitterTest, StopUsingProviderNullsProvider) { - EXPECT_FALSE(submitter_->Rendering()); - EXPECT_EQ(video_frame_provider_.get(), submitter_->Provider()); + EXPECT_FALSE(IsRendering()); + EXPECT_EQ(video_frame_provider_.get(), GetProvider()); submitter_->StopUsingProvider(); - EXPECT_EQ(nullptr, submitter_->Provider()); + EXPECT_EQ(nullptr, GetProvider()); } TEST_F(VideoFrameSubmitterTest, @@ -221,7 +248,7 @@ TEST_F(VideoFrameSubmitterTest, submitter_->StartRendering(); scoped_task_environment_.RunUntilIdle(); - EXPECT_TRUE(submitter_->Rendering()); + EXPECT_TRUE(IsRendering()); EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) .WillOnce(Return(media::VideoFrame::CreateFrame( @@ -238,7 +265,7 @@ TEST_F(VideoFrameSubmitterTest, scoped_task_environment_.RunUntilIdle(); - EXPECT_FALSE(submitter_->Rendering()); + EXPECT_FALSE(IsRendering()); } TEST_F(VideoFrameSubmitterTest, DidReceiveFrameDoesNothingIfRendering) { @@ -247,14 +274,14 @@ TEST_F(VideoFrameSubmitterTest, DidReceiveFrameDoesNothingIfRendering) { submitter_->StartRendering(); scoped_task_environment_.RunUntilIdle(); - EXPECT_TRUE(submitter_->Rendering()); + EXPECT_TRUE(IsRendering()); submitter_->DidReceiveFrame(); scoped_task_environment_.RunUntilIdle(); } TEST_F(VideoFrameSubmitterTest, DidReceiveFrameSubmitsFrame) { - EXPECT_FALSE(submitter_->Rendering()); + EXPECT_FALSE(IsRendering()); EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) .WillOnce(Return(media::VideoFrame::CreateFrame( @@ -272,37 +299,27 @@ TEST_F(VideoFrameSubmitterTest, DidReceiveFrameSubmitsFrame) { TEST_F(VideoFrameSubmitterTest, ShouldSubmitPreventsSubmission) { EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); - submitter_->UpdateSubmissionState(false); + submitter_->SetIsSurfaceVisible(false); scoped_task_environment_.RunUntilIdle(); - EXPECT_FALSE(submitter_->ShouldSubmit()); + EXPECT_FALSE(ShouldSubmit()); EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); submitter_->StartRendering(); scoped_task_environment_.RunUntilIdle(); EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - submitter_->UpdateSubmissionState(true); + submitter_->SetIsSurfaceVisible(true); scoped_task_environment_.RunUntilIdle(); - EXPECT_TRUE(submitter_->ShouldSubmit()); + EXPECT_TRUE(ShouldSubmit()); EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1); EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()).Times(0); - submitter_->UpdateSubmissionState(false); + submitter_->SetIsSurfaceVisible(false); scoped_task_environment_.RunUntilIdle(); - EXPECT_FALSE(submitter_->ShouldSubmit()); + EXPECT_FALSE(ShouldSubmit()); EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) .WillOnce(Return(media::VideoFrame::CreateFrame( @@ -310,17 +327,17 @@ TEST_F(VideoFrameSubmitterTest, ShouldSubmitPreventsSubmission) { gfx::Size(8, 8), base::TimeDelta()))); EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - submitter_->SubmitSingleFrame(); + SubmitSingleFrame(); } // Tests that when set to true SetForceSubmit forces frame submissions. // regardless of the internal submit state. TEST_F(VideoFrameSubmitterTest, SetForceSubmitForcesSubmission) { EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); - submitter_->UpdateSubmissionState(false); + submitter_->SetIsSurfaceVisible(false); scoped_task_environment_.RunUntilIdle(); - EXPECT_FALSE(submitter_->ShouldSubmit()); + EXPECT_FALSE(ShouldSubmit()); EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) .WillOnce(Return(media::VideoFrame::CreateFrame( @@ -328,7 +345,7 @@ TEST_F(VideoFrameSubmitterTest, SetForceSubmitForcesSubmission) { gfx::Size(8, 8), base::TimeDelta()))); EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); submitter_->SetForceSubmit(true); - EXPECT_TRUE(submitter_->ShouldSubmit()); + EXPECT_TRUE(ShouldSubmit()); EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1); @@ -340,34 +357,14 @@ TEST_F(VideoFrameSubmitterTest, SetForceSubmitForcesSubmission) { scoped_task_environment_.RunUntilIdle(); EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - submitter_->UpdateSubmissionState(true); + submitter_->SetIsSurfaceVisible(true); scoped_task_environment_.RunUntilIdle(); - - EXPECT_TRUE(submitter_->ShouldSubmit()); + EXPECT_TRUE(ShouldSubmit()); EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - submitter_->UpdateSubmissionState(false); + submitter_->SetIsSurfaceVisible(false); scoped_task_environment_.RunUntilIdle(); - - EXPECT_TRUE(submitter_->ShouldSubmit()); + EXPECT_TRUE(ShouldSubmit()); EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) .WillOnce(Return(media::VideoFrame::CreateFrame( @@ -375,12 +372,12 @@ TEST_F(VideoFrameSubmitterTest, SetForceSubmitForcesSubmission) { gfx::Size(8, 8), base::TimeDelta()))); EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - submitter_->SubmitSingleFrame(); + SubmitSingleFrame(); } TEST_F(VideoFrameSubmitterTest, RotationInformationPassedToResourceProvider) { // Check to see if rotation is communicated pre-rendering. - EXPECT_FALSE(submitter_->Rendering()); + EXPECT_FALSE(IsRendering()); submitter_->SetRotation(media::VideoRotation::VIDEO_ROTATION_90); @@ -462,138 +459,6 @@ TEST_F(VideoFrameSubmitterTest, RotationInformationPassedToResourceProvider) { scoped_task_environment_.RunUntilIdle(); } -TEST_F(VideoFrameSubmitterTest, IsOpaquePassedToResourceProvider) { - // Check to see if is_opaque is communicated pre-rendering. - EXPECT_FALSE(submitter_->Rendering()); - - // We submit a frame on opacity change. - EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - - submitter_->SetIsOpaque(false); - scoped_task_environment_.RunUntilIdle(); - - { - WTF::Vector<viz::ReturnedResource> resources; - EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_)); - submitter_->DidReceiveCompositorFrameAck(resources); - } - - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, false)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - - submitter_->DidReceiveFrame(); - scoped_task_environment_.RunUntilIdle(); - - { - WTF::Vector<viz::ReturnedResource> resources; - EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_)); - submitter_->DidReceiveCompositorFrameAck(resources); - } - - // Check to see if an update to is_opaque just before rendering is - // communicated. - EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - submitter_->SetIsOpaque(true); - scoped_task_environment_.RunUntilIdle(); - - EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); - submitter_->StartRendering(); - scoped_task_environment_.RunUntilIdle(); - - { - WTF::Vector<viz::ReturnedResource> resources; - EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_)); - submitter_->DidReceiveCompositorFrameAck(resources); - } - - EXPECT_CALL(*video_frame_provider_, UpdateCurrentFrame(_, _)) - .WillOnce(Return(true)); - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, true)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - - viz::BeginFrameArgs args = begin_frame_source_->CreateBeginFrameArgs( - BEGINFRAME_FROM_HERE, now_src_.get()); - submitter_->OnBeginFrame(args, {}); - scoped_task_environment_.RunUntilIdle(); - - { - WTF::Vector<viz::ReturnedResource> resources; - EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_)); - submitter_->DidReceiveCompositorFrameAck(resources); - } - - // Check to see if changing is_opaque while rendering is handled. - EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - - submitter_->SetIsOpaque(false); - scoped_task_environment_.RunUntilIdle(); - - { - WTF::Vector<viz::ReturnedResource> resources; - EXPECT_CALL(*resource_provider_, ReceiveReturnsFromParent(_)); - submitter_->DidReceiveCompositorFrameAck(resources); - } - - EXPECT_CALL(*video_frame_provider_, UpdateCurrentFrame(_, _)) - .WillOnce(Return(true)); - EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) - .WillOnce(Return(media::VideoFrame::CreateFrame( - media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), - gfx::Size(8, 8), base::TimeDelta()))); - EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)); - EXPECT_CALL(*video_frame_provider_, PutCurrentFrame()); - EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, false)); - EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); - EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - - submitter_->OnBeginFrame(args, {}); - scoped_task_environment_.RunUntilIdle(); - - // Updating |is_opaque_| with the same value should not cause a frame submit. - submitter_->SetIsOpaque(false); -} - TEST_F(VideoFrameSubmitterTest, OnBeginFrameSubmitsFrame) { EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); @@ -718,6 +583,26 @@ TEST_F(VideoFrameSubmitterTest, WaitingForAckPreventsNewFrame) { scoped_task_environment_.RunUntilIdle(); } +// Test that after context is lost, the CompositorFrameSink is recreated but the +// SurfaceEmbedder isn't. +TEST_F(VideoFrameSubmitterTest, RecreateCompositorFrameSinkAfterContextLost) { + MockEmbeddedFrameSinkProvider mock_embedded_frame_sink_provider; + mojo::Binding<mojom::blink::EmbeddedFrameSinkProvider> + embedded_frame_sink_provider_binding(&mock_embedded_frame_sink_provider); + auto override = + mock_embedded_frame_sink_provider.CreateScopedOverrideMojoInterface( + &embedded_frame_sink_provider_binding); + + EXPECT_CALL(*resource_provider_, Initialize(_, _)); + EXPECT_CALL(mock_embedded_frame_sink_provider, ConnectToEmbedder(_, _)) + .Times(0); + EXPECT_CALL(mock_embedded_frame_sink_provider, CreateCompositorFrameSink_(_)) + .Times(1); + submitter_->OnContextLost(); + OnReceivedContextProvider(true, context_provider_); + scoped_task_environment_.RunUntilIdle(); +} + // Test that no crash happens if the context is lost during a frame submission. TEST_F(VideoFrameSubmitterTest, ContextLostDuringSubmit) { EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); @@ -733,7 +618,7 @@ TEST_F(VideoFrameSubmitterTest, ContextLostDuringSubmit) { // This will post a task that will later call SubmitFrame(). The call will // happen after OnContextLost(). - submitter_->SubmitSingleFrame(); + SubmitSingleFrame(); submitter_->OnContextLost(); @@ -765,7 +650,7 @@ TEST_F(VideoFrameSubmitterTest, StopUsingProviderDuringContextLost) { // OnReceivedContextProvider returns. We don't run the actual function // because it would overwrite our fake |sink_| with a real one. - submitter_->SubmitSingleFrame(); + SubmitSingleFrame(); scoped_task_environment_.RunUntilIdle(); } @@ -776,14 +661,14 @@ TEST_F(VideoFrameSubmitterTest, StopUsingProviderDuringContextLost) { TEST_F(VideoFrameSubmitterTest, FrameSizeChangeUpdatesLocalSurfaceId) { { viz::LocalSurfaceId local_surface_id = - submitter_->child_local_surface_id_allocator_ + child_local_surface_id_allocator() .GetCurrentLocalSurfaceIdAllocation() .local_surface_id(); EXPECT_TRUE(local_surface_id.is_valid()); EXPECT_EQ(11u, local_surface_id.parent_sequence_number()); EXPECT_EQ(viz::kInitialChildSequenceNumber, local_surface_id.child_sequence_number()); - EXPECT_TRUE(submitter_->frame_size_.IsEmpty()); + EXPECT_TRUE(frame_size().IsEmpty()); } EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); @@ -801,19 +686,19 @@ TEST_F(VideoFrameSubmitterTest, FrameSizeChangeUpdatesLocalSurfaceId) { EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - submitter_->SubmitSingleFrame(); + SubmitSingleFrame(); scoped_task_environment_.RunUntilIdle(); { viz::LocalSurfaceId local_surface_id = - submitter_->child_local_surface_id_allocator_ + child_local_surface_id_allocator() .GetCurrentLocalSurfaceIdAllocation() .local_surface_id(); EXPECT_TRUE(local_surface_id.is_valid()); EXPECT_EQ(11u, local_surface_id.parent_sequence_number()); EXPECT_EQ(viz::kInitialChildSequenceNumber, local_surface_id.child_sequence_number()); - EXPECT_EQ(gfx::Size(8, 8), submitter_->frame_size_); + EXPECT_EQ(gfx::Size(8, 8), frame_size()); } EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()) @@ -826,19 +711,19 @@ TEST_F(VideoFrameSubmitterTest, FrameSizeChangeUpdatesLocalSurfaceId) { EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); - submitter_->SubmitSingleFrame(); + SubmitSingleFrame(); scoped_task_environment_.RunUntilIdle(); { viz::LocalSurfaceId local_surface_id = - submitter_->child_local_surface_id_allocator_ + child_local_surface_id_allocator() .GetCurrentLocalSurfaceIdAllocation() .local_surface_id(); EXPECT_TRUE(local_surface_id.is_valid()); EXPECT_EQ(11u, local_surface_id.parent_sequence_number()); EXPECT_EQ(viz::kInitialChildSequenceNumber + 1, local_surface_id.child_sequence_number()); - EXPECT_EQ(gfx::Size(2, 2), submitter_->frame_size_); + EXPECT_EQ(gfx::Size(2, 2), frame_size()); } } @@ -846,7 +731,7 @@ TEST_F(VideoFrameSubmitterTest, VideoRotationOutputRect) { MakeSubmitter(); EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); submitter_->StartRendering(); - EXPECT_TRUE(submitter_->Rendering()); + EXPECT_TRUE(IsRendering()); gfx::Size coded_size(1280, 720); gfx::Size natural_size(1280, 1024); @@ -947,4 +832,30 @@ TEST_F(VideoFrameSubmitterTest, VideoRotationOutputRect) { } } +TEST_F(VideoFrameSubmitterTest, PageVisibilityControlsSubmission) { + // Hide the page and ensure no begin frames are issued. + EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); + submitter_->SetIsPageVisible(false); + scoped_task_environment_.RunUntilIdle(); + EXPECT_FALSE(ShouldSubmit()); + + // Start rendering, but since page is hidden nothing should start yet. + EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); + submitter_->StartRendering(); + scoped_task_environment_.RunUntilIdle(); + + // Mark the page as visible and confirm frame submission. This should not + // submit since we're already rendering. + EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); + submitter_->SetIsPageVisible(true); + scoped_task_environment_.RunUntilIdle(); + + // Transition back to the page being hidden and ensure begin frames stop. + EXPECT_TRUE(ShouldSubmit()); + EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); + EXPECT_CALL(*video_frame_provider_, GetCurrentFrame()).Times(0); + submitter_->SetIsPageVisible(false); + scoped_task_environment_.RunUntilIdle(); +} + } // namespace blink |