Chromium Code Reviews| Index: cc/surfaces/compositor_frame_sink_support.cc |
| diff --git a/cc/surfaces/compositor_frame_sink_support.cc b/cc/surfaces/compositor_frame_sink_support.cc |
| index 97c351f2f9acc2d5472b096bf2dcfbbf655ef8d6..bcc0c7f704c38ce9906eb0a5bf92781dca53528d 100644 |
| --- a/cc/surfaces/compositor_frame_sink_support.cc |
| +++ b/cc/surfaces/compositor_frame_sink_support.cc |
| @@ -52,7 +52,7 @@ CompositorFrameSinkSupport::~CompositorFrameSinkSupport() { |
| // SurfaceFactory's destructor will attempt to return resources which will |
| // call back into here and access |client_| so we should destroy |
| // |surface_factory_|'s resources early on. |
| - surface_factory_.EvictSurface(); |
| + EvictFrame(); |
| surface_manager_->UnregisterSurfaceFactoryClient(frame_sink_id_); |
| if (handles_frame_sink_id_invalidation_) |
| surface_manager_->InvalidateFrameSinkId(frame_sink_id_); |
| @@ -63,20 +63,43 @@ void CompositorFrameSinkSupport::EvictFrame() { |
| } |
| void CompositorFrameSinkSupport::SetNeedsBeginFrame(bool needs_begin_frame) { |
| - needs_begin_frame_ = needs_begin_frame; |
| + client_needs_begin_frame_ = needs_begin_frame; |
| + bool was_observing = added_frame_observer_; |
| UpdateNeedsBeginFramesInternal(); |
| + |
| + // If we are observing because of a pending CompositorFrame, we may have |
| + // previously received a BeginFrame that we should now forward to the client. |
| + // BackToBackBeginFrameSource sends a new BeginFrame in a separate task |
| + // provided we weren't observing before, so we special-case it here. |
| + if (needs_begin_frame && !last_begin_frame_sent_to_client_ && |
| + (was_observing || begin_frame_source_->IsThrottled())) { |
| + last_begin_frame_sent_to_client_ = true; |
| + client_->OnBeginFrame(last_begin_frame_args_); |
| + } |
| } |
| void CompositorFrameSinkSupport::BeginFrameDidNotSwap( |
| const BeginFrameAck& ack) { |
| - // TODO(eseckler): While a pending CompositorFrame exists (see TODO below), we |
| - // should not acknowledge immediately. Instead, we should update the ack that |
| - // will be sent to DisplayScheduler when the pending frame is activated. |
| DCHECK_LE(BeginFrameArgs::kStartingFrameNumber, ack.sequence_number); |
| + |
| + if (ack.sequence_number < BeginFrameArgs::kStartingFrameNumber) { |
| + DLOG(ERROR) << "Received BeginFrameDidNotSwap with invalid BeginFrameAck."; |
| + return; |
| + } |
| // |has_damage| is not transmitted, but false by default. |
| DCHECK(!ack.has_damage); |
| - if (begin_frame_source_) |
| - begin_frame_source_->DidFinishFrame(this, ack); |
| + |
| + // Client can continue to request BeginFrames after submitting a |
| + // CompositorFrame, so we may end up with a pending frame here. |
| + if (has_pending_frame_) { |
| + // We will acknowledge the BeginFrame once the pending frame activates. |
| + begin_frame_ack_for_pending_frame_.source_id = ack.source_id; |
|
Fady Samuel
2017/03/31 00:09:02
I wonder if we can modify the pending CompositorFr
|
| + begin_frame_ack_for_pending_frame_.latest_confirmed_sequence_number = |
| + ack.latest_confirmed_sequence_number; |
| + return; |
| + } |
| + |
| + AcknowledgeBeginFrame(ack); |
| } |
| void CompositorFrameSinkSupport::SubmitCompositorFrame( |
| @@ -94,18 +117,24 @@ void CompositorFrameSinkSupport::SubmitCompositorFrame( |
| // |has_damage| is not transmitted. |
| frame.metadata.begin_frame_ack.has_damage = true; |
| + // The CompositorFrame submitted below might not be activated right away b/c |
| + // of surface synchronization. We only forward the CompositorFrame's |
| + // BeginFrameAck to DisplayScheduler once it is activated. While waiting for |
| + // activation, we continue to observe BeginFrames. If the CompositorFrame is |
| + // not activated before we receive the next BeginFrame, we will acknowledge |
| + // the current one without updates. |
| + has_pending_frame_ = true; |
|
Fady Samuel
2017/03/31 00:09:02
Surface::HasPendingFrame exists.
Would it make se
|
| + surface_id_for_pending_frame_ = local_surface_id; |
| + // If there was a previous pending frame that didn't get activated, this |
| + // overrides the pending BeginFrameAck. |
| + begin_frame_ack_for_pending_frame_ = frame.metadata.begin_frame_ack; |
| + // Ensure that we continue observing BeginFrames while the frame is pending. |
| + UpdateNeedsBeginFramesInternal(); |
| + |
| surface_factory_.SubmitCompositorFrame( |
| local_surface_id, std::move(frame), |
| base::Bind(&CompositorFrameSinkSupport::DidReceiveCompositorFrameAck, |
| weak_factory_.GetWeakPtr())); |
| - |
| - // TODO(eseckler): The CompositorFrame submitted below might not be activated |
| - // right away b/c of surface synchronization. We should only send the |
| - // BeginFrameAck to DisplayScheduler when it is activated. This also means |
| - // that we need to stay an active BFO while a CompositorFrame is pending. |
| - // See https://crbug.com/703079. |
| - if (begin_frame_source_) |
| - begin_frame_source_->DidFinishFrame(this, frame.metadata.begin_frame_ack); |
| } |
| void CompositorFrameSinkSupport::UpdateSurfaceReferences( |
| @@ -170,6 +199,7 @@ void CompositorFrameSinkSupport::DidReceiveCompositorFrameAck() { |
| } |
| void CompositorFrameSinkSupport::ForceReclaimResources() { |
| + PendingFrameDiscarded(); |
| surface_factory_.ClearSurface(); |
| } |
| @@ -229,11 +259,95 @@ void CompositorFrameSinkSupport::WillDrawSurface( |
| client_->WillDrawSurface(local_surface_id, damage_rect); |
| } |
| +void CompositorFrameSinkSupport::PendingFrameActivated( |
| + const LocalSurfaceId& local_surface_id) { |
| + // has_pending_frame_ may be false because ClearSurface() submits |
| + // CompositorFrames we don't track. |
| + if (!has_pending_frame_) |
| + return; |
| + DCHECK_EQ(surface_id_for_pending_frame_, local_surface_id); |
| + has_pending_frame_ = false; |
| + |
| + if (last_begin_frame_args_.IsValid()) { |
| + if (last_begin_frame_args_.source_id != |
| + begin_frame_ack_for_pending_frame_.source_id) { |
| + // BeginFrameSource has changed, we cannot confirm any sequence number. |
| + begin_frame_ack_for_pending_frame_.source_id = |
| + last_begin_frame_args_.source_id; |
| + begin_frame_ack_for_pending_frame_.latest_confirmed_sequence_number = |
| + BeginFrameArgs::kInvalidFrameNumber; |
| + } |
| + |
| + begin_frame_ack_for_pending_frame_.sequence_number = |
| + last_begin_frame_args_.sequence_number; |
| + } |
| + |
| + DCHECK(begin_frame_ack_for_pending_frame_.has_damage); |
| + AcknowledgeBeginFrame(begin_frame_ack_for_pending_frame_); |
| + // We may no longer need BeginFrames, since has_pending_frame_ changed. |
| + UpdateNeedsBeginFramesInternal(); |
| +} |
| + |
| +void CompositorFrameSinkSupport::SurfaceDiscarded( |
| + const LocalSurfaceId& local_surface_id) { |
| + // Don't call PendingFrameDiscarded() if an older surface was discarded and a |
| + // CompositorFrame may still be pending on the new surface. |
| + if (local_surface_id != surface_id_for_pending_frame_) |
| + return; |
| + |
| + PendingFrameDiscarded(); |
| +} |
| + |
| +void CompositorFrameSinkSupport::PendingFrameDiscarded() { |
| + if (!has_pending_frame_) |
| + return; |
| + |
| + has_pending_frame_ = false; |
| + AcknowledgeLastBeginFrameWithoutUpdates(); |
| + UpdateNeedsBeginFramesInternal(); |
| +} |
| + |
| void CompositorFrameSinkSupport::OnBeginFrame(const BeginFrameArgs& args) { |
| UpdateNeedsBeginFramesInternal(); |
| + |
| + // If we are observing BeginFrames while a pending frame exists, we are |
| + // deferring acknowledging until the pending frame activates. Thus, we may not |
| + // have acknowledged the last BeginFrame yet. Do that now. |
| + if (has_pending_frame_) |
| + AcknowledgeLastBeginFrameWithoutUpdates(); |
| + |
| last_begin_frame_args_ = args; |
| - if (client_) |
| + if (client_ && client_needs_begin_frame_) { |
| + last_begin_frame_sent_to_client_ = true; |
| client_->OnBeginFrame(args); |
| + } else { |
| + last_begin_frame_sent_to_client_ = false; |
| + } |
| +} |
| + |
| +void CompositorFrameSinkSupport::AcknowledgeLastBeginFrameWithoutUpdates() { |
| + // Not all clients wait for a BeginFrame before submitting CompositorFrames. |
| + if (!last_begin_frame_args_.IsValid()) |
| + return; |
| + |
| + uint64_t confirmed_sequence_number = BeginFrameArgs::kInvalidFrameNumber; |
| + if (last_begin_frame_args_.source_id == |
| + latest_confirmed_begin_frame_source_id_) { |
| + confirmed_sequence_number = latest_confirmed_begin_frame_sequence_number_; |
| + } |
| + AcknowledgeBeginFrame(BeginFrameAck(last_begin_frame_args_.source_id, |
| + last_begin_frame_args_.sequence_number, |
| + confirmed_sequence_number, false)); |
| +} |
| + |
| +void CompositorFrameSinkSupport::AcknowledgeBeginFrame( |
| + const BeginFrameAck& ack) { |
| + latest_confirmed_begin_frame_source_id_ = |
| + ack.latest_confirmed_sequence_number; |
| + latest_confirmed_begin_frame_sequence_number_ = |
| + ack.latest_confirmed_sequence_number; |
| + if (begin_frame_source_) |
| + begin_frame_source_->DidFinishFrame(this, ack); |
| } |
| const BeginFrameArgs& CompositorFrameSinkSupport::LastUsedBeginFrameArgs() |
| @@ -247,11 +361,16 @@ void CompositorFrameSinkSupport::UpdateNeedsBeginFramesInternal() { |
| if (!begin_frame_source_) |
| return; |
| - if (needs_begin_frame_ == added_frame_observer_) |
| + // We continue observing BeginFrames while a frame is pending to be activated, |
| + // so that we can eventually forward the corresponding BeginFrameAck to the |
| + // source. |
| + bool needs_begin_frame = client_needs_begin_frame_ || has_pending_frame_; |
| + |
| + if (needs_begin_frame == added_frame_observer_) |
| return; |
| - added_frame_observer_ = needs_begin_frame_; |
| - if (needs_begin_frame_) |
| + added_frame_observer_ = needs_begin_frame; |
| + if (added_frame_observer_) |
| begin_frame_source_->AddObserver(this); |
| else |
| begin_frame_source_->RemoveObserver(this); |