Reland again "Start gpu channel and compositor mojo pipe collection eagerly"

[email protected]
TBR=piman

SHERIFFS: This changes timing in the renderer, if (probably ChromeVOX)
tests get flaky they should be disabled please instead of reverting
this.

The flaky tests causing the last iteration of revert were disabled
in https://crrev.com/c/1361585.

This reverts commit d38eb8e01e09dc05802b062bf159f86942fce09e.

Original change's description:
> Start gpu channel and compositor mojo pipe collection eagerly
>
> When a RenderWidget is frozen, its compositor is stopped. However when
> the main frame is being navigated, we want to start requesting mojo
> pipes for the gpu and display compositor immediately so that it can
> happen in parallel with the navigation loading.
>
> Previously, we just always did this when creating a RenderWidget, and
> left them active when freezing the RenderWidget. After 678f025f7cde75
> however, we don't, and this causes time-to-first-pixels regressions
> on navigation.
>
> So we add a WarmupCompositor() method to RenderWidget, and call this
> from RenderFrameImpl::CreateFrame() when it makes the provisional
> frame, and the WebFrameWidget, since we expect to make use of the
> main frame RenderWidget shortly.
>
> Then, if RenderFrameImpl::FrameDetached() occurs, due to the
> navigation failing, we will AbortWarmupCompositor() to drop the
> mojo pipes instead of holding onto them indefinitely.
>
> This recovers the loading regressions introduced, while also not
> allocating mojo channels for frozen RenderWidgets indefinitely.
>
> In order to do this reasonably, we drop the "callback" from the
> request to RenderThreadImpl::RequestNewLayerTreeFrameSink so that
> it always returns something immediately. This way RenderWidget
> does not need to worry about having a task run to collect the
> new frame sink, and ordering with tasks from the compositor to
> collect it.
>
> [email protected]
>
> Change-Id: I6007e26e1622006652ce3619cdd080539d11e7b0
> Bug: 905191
> Reviewed-on: https://chromium-review.googlesource.com/c/1341073
> Commit-Queue: danakj <[email protected]>
> Reviewed-by: danakj <[email protected]>
> Reviewed-by: Daniel Cheng <[email protected]>
> Reviewed-by: Antoine Labour <[email protected]>
> Cr-Commit-Position: refs/heads/master@{#610909}

Change-Id: I100c65758b673a27f7d90bdbd6369abf8e8c608f
Reviewed-on: https://chromium-review.googlesource.com/c/1361598
Reviewed-by: danakj <[email protected]>
Commit-Queue: danakj <[email protected]>
Cr-Commit-Position: refs/heads/master@{#613670}
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 8d1028e..213908b 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -421,6 +421,7 @@
       was_shown_time_(base::TimeTicks::Now()),
       current_content_source_id_(0),
       widget_binding_(this, std::move(widget_request)),
+      warmup_weak_ptr_factory_(this),
       weak_ptr_factory_(this) {
   DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
   DCHECK(RenderThread::Get());
@@ -972,7 +973,7 @@
   // For widgets that are never visible, we don't start the compositor, so we
   // never get a request for a cc::LayerTreeFrameSink.
   DCHECK(!compositor_never_visible_);
-  // Inactive RenderWidgets should not be doing any compositing.
+  // Frozen RenderWidgets should not be doing any compositing.
   DCHECK(!is_frozen_);
 
   if (is_closing()) {
@@ -990,6 +991,23 @@
   if (for_child_local_root_frame_)
     CHECK(GetFrameWidget());
 
+  // If we have a warmup in progress, wait for that and store the callback
+  // to be run when the warmup completes.
+  if (warmup_frame_sink_request_pending_) {
+    after_warmup_callback_ = std::move(callback);
+    return;
+  }
+  // If a warmup previously completed, use the result.
+  if (warmup_frame_sink_) {
+    std::move(callback).Run(std::move(warmup_frame_sink_));
+    return;
+  }
+
+  DoRequestNewLayerTreeFrameSink(std::move(callback));
+}
+
+void RenderWidget::DoRequestNewLayerTreeFrameSink(
+    LayerTreeFrameSinkCallback callback) {
   // TODO(jonross): have this generated by the LayerTreeFrameSink itself, which
   // would then handle binding.
   mojom::RenderFrameMetadataObserverPtr ptr;
@@ -1613,6 +1631,55 @@
     StartCompositor();
 }
 
+void RenderWidget::WarmupCompositor() {
+  DCHECK(is_frozen_);
+
+  // Tests have no RenderThreadImpl /o\.
+  if (!RenderThreadImpl::current())
+    return;
+
+  // Keeping things simple. This would cancel any outstanding warmup if we
+  // happened to have one (this should be basically impossible). This avoids any
+  // extra book keeping about the outstanding reqeust.
+  warmup_weak_ptr_factory_.InvalidateWeakPtrs();
+  // And if we already did a warmup then we're done.
+  if (warmup_frame_sink_)
+    return;
+
+  // Mark us pending the warmup frame sink *before* calling
+  // DoRequestNewLayerTreeFrameSink() as it may run the reply callback
+  // synchronously. So we don't want to change any state after the call
+  // to DoRequestNewLayerTreeFrameSink() here.
+  warmup_frame_sink_request_pending_ = true;
+
+  auto cb = base::BindOnce(&RenderWidget::OnReplyForWarmupCompositor,
+                           warmup_weak_ptr_factory_.GetWeakPtr());
+  DoRequestNewLayerTreeFrameSink(std::move(cb));
+}
+
+void RenderWidget::OnReplyForWarmupCompositor(
+    std::unique_ptr<cc::LayerTreeFrameSink> sink) {
+  warmup_frame_sink_request_pending_ = false;
+
+  if (after_warmup_callback_)
+    std::move(after_warmup_callback_).Run(std::move(sink));
+  else
+    warmup_frame_sink_ = std::move(sink);
+}
+
+void RenderWidget::AbortWarmupCompositor() {
+  warmup_frame_sink_request_pending_ = false;
+  // Drop any pending warmup.
+  warmup_weak_ptr_factory_.InvalidateWeakPtrs();
+  // And drop any completed one.
+  warmup_frame_sink_.reset();
+
+  // If we had saved a callback to run after warmup, just do so now indicating
+  // failure.
+  if (after_warmup_callback_)
+    std::move(after_warmup_callback_).Run(nullptr);
+}
+
 void RenderWidget::DoDeferredClose() {
   Send(new WidgetHostMsg_Close(routing_id_));
 }