blob: ded1687c562d18205ea467989fac90ce3015d091 [file] [log] [blame]
// 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)) {
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) {
// Delete immediately if LayerTreeFrameSink was already lost.
if (holder->is_lost_)
return;
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) {
DCHECK(!is_lost_);
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) {
DCHECK(!is_lost_);
frame_sink_->DidNotProduceFrame(ack);
}
////////////////////////////////////////////////////////////////////////////////
// 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();
is_lost_ = true;
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