Cherry-pick: aw: Add and use DrawGL kModeSync

Clean cherry-pick of Chromium r285712

BUG: 16526750

Original description:

We need to support this new hidden api to avoid onDraw getting ahead of
DrawGL. Without this, onDraw can finish producing frame n+1 before DrawGL
consumes frame n, in which case DrawGL skips a frame.

Also make AwDrawGLInfo future proof.

Change-Id: I297341cce7d2aa85af1704898fdb6b48a1f4d6dd
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc
index 4ed2859..df7e361 100644
--- a/android_webview/browser/hardware_renderer.cc
+++ b/android_webview/browser/hardware_renderer.cc
@@ -76,11 +76,13 @@
       last_egl_context_(eglGetCurrentContext()),
       stencil_enabled_(false),
       viewport_clip_valid_for_dcheck_(false),
+      gl_surface_(new AwGLSurface),
       root_layer_(cc::Layer::Create()),
+      resource_collection_(new cc::DelegatedFrameResourceCollection),
       output_surface_(NULL) {
   DCHECK(last_egl_context_);
 
-  gl_surface_ = new AwGLSurface;
+  resource_collection_->SetClient(this);
 
   cc::LayerTreeSettings settings;
 
@@ -105,17 +107,15 @@
   root_layer_ = NULL;
   delegated_layer_ = NULL;
   frame_provider_ = NULL;
-  if (resource_collection_.get()) {
 #if DCHECK_IS_ON
-    // Check collection is empty.
-    cc::ReturnedResourceArray returned_resources;
-    resource_collection_->TakeUnusedResourcesForChildCompositor(
-        &returned_resources);
-    DCHECK_EQ(0u, returned_resources.size());
+  // Check collection is empty.
+  cc::ReturnedResourceArray returned_resources;
+  resource_collection_->TakeUnusedResourcesForChildCompositor(
+      &returned_resources);
+  DCHECK_EQ(0u, returned_resources.size());
 #endif  // DCHECK_IS_ON
 
-    resource_collection_->SetClient(NULL);
-  }
+  resource_collection_->SetClient(NULL);
 }
 
 void HardwareRenderer::DidBeginMainFrame() {
@@ -127,6 +127,48 @@
   output_surface_->SetDrawConstraints(viewport_, clip_);
 }
 
+void HardwareRenderer::CommitFrame() {
+  scoped_ptr<DrawGLInput> input = shared_renderer_state_->PassDrawGLInput();
+  if (!input.get()) {
+    DLOG(WARNING) << "No frame to commit";
+    return;
+  }
+
+  DCHECK(!input->frame.gl_frame_data);
+  DCHECK(!input->frame.software_frame_data);
+
+  // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
+  // renderer frame, assuming that the browser compositor will scale
+  // it back up to device scale.  But on Android we put our browser layers in
+  // physical pixels and set our browser CC device_scale_factor to 1, so this
+  // suppresses the transform.
+  input->frame.delegated_frame_data->device_scale_factor = 1.0f;
+
+  gfx::Size frame_size =
+      input->frame.delegated_frame_data->render_pass_list.back()
+          ->output_rect.size();
+  bool size_changed = frame_size != frame_size_;
+  frame_size_ = frame_size;
+  scroll_offset_ = input->scroll_offset;
+
+  if (!frame_provider_ || size_changed) {
+    if (delegated_layer_) {
+      delegated_layer_->RemoveFromParent();
+    }
+
+    frame_provider_ = new cc::DelegatedFrameProvider(
+        resource_collection_.get(), input->frame.delegated_frame_data.Pass());
+
+    delegated_layer_ = cc::DelegatedRendererLayer::Create(frame_provider_);
+    delegated_layer_->SetBounds(gfx::Size(input->width, input->height));
+    delegated_layer_->SetIsDrawable(true);
+
+    root_layer_->AddChild(delegated_layer_);
+  } else {
+    frame_provider_->SetFrameData(input->frame.delegated_frame_data.Pass());
+  }
+}
+
 void HardwareRenderer::DrawGL(bool stencil_enabled,
                               int framebuffer_binding_ext,
                               AwDrawGLInfo* draw_info) {
@@ -140,52 +182,15 @@
     return;
   }
 
