blob: 2e2d744e031e77ad8ceb750e7b60ef6e05b8f6fc [file] [log] [blame]
// 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/metrics/web_vital_metrics.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/renderer/platform/graphics/dark_mode_filter.h"
#include "third_party/blink/renderer/platform/graphics/dark_mode_settings_builder.h"
#include "third_party/blink/renderer/platform/graphics/raster_dark_mode_filter_impl.h"
#include "ui/gfx/presentation_feedback.h"
namespace cc {
class Layer;
}
namespace blink {
LayerTreeView::LayerTreeView(LayerTreeViewDelegate* delegate,
scheduler::WebThreadScheduler* scheduler)
: web_main_thread_scheduler_(scheduler),
animation_host_(cc::AnimationHost::CreateMainInstance()),
dark_mode_filter_(std::make_unique<RasterDarkModeFilterImpl>(
GetCurrentDarkModeSettings())),
delegate_(delegate) {}
LayerTreeView::~LayerTreeView() = default;
void LayerTreeView::Initialize(
const cc::LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_thread,
scoped_refptr<base::SingleThreadTaskRunner> compositor_thread,
cc::TaskGraphRunner* task_graph_runner,
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 = std::move(main_thread);
params.mutator_host = animation_host_.get();
params.dark_mode_filter = dark_mode_filter_.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(std::move(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::UpdateCompositorScrollState(
const cc::CompositorCommitData& commit_data) {
if (!delegate_)
return;
delegate_->UpdateCompositorScrollState(commit_data);
}
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();
}
std::unique_ptr<cc::WebVitalMetrics> LayerTreeView::GetWebVitalMetrics() {
if (!delegate_)
return nullptr;
return delegate_->GetWebVitalMetrics();
}
void LayerTreeView::NotifyThroughputTrackerResults(
cc::CustomTrackerResults results) {
NOTREACHED();
}
void LayerTreeView::DidObserveFirstScrollDelay(
base::TimeDelta first_scroll_delay,
base::TimeTicks first_scroll_timestamp) {
if (!delegate_) {
return;
}
delegate_->DidObserveFirstScrollDelay(first_scroll_delay,
first_scroll_timestamp);
}
void LayerTreeView::RunPaintBenchmark(int repeat_count,
cc::PaintBenchmarkResult& result) {
if (delegate_)
delegate_->RunPaintBenchmark(repeat_count, result);
}
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