Cherry-pick: [Android WebView] First cut memory management

Upstream info:
https://chromiumcodereview.appspot.com/23572023
crbug.com/286026

Conflicts:
	content/public/common/content_switches.h

BUG=10606165

Original CL description:

Based on simple algorithm of visible rect x constant.
Completely disregards the preferred allocation from based on
content of the page.

Constants extermined experimentally using current android
nexus devices.

Change-Id: I298f656be7fbab2bf4086f5b97bc4df9b92ab577
diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/in_process_view_renderer.cc
index 68ca450..7c84cc9 100644
--- a/android_webview/browser/in_process_view_renderer.cc
+++ b/android_webview/browser/in_process_view_renderer.cc
@@ -17,10 +17,12 @@
 #include "base/debug/trace_event.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/browser/android/synchronous_compositor.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/service/in_process_command_buffer.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -28,6 +30,7 @@
 #include "third_party/skia/include/core/SkGraphics.h"
 #include "third_party/skia/include/core/SkPicture.h"
 #include "third_party/skia/include/utils/SkCanvasStateUtils.h"
+#include "ui/gfx/android/device_display_info.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/transform.h"
 #include "ui/gfx/vector2d_conversions.h"
@@ -143,6 +146,13 @@
 
 const int64 kFallbackTickTimeoutInMilliseconds = 20;
 
+
+// Used to calculate memory and resource allocation. Determined experimentally.
+size_t g_memory_multiplier = 15;
+const size_t kMaxNumTilesToFillDisplay = 20;
+const size_t kBytesPerPixel = 4;
+const size_t kMemoryAllocationStep = 10 * 1024 * 1024;
+
 class ScopedAllowGL {
  public:
   ScopedAllowGL();
@@ -276,6 +286,39 @@
   compositor_ = NULL;
 }
 
+// static
+void InProcessViewRenderer::CalculateTileMemoryPolicy() {
+  CommandLine* cl = CommandLine::ForCurrentProcess();
+  if (cl->HasSwitch(switches::kTileMemoryMultiplier)) {
+    std::string string_value =
+        cl->GetSwitchValueASCII(switches::kTileMemoryMultiplier);
+    int int_value;
+    if (base::StringToInt(string_value, &int_value) &&
+        int_value >= 2 && int_value <= 50) {
+      g_memory_multiplier = int_value;
+    }
+  }
+
+  if (cl->HasSwitch(switches::kDefaultTileWidth) ||
+      cl->HasSwitch(switches::kDefaultTileHeight)) {
+    return;
+  }
+
+  // TODO(boliu): Should use view context to get the display dimensions, and
+  // pass tile size in a per WebContents setting instead of through command
+  // line switch.
+  gfx::DeviceDisplayInfo info;
+  int default_tile_size = 256;
+
+  if (info.GetDisplayWidth() >= 1080)
+    default_tile_size = 512;
+
+  std::stringstream size;
+  size << default_tile_size;
+  cl->AppendSwitchASCII(switches::kDefaultTileWidth, size.str());
+  cl->AppendSwitchASCII(switches::kDefaultTileHeight, size.str());
+}
+
 bool InProcessViewRenderer::RequestProcessGL() {
   return client_->RequestDrawGL(NULL);
 }
@@ -372,6 +415,18 @@
     return;
   }
 