+  if (!delegated_layer_.get()) {
+    DLOG(ERROR) << "No frame committed";
+    return;
+  }
+
   // TODO(boliu): Handle context loss.
   if (last_egl_context_ != current_context)
     DLOG(WARNING) << "EGLContextChanged";
 
-  scoped_ptr<DrawGLInput> input = shared_renderer_state_->PassDrawGLInput();
-  if (!resource_collection_.get()) {
-    resource_collection_ = new cc::DelegatedFrameResourceCollection;
-    resource_collection_->SetClient(this);
-  }
-
-  if (input.get()) {
-    DCHECK(!input->frame.gl_frame_data);
-    DCHECK(!input->frame.software_frame_data);
-
-    // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
-    // renderer frame, assuming that the browser compositor will scale
-    // it back up to device scale.  But on Android we put our browser layers in
-    // physical pixels and set our browser CC device_scale_factor to 1, so this
-    // suppresses the transform.
-    input->frame.delegated_frame_data->device_scale_factor = 1.0f;
-
-    gfx::Size frame_size =
-        input->frame.delegated_frame_data->render_pass_list.back()
-            ->output_rect.size();
-    bool size_changed = frame_size != frame_size_;
-    frame_size_ = frame_size;
-    scroll_offset_ = input->scroll_offset;
-
-    if (!frame_provider_ || size_changed) {
-      if (delegated_layer_) {
-        delegated_layer_->RemoveFromParent();
-      }
-
-      frame_provider_ = new cc::DelegatedFrameProvider(
-          resource_collection_.get(), input->frame.delegated_frame_data.Pass());
-
-      delegated_layer_ = cc::DelegatedRendererLayer::Create(frame_provider_);
-      delegated_layer_->SetBounds(gfx::Size(input->width, input->height));
-      delegated_layer_->SetIsDrawable(true);
-
-      root_layer_->AddChild(delegated_layer_);
-    } else {
-      frame_provider_->SetFrameData(input->frame.delegated_frame_data.Pass());
-    }
-  }
-
   viewport_.SetSize(draw_info->width, draw_info->height);
   layer_tree_host_->SetViewportSize(viewport_);
   clip_.SetRect(draw_info->clip_left,
diff --git a/android_webview/browser/hardware_renderer.h b/android_webview/browser/hardware_renderer.h
index 115ff0e..f69d587 100644
--- a/android_webview/browser/hardware_renderer.h
+++ b/android_webview/browser/hardware_renderer.h
@@ -35,6 +35,7 @@
   void DrawGL(bool stencil_enabled,
               int framebuffer_binding_ext,
               AwDrawGLInfo* draw_info);
+  void CommitFrame();
 
   // cc::LayerTreeHostClient overrides.
   virtual void WillBeginMainFrame(int frame_id) OVERRIDE {}
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 32cc8d1..cc5e6a3 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -342,6 +342,12 @@
 }
 
 void AwContents::DrawGL(AwDrawGLInfo* draw_info) {
+  if (draw_info->mode == AwDrawGLInfo::kModeSync) {
+    if (hardware_renderer_)
+      hardware_renderer_->CommitFrame();
+    return;
+  }
+
   {
     GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
     base::AutoLock lock(render_thread_lock_);
@@ -366,6 +372,7 @@
 
   if (!hardware_renderer_) {
     hardware_renderer_.reset(new HardwareRenderer(&shared_renderer_state_));
+    hardware_renderer_->CommitFrame();
   }
 
   hardware_renderer_->DrawGL(state_restore.stencil_enabled(),
diff --git a/android_webview/public/browser/draw_gl.h b/android_webview/public/browser/draw_gl.h
index 6409598..4a43523 100644
--- a/android_webview/public/browser/draw_gl.h
+++ b/android_webview/public/browser/draw_gl.h
@@ -9,11 +9,15 @@
 extern "C" {
 #endif
 
+static const int kAwDrawGLInfoVersion = 1;
+
 // Holds the information required to trigger an OpenGL drawing operation.
 struct AwDrawGLInfo {
+  int version;  // The AwDrawGLInfo this struct was built with.
+
   // Input: tells the draw function what action to perform.
   enum Mode {
-    kModeDraw,
+    kModeDraw = 0,
     kModeProcess,
     kModeProcessNoContext,
     kModeSync,