Cherry-pick: Android WebView: Perform idle gpu service work

Clean cherry-pick of chromium crrev.com/r286171

BUG: 16550863

Change-Id: Ifd76210139e28280030b30756e821900313b2f8a
diff --git a/android_webview/browser/deferred_gpu_command_service.cc b/android_webview/browser/deferred_gpu_command_service.cc
index cb31954..8a137a8 100644
--- a/android_webview/browser/deferred_gpu_command_service.cc
+++ b/android_webview/browser/deferred_gpu_command_service.cc
@@ -66,8 +66,13 @@
   allow_gl.Get().Set(false);
   g_request_pending.Get().Set(false);
 
-  if (g_service.Get())
-    g_service.Get()->RunTasks();
+  DeferredGpuCommandService* service = g_service.Get();
+  if (service) {
+    service->RunTasks();
+    if (service->HasIdleWork()) {
+      service->RequestProcessGL();
+    }
+  }
 }
 
 // static
@@ -123,9 +128,41 @@
   }
 }
 
+bool DeferredGpuCommandService::HasIdleWork() {
+  base::AutoLock lock(tasks_lock_);
+  return idle_tasks_.size() > 0;
+}
+
 void DeferredGpuCommandService::ScheduleIdleWork(
     const base::Closure& callback) {
-  // TODO(sievers): Should this do anything?
+  {
+    base::AutoLock lock(tasks_lock_);
+    idle_tasks_.push(std::make_pair(base::Time::Now(), callback));
+  }
+  RequestProcessGL();
+}
+
+void DeferredGpuCommandService::PerformIdleWork(bool is_idle) {
+  DCHECK(ScopedAllowGL::IsAllowed());
+  static const base::TimeDelta kMaxIdleAge =
+      base::TimeDelta::FromMilliseconds(16);
+
+  const base::Time now = base::Time::Now();
+  while (HasIdleWork()) {
+    base::Closure task;
+    {
+      base::AutoLock lock(tasks_lock_);
+      if (!is_idle) {
+        // Only run old tasks if we are not really idle right now.
+        base::TimeDelta age(now - idle_tasks_.front().first);
+        if (age < kMaxIdleAge)
+          break;
+      }
+      task = idle_tasks_.front().second;
+      idle_tasks_.pop();
+    }
+    task.Run();
+  }
 }
 
 bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; }
diff --git a/android_webview/browser/deferred_gpu_command_service.h b/android_webview/browser/deferred_gpu_command_service.h
index 696854d..9a19fdd 100644
--- a/android_webview/browser/deferred_gpu_command_service.h
+++ b/android_webview/browser/deferred_gpu_command_service.h
@@ -6,10 +6,12 @@
 #define ANDROID_WEBVIEW_BROWSER_DEFERRED_GPU_COMMAND_SERVICE_H_
 
 #include <queue>
+#include <utility>
 
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_local.h"
+#include "base/time/time.h"
 #include "gpu/command_buffer/service/in_process_command_buffer.h"
 
 namespace android_webview {
@@ -41,6 +43,9 @@
       shader_translator_cache() OVERRIDE;
 
   void RunTasks();
+  // If |is_idle| is false, this will only run older idle tasks.
+  void PerformIdleWork(bool is_idle);
+  bool HasIdleWork();
 
   virtual void AddRef() const OVERRIDE;
   virtual void Release() const OVERRIDE;
@@ -50,12 +55,14 @@
   friend class base::RefCountedThreadSafe<DeferredGpuCommandService>;
 
  private:
+  friend class ScopedAllowGL;
   static void RequestProcessGL();
 
   DeferredGpuCommandService();
 
   base::Lock tasks_lock_;
   std::queue<base::Closure> tasks_;
+  std::queue<std::pair<base::Time, base::Closure> > idle_tasks_;
 
   scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache_;
   DISALLOW_COPY_AND_ASSIGN(DeferredGpuCommandService);
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 04b6da1..5cecb00 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -367,8 +367,12 @@
     return;
   }
 
-  if (draw_info->mode != AwDrawGLInfo::kModeDraw)
+  if (draw_info->mode != AwDrawGLInfo::kModeDraw) {
+    if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
+      DeferredGpuCommandService::GetInstance()->PerformIdleWork(true);
+    }
     return;
+  }
 
   if (!hardware_renderer_) {
     hardware_renderer_.reset(new HardwareRenderer(&shared_renderer_state_));
@@ -378,6 +382,7 @@
   hardware_renderer_->DrawGL(state_restore.stencil_enabled(),
                              state_restore.framebuffer_binding_ext(),
                              draw_info);
+  DeferredGpuCommandService::GetInstance()->PerformIdleWork(false);
 }
 
 namespace {