| // Copyright 2020 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/widget/compositing/widget_compositor.h" |
| |
| #include "cc/trees/layer_tree_host.h" |
| #include "third_party/blink/renderer/platform/widget/compositing/queue_report_time_swap_promise.h" |
| #include "third_party/blink/renderer/platform/widget/widget_base.h" |
| #include "third_party/blink/renderer/platform/widget/widget_base_client.h" |
| |
| namespace blink { |
| |
| WidgetCompositor::WidgetCompositor( |
| base::WeakPtr<WidgetBase> widget_base, |
| scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner, |
| mojo::PendingReceiver<mojom::blink::WidgetCompositor> receiver) |
| : widget_base_(widget_base), |
| main_task_runner_(std::move(main_task_runner)), |
| compositor_task_runner_(std::move(compositor_task_runner)), |
| swap_queue_(std::make_unique<WidgetSwapQueue>()) { |
| if (!compositor_task_runner_) { |
| BindOnThread(std::move(receiver)); |
| } else { |
| compositor_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&WidgetCompositor::BindOnThread, |
| base::Unretained(this), std::move(receiver))); |
| } |
| } |
| |
| void WidgetCompositor::Shutdown() { |
| if (!compositor_task_runner_) { |
| ResetOnThread(); |
| } else { |
| compositor_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&WidgetCompositor::ResetOnThread, |
| scoped_refptr<WidgetCompositor>(this))); |
| } |
| } |
| |
| void WidgetCompositor::BindOnThread( |
| mojo::PendingReceiver<mojom::blink::WidgetCompositor> receiver) { |
| DCHECK(CalledOnValidCompositorThread()); |
| receiver_.Bind(std::move(receiver), compositor_task_runner_); |
| } |
| |
| void WidgetCompositor::ResetOnThread() { |
| DCHECK(CalledOnValidCompositorThread()); |
| receiver_.reset(); |
| } |
| |
| void WidgetCompositor::VisualStateRequest(VisualStateRequestCallback callback) { |
| DCHECK(CalledOnValidCompositorThread()); |
| |
| auto drain_callback = |
| base::BindOnce(&WidgetCompositor::DrainQueue, base::RetainedRef(this)); |
| auto swap_callback = base::BindOnce(&WidgetCompositor::VisualStateResponse, |
| base::RetainedRef(this)); |
| if (!compositor_task_runner_) { |
| CreateQueueSwapPromise(std::move(drain_callback), std::move(swap_callback), |
| std::move(callback)); |
| } else { |
| main_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&WidgetCompositor::CreateQueueSwapPromise, |
| base::RetainedRef(this), std::move(drain_callback), |
| std::move(swap_callback), std::move(callback))); |
| } |
| } |
| |
| cc::LayerTreeHost* WidgetCompositor::LayerTreeHost() const { |
| return widget_base_->LayerTreeHost(); |
| } |
| |
| void WidgetCompositor::CreateQueueSwapPromise( |
| base::OnceCallback<void(int)> drain_callback, |
| base::OnceClosure swap_callback, |
| VisualStateRequestCallback callback) { |
| DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| |
| bool first_message_for_frame = false; |
| int source_frame_number = 0; |
| if (widget_base_) { |
| source_frame_number = LayerTreeHost()->SourceFrameNumber(); |
| swap_queue_->Queue(source_frame_number, std::move(callback), |
| &first_message_for_frame); |
| } |
| |
| if (first_message_for_frame) { |
| LayerTreeHost()->QueueSwapPromise( |
| std::make_unique<QueueReportTimeSwapPromise>( |
| source_frame_number, std::move(drain_callback), |
| std::move(swap_callback), compositor_task_runner_)); |
| // Request a main frame if one is not already in progress. This might either |
| // A) request a commit ahead of time or B) request a commit which is not |
| // needed because there are not pending updates. If B) then the frame will |
| // be aborted early and the swap promises will be broken (see |
| // EarlyOut_NoUpdates). |
| LayerTreeHost()->SetNeedsAnimateIfNotInsideMainFrame(); |
| |
| // In web tests the request does not actually cause a commit, because the |
| // compositor is scheduled by the test runner to avoid flakiness. So for |
| // this case we must request a main frame. |
| widget_base_->client()->ScheduleAnimationForWebTests(); |
| } else if (compositor_task_runner_) { |
| // Delete callbacks on the compositor thread. |
| compositor_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce([](base::OnceCallback<void(int)>, base::OnceClosure) {}, |
| std::move(drain_callback), std::move(swap_callback))); |
| } |
| } |
| |
| void WidgetCompositor::VisualStateResponse() { |
| DCHECK(CalledOnValidCompositorThread()); |
| Vector<VisualStateRequestCallback> callbacks; |
| swap_queue_->GetCallbacks(&callbacks); |
| for (auto& callback : callbacks) |
| std::move(callback).Run(); |
| } |
| |
| void WidgetCompositor::DrainQueue(int source_frame_number) { |
| DCHECK(CalledOnValidCompositorThread()); |
| swap_queue_->Drain(source_frame_number); |
| } |
| |
| bool WidgetCompositor::CalledOnValidCompositorThread() { |
| return !compositor_task_runner_ || |
| compositor_task_runner_->BelongsToCurrentThread(); |
| } |
| |
| } // namespace blink |