+  // Update memory budget. This will no-op in compositor if the policy has not
+  // changed since last draw.
+  content::SynchronousCompositorMemoryPolicy policy;
+  policy.bytes_limit = g_memory_multiplier * kBytesPerPixel *
+                       cached_global_visible_rect_.width() *
+                       cached_global_visible_rect_.height();
+  // Round up to a multiple of kMemoryAllocationStep.
+  policy.bytes_limit =
+      (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
+  policy.num_resources_limit = kMaxNumTilesToFillDisplay * g_memory_multiplier;
+  compositor_->SetMemoryPolicy(policy);
+
   DCHECK(gl_surface_);
   gl_surface_->SetBackingFrameBufferObject(
       state_restore.framebuffer_binding_ext());
diff --git a/android_webview/browser/in_process_view_renderer.h b/android_webview/browser/in_process_view_renderer.h
index 620f010..a864a39 100644
--- a/android_webview/browser/in_process_view_renderer.h
+++ b/android_webview/browser/in_process_view_renderer.h
@@ -30,6 +30,8 @@
 class InProcessViewRenderer : public BrowserViewRenderer,
                               public content::SynchronousCompositorClient {
  public:
+  static void CalculateTileMemoryPolicy();
+
   InProcessViewRenderer(BrowserViewRenderer::Client* client,
                         JavaHelper* java_helper,
                         content::WebContents* web_contents);
diff --git a/android_webview/common/aw_switches.cc b/android_webview/common/aw_switches.cc
index a87e93a..b2663fa 100644
--- a/android_webview/common/aw_switches.cc
+++ b/android_webview/common/aw_switches.cc
@@ -10,4 +10,6 @@
 
 const char kDisableWebViewGLMode[] = "disable-webview-gl-mode";
 
+const char kTileMemoryMultiplier[] = "tile-memory-multiplier";
+
 }  // namespace switches
diff --git a/android_webview/common/aw_switches.h b/android_webview/common/aw_switches.h
index 2c7db28..e855bb7 100644
--- a/android_webview/common/aw_switches.h
+++ b/android_webview/common/aw_switches.h
@@ -13,6 +13,10 @@
 // When set, forces use of fallback SW path even on HW canvas.
 extern const char kDisableWebViewGLMode[];
 
+// Used to make tile memory allocation decision. Roughly the number of
+// displays that a single layer will have enough memory for.
+extern const char kTileMemoryMultiplier[];
+
 }  // namespace switches
 
 #endif  // ANDROID_WEBVIEW_COMMON_AW_SWITCHES_H_
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc
index 03194a4..6030ddb 100644
--- a/android_webview/lib/main/aw_main_delegate.cc
+++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "android_webview/browser/aw_content_browser_client.h"
 #include "android_webview/browser/gpu_memory_buffer_factory_impl.h"
+#include "android_webview/browser/in_process_view_renderer.h"
 #include "android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h"
 #include "android_webview/lib/aw_browser_dependency_factory_impl.h"
 #include "android_webview/native/aw_geolocation_permission_context.h"
@@ -50,6 +51,8 @@
       gpu_memory_buffer_factory_.get());
   gpu::InProcessCommandBuffer::EnableVirtualizedContext();
 
+  InProcessViewRenderer::CalculateTileMemoryPolicy();
+
   CommandLine* cl = CommandLine::ForCurrentProcess();
   cl->AppendSwitch(switches::kEnableBeginFrameScheduling);
   if (!cl->HasSwitch("disable-map-image"))
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc
index d9fe170..ac46918 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -331,6 +331,14 @@
   return output_surface_->DemandDrawSw(canvas);
 }
 
+void SynchronousCompositorImpl::SetMemoryPolicy(
+    const SynchronousCompositorMemoryPolicy& policy) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(output_surface_);
+
+  return output_surface_->SetMemoryPolicy(policy);
+}
+
 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
   if (input_handler_)
     input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.h b/content/browser/android/in_process/synchronous_compositor_impl.h
index 854c5eb..3189dcc 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.h
+++ b/content/browser/android/in_process/synchronous_compositor_impl.h
@@ -58,6 +58,8 @@
       gfx::Rect clip,
       bool stencil_enabled) OVERRIDE;
   virtual bool DemandDrawSw(SkCanvas* canvas) OVERRIDE;
+  virtual void SetMemoryPolicy(
+      const SynchronousCompositorMemoryPolicy& policy) OVERRIDE;
   virtual void DidChangeRootLayerScrollOffset() OVERRIDE;
 
   // SynchronousCompositorOutputSurfaceDelegate
diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
index 7e9b32e..dbf8274 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
@@ -9,7 +9,6 @@
 #include "cc/output/begin_frame_args.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/context_provider.h"
-#include "cc/output/managed_memory_policy.h"
 #include "cc/output/output_surface_client.h"
 #include "cc/output/software_output_device.h"
 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
@@ -112,7 +111,9 @@
       needs_begin_frame_(false),
       invoking_composite_(false),
       did_swap_buffer_(false),
