viz: Implement surface synchronization for OOPIFs

This CL implements surface synchronization for out-of-process iframes and <webview>.

RenderFrameProxy waits until there is a single frame guaranteed to be available in the 
display compositor before using surface synchronization. Once there's an available fallback
surface that can be employed, then the primary surface is updated as soon as the frame rect
changes. The compositing system will attempt to composite the primary surface within a given
deadline (4 frames is the default). If the primary surface isn't available for four frames,
then the fallback surface will be used.

In order to construct a SurfaceId for the primary SurfaceInfo, both a FrameSinkId and
LocalSurfaceId must be available in RenderFrameProxy. The FrameSinkId changes every time
the RenderWidgetHostViewChildFrame changes and so we propagate the FrameSinkId of the view
up to the proxy on ViewChange.

Finally, the iframe's embedder (typically a top level page) fallback is not available for some
period of time until "OnFirstSurfaceActivation". When no clients are using surface synchronization,
then the fallback can be set immediately. However, because RWHVAura can have children that
synchronize, the fallback surface will not be available immediately. In order to ensure that
frames aren't missed in SurfaceAggregator, we don't update the fallback in DelegatedFrameHost until
the surface activates in OnFirstSurfaceActivation.

Bug: 672962
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_site_isolation
Change-Id: I42c4c5fa312d9aed08ff34b07c4d04d311a2eff5
Reviewed-on: https://chromium-review.googlesource.com/639366
Reviewed-by: Antoine Labour <[email protected]>
Reviewed-by: Ken Buchanan <[email protected]>
Commit-Queue: Fady Samuel <[email protected]>
Cr-Commit-Position: refs/heads/master@{#498164}
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index 7576665..173f337 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -90,7 +90,8 @@
     if (is_hidden_)
       OnVisibilityChanged(false);
     frame_proxy_in_parent_renderer_->Send(new FrameMsg_ViewChanged(
-        frame_proxy_in_parent_renderer_->GetRoutingID()));
+        frame_proxy_in_parent_renderer_->GetRoutingID(),
+        view_->GetFrameSinkId()));
   }
 }
 
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index 74624ca..95ba400ec 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -450,10 +450,6 @@
                                        skipped_latency_info_list_.end());
     skipped_latency_info_list_.clear();
 
-    bool result =
-        support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
-    DCHECK(result);
-
     if (local_surface_id != local_surface_id_ || !has_frame_) {
       // manager must outlive compositors using it.
       viz::SurfaceId surface_id(frame_sink_id_, local_surface_id);
@@ -461,12 +457,19 @@
                                     frame_size);
       client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface(
           surface_info, manager->surface_manager()->reference_factory());
-      client_->DelegatedFrameHostGetLayer()->SetFallbackSurface(surface_info);
       current_surface_size_ = frame_size;
       current_scale_factor_ = frame_device_scale_factor;
     }
 
     has_frame_ = true;
+
+    // If surface synchronization is off, then OnFirstSurfaceActivation will be
+    // called in the same call stack and so to ensure that the fallback surface
+    // is set, then primary surface must be set prior to calling
+    // CompositorFrameSinkSupport::SubmitCompositorFrame.
+    bool result =
+        support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
+    DCHECK(result);
   }
   local_surface_id_ = local_surface_id;
 
@@ -520,8 +523,8 @@
 
 void DelegatedFrameHost::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
