Commit c1e540d0 authored by boliu@chromium.org's avatar boliu@chromium.org

[Android WebView] OnMemoryPressure to drop tile memory

In OnMemoryPressure, drop tiles on invisible browser views.

Not reusing base::MemoryPressureListener because Android
WebView requires onTrimMemory to be called synchronously.

BUG=
NOTRY=true

Review URL: https://codereview.chromium.org/25082006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226643 0039d316-1c4b-4281-b951-d872f2087c98
parent 317caf49
......@@ -140,6 +140,9 @@ class BrowserViewRenderer {
virtual bool IsVisible() = 0;
virtual gfx::Rect GetScreenRect() = 0;
// ComponentCallbacks2.onTrimMemory callback.
virtual void TrimMemory(int level) = 0;
virtual ~BrowserViewRenderer() {}
};
......
......@@ -19,7 +19,6 @@
#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"
......@@ -316,6 +315,65 @@ bool InProcessViewRenderer::RequestProcessGL() {
return client_->RequestDrawGL(NULL);
}
void InProcessViewRenderer::TrimMemory(int level) {
// 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;
// Nothing to drop.
if (!attached_to_window_ || !hardware_initialized_ || !compositor_)
return;
// Do not release resources on view we expect to get DrawGL soon.
if (level < TRIM_MEMORY_BACKGROUND) {
client_->UpdateGlobalVisibleRect();
if (view_visible_ && window_visible_ &&
!cached_global_visible_rect_.IsEmpty()) {
return;
}
}
if (!eglGetCurrentContext()) {
NOTREACHED();
return;
}
// Just set the memory limit to 0 and drop all tiles. This will be reset to
// normal levels in the next DrawGL call.
content::SynchronousCompositorMemoryPolicy policy;
policy.bytes_limit = 0;
policy.num_resources_limit = 0;
if (memory_policy_ == policy)
return;
TRACE_EVENT0("android_webview", "InProcessViewRenderer::TrimMemory");
ScopedAppGLStateRestore state_restore(
ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
ScopedAllowGL allow_gl;
SetMemoryPolicy(policy);
ForceFakeCompositeSW();
}
void InProcessViewRenderer::SetMemoryPolicy(
content::SynchronousCompositorMemoryPolicy& new_policy) {
if (memory_policy_ == new_policy)
return;
memory_policy_ = new_policy;
compositor_->SetMemoryPolicy(memory_policy_);
}
void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
client_->UpdateGlobalVisibleRect();
}
......@@ -423,7 +481,7 @@ void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
policy.bytes_limit =
(policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
policy.num_resources_limit = kMaxNumTilesToFillDisplay * g_memory_multiplier;
compositor_->SetMemoryPolicy(policy);
SetMemoryPolicy(policy);
DCHECK(gl_surface_);
gl_surface_->SetBackingFrameBufferObject(
......@@ -638,7 +696,7 @@ void InProcessViewRenderer::OnDetachedFromWindow() {
DCHECK(compositor_);
ScopedAppGLStateRestore state_restore(
ScopedAppGLStateRestore::MODE_DETACH_FROM_WINDOW);
ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
ScopedAllowGL allow_gl;
compositor_->ReleaseHwDraw();
......@@ -869,11 +927,15 @@ void InProcessViewRenderer::FallbackTickFired() {
// This should only be called if OnDraw or DrawGL did not come in time, which
// means block_invalidates_ must still be true.
DCHECK(block_invalidates_);
if (compositor_needs_continuous_invalidate_ && compositor_) {
if (compositor_needs_continuous_invalidate_ && compositor_)
ForceFakeCompositeSW();
}
void InProcessViewRenderer::ForceFakeCompositeSW() {
DCHECK(compositor_);
SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 1, 1);
SkCanvas canvas(&device);
CompositeSW(&canvas);
}
}
bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) {
......
......@@ -10,6 +10,7 @@
#include "android_webview/browser/browser_view_renderer.h"
#include "android_webview/browser/gl_view_renderer_manager.h"
#include "base/cancelable_callback.h"
#include "content/public/browser/android/synchronous_compositor.h"
#include "content/public/browser/android/synchronous_compositor_client.h"
#include "ui/gfx/vector2d_f.h"
......@@ -71,6 +72,7 @@ class InProcessViewRenderer : public BrowserViewRenderer,
virtual bool IsAttachedToWindow() OVERRIDE;
virtual bool IsVisible() OVERRIDE;
virtual gfx::Rect GetScreenRect() OVERRIDE;
virtual void TrimMemory(int level) OVERRIDE;
// SynchronousCompositorClient overrides
virtual void DidInitializeCompositor(
......@@ -108,6 +110,7 @@ class InProcessViewRenderer : public BrowserViewRenderer,
// If we call up view invalidate and OnDraw is not called before a deadline,
// then we keep ticking the SynchronousCompositor so it can make progress.
void FallbackTickFired();
void ForceFakeCompositeSW();
void NoLongerExpectsDrawGL();
......@@ -115,6 +118,8 @@ class InProcessViewRenderer : public BrowserViewRenderer,
gfx::Vector2d max_scroll_offset() const;
void SetMemoryPolicy(content::SynchronousCompositorMemoryPolicy& new_policy);
// For debug tracing or logging. Return the string representation of this
// view renderer's state and the |draw_info| if provided.
std::string ToString(AwDrawGLInfo* draw_info) const;
......@@ -176,6 +181,8 @@ class InProcessViewRenderer : public BrowserViewRenderer,
GLViewRendererManager::Key manager_key_;
content::SynchronousCompositorMemoryPolicy memory_policy_;
DISALLOW_COPY_AND_ASSIGN(InProcessViewRenderer);
};
......
......@@ -64,7 +64,7 @@ ScopedAppGLStateRestore::ScopedAppGLStateRestore(CallMode mode) : mode_(mode) {
DCHECK_EQ(0, vertex_array_buffer_binding_);
DCHECK_EQ(0, index_array_buffer_binding_);
break;
case MODE_DETACH_FROM_WINDOW:
case MODE_RESOURCE_MANAGEMENT:
glGetBooleanv(GL_BLEND, &blend_enabled_);
glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb_);
glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha_);
......@@ -205,7 +205,11 @@ ScopedAppGLStateRestore::~ScopedAppGLStateRestore() {
enable_sample_alpha_to_coverage_);
GLEnableDisable(GL_SAMPLE_COVERAGE, enable_sample_coverage_);
if (mode_ == MODE_DETACH_FROM_WINDOW) {
switch(mode_) {
case MODE_DRAW:
// No-op.
break;
case MODE_RESOURCE_MANAGEMENT:
GLEnableDisable(GL_BLEND, blend_enabled_);
glBlendFuncSeparate(
blend_src_rgb_, blend_dest_rgb_, blend_src_alpha_, blend_dest_alpha_);
......@@ -216,6 +220,7 @@ ScopedAppGLStateRestore::~ScopedAppGLStateRestore() {
glScissor(
scissor_box_[0], scissor_box_[1], scissor_box_[2], scissor_box_[3]);
break;
}
GLEnableDisable(GL_STENCIL_TEST, stencil_test_);
......
......@@ -18,7 +18,7 @@ class ScopedAppGLStateRestore {
public:
enum CallMode {
MODE_DRAW,
MODE_DETACH_FROM_WINDOW
MODE_RESOURCE_MANAGEMENT,
};
ScopedAppGLStateRestore(CallMode mode);
......
......@@ -4,6 +4,8 @@
package org.chromium.android_webview;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
......@@ -193,6 +195,8 @@ public class AwContents {
private AwAutofillManagerDelegate mAwAutofillManagerDelegate;
private ComponentCallbacks2 mComponentCallbacks;
private static final class DestroyRunnable implements Runnable {
private int mNativeAwContents;
private DestroyRunnable(int nativeAwContents) {
......@@ -431,6 +435,22 @@ public class AwContents {
}
}
private class AwComponentCallbacks implements ComponentCallbacks2 {
@Override
public void onTrimMemory(int level) {
if (mNativeAwContents == 0) return;
nativeTrimMemory(mNativeAwContents, level);
}
@Override
public void onLowMemory() {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
};
/**
* @param browserContext the browsing context to associate this view contents with.
* @param containerView the view-hierarchy item this object will be bound to.
......@@ -1480,6 +1500,10 @@ public class AwContents {
mContentViewCore.onAttachedToWindow();
nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(),
mContainerView.getHeight());
if (mComponentCallbacks != null) return;
mComponentCallbacks = new AwComponentCallbacks();
mContainerView.getContext().registerComponentCallbacks(mComponentCallbacks);
}
/**
......@@ -1494,6 +1518,11 @@ public class AwContents {
mContentViewCore.onDetachedFromWindow();
if (mComponentCallbacks != null) {
mContainerView.getContext().unregisterComponentCallbacks(mComponentCallbacks);
mComponentCallbacks = null;
}
if (mPendingDetachCleanupReferences != null) {
for (int i = 0; i < mPendingDetachCleanupReferences.size(); ++i) {
mPendingDetachCleanupReferences.get(i).cleanupNow();
......@@ -1967,4 +1996,6 @@ public class AwContents {
int nativeAwContents, boolean value, String requestingFrame);
private native void nativeSetJsOnlineProperty(int nativeAwContents, boolean networkUp);
private native void nativeTrimMemory(int nativeAwContents, int level);
}
......@@ -898,4 +898,8 @@ void AwContents::SetJsOnlineProperty(JNIEnv* env,
render_view_host_ext_->SetJsOnlineProperty(network_up);
}
void AwContents::TrimMemory(JNIEnv* env, jobject obj, jint level) {
browser_view_renderer_->TrimMemory(level);
}
} // namespace android_webview
......@@ -179,6 +179,7 @@ class AwContents : public FindHelper::Listener,
void SetAwAutofillManagerDelegate(jobject delegate);
void SetJsOnlineProperty(JNIEnv* env, jobject obj, jboolean network_up);
void TrimMemory(JNIEnv* env, jobject obj, jint level);
private:
void InitAutofillIfNecessary(bool enabled);
......
......@@ -9,4 +9,15 @@ namespace content {
SynchronousCompositorMemoryPolicy::SynchronousCompositorMemoryPolicy()
: bytes_limit(0), num_resources_limit(0) {}
bool SynchronousCompositorMemoryPolicy::operator==(
const SynchronousCompositorMemoryPolicy& other) const {
return bytes_limit == other.bytes_limit &&
num_resources_limit == other.num_resources_limit;
}
bool SynchronousCompositorMemoryPolicy::operator!=(
const SynchronousCompositorMemoryPolicy& other) const {
return !(*this == other);
}
} // namespace content
......@@ -31,6 +31,9 @@ struct CONTENT_EXPORT SynchronousCompositorMemoryPolicy {
size_t num_resources_limit;
SynchronousCompositorMemoryPolicy();
bool operator==(const SynchronousCompositorMemoryPolicy& other) const;
bool operator!=(const SynchronousCompositorMemoryPolicy& other) const;
};
// Interface for embedders that wish to direct compositing operations
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment