Chromium Code Reviews| 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(); |
| } |