| Index: content/browser/renderer_host/compositor_impl_android.cc
|
| diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
|
| index eaf4bcd4e906e0b557b66e319336af226c150aae..b6453a6e887128451f8c9600b08034adfdd2e136 100644
|
| --- a/content/browser/renderer_host/compositor_impl_android.cc
|
| +++ b/content/browser/renderer_host/compositor_impl_android.cc
|
| @@ -69,6 +69,7 @@
|
|
|
| namespace {
|
|
|
| +const unsigned int kMaxUiSwapBuffers = 1U;
|
| const unsigned int kMaxDisplaySwapBuffers = 1U;
|
|
|
| // Used to override capabilities_.adjust_deadline_for_parent to false
|
| @@ -141,7 +142,8 @@
|
| OutputSurface::OnSwapBuffersComplete();
|
| }
|
|
|
| - void OnVSync(base::TimeTicks timebase, base::TimeDelta interval) override {
|
| + void OnUpdateVSyncParameters(base::TimeTicks timebase,
|
| + base::TimeDelta interval) override {
|
| CommitVSyncParameters(timebase, interval);
|
| }
|
|
|
| @@ -151,36 +153,6 @@
|
| gfx::SwapResult)>
|
| swap_buffers_completion_callback_;
|
| scoped_ptr<cc::OverlayCandidateValidator> overlay_candidate_validator_;
|
| -};
|
| -
|
| -class ExternalBeginFrameSource : public cc::BeginFrameSourceBase,
|
| - public CompositorImpl::VSyncObserver {
|
| - public:
|
| - ExternalBeginFrameSource(CompositorImpl* compositor)
|
| - : compositor_(compositor) {
|
| - compositor_->AddObserver(this);
|
| - }
|
| -
|
| - ~ExternalBeginFrameSource() override {
|
| - compositor_->RemoveObserver(this);
|
| - }
|
| -
|
| - // cc::BeginFrameSourceBase implementation:
|
| - void OnNeedsBeginFramesChange(
|
| - bool needs_begin_frames) override {
|
| - compositor_->OnNeedsBeginFramesChange(needs_begin_frames);
|
| - }
|
| -
|
| - // CompositorImpl::VSyncObserver implementation:
|
| - void OnVSync(base::TimeTicks frame_time,
|
| - base::TimeDelta vsync_period) override {
|
| - CallOnBeginFrame(cc::BeginFrameArgs::Create(
|
| - BEGINFRAME_FROM_HERE, frame_time, base::TimeTicks::Now(), vsync_period,
|
| - cc::BeginFrameArgs::NORMAL));
|
| - }
|
| -
|
| - private:
|
| - CompositorImpl* compositor_;
|
| };
|
|
|
| static bool g_initialized = false;
|
| @@ -265,11 +237,15 @@
|
| surface_id_(0),
|
| client_(client),
|
| root_window_(root_window),
|
| + did_post_swapbuffers_(false),
|
| + ignore_schedule_composite_(false),
|
| + needs_composite_(false),
|
| needs_animate_(false),
|
| + will_composite_immediately_(false),
|
| + composite_on_vsync_trigger_(DO_NOT_COMPOSITE),
|
| pending_swapbuffers_(0U),
|
| num_successive_context_creation_failures_(0),
|
| output_surface_request_pending_(false),
|
| - needs_begin_frames_(false),
|
| weak_factory_(this) {
|
| DCHECK(client);
|
| DCHECK(root_window);
|
| @@ -282,6 +258,111 @@
|
| root_window_->DetachCompositor();
|
| // Clean-up any surface references.
|
| SetSurface(NULL);
|
| +}
|
| +
|
| +void CompositorImpl::PostComposite(CompositingTrigger trigger) {
|
| + DCHECK(host_->visible());
|
| + DCHECK(needs_composite_);
|
| + DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY);
|
| +
|
| + if (will_composite_immediately_ ||
|
| + (trigger == COMPOSITE_EVENTUALLY && WillComposite())) {
|
| + // We will already composite soon enough.
|
| + DCHECK(WillComposite());
|
| + return;
|
| + }
|
| +
|
| + if (DidCompositeThisFrame()) {
|
| + DCHECK(!WillCompositeThisFrame());
|
| + if (composite_on_vsync_trigger_ != COMPOSITE_IMMEDIATELY) {
|
| + composite_on_vsync_trigger_ = trigger;
|
| + root_window_->RequestVSyncUpdate();
|
| + }
|
| + DCHECK(WillComposite());
|
| + return;
|
| + }
|
| +
|
| + base::TimeDelta delay;
|
| + if (trigger == COMPOSITE_IMMEDIATELY) {
|
| + will_composite_immediately_ = true;
|
| + composite_on_vsync_trigger_ = DO_NOT_COMPOSITE;
|
| + } else {
|
| + DCHECK(!WillComposite());
|
| + const base::TimeDelta estimated_composite_time = vsync_period_ / 4;
|
| + const base::TimeTicks now = base::TimeTicks::Now();
|
| +
|
| + if (!last_vsync_.is_null() && (now - last_vsync_) < vsync_period_) {
|
| + base::TimeTicks next_composite =
|
| + last_vsync_ + vsync_period_ - estimated_composite_time;
|
| + if (next_composite < now) {
|
| + // It's too late, we will reschedule composite as needed on the next
|
| + // vsync.
|
| + composite_on_vsync_trigger_ = COMPOSITE_EVENTUALLY;
|
| + root_window_->RequestVSyncUpdate();
|
| + DCHECK(WillComposite());
|
| + return;
|
| + }
|
| +
|
| + delay = next_composite - now;
|
| + }
|
| + }
|
| + TRACE_EVENT2("cc,benchmark", "CompositorImpl::PostComposite",
|
| + "trigger", trigger,
|
| + "delay", delay.InMillisecondsF());
|
| +
|
| + DCHECK(composite_on_vsync_trigger_ == DO_NOT_COMPOSITE);
|
| + if (current_composite_task_)
|
| + current_composite_task_->Cancel();
|
| +
|
| + // Unretained because we cancel the task on shutdown.
|
| + current_composite_task_.reset(new base::CancelableClosure(
|
| + base::Bind(&CompositorImpl::Composite, base::Unretained(this), trigger)));
|
| + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| + FROM_HERE, current_composite_task_->callback(), delay);
|
| +}
|
| +
|
| +void CompositorImpl::Composite(CompositingTrigger trigger) {
|
| + if (trigger == COMPOSITE_IMMEDIATELY)
|
| + will_composite_immediately_ = false;
|
| +
|
| + DCHECK(host_->visible());
|
| + DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY);
|
| + DCHECK(needs_composite_);
|
| + DCHECK(!DidCompositeThisFrame());
|
| +
|
| + DCHECK_LE(pending_swapbuffers_, kMaxUiSwapBuffers);
|
| + // Swap Ack accounting is unreliable if the OutputSurface was lost.
|
| + // In that case still attempt to composite, which will cause creation of a
|
| + // new OutputSurface and reset pending_swapbuffers_.
|
| + if (pending_swapbuffers_ == kMaxUiSwapBuffers &&
|
| + !host_->output_surface_lost()) {
|
| + TRACE_EVENT0("compositor", "CompositorImpl_SwapLimit");
|
| + return;
|
| + }
|
| +
|
| + // Reset state before Layout+Composite since that might create more
|
| + // requests to Composite that we need to respect.
|
| + needs_composite_ = false;
|
| +
|
| + // Only allow compositing once per vsync.
|
| + current_composite_task_->Cancel();
|
| + DCHECK(DidCompositeThisFrame() && !WillComposite());
|
| +
|
| + const base::TimeTicks frame_time = base::TimeTicks::Now();
|
| + if (needs_animate_) {
|
| + base::AutoReset<bool> auto_reset_ignore_schedule(
|
| + &ignore_schedule_composite_, true);
|
| + needs_animate_ = false;
|
| + root_window_->Animate(frame_time);
|
| + }
|
| +
|
| + did_post_swapbuffers_ = false;
|
| + host_->Composite(frame_time);
|
| + if (did_post_swapbuffers_)
|
| + pending_swapbuffers_++;
|
| +
|
| + // Need to track vsync to avoid compositing more than once per frame.
|
| + root_window_->RequestVSyncUpdate();
|
| }
|
|
|
| ui::UIResourceProvider& CompositorImpl::GetUIResourceProvider() {
|
| @@ -344,20 +425,27 @@
|
|
|
| void CompositorImpl::CreateLayerTreeHost() {
|
| DCHECK(!host_);
|
| + DCHECK(!WillCompositeThisFrame());
|
| +
|
| + // Just in case, since we immediately hide the LTH in this function,
|
| + // and we do not want to end up with a pending Composite task when the
|
| + // host is hidden.
|
| + base::AutoReset<bool> auto_reset_ignore_schedule(&ignore_schedule_composite_,
|
| + true);
|
|
|
| cc::LayerTreeSettings settings;
|
| settings.renderer_settings.refresh_rate = 60.0;
|
| settings.renderer_settings.allow_antialiasing = false;
|
| settings.renderer_settings.highp_threshold_min = 2048;
|
| settings.use_zero_copy = true;
|
| - settings.use_external_begin_frame_source = true;
|
|
|
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
| settings.initial_debug_state.SetRecordRenderingStats(
|
| command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
|
| if (command_line->HasSwitch(cc::switches::kDisableCompositorPropertyTrees))
|
| settings.use_property_trees = false;
|
| - settings.single_thread_proxy_scheduler = true;
|
| + // TODO(enne): Update this this compositor to use the scheduler.
|
| + settings.single_thread_proxy_scheduler = false;
|
|
|
| settings.use_compositor_animation_timelines = !command_line->HasSwitch(
|
| switches::kDisableAndroidCompositorAnimationTimelines);
|
| @@ -369,7 +457,6 @@
|
| params.task_graph_runner = g_task_graph_runner.Pointer();
|
| params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
|
| params.settings = &settings;
|
| - params.external_begin_frame_source.reset(new ExternalBeginFrameSource(this));
|
| host_ = cc::LayerTreeHost::CreateSingleThreaded(this, ¶ms);
|
| DCHECK(!host_->visible());
|
| host_->SetRootLayer(root_layer_);
|
| @@ -385,16 +472,39 @@
|
| TRACE_EVENT1("cc", "CompositorImpl::SetVisible", "visible", visible);
|
| if (!visible) {
|
| DCHECK(host_->visible());
|
| + // Look for any layers that were attached to the root for readback
|
| + // and are waiting for Composite() to happen.
|
| + bool readback_pending = false;
|
| + for (size_t i = 0; i < root_layer_->children().size(); ++i) {
|
| + if (root_layer_->children()[i]->HasCopyRequest()) {
|
| + readback_pending = true;
|
| + break;
|
| + }
|
| + }
|
| + if (readback_pending) {
|
| + base::AutoReset<bool> auto_reset_ignore_schedule(
|
| + &ignore_schedule_composite_, true);
|
| + host_->Composite(base::TimeTicks::Now());
|
| + }
|
| + if (WillComposite())
|
| + CancelComposite();
|
| host_->SetVisible(false);
|
| if (!host_->output_surface_lost())
|
| host_->ReleaseOutputSurface();
|
| pending_swapbuffers_ = 0;
|
| + needs_composite_ = false;
|
| + composite_on_vsync_trigger_ = DO_NOT_COMPOSITE;
|
| establish_gpu_channel_timeout_.Stop();
|
| display_client_.reset();
|
| + if (current_composite_task_) {
|
| + current_composite_task_->Cancel();
|
| + current_composite_task_.reset();
|
| + }
|
| } else {
|
| host_->SetVisible(true);
|
| if (output_surface_request_pending_)
|
| RequestNewOutputSurface();
|
| + SetNeedsComposite();
|
| }
|
| }
|
|
|
| @@ -425,7 +535,10 @@
|
| void CompositorImpl::SetNeedsComposite() {
|
| if (!host_->visible())
|
| return;
|
| - host_->SetNeedsAnimate();
|
| + DCHECK(!needs_composite_ || WillComposite());
|
| +
|
| + needs_composite_ = true;
|
| + PostComposite(COMPOSITE_IMMEDIATELY);
|
| }
|
|
|
| static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
|
| @@ -459,11 +572,9 @@
|
| }
|
|
|
| void CompositorImpl::UpdateLayerTreeHost() {
|
| + base::AutoReset<bool> auto_reset_ignore_schedule(&ignore_schedule_composite_,
|
| + true);
|
| client_->UpdateLayerTreeHost();
|
| - if (needs_animate_) {
|
| - needs_animate_ = false;
|
| - root_window_->Animate(base::TimeTicks::Now());
|
| - }
|
| }
|
|
|
| void CompositorImpl::OnGpuChannelEstablished() {
|
| @@ -593,15 +704,44 @@
|
| return gpu_capabilities_.texture_format_etc1_npot;
|
| }
|
|
|
| +void CompositorImpl::ScheduleComposite() {
|
| + if (ignore_schedule_composite_ || !host_->visible())
|
| + return;
|
| +
|
| + DCHECK(!needs_composite_ || WillComposite());
|
| + needs_composite_ = true;
|
| + // We currently expect layer tree invalidations at most once per frame
|
| + // during normal operation and therefore try to composite immediately
|
| + // to minimize latency.
|
| + PostComposite(COMPOSITE_IMMEDIATELY);
|
| +}
|
| +
|
| +void CompositorImpl::ScheduleAnimation() {
|
| + needs_animate_ = true;
|
| +
|
| + if (!host_->visible())
|
| + return;
|
| +
|
| + if (needs_composite_) {
|
| + DCHECK(WillComposite());
|
| + return;
|
| + }
|
| +
|
| + TRACE_EVENT0("cc", "CompositorImpl::ScheduleAnimation");
|
| + needs_composite_ = true;
|
| + PostComposite(COMPOSITE_EVENTUALLY);
|
| +}
|
| +
|
| void CompositorImpl::DidPostSwapBuffers() {
|
| TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers");
|
| - pending_swapbuffers_++;
|
| + did_post_swapbuffers_ = true;
|
| }
|
|
|
| void CompositorImpl::DidCompleteSwapBuffers() {
|
| TRACE_EVENT0("compositor", "CompositorImpl::DidCompleteSwapBuffers");
|
| DCHECK_GT(pending_swapbuffers_, 0U);
|
| - pending_swapbuffers_--;
|
| + if (pending_swapbuffers_-- == kMaxUiSwapBuffers && needs_composite_)
|
| + PostComposite(COMPOSITE_IMMEDIATELY);
|
| client_->OnSwapBuffersCompleted(pending_swapbuffers_);
|
| }
|
|
|
| @@ -610,8 +750,7 @@
|
| // This really gets called only once from
|
| // SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() when the
|
| // context was lost.
|
| - if (host_->visible())
|
| - host_->SetNeedsCommit();
|
| + ScheduleComposite();
|
| client_->OnSwapBuffersCompleted(0);
|
| }
|
|
|
| @@ -630,19 +769,28 @@
|
|
|
| void CompositorImpl::OnVSync(base::TimeTicks frame_time,
|
| base::TimeDelta vsync_period) {
|
| + vsync_period_ = vsync_period;
|
| + last_vsync_ = frame_time;
|
| +
|
| + if (WillCompositeThisFrame()) {
|
| + // We somehow missed the last vsync interval, so reschedule for deadline.
|
| + // We cannot schedule immediately, or will get us out-of-phase with new
|
| + // renderer frames.
|
| + CancelComposite();
|
| + composite_on_vsync_trigger_ = COMPOSITE_EVENTUALLY;
|
| + } else {
|
| + current_composite_task_.reset();
|
| + }
|
| +
|
| + DCHECK(!DidCompositeThisFrame() && !WillCompositeThisFrame());
|
| + if (composite_on_vsync_trigger_ != DO_NOT_COMPOSITE) {
|
| + CompositingTrigger trigger = composite_on_vsync_trigger_;
|
| + composite_on_vsync_trigger_ = DO_NOT_COMPOSITE;
|
| + PostComposite(trigger);
|
| + }
|
| +
|
| FOR_EACH_OBSERVER(VSyncObserver, observer_list_,
|
| - OnVSync(frame_time, vsync_period));
|
| - if (needs_begin_frames_)
|
| - root_window_->RequestVSyncUpdate();
|
| -}
|
| -
|
| -void CompositorImpl::OnNeedsBeginFramesChange(bool needs_begin_frames) {
|
| - if (needs_begin_frames_ == needs_begin_frames)
|
| - return;
|
| -
|
| - needs_begin_frames_ = needs_begin_frames;
|
| - if (needs_begin_frames_)
|
| - root_window_->RequestVSyncUpdate();
|
| + OnUpdateVSyncParameters(frame_time, vsync_period));
|
| }
|
|
|
| void CompositorImpl::SetNeedsAnimate() {
|
|
|