Index: android_webview/browser/browser_view_renderer.cc |
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc |
index c6188e3e4c60344fde7d02557aec2f510c28900f..7db981674578754db45baded9786af9ba539e759 100644 |
--- a/android_webview/browser/browser_view_renderer.cc |
+++ b/android_webview/browser/browser_view_renderer.cc |
@@ -9,11 +9,15 @@ |
#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" |
@@ -23,6 +27,8 @@ |
using base::android::AttachCurrentThread; |
using base::android::JavaRef; |
using base::android::ScopedJavaLocalRef; |
+using content::BrowserThread; |
+using content::SynchronousCompositorMemoryPolicy; |
namespace android_webview { |
@@ -30,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, |
@@ -57,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, |
@@ -90,6 +124,99 @@ 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 = std::max(width * height * kTileMultiplier / g_tile_area, 1u); |
+ // Round up to a multiple of kTileAllocationStep. The minimum number of tiles |
+ // is also kTileAllocationStep. |
+ tiles = (tiles + kTileAllocationStep - 1) / kTileAllocationStep * |
+ 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, |
@@ -106,10 +233,23 @@ bool BrowserViewRenderer::OnDraw(jobject java_canvas, |
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, false); |
+ 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); |
@@ -230,11 +370,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 { |
@@ -268,6 +415,8 @@ 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) { |