Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2891)

Unified Diff: android_webview/browser/browser_view_renderer.cc

Issue 226363004: Global GPU memory manager for android webview (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address Bo's comments Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 937ed13259c1de75bde6d7c190b38566373c5351..7a3faedde7139e573bb1c71f811a33a007905006 100644
--- a/android_webview/browser/browser_view_renderer.cc
+++ b/android_webview/browser/browser_view_renderer.cc
@@ -13,6 +13,7 @@
#include "base/logging.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 "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -22,6 +23,8 @@
using base::android::AttachCurrentThread;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
+using content::BrowserThread;
+using content::SynchronousCompositorMemoryPolicy;
namespace android_webview {
@@ -29,6 +32,17 @@ namespace {
const int64 kFallbackTickTimeoutInMilliseconds = 20;
+// Used to calculate memory and resource allocation. Determined experimentally.
+const size_t kMemoryMultiplier = 10;
+// The number of tiles needed if the view takes up the whole viewport.
+const size_t kNumGrallocLimit = 150;
+const size_t kBytesPerPixel = 4;
+const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
+const size_t kTileAllocationStep = 20;
+// Becomes starved if the resource request cannot be granted kStarvedTimes in a
+// row. Let it be 1 for now to make it super aggresssive to evict other views.
+const size_t kStarvedTimes = 1;
+
class AutoResetWithLock {
public:
AutoResetWithLock(gfx::Vector2dF* scoped_variable,
@@ -79,16 +93,122 @@ BrowserViewRenderer::BrowserViewRenderer(
compositor_needs_continuous_invalidate_(false),
block_invalidates_(false),
width_(0),
- height_(0) {
+ height_(0),
+ num_consecutive_hungry_frames_(0) {
CHECK(web_contents_);
content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
-
// Currently the logic in this class relies on |has_compositor_| remaining
// false until the DidInitializeCompositor() call, hence it is not set here.
}
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);
+ ForceDropTiles();
+}
+
+SynchronousCompositorMemoryPolicy
+BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
+ SynchronousCompositorMemoryPolicy policy;
+ policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel *
+ draw_gl_input_.global_visible_rect.width() *
+ draw_gl_input_.global_visible_rect.height();
+ // Round up to a multiple of kMemoryAllocationStep.
+ policy.bytes_limit =
+ (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
+ policy.num_resources_limit = CalculateTileRequest();
+ 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) {
+ SynchronousCompositorMemoryPolicy current_policy =
+ shared_renderer_state_->GetMemoryPolicy();
+ GlobalTileManager* manager = GlobalTileManager::GetInstance();
+
+ size_t num_tiles = manager->RequestTiles(current_policy.num_resources_limit,
+ new_policy.num_resources_limit,
+ NeedsEviction(),
+ tile_manager_key_);
+ if (num_tiles < new_policy.num_resources_limit)
+ num_consecutive_hungry_frames_++;
+ else
+ num_consecutive_hungry_frames_ = 0;
+
+ new_policy.num_resources_limit = num_tiles;
+ shared_renderer_state_->SetMemoryPolicy(new_policy);
+}
+
+size_t BrowserViewRenderer::CalculateTileRequest() const {
+ double area = (double)draw_gl_input_.global_visible_rect.width() *
boliu 2014/05/01 00:37:40 against style guide to use c-style casts, always u
hush (inactive) 2014/05/01 19:03:04 CalculateTileRequest() is an inherited method. I w
+ draw_gl_input_.global_visible_rect.height();
+ double viewport = (double)draw_gl_input_.width * draw_gl_input_.height;
+ // Round up to a multiple of kTileAllocationStep. The minimum number of tiles
+ // is also kTileAllocationStep.
+ size_t tiles = std::max(kNumGrallocLimit * (area / viewport), 1.0);
+ tiles = (tiles + kTileAllocationStep - 1) / kTileAllocationStep *
+ kTileAllocationStep;
+ return tiles;
+}
+
+bool BrowserViewRenderer::NeedsEviction() const {
+ // If the hardware renderer is hungry for kStarvedTimes in a row, this
+ // browser view renderer is considered starved.
+ return num_consecutive_hungry_frames_ >= kStarvedTimes;
+}
+
+size_t BrowserViewRenderer::ForceDropTiles() {
+ size_t dropped_tiles = GetTilesNum();
+ SynchronousCompositorMemoryPolicy zero_policy;
+
+ shared_renderer_state_->SetMemoryPolicy(zero_policy);
+ shared_renderer_state_->GetCompositor()->SetMemoryPolicy(zero_policy);
+
+ // Now force a fake SW draw to make sure the tiles are dropped because the
+ // tile manager only manages tiles after a Draw.
+ // Making a fake SW draw is a hacky way to forcibly drop tiles. Maybe we can
+ // find better implementations.
+ ForceFakeCompositeSW();
+ return dropped_tiles;
+}
+
+size_t BrowserViewRenderer::GetTilesNum() const {
+ return shared_renderer_state_->GetMemoryPolicy().num_resources_limit;
}
bool BrowserViewRenderer::OnDraw(jobject java_canvas,
@@ -105,10 +225,22 @@ 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);
+ bool did_draw_gl = has_compositor_ && client_->RequestDrawGL(java_canvas);
+ 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 +362,20 @@ void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
attached_to_window_ = true;
width_ = width;
height_ = height;
+ tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this);
+ num_consecutive_hungry_frames_ = 0;
}
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_);
+ num_consecutive_hungry_frames_ = 0;
+ // 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 +409,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) {

Powered by Google App Engine
This is Rietveld 408576698