content: Double tile memory for large monitors (4k)

With the current memory limits, the compositor experiences frequent out
of memory issues when running on 4k monitors. This patch doubles the
memory allowed to use when the screen resolution is high enough
(>= 3500px by default).

R=ericrk@chromium.org, piman@chromium.org

Bug: 695427
Change-Id: I73884ae93d7ccd32fd76b8e40f3a596a02e4eaae
Reviewed-on: https://chromium-review.googlesource.com/575445
Reviewed-by: Eric Karl <ericrk@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Commit-Queue: Vladimir Levin <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#487364}
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index fd27299..476888c 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -534,7 +534,7 @@
     settings.max_staging_buffer_usage_in_bytes /= 4;
 
   cc::ManagedMemoryPolicy defaults = settings.gpu_memory_policy;
-  settings.gpu_memory_policy = GetGpuMemoryPolicy(defaults);
+  settings.gpu_memory_policy = GetGpuMemoryPolicy(defaults, screen_info);
   settings.software_memory_policy.num_resources_limit =
       base::SharedMemory::GetHandleLimit() / 3;
 
@@ -546,7 +546,8 @@
 
 // static
 cc::ManagedMemoryPolicy RenderWidgetCompositor::GetGpuMemoryPolicy(
-    const cc::ManagedMemoryPolicy& default_policy) {
+    const cc::ManagedMemoryPolicy& default_policy,
+    const ScreenInfo& screen_info) {
   cc::ManagedMemoryPolicy actual = default_policy;
   actual.bytes_limit_when_visible = 0;
 
@@ -628,6 +629,16 @@
   actual.bytes_limit_when_visible = 512 * 1024 * 1024;
   actual.priority_cutoff_when_visible =
       gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
+
+  // For large monitors (4k), double the tile memory to avoid frequent out of
+  // memory problems. 4k could mean a screen width of anywhere from 3840 to 4096
+  // (see https://en.wikipedia.org/wiki/4K_resolution). We use 3500 as a proxy
+  // for "large enough".
+  static const int kLargeDisplayThreshold = 3500;
+  int display_width =
+      std::round(screen_info.rect.width() * screen_info.device_scale_factor);
+  if (display_width >= kLargeDisplayThreshold)
+    actual.bytes_limit_when_visible *= 2;
 #endif
   return actual;
 }
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index bf36242d..719c56d 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -83,7 +83,8 @@
                   std::unique_ptr<cc::AnimationHost> animation_host);
 
   static cc::ManagedMemoryPolicy GetGpuMemoryPolicy(
-      const cc::ManagedMemoryPolicy& policy);
+      const cc::ManagedMemoryPolicy& policy,
+      const ScreenInfo& screen_info);
 
   void SetNeverVisible();
   const base::WeakPtr<cc::InputHandler>& GetInputHandler();
diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc
index 05192682..b7c0b63 100644
--- a/content/renderer/gpu/render_widget_compositor_unittest.cc
+++ b/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -315,5 +315,36 @@
 }
 #endif
 
+// Verify desktop memory limit calculations.
+#if !defined(OS_ANDROID)
+TEST(RenderWidgetCompositorTest, IgnoreGivenMemoryPolicy) {
+  auto policy = RenderWidgetCompositor::GetGpuMemoryPolicy(
+      cc::ManagedMemoryPolicy(256), ScreenInfo());
+  EXPECT_EQ(512u * 1024u * 1024u, policy.bytes_limit_when_visible);
+  EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
+            policy.priority_cutoff_when_visible);
+}
+
+TEST(RenderWidgetCompositorTest, LargeScreensUseMoreMemory) {
+  ScreenInfo screen_info;
+
+  screen_info.rect = gfx::Rect(4096, 2160);
+  screen_info.device_scale_factor = 1.f;
+  auto policy = RenderWidgetCompositor::GetGpuMemoryPolicy(
+      cc::ManagedMemoryPolicy(256), screen_info);
+  EXPECT_EQ(2u * 512u * 1024u * 1024u, policy.bytes_limit_when_visible);
+  EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
+            policy.priority_cutoff_when_visible);
+
+  screen_info.rect = gfx::Rect(2048, 1080);
+  screen_info.device_scale_factor = 2.f;
+  policy = RenderWidgetCompositor::GetGpuMemoryPolicy(
+      cc::ManagedMemoryPolicy(256), screen_info);
+  EXPECT_EQ(2u * 512u * 1024u * 1024u, policy.bytes_limit_when_visible);
+  EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
+            policy.priority_cutoff_when_visible);
+}
+#endif  // !defined(OS_ANDROID)
+
 }  // namespace
 }  // namespace content