-  // TODO(fsamuel): Once surface synchronization is turned on, the fallback
-  // surface should be set here.
+  if (has_frame_)
+    client_->DelegatedFrameHostGetLayer()->SetFallbackSurface(surface_info);
 }
 
 void DelegatedFrameHost::OnBeginFrame(const viz::BeginFrameArgs& args) {
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index b54c9d2..7fcc512 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -872,7 +872,7 @@
 
 // Notifies RenderFrameProxy that its associated RenderWidgetHostView has
 // changed.
-IPC_MESSAGE_ROUTED0(FrameMsg_ViewChanged)
+IPC_MESSAGE_ROUTED1(FrameMsg_ViewChanged, viz::FrameSinkId /* frame_sink_id */)
 
 // Notifies this frame or proxy that it is now focused.  This is used to
 // support cross-process focused frame changes.
diff --git a/content/renderer/child_frame_compositing_helper.cc b/content/renderer/child_frame_compositing_helper.cc
index 8fad0fb1..b8440c9 100644
--- a/content/renderer/child_frame_compositing_helper.cc
+++ b/content/renderer/child_frame_compositing_helper.cc
@@ -275,6 +275,7 @@
   viz::SurfaceInfo modified_surface_info(surface_info.id(), scale_factor,
                                          surface_info.size_in_pixels());
   surface_layer_->SetPrimarySurfaceInfo(modified_surface_info);
+  surface_layer_->SetFallbackSurfaceInfo(fallback_surface_info_);
 
   std::unique_ptr<cc_blink::WebLayerImpl> layer(
       new cc_blink::WebLayerImpl(surface_layer_));
@@ -294,6 +295,7 @@
 void ChildFrameCompositingHelper::SetFallbackSurfaceInfo(
     const viz::SurfaceInfo& surface_info,
     const viz::SurfaceSequence& sequence) {
+  fallback_surface_info_ = surface_info;
   float scale_factor = surface_info.device_scale_factor();
   // TODO(oshima): This is a stopgap fix so that the compositor does not
   // scaledown the content when 2x frame data is added to 1x parent frame data.
diff --git a/content/renderer/child_frame_compositing_helper.h b/content/renderer/child_frame_compositing_helper.h
index 4346ec9..31c9d3d6 100644
--- a/content/renderer/child_frame_compositing_helper.h
+++ b/content/renderer/child_frame_compositing_helper.h
@@ -87,6 +87,8 @@
   viz::SurfaceId last_primary_surface_id_;
   gfx::Size last_surface_size_in_pixels_;
 
+  viz::SurfaceInfo fallback_surface_info_;
+
   // The lifetime of this weak pointer should be greater than the lifetime of
   // other member objects, as they may access this pointer during their
   // destruction.
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 35707b7..c754839 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -10,6 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
+#include "components/viz/common/switches.h"
 #include "content/child/feature_policy/feature_policy_platform.h"
 #include "content/child/web_url_request_util.h"
 #include "content/child/webmessageportchannel_impl.h"
@@ -22,6 +23,7 @@
 #include "content/common/site_isolation_policy.h"
 #include "content/common/swapped_out_messages.h"
 #include "content/common/view_messages.h"
+#include "content/public/common/content_switches.h"
 #include "content/renderer/child_frame_compositing_helper.h"
 #include "content/renderer/frame_owner_properties.h"
 #include "content/renderer/render_frame_impl.h"
@@ -52,6 +54,11 @@
 base::LazyInstance<FrameMap>::DestructorAtExit g_frame_map =
     LAZY_INSTANCE_INITIALIZER;
 
+bool IsRunningInMash() {
+  const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
+  return cmdline->HasSwitch(switches::kIsRunningInMash);
+}
+
 }  // namespace
 
 // static
@@ -211,6 +218,12 @@
   std::pair<FrameMap::iterator, bool> result =
       g_frame_map.Get().insert(std::make_pair(web_frame_, this));
   CHECK(result.second) << "Inserted a duplicate item.";
+
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+  enable_surface_synchronization_ =
+      IsRunningInMash() ||
+      command_line.HasSwitch(switches::kEnableSurfaceSynchronization);
 }
 
 void RenderFrameProxy::ResendFrameRects() {
@@ -221,7 +234,7 @@
 }
 
 void RenderFrameProxy::WillBeginCompositorFrame() {
-  if (compositing_helper_) {
+  if (compositing_helper_ && compositing_helper_->surface_id().is_valid()) {
     FrameHostMsg_HittestData_Params params;
     params.surface_id = compositing_helper_->surface_id();
     params.ignored_for_hittest = web_frame_->IsIgnoredForHitTest();
@@ -328,7 +341,7 @@
 }
 
 void RenderFrameProxy::OnChildFrameProcessGone() {
-  if (compositing_helper_.get())
+  if (compositing_helper_)
     compositing_helper_->ChildFrameGone();
 }
 
@@ -342,14 +355,27 @@
   if (!web_frame()->Parent())
     return;
 
-  if (!compositing_helper_.get()) {
+  if (!compositing_helper_) {
     compositing_helper_ =
         ChildFrameCompositingHelper::CreateForRenderFrameProxy(this);
+    if (enable_surface_synchronization_) {
+      // We wait until there is a single CompositorFrame guaranteed to be
+      // available and ready for display in the display compositor before using
+      // surface synchronization. This guarantees that we will have something to
+      // display when the compositor goes to produce a display frame.
+      //
+      // Once there's an available fallback surface that can be employed, then
+      // the primary surface is updated as soon as the frame rect changes.
+      //
+      // The compositor will attempt to composite the primary surface within a
+      // give deadline (4 frames is the default). If the primary surface isn't
+      // available for four frames, then the fallback surface will be used.
+      compositing_helper_->SetPrimarySurfaceInfo(surface_info);
+    }
   }
-  // TODO(fsamuel): When surface synchronization is enabled, only set the
-  // fallback here. The primary should be updated on resize/device scale factor
-  // change.
-  compositing_helper_->SetPrimarySurfaceInfo(surface_info);
+
+  if (!enable_surface_synchronization_)
+    compositing_helper_->SetPrimarySurfaceInfo(surface_info);
   compositing_helper_->SetFallbackSurfaceInfo(surface_info, sequence);
 }
 
@@ -362,7 +388,8 @@
   web_frame_->DidStartLoading();
 }
 
-void RenderFrameProxy::OnViewChanged() {
+void RenderFrameProxy::OnViewChanged(const viz::FrameSinkId& frame_sink_id) {
+  frame_sink_id_ = frame_sink_id;
   // Resend the FrameRects and allocate a new viz::LocalSurfaceId when the view
   // changes.
   ResendFrameRects();
@@ -521,8 +548,19 @@
 
 void RenderFrameProxy::FrameRectsChanged(const blink::WebRect& frame_rect) {
   gfx::Rect rect = frame_rect;
-  if (frame_rect_.size() != rect.size() || !local_surface_id_.is_valid())
+  if (frame_rect_.size() != rect.size() || !local_surface_id_.is_valid()) {
     local_surface_id_ = local_surface_id_allocator_.GenerateId();
+    if (compositing_helper_ && enable_surface_synchronization_ &&
+        frame_sink_id_.is_valid()) {
+      float device_scale_factor =
+          render_widget()->GetOriginalDeviceScaleFactor();
+      viz::SurfaceInfo surface_info(
+          viz::SurfaceId(frame_sink_id_, local_surface_id_),
+          device_scale_factor,
+          gfx::ScaleToCeiledSize(frame_rect_.size(), device_scale_factor));
+      compositing_helper_->SetPrimarySurfaceInfo(surface_info);
+    }
+  }
 
   frame_rect_ = rect;
 
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index a471d36c..3c203de6 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -169,7 +169,7 @@
   void OnSetChildFrameSurface(const viz::SurfaceInfo& surface_info,
                               const viz::SurfaceSequence& sequence);
   void OnUpdateOpener(int opener_routing_id);
-  void OnViewChanged();
+  void OnViewChanged(const viz::FrameSinkId& frame_sink_id);
   void OnDidStopLoading();
   void OnDidUpdateFramePolicy(
       blink::WebSandboxFlags flags,
@@ -205,9 +205,12 @@
   RenderWidget* render_widget_;
 
   gfx::Rect frame_rect_;
+  viz::FrameSinkId frame_sink_id_;
   viz::LocalSurfaceId local_surface_id_;
   viz::LocalSurfaceIdAllocator local_surface_id_allocator_;
 
+  bool enable_surface_synchronization_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(RenderFrameProxy);
 };