| // Copyright 2019 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 "android_webview/browser/gfx/root_frame_sink.h" |
| |
| #include "android_webview/browser/gfx/child_frame.h" |
| #include "android_webview/browser/gfx/display_scheduler_webview.h" |
| #include "android_webview/browser/gfx/viz_compositor_thread_runner_webview.h" |
| #include "base/no_destructor.h" |
| #include "base/trace_event/trace_event.h" |
| #include "components/viz/common/surfaces/frame_sink_id_allocator.h" |
| #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" |
| #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" |
| |
| namespace android_webview { |
| |
| namespace { |
| |
| viz::FrameSinkId AllocateParentSinkId() { |
| static base::NoDestructor<viz::FrameSinkIdAllocator> allocator(0u); |
| return allocator->NextFrameSinkId(); |
| } |
| |
| } // namespace |
| |
| class RootFrameSink::ChildCompositorFrameSink |
| : public viz::mojom::CompositorFrameSinkClient { |
| public: |
| ChildCompositorFrameSink(RootFrameSink* owner, |
| uint32_t layer_tree_frame_sink_id, |
| viz::FrameSinkId frame_sink_id) |
| : owner_(owner), |
| layer_tree_frame_sink_id_(layer_tree_frame_sink_id), |
| frame_sink_id_(frame_sink_id), |
| support_(std::make_unique<viz::CompositorFrameSinkSupport>( |
| this, |
| owner->GetFrameSinkManager(), |
| frame_sink_id, |
| false)) { |
| support_->SetBeginFrameSource(nullptr); |
| } |
| |
| void DidReceiveCompositorFrameAck( |
| const std::vector<viz::ReturnedResource>& resources) override { |
| ReclaimResources(resources); |
| } |
| void OnBeginFrame(const viz::BeginFrameArgs& args, |
| const viz::FrameTimingDetailsMap& feedbacks) override {} |
| void OnBeginFramePausedChanged(bool paused) override {} |
| void ReclaimResources( |
| const std::vector<viz::ReturnedResource>& resources) override { |
| owner_->ReturnResources(frame_sink_id_, layer_tree_frame_sink_id_, |
| resources); |
| } |
| |
| const viz::FrameSinkId frame_sink_id() { return frame_sink_id_; } |
| |
| uint32_t layer_tree_frame_sink_id() { return layer_tree_frame_sink_id_; } |
| |
| viz::CompositorFrameSinkSupport* support() { return support_.get(); } |
| gfx::Size size() { return size_; } |
| |
| void SubmitCompositorFrame( |
| const viz::LocalSurfaceId& local_surface_id, |
| viz::CompositorFrame frame, |
| base::Optional<viz::HitTestRegionList> hit_test_region_list) { |
| size_ = frame.size_in_pixels(); |
| support()->SubmitCompositorFrame(local_surface_id, std::move(frame), |
| std::move(hit_test_region_list)); |
| } |
| |
| private: |
| RootFrameSink* const owner_; |
| const uint32_t layer_tree_frame_sink_id_; |
| const viz::FrameSinkId frame_sink_id_; |
| std::unique_ptr<viz::CompositorFrameSinkSupport> support_; |
| gfx::Size size_; |
| }; |
| |
| RootFrameSink::RootFrameSink(RootFrameSinkClient* client) |
| : root_frame_sink_id_(AllocateParentSinkId()), client_(client) { |
| constexpr bool is_root = true; |
| GetFrameSinkManager()->RegisterFrameSinkId(root_frame_sink_id_, |
| false /* report_activationa */); |
| support_ = std::make_unique<viz::CompositorFrameSinkSupport>( |
| this, GetFrameSinkManager(), root_frame_sink_id_, is_root); |
| begin_frame_source_ = std::make_unique<viz::ExternalBeginFrameSource>(this); |
| GetFrameSinkManager()->RegisterBeginFrameSource(begin_frame_source_.get(), |
| root_frame_sink_id_); |
| } |
| |
| RootFrameSink::~RootFrameSink() { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| GetFrameSinkManager()->UnregisterBeginFrameSource(begin_frame_source_.get()); |
| begin_frame_source_.reset(); |
| support_.reset(); |
| GetFrameSinkManager()->InvalidateFrameSinkId(root_frame_sink_id_); |
| } |
| |
| viz::FrameSinkManagerImpl* RootFrameSink::GetFrameSinkManager() { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| // FrameSinkManagerImpl is global and not owned by this class, which is |
| // per-AwContents. |
| return VizCompositorThreadRunnerWebView::GetInstance()->GetFrameSinkManager(); |
| } |
| |
| void RootFrameSink::DidReceiveCompositorFrameAck( |
| const std::vector<viz::ReturnedResource>& resources) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| ReclaimResources(resources); |
| } |
| |
| void RootFrameSink::ReclaimResources( |
| const std::vector<viz::ReturnedResource>& resources) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| // Root surface should have no resources to return. |
| CHECK(resources.empty()); |
| } |
| |
| void RootFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| TRACE_EVENT_INSTANT1("android_webview", "RootFrameSink::OnNeedsBeginFrames", |
| TRACE_EVENT_SCOPE_THREAD, "needs_begin_frames", |
| needs_begin_frames); |
| needs_begin_frames_ = needs_begin_frames; |
| if (client_) |
| client_->SetNeedsBeginFrames(needs_begin_frames); |
| } |
| |
| void RootFrameSink::AddChildFrameSinkId(const viz::FrameSinkId& frame_sink_id) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| child_frame_sink_ids_.insert(frame_sink_id); |
| GetFrameSinkManager()->RegisterFrameSinkHierarchy(root_frame_sink_id_, |
| frame_sink_id); |
| } |
| |
| void RootFrameSink::RemoveChildFrameSinkId( |
| const viz::FrameSinkId& frame_sink_id) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| child_frame_sink_ids_.erase(frame_sink_id); |
| GetFrameSinkManager()->UnregisterFrameSinkHierarchy(root_frame_sink_id_, |
| frame_sink_id); |
| } |
| |
| bool RootFrameSink::BeginFrame(const viz::BeginFrameArgs& args, |
| bool had_input_event) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| |
| // This handles only invalidation of sub clients, root client invalidation is |
| // handled by Invalidate() from cc to |SynchronousLayerTreeFrameSink|. So we |
| // return false unless we already have damage. |
| bool invalidate = had_input_event || needs_draw_; |
| |
| TRACE_EVENT_INSTANT1("android_webview", "RootFrameSink::BeginFrame", |
| TRACE_EVENT_SCOPE_THREAD, "invalidate", invalidate); |
| |
| if (needs_begin_frames_) { |
| begin_frame_source_->OnBeginFrame(args); |
| } |
| |
| return invalidate; |
| } |
| |
| void RootFrameSink::SetBeginFrameSourcePaused(bool paused) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| begin_frame_source_->OnSetBeginFrameSourcePaused(paused); |
| } |
| |
| void RootFrameSink::SetNeedsDraw(bool needs_draw) { |
| needs_draw_ = needs_draw; |
| |
| // It's possible that client submitted last frame and unsubscribed from |
| // BeginFrames, but we haven't draw it yet. |
| if (!needs_begin_frames_ && needs_draw) { |
| if (client_) |
| client_->Invalidate(); |
| } |
| } |
| |
| bool RootFrameSink::IsChildSurface(const viz::FrameSinkId& frame_sink_id) { |
| return child_frame_sink_ids_.contains(frame_sink_id); |
| } |
| |
| void RootFrameSink::ReturnResources( |
| viz::FrameSinkId frame_sink_id, |
| uint32_t layer_tree_frame_sink_id, |
| std::vector<viz::ReturnedResource> resources) { |
| if (client_) |
| client_->ReturnResources(frame_sink_id, layer_tree_frame_sink_id, |
| std::move(resources)); |
| } |
| |
| void RootFrameSink::DettachClient() { |
| client_ = nullptr; |
| } |
| |
| void RootFrameSink::SubmitChildCompositorFrame(ChildFrame* child_frame) { |
| DCHECK(child_frame->frame); |
| if (!child_sink_support_ || |
| child_sink_support_->frame_sink_id() != child_frame->frame_sink_id || |
| child_sink_support_->layer_tree_frame_sink_id() != |
| child_frame->layer_tree_frame_sink_id) { |
| child_sink_support_.reset(); |
| |
| child_sink_support_ = std::make_unique<ChildCompositorFrameSink>( |
| this, child_frame->layer_tree_frame_sink_id, |
| child_frame->frame_sink_id); |
| } |
| |
| child_sink_support_->SubmitCompositorFrame( |
| child_frame->local_surface_id, std::move(*child_frame->frame), |
| std::move(child_frame->hit_test_region_list)); |
| child_frame->frame.reset(); |
| } |
| |
| viz::FrameTimingDetailsMap RootFrameSink::TakeChildFrameTimingDetailsMap() { |
| if (child_sink_support_) |
| return child_sink_support_->support()->TakeFrameTimingDetailsMap(); |
| return viz::FrameTimingDetailsMap(); |
| } |
| |
| gfx::Size RootFrameSink::GetChildFrameSize() { |
| // TODO(vasilyt): This is not going to work with VizFrameSubmissionForWebView. |
| if (child_sink_support_) { |
| return child_sink_support_->size(); |
| } |
| return gfx::Size(); |
| } |
| |
| } // namespace android_webview |