Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / android_webview / browser / browser_view_renderer.cc
index 5bbc1ab..2fc8022 100644 (file)
@@ -9,19 +9,26 @@
 #include "android_webview/public/browser/draw_gl.h"
 #include "base/android/jni_android.h"
 #include "base/auto_reset.h"
+#include "base/command_line.h"
 #include "base/debug/trace_event.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 "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
 #include "ui/gfx/vector2d_conversions.h"
 
 using base::android::AttachCurrentThread;
 using base::android::JavaRef;
 using base::android::ScopedJavaLocalRef;
+using content::BrowserThread;
+using content::SynchronousCompositorMemoryPolicy;
 
 namespace android_webview {
 
@@ -29,6 +36,18 @@ namespace {
 
 const int64 kFallbackTickTimeoutInMilliseconds = 20;
 
+// Used to calculate memory allocation. Determined experimentally.
+const size_t kMemoryMultiplier = 10;
+const size_t kBytesPerPixel = 4;
+const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
+
+// Used to calculate tile allocation. Determined experimentally.
+const size_t kTileMultiplier = 12;
+const size_t kTileAllocationStep = 20;
+// This will be set by static function CalculateTileMemoryPolicy() during init.
+// See AwMainDelegate::BasicStartupComplete.
+size_t g_tile_area;
+
 class AutoResetWithLock {
  public:
   AutoResetWithLock(gfx::Vector2dF* scoped_variable,
@@ -56,6 +75,22 @@ class AutoResetWithLock {
 
 }  // namespace
 
+// static
+void BrowserViewRenderer::CalculateTileMemoryPolicy() {
+  CommandLine* cl = CommandLine::ForCurrentProcess();
+  const char kDefaultTileSize[] = "384";
+
+  if (!cl->HasSwitch(switches::kDefaultTileWidth))
+    cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
+
+  if (!cl->HasSwitch(switches::kDefaultTileHeight))
+    cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
+
+  size_t tile_size;
+  base::StringToSizeT(kDefaultTileSize, &tile_size);
+  g_tile_area = tile_size * tile_size;
+}
+
 BrowserViewRenderer::BrowserViewRenderer(
     BrowserViewRendererClient* client,
     SharedRendererState* shared_renderer_state,
@@ -79,7 +114,9 @@ BrowserViewRenderer::BrowserViewRenderer(
       compositor_needs_continuous_invalidate_(false),
       block_invalidates_(false),
       width_(0),
-      height_(0) {
+      height_(0),
+      num_tiles_(0u),
+      num_bytes_(0u) {
   CHECK(web_contents_);
   content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
 
@@ -89,6 +126,98 @@ BrowserViewRenderer::BrowserViewRenderer(
 
 BrowserViewRenderer::~BrowserViewRenderer() {
   content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
+  // OnDetachedFromWindow should be called before the destructor, so the memory
+  // policy should have already been updated.
+}
+
+// This function updates the cached memory policy in shared renderer state, as
+// well as the tile resource allocation in GlobalTileManager.
+void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  // Constants from Android ComponentCallbacks2.
+  enum {
+    TRIM_MEMORY_RUNNING_LOW = 10,
+    TRIM_MEMORY_UI_HIDDEN = 20,
+    TRIM_MEMORY_BACKGROUND = 40,
+  };
+
+  // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
+  // it does not indicate memory pressure, but merely that the app is
+  // backgrounded.
+  if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
+    return;
+
+  // Do not release resources on view we expect to get DrawGL soon.
+  if (level < TRIM_MEMORY_BACKGROUND && visible)
+    return;
+
+  // Just set the memory limit to 0 and drop all tiles. This will be reset to
+  // normal levels in the next DrawGL call.
+  SynchronousCompositorMemoryPolicy zero_policy;
+  if (shared_renderer_state_->GetMemoryPolicy() == zero_policy)
+    return;
+
+  TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
+
+  RequestMemoryPolicy(zero_policy);
+  EnforceMemoryPolicyImmediately(zero_policy);
+}
+
+SynchronousCompositorMemoryPolicy
+BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
+  SynchronousCompositorMemoryPolicy policy;
+  size_t width = draw_gl_input_.global_visible_rect.width();
+  size_t height = draw_gl_input_.global_visible_rect.height();
+  policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
+  // Round up to a multiple of kMemoryAllocationStep.
+  policy.bytes_limit =
+      (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
+
+  size_t tiles = width * height * kTileMultiplier / g_tile_area;
+  // Round up to a multiple of kTileAllocationStep. The minimum number of tiles
+  // is also kTileAllocationStep.
+  tiles = (tiles / kTileAllocationStep + 1) * kTileAllocationStep;
+  policy.num_resources_limit = tiles;
+  return policy;
+}
+
+// This function updates the cached memory policy in shared renderer state, as
+// well as the tile resource allocation in GlobalTileManager.
+void BrowserViewRenderer::RequestMemoryPolicy(
+    SynchronousCompositorMemoryPolicy& new_policy) {
+  // This will be used in SetNumTiles.
+  num_bytes_ = new_policy.bytes_limit;
+
+  GlobalTileManager* manager = GlobalTileManager::GetInstance();
+
+  // The following line will call BrowserViewRenderer::SetTilesNum().
+  manager->RequestTiles(new_policy.num_resources_limit, tile_manager_key_);
+}
+
+void BrowserViewRenderer::SetNumTiles(size_t num_tiles,
+                                      bool effective_immediately) {
+  if (num_tiles == num_tiles_)
+    return;
+  num_tiles_ = num_tiles;
+
+  SynchronousCompositorMemoryPolicy new_policy;
+  new_policy.num_resources_limit = num_tiles_;
+  new_policy.bytes_limit = num_bytes_;
+  shared_renderer_state_->SetMemoryPolicy(new_policy);
+
+  if (effective_immediately)
+    EnforceMemoryPolicyImmediately(new_policy);
+}
+
+void BrowserViewRenderer::EnforceMemoryPolicyImmediately(
+    SynchronousCompositorMemoryPolicy new_policy) {
+  shared_renderer_state_->GetCompositor()->SetMemoryPolicy(new_policy);
+  ForceFakeCompositeSW();
+  shared_renderer_state_->SetMemoryPolicyDirty(false);
+}
+
+size_t BrowserViewRenderer::GetNumTiles() const {
+  return shared_renderer_state_->GetMemoryPolicy().num_resources_limit;
 }
 
 bool BrowserViewRenderer::OnDraw(jobject java_canvas,
@@ -99,14 +228,29 @@ bool BrowserViewRenderer::OnDraw(jobject java_canvas,
   draw_gl_input_.frame_id++;
   draw_gl_input_.scroll_offset = scroll;
   draw_gl_input_.global_visible_rect = global_visible_rect;
+  draw_gl_input_.width = width_;
+  draw_gl_input_.height = height_;
   if (clear_view_)
     return false;
   if (is_hardware_canvas && attached_to_window_) {
     shared_renderer_state_->SetDrawGLInput(draw_gl_input_);
+
+    SynchronousCompositorMemoryPolicy old_policy =
+        shared_renderer_state_->GetMemoryPolicy();
+    SynchronousCompositorMemoryPolicy new_policy =
+        CalculateDesiredMemoryPolicy();
+    RequestMemoryPolicy(new_policy);
     // We should be performing a hardware draw here. If we don't have the
     // compositor yet or if RequestDrawGL fails, it means we failed this draw
     // and thus return false here to clear to background color for this draw.
-    return has_compositor_ && client_->RequestDrawGL(java_canvas);
+    bool did_draw_gl =
+        has_compositor_ && client_->RequestDrawGL(java_canvas, false);
+    if (did_draw_gl)
+      GlobalTileManager::GetInstance()->DidUse(tile_manager_key_);
+    else
+      RequestMemoryPolicy(old_policy);
+
+    return did_draw_gl;
   }
   // Perform a software draw
   return DrawSWInternal(java_canvas, clip);
@@ -144,21 +288,20 @@ skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
   TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
 
   // Return empty Picture objects for empty SkPictures.
-  skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
   if (width <= 0 || height <= 0) {
-    return picture;
+    return skia::AdoptRef(new SkPicture);
   }
 
   // Reset scroll back to the origin, will go back to the old
   // value when scroll_reset is out of scope.
   AutoResetWithLock scroll_reset(
-      &scroll_offset_dip_, gfx::Vector2dF(), scroll_offset_dip_lock_);
+      &scroll_offset_dip_, gfx::Vector2dF(), render_thread_lock_);
 
-  SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
+  SkPictureRecorder recorder;
+  SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
   if (has_compositor_)
     CompositeSW(rec_canvas);
-  picture->endRecording();
-  return picture;
+  return skia::AdoptRef(recorder.endRecording());
 }
 
 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
@@ -228,11 +371,18 @@ void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
   attached_to_window_ = true;
   width_ = width;
   height_ = height;
+  tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this);
 }
 
 void BrowserViewRenderer::OnDetachedFromWindow() {
   TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
   attached_to_window_ = false;
+  SynchronousCompositorMemoryPolicy zero_policy;
+  RequestMemoryPolicy(zero_policy);
+  GlobalTileManager::GetInstance()->Remove(tile_manager_key_);
+  // The hardware resources are released in the destructor of hardware renderer,
+  // so we don't need to do it here.
+  // See AwContents::ReleaseHardwareDrawOnRenderThread(JNIEnv*, jobject).
 }
 
 bool BrowserViewRenderer::IsAttachedToWindow() const {
@@ -266,27 +416,33 @@ void BrowserViewRenderer::DidDestroyCompositor(
   DCHECK(ui_task_runner_->BelongsToCurrentThread());
   has_compositor_ = false;
   shared_renderer_state_->SetCompositorOnUiThread(NULL);
+  SynchronousCompositorMemoryPolicy zero_policy;
+  DCHECK(shared_renderer_state_->GetMemoryPolicy() == zero_policy);
 }
 
 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
-  if (!ui_task_runner_->BelongsToCurrentThread()) {
-    ui_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&BrowserViewRenderer::SetContinuousInvalidate,
-                   ui_thread_weak_ptr_,
-                   invalidate));
-    return;
+  {
+    base::AutoLock lock(render_thread_lock_);
+    if (compositor_needs_continuous_invalidate_ == invalidate)
+      return;
+
+    TRACE_EVENT_INSTANT1("android_webview",
+                         "BrowserViewRenderer::SetContinuousInvalidate",
+                         TRACE_EVENT_SCOPE_THREAD,
+                         "invalidate",
+                         invalidate);
+    compositor_needs_continuous_invalidate_ = invalidate;
   }
-  if (compositor_needs_continuous_invalidate_ == invalidate)
-    return;
 
-  TRACE_EVENT_INSTANT1("android_webview",
-                       "BrowserViewRenderer::SetContinuousInvalidate",
-                       TRACE_EVENT_SCOPE_THREAD,
-                       "invalidate",
-                       invalidate);
-  compositor_needs_continuous_invalidate_ = invalidate;
-  EnsureContinuousInvalidation(false);
+  if (ui_task_runner_->BelongsToCurrentThread()) {
+    EnsureContinuousInvalidation(false);
+    return;
+  }
+  ui_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&BrowserViewRenderer::EnsureContinuousInvalidation,
+                 ui_thread_weak_ptr_,
+                 false));
 }
 
 void BrowserViewRenderer::SetDipScale(float dip_scale) {
@@ -322,7 +478,7 @@ void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
   DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
 
   {
-    base::AutoLock lock(scroll_offset_dip_lock_);
+    base::AutoLock lock(render_thread_lock_);
     if (scroll_offset_dip_ == scroll_offset_dip)
       return;
 
@@ -330,7 +486,8 @@ void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
   }
 
   if (has_compositor_)
-    shared_renderer_state_->CompositorDidChangeRootLayerScrollOffset();
+    shared_renderer_state_->GetCompositor()->
+        DidChangeRootLayerScrollOffset();
 }
 
 void BrowserViewRenderer::DidUpdateContent() {
@@ -379,7 +536,7 @@ void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
   }
 
   {
-    base::AutoLock lock(scroll_offset_dip_lock_);
+    base::AutoLock lock(render_thread_lock_);
     // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
     // DrawGl when http://crbug.com/249972 is fixed.
     if (scroll_offset_dip_ == scroll_offset_dip)
@@ -413,7 +570,7 @@ void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
 }
 
 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
-  base::AutoLock lock(scroll_offset_dip_lock_);
+  base::AutoLock lock(render_thread_lock_);
   return scroll_offset_dip_;
 }
 
@@ -549,7 +706,8 @@ void BrowserViewRenderer::ForceFakeCompositeSW() {
 
 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
   DCHECK(has_compositor_);
-  bool result = shared_renderer_state_->CompositorDemandDrawSw(canvas);
+  bool result = shared_renderer_state_->GetCompositor()->
+      DemandDrawSw(canvas);
   DidComposite(false);
   return result;
 }