| 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"
|
| #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;
|
| +
|
| + 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();
|
| }
|
|
|