// 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 "cc/surfaces/surface_dependency_tracker.h" #include "cc/surfaces/surface.h" #include "cc/surfaces/surface_info.h" #include "cc/surfaces/surface_manager.h" namespace cc { namespace { constexpr uint32_t kMaxBeginFrameCount = 4; } SurfaceDependencyTracker::SurfaceDependencyTracker( SurfaceManager* surface_manager, BeginFrameSource* begin_frame_source) : surface_manager_(surface_manager), begin_frame_source_(begin_frame_source) { surface_manager_->AddObserver(this); begin_frame_source_->AddObserver(this); } SurfaceDependencyTracker::~SurfaceDependencyTracker() { surface_manager_->RemoveObserver(this); begin_frame_source_->RemoveObserver(this); for (Surface* pending_surface : pending_surfaces_) pending_surface->RemoveObserver(this); pending_surfaces_.clear(); } void SurfaceDependencyTracker::RequestSurfaceResolution(Surface* surface) { DCHECK(surface->HasPendingFrame()); const CompositorFrame& pending_frame = surface->GetPendingFrame(); bool needs_begin_frame = pending_frame.metadata.can_activate_before_dependencies; // Referenced surface IDs that aren't currently known to the surface manager // or do not have an active CompsotiorFrame block this frame. for (const SurfaceId& surface_id : pending_frame.metadata.referenced_surfaces) { Surface* surface_dependency = surface_manager_->GetSurfaceForId(surface_id); if (!surface_dependency || !surface_dependency->HasActiveFrame()) blocked_surfaces_[surface_id].insert(surface); } if (!pending_surfaces_.count(surface)) { surface->AddObserver(this); pending_surfaces_.insert(surface); } if (needs_begin_frame && !frames_since_deadline_set_) frames_since_deadline_set_ = 0; } void SurfaceDependencyTracker::OnBeginFrame(const BeginFrameArgs& args) { // If no deadline is set then we have nothing to do. if (!frames_since_deadline_set_) return; // TODO(fsamuel, kylechar): We have a single global deadline here. We should // scope deadlines to surface subtrees. We cannot do that until // SurfaceReferences have been fully implemented // (see https://crbug.com/689719). last_begin_frame_args_ = args; // Nothing to do if we haven't hit a deadline yet. if (++(*frames_since_deadline_set_) != kMaxBeginFrameCount) return; // Activate all surfaces that respect the deadline. PendingSurfaceSet pending_surfaces(pending_surfaces_); for (Surface* pending_surface : pending_surfaces) pending_surface->ActivatePendingFrameForDeadline(); frames_since_deadline_set_.reset(); } const BeginFrameArgs& SurfaceDependencyTracker::LastUsedBeginFrameArgs() const { return last_begin_frame_args_; } void SurfaceDependencyTracker::OnBeginFrameSourcePausedChanged(bool paused) {} void SurfaceDependencyTracker::OnReferencedSurfacesChanged( Surface* surface, const std::vector* active_referenced_surfaces, const std::vector* pending_referenced_surfaces) {} void SurfaceDependencyTracker::OnSurfaceDiscarded(Surface* surface) { // If the surface being destroyed doesn't have a pending frame then we have // nothing to do here. if (!surface->HasPendingFrame()) return; const CompositorFrame& pending_frame = surface->GetPendingFrame(); DCHECK(!pending_frame.metadata.referenced_surfaces.empty()); for (const SurfaceId& surface_id : pending_frame.metadata.referenced_surfaces) { auto it = blocked_surfaces_.find(surface_id); if (it == blocked_surfaces_.end()) continue; auto& pending_surface_set = it->second; auto pending_surface_it = pending_surface_set.find(surface); if (pending_surface_it != pending_surface_set.end()) { pending_surface_set.erase(surface); if (pending_surface_set.empty()) blocked_surfaces_.erase(surface_id); } } if (blocked_surfaces_.empty()) frames_since_deadline_set_.reset(); pending_surfaces_.erase(surface); surface->RemoveObserver(this); // Pretend that the discarded surface's SurfaceId is now available to unblock // dependencies because we now know the surface will never activate. NotifySurfaceIdAvailable(surface->surface_id()); } void SurfaceDependencyTracker::OnSurfaceActivated(Surface* surface) { surface->RemoveObserver(this); pending_surfaces_.erase(surface); NotifySurfaceIdAvailable(surface->surface_id()); } void SurfaceDependencyTracker::OnSurfaceDependenciesChanged( Surface* surface, const SurfaceDependencies& added_dependencies, const SurfaceDependencies& removed_dependencies) { // Update the |blocked_surfaces_| map with the changes in dependencies. for (const SurfaceId& surface_id : added_dependencies) blocked_surfaces_[surface_id].insert(surface); for (const SurfaceId& surface_id : removed_dependencies) { auto it = blocked_surfaces_.find(surface_id); it->second.erase(surface); if (it->second.empty()) blocked_surfaces_.erase(it); } // If there are no more dependencies to resolve then we don't need to have a // deadline. if (blocked_surfaces_.empty()) frames_since_deadline_set_.reset(); } // SurfaceObserver implementation: void SurfaceDependencyTracker::OnSurfaceCreated( const SurfaceInfo& surface_info) { // This is called when a Surface has an activated frame for the first time. // SurfaceDependencyTracker only observes Surfaces that contain pending // frames. SurfaceDependencyTracker becomes aware of CompositorFrames that // activate immediately go through here. NotifySurfaceIdAvailable(surface_info.id()); } void SurfaceDependencyTracker::OnSurfaceDamaged(const SurfaceId& surface_id, bool* changed) {} void SurfaceDependencyTracker::NotifySurfaceIdAvailable( const SurfaceId& surface_id) { auto it = blocked_surfaces_.find(surface_id); if (it == blocked_surfaces_.end()) return; // Unblock surfaces that depend on this |surface_id|. PendingSurfaceSet blocked_pending_surface_set(it->second); blocked_surfaces_.erase(it); // If there are no more blockers in the system, then we no longer need to // have a deadline. if (blocked_surfaces_.empty()) frames_since_deadline_set_.reset(); // Tell each surface about the availability of its blocker. for (Surface* blocked_pending_surface : blocked_pending_surface_set) blocked_pending_surface->NotifySurfaceIdAvailable(surface_id); } } // namespace cc