| // Copyright 2016 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 "components/exo/layer_tree_frame_sink_holder.h" |
| |
| #include "base/stl_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "cc/trees/layer_tree_frame_sink.h" |
| #include "components/exo/surface_tree_host.h" |
| #include "components/viz/common/hit_test/hit_test_region_list.h" |
| #include "components/viz/common/resources/returned_resource.h" |
| |
| namespace exo { |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LayerTreeFrameSinkHolder, public: |
| |
| LayerTreeFrameSinkHolder::LayerTreeFrameSinkHolder( |
| SurfaceTreeHost* surface_tree_host, |
| std::unique_ptr<cc::LayerTreeFrameSink> frame_sink) |
| : surface_tree_host_(surface_tree_host), |
| frame_sink_(std::move(frame_sink)), |
| weak_ptr_factory_(this) { |
| frame_sink_->BindToClient(this); |
| } |
| |
| LayerTreeFrameSinkHolder::~LayerTreeFrameSinkHolder() { |
| if (frame_sink_) |
| frame_sink_->DetachFromClient(); |
| |
| if (lifetime_manager_) |
| lifetime_manager_->RemoveObserver(this); |
| } |
| |
| // static |
| void LayerTreeFrameSinkHolder::DeleteWhenLastResourceHasBeenReclaimed( |
| std::unique_ptr<LayerTreeFrameSinkHolder> holder) { |
| if (holder->last_frame_size_in_pixels_.IsEmpty()) { |
| // Delete sink holder immediately if no frame has been submitted. |
| DCHECK(holder->last_frame_resources_.empty()); |
| return; |
| } |
| |
| // Submit an empty frame to ensure that pending release callbacks will be |
| // processed in a finite amount of time. |
| viz::CompositorFrame frame; |
| frame.metadata.begin_frame_ack.source_id = |
| viz::BeginFrameArgs::kManualSourceId; |
| frame.metadata.begin_frame_ack.sequence_number = |
| viz::BeginFrameArgs::kStartingFrameNumber; |
| frame.metadata.begin_frame_ack.has_damage = true; |
| frame.metadata.frame_token = ++holder->next_frame_token_; |
| frame.metadata.device_scale_factor = holder->last_frame_device_scale_factor_; |
| frame.metadata.local_surface_id_allocation_time = |
| holder->last_local_surface_id_allocation_time_; |
| std::unique_ptr<viz::RenderPass> pass = viz::RenderPass::Create(); |
| pass->SetNew(1, gfx::Rect(holder->last_frame_size_in_pixels_), |
| gfx::Rect(holder->last_frame_size_in_pixels_), gfx::Transform()); |
| frame.render_pass_list.push_back(std::move(pass)); |
| holder->last_frame_resources_.clear(); |
| holder->frame_sink_->SubmitCompositorFrame(std::move(frame), |
| /*hit_test_data_changed=*/true, |
| /*show_hit_test_borders=*/false); |
| |
| // Delete sink holder immediately if not waiting for resources to be |
| // reclaimed. |
| if (holder->resource_manager_.HasNoCallbacks()) |
| return; |
| |
| WMHelper::LifetimeManager* lifetime_manager = |
| WMHelper::GetInstance()->GetLifetimeManager(); |
| holder->lifetime_manager_ = lifetime_manager; |
| holder->surface_tree_host_ = nullptr; |
| |
| // If we have pending release callbacks then extend the lifetime of holder |
| // by adding it as a LifetimeManager observer. The holder will delete itself |
| // when LifetimeManager shuts down or when all pending release callbacks have |
| // been called. |
| lifetime_manager->AddObserver(holder.release()); |
| } |
| |
| void LayerTreeFrameSinkHolder::SubmitCompositorFrame( |
| viz::CompositorFrame frame) { |
| last_frame_size_in_pixels_ = frame.size_in_pixels(); |
| last_frame_device_scale_factor_ = frame.metadata.device_scale_factor; |
| last_local_surface_id_allocation_time_ = |
| frame.metadata.local_surface_id_allocation_time; |
| last_frame_resources_.clear(); |
| for (auto& resource : frame.resource_list) |
| last_frame_resources_.push_back(resource.id); |
| frame_sink_->SubmitCompositorFrame(std::move(frame), |
| /*hit_test_data_changed=*/true, |
| /*show_hit_test_borders=*/false); |
| } |
| |
| void LayerTreeFrameSinkHolder::DidNotProduceFrame( |
| const viz::BeginFrameAck& ack) { |
| frame_sink_->DidNotProduceFrame(ack); |
| } |
| |
| base::WeakPtr<LayerTreeFrameSinkHolder> LayerTreeFrameSinkHolder::GetWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // cc::LayerTreeFrameSinkClient overrides: |
| |
| base::Optional<viz::HitTestRegionList> |
| LayerTreeFrameSinkHolder::BuildHitTestData() { |
| return {}; |
| } |
| |
| void LayerTreeFrameSinkHolder::ReclaimResources( |
| const std::vector<viz::ReturnedResource>& resources) { |
| for (auto& resource : resources) { |
| // Skip resources that are also in last frame. This can happen if |
| // the frame sink id changed. |
| if (base::ContainsValue(last_frame_resources_, resource.id)) { |
| continue; |
| } |
| resource_manager_.ReclaimResource(resource); |
| } |
| |
| if (lifetime_manager_ && resource_manager_.HasNoCallbacks()) |
| ScheduleDelete(); |
| } |
| |
| void LayerTreeFrameSinkHolder::DidReceiveCompositorFrameAck() { |
| if (surface_tree_host_) |
| surface_tree_host_->DidReceiveCompositorFrameAck(); |
| } |
| |
| void LayerTreeFrameSinkHolder::DidPresentCompositorFrame( |
| uint32_t presentation_token, |
| const gfx::PresentationFeedback& feedback) { |
| if (surface_tree_host_) |
| surface_tree_host_->DidPresentCompositorFrame(presentation_token, feedback); |
| } |
| |
| void LayerTreeFrameSinkHolder::DidLoseLayerTreeFrameSink() { |
| last_frame_resources_.clear(); |
| resource_manager_.ClearAllCallbacks(); |
| |
| if (lifetime_manager_) |
| ScheduleDelete(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LayerTreeFrameSinkHolder, private: |
| |
| void LayerTreeFrameSinkHolder::ScheduleDelete() { |
| if (delete_pending_) |
| return; |
| delete_pending_ = true; |
| base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); |
| } |
| |
| void LayerTreeFrameSinkHolder::OnDestroyed() { |
| lifetime_manager_->RemoveObserver(this); |
| lifetime_manager_ = nullptr; |
| |
| // Make sure frame sink never outlives the shell. |
| frame_sink_->DetachFromClient(); |
| frame_sink_.reset(); |
| ScheduleDelete(); |
| } |
| |
| } // namespace exo |