Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(366)

Unified Diff: cc/surfaces/surface.cc

Issue 2676373004: Implement service-side surface synchronization (Closed)
Patch Set: Better unit test name Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: cc/surfaces/surface.cc
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index dd41c3de17b9ac999f29effb6fb84459ec1e3fc5..57e3a3c98f3c47e4a35a5256a168900be8d0794b 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -12,6 +12,7 @@
#include "cc/base/container_util.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/copy_output_request.h"
+#include "cc/surfaces/pending_frame_observer.h"
kylechar 2017/02/09 15:50:31 Duplicate include.
#include "cc/surfaces/surface_factory.h"
#include "cc/surfaces/surface_id_allocator.h"
#include "cc/surfaces/surface_manager.h"
@@ -31,11 +32,18 @@ Surface::Surface(const SurfaceId& id, base::WeakPtr<SurfaceFactory> factory)
Surface::~Surface() {
ClearCopyRequests();
- if (current_frame_ && factory_) {
- UnrefFrameResources(*current_frame_);
+ if (factory_) {
+ if (pending_frame_)
+ UnrefFrameResources(*pending_frame_);
+ if (active_frame_)
+ UnrefFrameResources(*active_frame_);
}
if (!draw_callback_.is_null())
draw_callback_.Run();
+
+ for (auto& observer : observers_)
+ observer.OnSurfaceDiscarded(this);
+ observers_.Clear();
}
void Surface::SetPreviousFrameSurface(Surface* surface) {
@@ -45,94 +53,221 @@ void Surface::SetPreviousFrameSurface(Surface* surface) {
}
void Surface::QueueFrame(CompositorFrame frame, const DrawCallback& callback) {
+ base::Optional<CompositorFrame> previous_pending_frame =
+ std::move(pending_frame_);
+ pending_frame_.reset();
+
+ UpdateBlockingSurfaces(previous_pending_frame, frame);
+
+ if (!blocking_surfaces_.empty()) {
+ pending_frame_ = std::move(frame);
+ if (pending_frame_) {
+ factory_->ReceiveFromChild(pending_frame_->resource_list);
+ // Ask the surface manager to inform |this| when its dependencies are
+ // resolved.
+ factory_->manager()->RequestSurfaceResolution(this);
+ }
+ } else {
+ // If there are no blockers, then immediately activate the frame.
+ ActivateFrame(std::move(frame));
+ }
+
+ // Returns resources for the previous pending frame.
+ if (previous_pending_frame)
+ UnrefFrameResources(*previous_pending_frame);
+
+ if (!draw_callback_.is_null())
+ draw_callback_.Run();
+ draw_callback_ = callback;
+}
+
+void Surface::EvictFrame() {
+ QueueFrame(CompositorFrame(), DrawCallback());
+ active_frame_.reset();
+}
+
+void Surface::RequestCopyOfOutput(
+ std::unique_ptr<CopyOutputRequest> copy_request) {
+ if (!active_frame_ || active_frame_->render_pass_list.empty()) {
+ copy_request->SendEmptyResult();
+ return;
+ }
+
+ std::vector<std::unique_ptr<CopyOutputRequest>>& copy_requests =
+ active_frame_->render_pass_list.back()->copy_requests;
+
+ if (copy_request->has_source()) {
+ const base::UnguessableToken& source = copy_request->source();
+ // Remove existing CopyOutputRequests made on the Surface by the same
+ // source.
+ auto to_remove =
+ std::remove_if(copy_requests.begin(), copy_requests.end(),
+ [&source](const std::unique_ptr<CopyOutputRequest>& x) {
+ return x->has_source() && x->source() == source;
+ });
+ copy_requests.erase(to_remove, copy_requests.end());
+ }
+ copy_requests.push_back(std::move(copy_request));
+}
+
+void Surface::NotifySurfaceIdAvailable(const SurfaceId& surface_id) {
+ auto it = blocking_surfaces_.find(surface_id);
+ // This surface may no longer have blockers if the deadline has passed.
+ if (it == blocking_surfaces_.end())
+ return;
+
+ blocking_surfaces_.erase(it);
+
+ if (!blocking_surfaces_.empty())
+ return;
+
+ // All blockers have been cleared. The surface can be activated now.
+ ActivatePendingFrame();
+}
+
+void Surface::AddObserver(PendingFrameObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void Surface::RemoveObserver(PendingFrameObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void Surface::ActivatePendingFrameForDeadline() {
+ if (!pending_frame_ ||
+ !pending_frame_->metadata.can_activate_before_dependencies) {
+ return;
+ }
+
+ // If a frame is being activated because of a deadline, then clear its set
+ // of blockers.
+ blocking_surfaces_.clear();
+ ActivatePendingFrame();
+}
+
+void Surface::ActivatePendingFrame() {
+ DCHECK(pending_frame_);
+ ActivateFrame(std::move(pending_frame_.value()));
+ pending_frame_.reset();
+ // ActiveFrame resources are now double ref-ed. Unref.
+ UnrefFrameResources(*active_frame_);
+}
+
+// A frame is activated if all its Surface ID dependences are active or a
+// deadline has hit and the frame was forcibly activated by the display
+// compositor.
+void Surface::ActivateFrame(CompositorFrame frame) {
DCHECK(factory_);
ClearCopyRequests();
TakeLatencyInfo(&frame.metadata.latency_info);
- base::Optional<CompositorFrame> previous_frame = std::move(current_frame_);
- current_frame_ = std::move(frame);
+ base::Optional<CompositorFrame> previous_frame = std::move(active_frame_);
+ active_frame_ = std::move(frame);
- if (current_frame_) {
- factory_->ReceiveFromChild(current_frame_->resource_list);
- }
+ factory_->ReceiveFromChild(active_frame_->resource_list);
// Empty frames shouldn't be drawn and shouldn't contribute damage, so don't
// increment frame index for them.
- if (current_frame_ && !current_frame_->render_pass_list.empty()) {
+ if (!active_frame_->render_pass_list.empty())
++frame_index_;
- }
previous_frame_surface_id_ = surface_id();
if (previous_frame)
UnrefFrameResources(*previous_frame);
- if (!draw_callback_.is_null())
- draw_callback_.Run();
- draw_callback_ = callback;
+ referenced_surfaces_ = active_frame_->metadata.referenced_surfaces;
- referenced_surfaces_ = current_frame_->metadata.referenced_surfaces;
+ for (auto& observer : observers_)
+ observer.OnSurfaceActivated(this);
}
-void Surface::EvictFrame() {
- QueueFrame(CompositorFrame(), DrawCallback());
- current_frame_.reset();
-}
+void Surface::UpdateBlockingSurfaces(
+ const base::Optional<CompositorFrame>& previous_pending_frame,
+ const CompositorFrame& current_frame) {
+ // If there is no SurfaceDependencyTracker installed then the |current_frame|
+ // does not block on anything.
+ if (!factory_->manager()->dependency_tracker()) {
+ blocking_surfaces_.clear();
+ return;
+ }
-void Surface::RequestCopyOfOutput(
- std::unique_ptr<CopyOutputRequest> copy_request) {
- if (current_frame_ && !current_frame_->render_pass_list.empty()) {
- std::vector<std::unique_ptr<CopyOutputRequest>>& copy_requests =
- current_frame_->render_pass_list.back()->copy_requests;
-
- if (copy_request->has_source()) {
- const base::UnguessableToken& source = copy_request->source();
- // Remove existing CopyOutputRequests made on the Surface by the same
- // source.
- auto to_remove = std::remove_if(
- copy_requests.begin(), copy_requests.end(),
- [&source](const std::unique_ptr<CopyOutputRequest>& x) {
- return x->has_source() && x->source() == source;
- });
- copy_requests.erase(to_remove, copy_requests.end());
+ base::flat_set<SurfaceId> new_blocking_surfaces;
kylechar 2017/02/09 15:50:31 Why mix SurfaceDependencies and base::flat_set<Sur
+
+ for (const SurfaceId& surface_id :
+ current_frame.metadata.referenced_surfaces) {
+ Surface* surface = factory_->manager()->GetSurfaceForId(surface_id);
+ // If a referenced surface does not have a corresponding active frame in the
+ // display compositor, then it blocks this frame.
+ if (!surface || !surface->HasActiveFrame())
+ new_blocking_surfaces.insert(surface_id);
+ }
+
+ // If this Surface has a previous pending frame, then we must determine the
+ // changes in dependencies so that we can update the SurfaceDependencyTracker
+ // map.
+ if (previous_pending_frame.has_value()) {
+ SurfaceDependencies removed_dependencies;
+ for (const SurfaceId& surface_id : blocking_surfaces_) {
+ if (!new_blocking_surfaces.count(surface_id))
+ removed_dependencies.insert(surface_id);
+ }
+
+ SurfaceDependencies added_dependencies;
+ for (const SurfaceId& surface_id : new_blocking_surfaces) {
+ if (!blocking_surfaces_.count(surface_id))
+ added_dependencies.insert(surface_id);
+ }
+
+ // If there is a change in the dependency set, then inform observers.
+ if (!added_dependencies.empty() || !removed_dependencies.empty()) {
+ for (auto& observer : observers_) {
+ observer.OnSurfaceDependenciesChanged(this, added_dependencies,
+ removed_dependencies);
+ }
}
- copy_requests.push_back(std::move(copy_request));
- } else {
- copy_request->SendEmptyResult();
}
+
+ blocking_surfaces_ = std::move(new_blocking_surfaces);
}
void Surface::TakeCopyOutputRequests(
std::multimap<int, std::unique_ptr<CopyOutputRequest>>* copy_requests) {
DCHECK(copy_requests->empty());
- if (current_frame_) {
- for (const auto& render_pass : current_frame_->render_pass_list) {
- for (auto& request : render_pass->copy_requests) {
- copy_requests->insert(
- std::make_pair(render_pass->id, std::move(request)));
- }
- render_pass->copy_requests.clear();
+ if (!active_frame_)
+ return;
+
+ for (const auto& render_pass : active_frame_->render_pass_list) {
+ for (auto& request : render_pass->copy_requests) {
+ copy_requests->insert(
+ std::make_pair(render_pass->id, std::move(request)));
}
+ render_pass->copy_requests.clear();
}
}
-const CompositorFrame& Surface::GetEligibleFrame() const {
- DCHECK(current_frame_);
- return current_frame_.value();
+const CompositorFrame& Surface::GetActiveFrame() const {
+ DCHECK(active_frame_);
+ return active_frame_.value();
+}
+
+const CompositorFrame& Surface::GetPendingFrame() {
+ DCHECK(pending_frame_);
+ return pending_frame_.value();
}
void Surface::TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info) {
- if (!current_frame_)
+ if (!active_frame_)
return;
if (latency_info->empty()) {
- current_frame_->metadata.latency_info.swap(*latency_info);
+ active_frame_->metadata.latency_info.swap(*latency_info);
return;
}
- std::copy(current_frame_->metadata.latency_info.begin(),
- current_frame_->metadata.latency_info.end(),
+ std::copy(active_frame_->metadata.latency_info.begin(),
+ active_frame_->metadata.latency_info.end(),
std::back_inserter(*latency_info));
- current_frame_->metadata.latency_info.clear();
+ active_frame_->metadata.latency_info.clear();
}
void Surface::RunDrawCallbacks() {
@@ -170,8 +305,8 @@ void Surface::UnrefFrameResources(const CompositorFrame& frame) {
}
void Surface::ClearCopyRequests() {
- if (current_frame_) {
- for (const auto& render_pass : current_frame_->render_pass_list) {
+ if (active_frame_) {
+ for (const auto& render_pass : active_frame_->render_pass_list) {
for (const auto& copy_request : render_pass->copy_requests)
copy_request->SendEmptyResult();
}

Powered by Google App Engine
This is Rietveld 408576698