summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc')
-rw-r--r--chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc375
1 files changed, 375 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
new file mode 100644
index 00000000000..cb929c85cc3
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
@@ -0,0 +1,375 @@
+// Copyright (c) 2013 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/layer_tree_view.h"
+
+#include <stddef.h>
+#include <string>
+#include <utility>
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/feature_list.h"
+#include "base/location.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "cc/animation/animation_host.h"
+#include "cc/animation/animation_timeline.h"
+#include "cc/base/region.h"
+#include "cc/benchmarks/micro_benchmark.h"
+#include "cc/debug/layer_tree_debug_state.h"
+#include "cc/input/layer_selection_bound.h"
+#include "cc/layers/layer.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_mutator.h"
+#include "cc/trees/render_frame_metadata_observer.h"
+#include "cc/trees/swap_promise.h"
+#include "cc/trees/ukm_manager.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/quads/compositor_frame_metadata.h"
+#include "components/viz/common/resources/single_release_callback.h"
+#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
+#include "third_party/blink/public/web/blink.h"
+#include "ui/gfx/presentation_feedback.h"
+
+namespace base {
+class Value;
+}
+
+namespace cc {
+class Layer;
+}
+
+namespace blink {
+
+LayerTreeView::LayerTreeView(
+ LayerTreeViewDelegate* delegate,
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_thread,
+ cc::TaskGraphRunner* task_graph_runner,
+ scheduler::WebThreadScheduler* scheduler)
+ : main_thread_(std::move(main_thread)),
+ compositor_thread_(std::move(compositor_thread)),
+ task_graph_runner_(task_graph_runner),
+ web_main_thread_scheduler_(scheduler),
+ animation_host_(cc::AnimationHost::CreateMainInstance()),
+ delegate_(delegate) {}
+
+LayerTreeView::~LayerTreeView() = default;
+
+void LayerTreeView::Initialize(
+ const cc::LayerTreeSettings& settings,
+ std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory) {
+ DCHECK(delegate_);
+ const bool is_threaded = !!compositor_thread_;
+
+ cc::LayerTreeHost::InitParams params;
+ params.client = this;
+ params.scheduling_client = this;
+ params.settings = &settings;
+ params.task_graph_runner = task_graph_runner_;
+ params.main_task_runner = main_thread_;
+ params.mutator_host = animation_host_.get();
+ params.ukm_recorder_factory = std::move(ukm_recorder_factory);
+ if (base::ThreadPoolInstance::Get()) {
+ // The image worker thread needs to allow waiting since it makes discardable
+ // shared memory allocations which need to make synchronous calls to the
+ // IO thread.
+ params.image_worker_task_runner =
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::WithBaseSyncPrimitives(), base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+ }
+ if (!is_threaded) {
+ // Single-threaded web tests, and unit tests.
+ layer_tree_host_ =
+ cc::LayerTreeHost::CreateSingleThreaded(this, std::move(params));
+ } else {
+ layer_tree_host_ = cc::LayerTreeHost::CreateThreaded(compositor_thread_,
+ std::move(params));
+ }
+}
+
+void LayerTreeView::Disconnect() {
+ DCHECK(delegate_);
+ // Drop compositor resources immediately, while keeping the compositor alive
+ // until after this class is destroyed.
+ layer_tree_host_->SetVisible(false);
+ layer_tree_host_->ReleaseLayerTreeFrameSink();
+ delegate_ = nullptr;
+}
+
+void LayerTreeView::SetVisible(bool visible) {
+ DCHECK(delegate_);
+ layer_tree_host_->SetVisible(visible);
+
+ if (visible && layer_tree_frame_sink_request_failed_while_invisible_)
+ DidFailToInitializeLayerTreeFrameSink();
+}
+
+void LayerTreeView::SetLayerTreeFrameSink(
+ std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink,
+ std::unique_ptr<cc::RenderFrameMetadataObserver>
+ render_frame_metadata_observer) {
+ DCHECK(delegate_);
+ if (!layer_tree_frame_sink) {
+ DidFailToInitializeLayerTreeFrameSink();
+ return;
+ }
+ if (render_frame_metadata_observer) {
+ layer_tree_host_->SetRenderFrameObserver(
+ std::move(render_frame_metadata_observer));
+ }
+ layer_tree_host_->SetLayerTreeFrameSink(std::move(layer_tree_frame_sink));
+}
+
+void LayerTreeView::WillBeginMainFrame() {
+ if (!delegate_)
+ return;
+ delegate_->WillBeginMainFrame();
+}
+
+void LayerTreeView::DidBeginMainFrame() {
+ if (!delegate_)
+ return;
+ delegate_->DidBeginMainFrame();
+}
+
+void LayerTreeView::WillUpdateLayers() {
+ if (!delegate_)
+ return;
+ delegate_->BeginUpdateLayers();
+}
+
+void LayerTreeView::DidUpdateLayers() {
+ if (!delegate_)
+ return;
+ delegate_->EndUpdateLayers();
+ // Dump property trees and layers if run with:
+ // --vmodule=layer_tree_view=3
+ VLOG(3) << "After updating layers:\n"
+ << "property trees:\n"
+ << layer_tree_host_->property_trees()->ToString() << "\n"
+ << "cc::Layers:\n"
+ << layer_tree_host_->LayersAsString();
+}
+
+void LayerTreeView::BeginMainFrame(const viz::BeginFrameArgs& args) {
+ if (!delegate_)
+ return;
+ if (web_main_thread_scheduler_)
+ web_main_thread_scheduler_->WillBeginFrame(args);
+ delegate_->BeginMainFrame(args.frame_time);
+}
+
+void LayerTreeView::OnDeferMainFrameUpdatesChanged(bool status) {
+ if (!delegate_)
+ return;
+ delegate_->OnDeferMainFrameUpdatesChanged(status);
+}
+
+void LayerTreeView::OnDeferCommitsChanged(bool status) {
+ if (!delegate_)
+ return;
+ delegate_->OnDeferCommitsChanged(status);
+}
+
+void LayerTreeView::BeginMainFrameNotExpectedSoon() {
+ if (!delegate_ || !web_main_thread_scheduler_)
+ return;
+ web_main_thread_scheduler_->BeginFrameNotExpectedSoon();
+}
+
+void LayerTreeView::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {
+ if (!delegate_ || !web_main_thread_scheduler_)
+ return;
+ web_main_thread_scheduler_->BeginMainFrameNotExpectedUntil(time);
+}
+
+void LayerTreeView::UpdateLayerTreeHost() {
+ if (!delegate_)
+ return;
+ delegate_->UpdateVisualState();
+}
+
+void LayerTreeView::ApplyViewportChanges(
+ const cc::ApplyViewportChangesArgs& args) {
+ if (!delegate_)
+ return;
+ delegate_->ApplyViewportChanges(args);
+}
+
+void LayerTreeView::RecordManipulationTypeCounts(cc::ManipulationInfo info) {
+ if (!delegate_)
+ return;
+ delegate_->RecordManipulationTypeCounts(info);
+}
+
+void LayerTreeView::SendOverscrollEventFromImplSide(
+ const gfx::Vector2dF& overscroll_delta,
+ cc::ElementId scroll_latched_element_id) {
+ if (!delegate_)
+ return;
+ delegate_->SendOverscrollEventFromImplSide(overscroll_delta,
+ scroll_latched_element_id);
+}
+
+void LayerTreeView::SendScrollEndEventFromImplSide(
+ cc::ElementId scroll_latched_element_id) {
+ if (!delegate_)
+ return;
+ delegate_->SendScrollEndEventFromImplSide(scroll_latched_element_id);
+}
+
+void LayerTreeView::RequestNewLayerTreeFrameSink() {
+ if (!delegate_)
+ return;
+ // When the compositor is not visible it would not request a
+ // LayerTreeFrameSink so this is a race where it requested one on the
+ // compositor thread while becoming non-visible on the main thread. In that
+ // case, we can wait for it to become visible again before replying.
+ if (!layer_tree_host_->IsVisible()) {
+ layer_tree_frame_sink_request_failed_while_invisible_ = true;
+ return;
+ }
+
+ delegate_->RequestNewLayerTreeFrameSink(base::BindOnce(
+ &LayerTreeView::SetLayerTreeFrameSink, weak_factory_.GetWeakPtr()));
+}
+
+void LayerTreeView::DidInitializeLayerTreeFrameSink() {}
+
+void LayerTreeView::DidFailToInitializeLayerTreeFrameSink() {
+ if (!delegate_)
+ return;
+ // When the RenderWidget is made hidden while an async request for a
+ // LayerTreeFrameSink is being processed, then if it fails we would arrive
+ // here. Since the compositor does not request a LayerTreeFrameSink while not
+ // visible, we can delay trying again until becoming visible again.
+ if (!layer_tree_host_->IsVisible()) {
+ layer_tree_frame_sink_request_failed_while_invisible_ = true;
+ return;
+ }
+ layer_tree_frame_sink_request_failed_while_invisible_ = false;
+ layer_tree_host_->GetTaskRunnerProvider()->MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&LayerTreeView::RequestNewLayerTreeFrameSink,
+ weak_factory_.GetWeakPtr()));
+}
+
+void LayerTreeView::WillCommit() {
+ if (!delegate_)
+ return;
+ delegate_->WillCommitCompositorFrame();
+}
+
+void LayerTreeView::DidCommit(base::TimeTicks commit_start_time) {
+ if (!delegate_)
+ return;
+ delegate_->DidCommitCompositorFrame(commit_start_time);
+ if (web_main_thread_scheduler_)
+ web_main_thread_scheduler_->DidCommitFrameToCompositor();
+}
+
+void LayerTreeView::DidCommitAndDrawFrame() {
+ if (!delegate_)
+ return;
+ delegate_->DidCommitAndDrawCompositorFrame();
+}
+
+void LayerTreeView::DidCompletePageScaleAnimation() {
+ if (!delegate_)
+ return;
+ delegate_->DidCompletePageScaleAnimation();
+}
+
+void LayerTreeView::DidPresentCompositorFrame(
+ uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback) {
+ if (!delegate_)
+ return;
+ DCHECK(layer_tree_host_->GetTaskRunnerProvider()
+ ->MainThreadTaskRunner()
+ ->RunsTasksInCurrentSequence());
+ while (!presentation_callbacks_.empty()) {
+ const auto& front = presentation_callbacks_.begin();
+ if (viz::FrameTokenGT(front->first, frame_token))
+ break;
+ for (auto& callback : front->second)
+ std::move(callback).Run(feedback.timestamp);
+ presentation_callbacks_.erase(front);
+ }
+}
+
+void LayerTreeView::RecordStartOfFrameMetrics() {
+ if (!delegate_)
+ return;
+ delegate_->RecordStartOfFrameMetrics();
+}
+
+void LayerTreeView::RecordEndOfFrameMetrics(
+ base::TimeTicks frame_begin_time,
+ cc::ActiveFrameSequenceTrackers trackers) {
+ if (!delegate_)
+ return;
+ delegate_->RecordEndOfFrameMetrics(frame_begin_time, trackers);
+}
+
+std::unique_ptr<cc::BeginMainFrameMetrics>
+LayerTreeView::GetBeginMainFrameMetrics() {
+ if (!delegate_)
+ return nullptr;
+ return delegate_->GetBeginMainFrameMetrics();
+}
+
+void LayerTreeView::NotifyThroughputTrackerResults(
+ cc::CustomTrackerResults results) {
+ NOTREACHED();
+}
+
+void LayerTreeView::DidScheduleBeginMainFrame() {
+ if (!delegate_ || !web_main_thread_scheduler_)
+ return;
+ web_main_thread_scheduler_->DidScheduleBeginMainFrame();
+}
+
+void LayerTreeView::DidRunBeginMainFrame() {
+ if (!delegate_ || !web_main_thread_scheduler_)
+ return;
+ web_main_thread_scheduler_->DidRunBeginMainFrame();
+}
+
+void LayerTreeView::DidSubmitCompositorFrame() {}
+
+void LayerTreeView::DidLoseLayerTreeFrameSink() {}
+
+void LayerTreeView::AddPresentationCallback(
+ uint32_t frame_token,
+ base::OnceCallback<void(base::TimeTicks)> callback) {
+ DCHECK(delegate_);
+ if (!presentation_callbacks_.empty()) {
+ auto& previous = presentation_callbacks_.back();
+ uint32_t previous_frame_token = previous.first;
+ if (previous_frame_token == frame_token) {
+ previous.second.push_back(std::move(callback));
+ DCHECK_LE(previous.second.size(), 250u);
+ return;
+ }
+ DCHECK(viz::FrameTokenGT(frame_token, previous_frame_token));
+ }
+ std::vector<base::OnceCallback<void(base::TimeTicks)>> callbacks;
+ callbacks.push_back(std::move(callback));
+ presentation_callbacks_.push_back({frame_token, std::move(callbacks)});
+ DCHECK_LE(presentation_callbacks_.size(), 25u);
+}
+
+} // namespace blink