blob: 60b2c28e1168b9bd207accbb4b6e36d2a0b239b2 [file] [log] [blame]
// 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 "components/viz/service/display/display_damage_tracker.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/display/surface_aggregator.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_manager.h"
namespace viz {
DisplayDamageTracker::DisplayDamageTracker(SurfaceManager* surface_manager,
SurfaceAggregator* aggregator)
: surface_manager_(surface_manager), aggregator_(aggregator) {
DCHECK(surface_manager_);
DCHECK(aggregator_);
surface_manager_->AddObserver(this);
}
DisplayDamageTracker::~DisplayDamageTracker() {
surface_manager_->RemoveObserver(this);
}
void DisplayDamageTracker::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void DisplayDamageTracker::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void DisplayDamageTracker::SetRootFrameMissing(bool missing) {
TRACE_EVENT1("viz", "DisplayDamageTracker::SetRootFrameMissing", "missing",
missing);
if (root_frame_missing_ == missing)
return;
root_frame_missing_ = missing;
NotifyRootFrameMissing(missing);
}
void DisplayDamageTracker::SetNewRootSurface(const SurfaceId& root_surface_id) {
TRACE_EVENT0("viz", "DisplayDamageTracker::SetNewRootSurface");
root_surface_id_ = root_surface_id;
UpdateRootFrameMissing();
SetRootSurfaceDamaged();
}
void DisplayDamageTracker::SetRootSurfaceDamaged() {
BeginFrameAck ack;
ack.has_damage = true;
ProcessSurfaceDamage(root_surface_id_, ack, true);
}
bool DisplayDamageTracker::IsRootSurfaceValid() const {
return root_surface_id_.is_valid();
}
void DisplayDamageTracker::DisplayResized() {
expecting_root_surface_damage_because_of_resize_ = true;
// Technically we don't have any damage yet, but we need to draw after resize,
// so we report display damaged here.
NotifyDisplayDamaged(root_surface_id_);
}
void DisplayDamageTracker::ProcessSurfaceDamage(const SurfaceId& surface_id,
const BeginFrameAck& ack,
bool display_damaged) {
TRACE_EVENT1("viz", "DisplayDamageTracker::SurfaceDamaged", "surface_id",
surface_id.ToString());
if (surface_id == root_surface_id_)
expecting_root_surface_damage_because_of_resize_ = false;
// Update surface state.
bool valid_ack = ack.frame_id.IsSequenceValid();
if (valid_ack) {
auto it = surface_states_.find(surface_id);
// Ignore stray acknowledgments for prior BeginFrames, to ensure we don't
// override a newer sequence number in the surface state. We may receive
// such stray acks e.g. when a CompositorFrame activates in a later
// BeginFrame than it was created.
if (it != surface_states_.end() &&
!it->second.last_ack.frame_id.IsNextInSequenceTo(ack.frame_id)) {
it->second.last_ack = ack;
} else {
valid_ack = false;
}
}
if (display_damaged) {
NotifyDisplayDamaged(surface_id);
} else if (valid_ack) {
NotifyPendingSurfacesChanged();
}
}
bool DisplayDamageTracker::SurfaceHasUnackedFrame(
const SurfaceId& surface_id) const {
Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
if (!surface)
return false;
return surface->HasUnackedActiveFrame();
}
bool DisplayDamageTracker::HasPendingSurfaces(
const BeginFrameArgs& begin_frame_args) {
for (auto& entry : surface_states_) {
const SurfaceId& surface_id = entry.first;
const SurfaceBeginFrameState& state = entry.second;
// Surface is ready if it hasn't received the current BeginFrame or receives
// BeginFrames from a different source and thus likely belongs to a
// different surface hierarchy.
if (!state.last_args.IsValid() ||
state.last_args.frame_id != begin_frame_args.frame_id) {
continue;
}
// Surface is ready if it has acknowledged the current BeginFrame.
if (state.last_ack.frame_id == begin_frame_args.frame_id) {
continue;
}
// Surface is ready if there is an unacked active CompositorFrame, because
// its producer is CompositorFrameAck throttled.
if (SurfaceHasUnackedFrame(surface_id))
continue;
TRACE_EVENT_INSTANT2("viz", "DisplayDamageTracker::HasPendingSurfaces",
TRACE_EVENT_SCOPE_THREAD, "has_pending_surfaces", true,
"pending_surface_id", surface_id.ToString());
return true;
}
TRACE_EVENT_INSTANT1("viz", "DisplayDamageTracker::HasPendingSurfaces",
TRACE_EVENT_SCOPE_THREAD, "has_pending_surfaces", false);
return false;
}
void DisplayDamageTracker::OnSurfaceMarkedForDestruction(
const SurfaceId& surface_id) {
auto it = surface_states_.find(surface_id);
if (it == surface_states_.end())
return;
surface_states_.erase(it);
NotifyPendingSurfacesChanged();
}
bool DisplayDamageTracker::OnSurfaceDamaged(const SurfaceId& surface_id,
const BeginFrameAck& ack) {
bool display_damaged = false;
if (ack.has_damage) {
display_damaged =
aggregator_->NotifySurfaceDamageAndCheckForDisplayDamage(surface_id);
if (surface_id == root_surface_id_)
display_damaged = true;
if (display_damaged)
surfaces_to_ack_on_next_draw_.push_back(surface_id);
}
if (surface_id == root_surface_id_)
UpdateRootFrameMissing();
ProcessSurfaceDamage(surface_id, ack, display_damaged);
return display_damaged;
}
void DisplayDamageTracker::OnSurfaceDestroyed(const SurfaceId& surface_id) {
TRACE_EVENT0("viz", "DisplayDamageTracker::SurfaceDestroyed");
aggregator_->ReleaseResources(surface_id);
}
void DisplayDamageTracker::OnSurfaceDamageExpected(const SurfaceId& surface_id,
const BeginFrameArgs& args) {
TRACE_EVENT1("viz", "DisplayDamageTracker::SurfaceDamageExpected",
"surface_id", surface_id.ToString());
// Insert a new state for the surface if we don't know of it yet. We don't use
// OnSurfaceCreated() for this, because it may not be called if a
// CompositorFrameSinkSupport starts submitting frames to a different Display,
// but continues using the same Surface, or if a Surface does not activate its
// first CompositorFrame immediately.
surface_states_[surface_id].last_args = args;
NotifyPendingSurfacesChanged();
}
void DisplayDamageTracker::UpdateRootFrameMissing() {
Surface* surface = surface_manager_->GetSurfaceForId(root_surface_id_);
SetRootFrameMissing(!surface || !surface->HasActiveFrame());
}
void DisplayDamageTracker::RunDrawCallbacks() {
for (const auto& surface_id : surfaces_to_ack_on_next_draw_) {
Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
if (surface)
surface->SendAckToClient();
}
surfaces_to_ack_on_next_draw_.clear();
// |surfaces_to_ack_on_next_draw_| does not cover surfaces that are being
// embedded for the first time, so also go through SurfaceAggregator's list.
for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
if (surface)
surface->SendAckToClient();
}
}
void DisplayDamageTracker::NotifyDisplayDamaged(SurfaceId surface_id) {
for (auto& observer : observers_)
observer.OnDisplayDamaged(surface_id);
}
void DisplayDamageTracker::NotifyRootFrameMissing(bool missing) {
for (auto& observer : observers_)
observer.OnRootFrameMissing(missing);
}
void DisplayDamageTracker::NotifyPendingSurfacesChanged() {
for (auto& observer : observers_)
observer.OnPendingSurfacesChanged();
}
} // namespace viz