-      current_sw_canvas_(NULL) {
+      current_sw_canvas_(NULL),
+      memory_policy_(0),
+      output_surface_client_(NULL) {
   capabilities_.deferred_gl_initialization = true;
   capabilities_.draw_and_swap_full_viewport_every_frame = true;
   capabilities_.adjust_deadline_for_parent = false;
@@ -140,21 +141,16 @@
   DCHECK(CalledOnValidThread());
   if (!cc::OutputSurface::BindToClient(surface_client))
     return false;
-  surface_client->SetTreeActivationCallback(
+
+  output_surface_client_ = surface_client;
+  output_surface_client_->SetTreeActivationCallback(
       base::Bind(&DidActivatePendingTree, routing_id_));
+  output_surface_client_->SetMemoryPolicy(memory_policy_);
+
   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
   if (delegate)
     delegate->DidBindOutputSurface(this);
 
-  const int bytes_limit = 64 * 1024 * 1024;
-  const int num_resources_limit = 100;
-  surface_client->SetMemoryPolicy(
-      cc::ManagedMemoryPolicy(bytes_limit,
-                              cc::ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
-                              0,
-                              cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
-                              num_resources_limit));
-
   return true;
 }
 
@@ -175,6 +171,7 @@
 
 void SynchronousCompositorOutputSurface::SwapBuffers(
     cc::CompositorFrame* frame) {
+  DCHECK(CalledOnValidThread());
   if (!ForcedDrawToSoftwareDevice()) {
     DCHECK(context3d());
     context3d()->shallowFlushCHROMIUM();
@@ -209,6 +206,7 @@
 }
 
 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
+  DCHECK(CalledOnValidThread());
   cc::OutputSurface::ReleaseGL();
 }
 
@@ -286,6 +284,16 @@
   // intentionally no-op here.
 }
 
+void SynchronousCompositorOutputSurface::SetMemoryPolicy(
+    const SynchronousCompositorMemoryPolicy& policy) {
+  DCHECK(CalledOnValidThread());
+  memory_policy_.bytes_limit_when_visible = policy.bytes_limit;
+  memory_policy_.num_resources_limit = policy.num_resources_limit;
+
+  if (output_surface_client_)
+    output_surface_client_->SetMemoryPolicy(memory_policy_);
+}
+
 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
 // thread.
diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.h b/content/browser/android/in_process/synchronous_compositor_output_surface.h
index 1573019..f28a58a 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.h
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.h
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "cc/output/managed_memory_policy.h"
 #include "cc/output/output_surface.h"
 #include "content/public/browser/android/synchronous_compositor.h"
 #include "ui/gfx/transform.h"
@@ -72,6 +73,7 @@
                     gfx::Rect clip,
                     bool stencil_enabled);
   bool DemandDrawSw(SkCanvas* canvas);
+  void SetMemoryPolicy(const SynchronousCompositorMemoryPolicy& policy);
 
  private:
   class SoftwareDevice;
@@ -99,6 +101,10 @@
   // Only valid (non-NULL) during a DemandDrawSw() call.
   SkCanvas* current_sw_canvas_;
 
+  cc::ManagedMemoryPolicy memory_policy_;
+
+  cc::OutputSurfaceClient* output_surface_client_;
+
   DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorOutputSurface);
 };
 
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index da6449c..6f9393d 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -37,6 +37,7 @@
     'public/browser/android/devtools_auth.h',
     'public/browser/android/download_controller_android.h',
     'public/browser/android/synchronous_compositor_client.h',
+    'public/browser/android/synchronous_compositor.cc',
     'public/browser/android/synchronous_compositor.h',
     'public/browser/browser_accessibility_state.h',
     'public/browser/browser_child_process_host.h',
diff --git a/content/content_browser.target.darwin-arm.mk b/content/content_browser.target.darwin-arm.mk
index 0f3c0c7..dc0ff47 100644
--- a/content/content_browser.target.darwin-arm.mk
+++ b/content/content_browser.target.darwin-arm.mk
@@ -42,6 +42,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit
 
 LOCAL_SRC_FILES := \
+	content/public/browser/android/synchronous_compositor.cc \
 	content/public/browser/browser_child_process_host_delegate.cc \
 	content/public/browser/browser_child_process_host_iterator.cc \
 	content/public/browser/browser_child_process_observer.cc \
diff --git a/content/content_browser.target.darwin-mips.mk b/content/content_browser.target.darwin-mips.mk
index 1446c16..f4c97e4 100644
--- a/content/content_browser.target.darwin-mips.mk
+++ b/content/content_browser.target.darwin-mips.mk
@@ -42,6 +42,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit
 
 LOCAL_SRC_FILES := \
+	content/public/browser/android/synchronous_compositor.cc \
 	content/public/browser/browser_child_process_host_delegate.cc \
 	content/public/browser/browser_child_process_host_iterator.cc \
 	content/public/browser/browser_child_process_observer.cc \
diff --git a/content/content_browser.target.darwin-x86.mk b/content/content_browser.target.darwin-x86.mk
index 5aaa636..b063950 100644
--- a/content/content_browser.target.darwin-x86.mk
+++ b/content/content_browser.target.darwin-x86.mk
@@ -42,6 +42,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit
 
 LOCAL_SRC_FILES := \
+	content/public/browser/android/synchronous_compositor.cc \
 	content/public/browser/browser_child_process_host_delegate.cc \
 	content/public/browser/browser_child_process_host_iterator.cc \
 	content/public/browser/browser_child_process_observer.cc \
