Chromium Code Reviews| Index: cc/surfaces/surface_dependency_tracker.cc |
| diff --git a/cc/surfaces/surface_dependency_tracker.cc b/cc/surfaces/surface_dependency_tracker.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2f7b3580f2121067a3f8f92e5b06ff0b46c115a5 |
| --- /dev/null |
| +++ b/cc/surfaces/surface_dependency_tracker.cc |
| @@ -0,0 +1,189 @@ |
| +// 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); |
| +} |
| + |
| +void SurfaceDependencyTracker::RequestSurfaceResolution(Surface* surface) { |
| + DCHECK(surface->HasPendingFrame()); |
| + |
| + const CompositorFrame& pending_frame = surface->GetPendingFrame(); |
| + bool needs_begin_frame = |
| + pending_frame.metadata.can_activate_without_dependencies; |
|
vmpstr
2017/02/08 19:25:40
oh, maybe "can_activate_before_dependencies" :D
Fady Samuel
2017/02/08 23:39:58
Done.
|
| + |
| + // 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_dep = surface_manager_->GetSurfaceForId(surface_id); |
|
vmpstr
2017/02/08 19:25:39
s/surface_dep/dependency/
Fady Samuel
2017/02/08 23:39:58
Done.
|
| + if (!surface_dep || !surface_dep->HasActiveFrame()) |
| + blocking_surfaces_[surface_id].insert(surface); |
|
vmpstr
2017/02/08 19:25:40
this to me says if the dependency isn't satisfied,
Fady Samuel
2017/02/08 23:39:58
If the dependency isn't satisfied, then it blocks
|
| + } |
| + |
| + if (!pending_surfaces_.count(surface)) { |
| + surface->AddObserver(this); |
| + pending_surfaces_.insert(surface); |
| + } |
| + |
| + if (needs_begin_frame) { |
|
vmpstr
2017/02/08 19:25:40
When can RequestSurfaceResolution be called? My wo
Fady Samuel
2017/02/08 23:39:58
Done.
|
| + has_deadline_ = true; |
| + begin_frame_count_ = 0; |
| + } |
| +} |
| + |
| +void SurfaceDependencyTracker::OnBeginFrame(const BeginFrameArgs& args) { |
| + // If no deadline is set then we have nothing to do. |
| + if (!has_deadline_) |
| + 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 (++begin_frame_count_ != kMaxBeginFrameCount) |
| + return; |
| + |
| + // Activate all surfaces that respect the deadline. |
| + PendingSurfaceSet pending_surfaces(pending_surfaces_); |
| + for (Surface* pending_surface : pending_surfaces) |
| + pending_surface->ActivatePendingFrameForDeadline(); |
| + |
| + has_deadline_ = false; |
| + begin_frame_count_ = 0; |
|
vmpstr
2017/02/08 19:25:39
You might hate the idea, but having a bool and an
Fady Samuel
2017/02/08 23:39:58
added base::Optional<uint32_t> frames_since_deadli
|
| +} |
| + |
| +const BeginFrameArgs& SurfaceDependencyTracker::LastUsedBeginFrameArgs() const { |
| + return last_begin_frame_args_; |
| +} |
| + |
| +void SurfaceDependencyTracker::OnBeginFrameSourcePausedChanged(bool paused) {} |
| + |
| +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 = blocking_surfaces_.find(surface_id); |
| + if (it == blocking_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()) |
| + blocking_surfaces_.erase(surface_id); |
| + } |
| + } |
| + |
| + if (blocking_surfaces_.empty()) { |
| + has_deadline_ = false; |
| + begin_frame_count_ = 0; |
| + } |
| + |
| + pending_surfaces_.erase(surface); |
| + surface->RemoveObserver(this); |
| + |
| + // TODO(fsamuel): We should consider removing this surface as a dependency on |
| + // other surfaces. This dependency will be removed when the deadline hits |
| + // anyway but maybe we should try to actiate these frames early (see |
| + // https://crbug.com/689725). |
| +} |
| + |
| +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 |blocking_surfaces_| map with the changes in dependencies. |
| + for (const SurfaceId& surface_id : added_dependencies) |
| + blocking_surfaces_[surface_id].insert(surface); |
| + |
| + for (const SurfaceId& surface_id : removed_dependencies) { |
| + auto it = blocking_surfaces_.find(surface_id); |
| + it->second.erase(surface); |
| + if (it->second.empty()) |
| + blocking_surfaces_.erase(it); |
| + } |
| + |
| + // If there are no more dependencies to resolve then we don't need to have a |
| + // deadline. |
| + if (blocking_surfaces_.empty()) { |
| + has_deadline_ = false; |
| + begin_frame_count_ = 0; |
| + } |
| +} |
| + |
| +// 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 = blocking_surfaces_.find(surface_id); |
| + if (it == blocking_surfaces_.end()) |
| + return; |
| + |
| + // Unblock surfaces that depend on this pending surface. |
| + PendingSurfaceSet blocked_pending_surface_set(it->second); |
| + blocking_surfaces_.erase(it); |
| + // If there are no more blockers in the system, then we no longer need to |
| + // have a deadline. |
| + if (blocking_surfaces_.empty()) { |
| + has_deadline_ = false; |
| + begin_frame_count_ = 0; |
| + } |
| + |
| + // 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 |