diff --git a/content/content_browser.target.linux-arm.mk b/content/content_browser.target.linux-arm.mk
index 0f3c0c7..dc0ff47 100644
--- a/content/content_browser.target.linux-arm.mk
+++ b/content/content_browser.target.linux-arm.mk
@@ -42,6 +42,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit
 
 LOCAL_SRC_FILES := \
+	content/public/browser/android/synchronous_compositor.cc \
 	content/public/browser/browser_child_process_host_delegate.cc \
 	content/public/browser/browser_child_process_host_iterator.cc \
 	content/public/browser/browser_child_process_observer.cc \
diff --git a/content/content_browser.target.linux-mips.mk b/content/content_browser.target.linux-mips.mk
index 1446c16..f4c97e4 100644
--- a/content/content_browser.target.linux-mips.mk
+++ b/content/content_browser.target.linux-mips.mk
@@ -42,6 +42,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit
 
 LOCAL_SRC_FILES := \
+	content/public/browser/android/synchronous_compositor.cc \
 	content/public/browser/browser_child_process_host_delegate.cc \
 	content/public/browser/browser_child_process_host_iterator.cc \
 	content/public/browser/browser_child_process_observer.cc \
diff --git a/content/content_browser.target.linux-x86.mk b/content/content_browser.target.linux-x86.mk
index 5aaa636..b063950 100644
--- a/content/content_browser.target.linux-x86.mk
+++ b/content/content_browser.target.linux-x86.mk
@@ -42,6 +42,7 @@
 	$(gyp_shared_intermediate_dir)/ui/ui_resources/grit
 
 LOCAL_SRC_FILES := \
+	content/public/browser/android/synchronous_compositor.cc \
 	content/public/browser/browser_child_process_host_delegate.cc \
 	content/public/browser/browser_child_process_host_iterator.cc \
 	content/public/browser/browser_child_process_observer.cc \
diff --git a/content/public/browser/android/synchronous_compositor.cc b/content/public/browser/android/synchronous_compositor.cc
new file mode 100644
index 0000000..051aa5b
--- /dev/null
+++ b/content/public/browser/android/synchronous_compositor.cc
@@ -0,0 +1,12 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/android/synchronous_compositor.h"
+
+namespace content {
+
+SynchronousCompositorMemoryPolicy::SynchronousCompositorMemoryPolicy()
+    : bytes_limit(0), num_resources_limit(0) {}
+
+}  // namespace content
diff --git a/content/public/browser/android/synchronous_compositor.h b/content/public/browser/android/synchronous_compositor.h
index 810daf2..45b01eb 100644
--- a/content/public/browser/android/synchronous_compositor.h
+++ b/content/public/browser/android/synchronous_compositor.h
@@ -23,6 +23,16 @@
 
 class SynchronousCompositorClient;
 
+struct CONTENT_EXPORT SynchronousCompositorMemoryPolicy {
+  // Memory limit for rendering and pre-rendering.
+  size_t bytes_limit;
+
+  // Limit of number of GL resources used for rendering and pre-rendering.
+  size_t num_resources_limit;
+
+  SynchronousCompositorMemoryPolicy();
+};
+
 // Interface for embedders that wish to direct compositing operations
 // synchronously under their own control. Only meaningful when the
 // kEnableSyncrhonousRendererCompositor flag is specified.
@@ -65,6 +75,10 @@
   // and clip set there-in).
   virtual bool DemandDrawSw(SkCanvas* canvas) = 0;
 
+  // Set the memory limit policy of this compositor.
+  virtual void SetMemoryPolicy(
+      const SynchronousCompositorMemoryPolicy& policy) = 0;
+
   // Should be called by the embedder after the embedder had modified the
   // scroll offset of the root layer (as returned by
   // SynchronousCompositorClient::GetTotalRootLayerScrollOffset).
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 949400a..1542460 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -26,8 +26,8 @@
 CONTENT_EXPORT extern const char kBrowserCrashTest[];
 CONTENT_EXPORT extern const char kBrowserSubprocessPath[];
 extern const char kDebugPluginLoading[];
-extern const char kDefaultTileWidth[];
-extern const char kDefaultTileHeight[];
+CONTENT_EXPORT extern const char kDefaultTileWidth[];
+CONTENT_EXPORT extern const char kDefaultTileHeight[];
 CONTENT_EXPORT extern const char kDisable2dCanvasAntialiasing[];
 CONTENT_EXPORT extern const char kDisable3DAPIs[];
 CONTENT_EXPORT extern const char kDisableAccelerated2dCanvas[];