Chromium Code Reviews| 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..c0ae0d9ccc256cb1bdd05a69cf704d54e89d5402 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,100 @@ 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, true); |
| +} |
| + |
| +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; |
| + policy.num_resources_limit = CalculateTileRequest(width, height); |
| + 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, |
| + bool effective_immediately) { |
| + // 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, effective_immediately, tile_manager_key_); |
| +} |
| + |
| +size_t BrowserViewRenderer::CalculateTileRequest( |
|
boliu
2014/05/02 20:28:34
Don't need this helper, this is only called from o
hush (inactive)
2014/05/02 22:07:40
Done.
|
| + size_t global_visible_width, |
| + size_t global_visible_height) const { |
| + double area = |
| + static_cast<double>(global_visible_width * global_visible_height); |
|
boliu
2014/05/02 20:28:34
Do we really need to cast it to double? We are rou
hush (inactive)
2014/05/02 22:07:40
(talked in person)
I wanted to use double to preve
|
| + size_t tiles = std::max(area / g_tile_area * kTileMultiplier, 1.0); |
| + // Round up to a multiple of kTileAllocationStep. The minimum number of tiles |
| + // is also kTileAllocationStep. |
| + tiles = (tiles + kTileAllocationStep - 1) / kTileAllocationStep * |
| + kTileAllocationStep; |
| + return tiles; |
| +} |
| + |
| +void BrowserViewRenderer::SetNumTiles(size_t num_tiles, |
| + bool effective_immediately) { |
| + num_tiles_ = num_tiles; |
|
boliu
2014/05/02 20:28:34
Early out if these two are the same already.
hush (inactive)
2014/05/02 22:07:40
Done.
|
| + |
| + 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) { |
| + shared_renderer_state_->GetCompositor()->SetMemoryPolicy(new_policy); |
| + ForceFakeCompositeSW(); |
|
boliu
2014/05/02 20:28:34
Set dirty to false after this.
hush (inactive)
2014/05/02 22:07:40
Done.
|
| + } |
| +} |
| + |
| +size_t BrowserViewRenderer::GetNumTiles() const { |
| + return shared_renderer_state_->GetMemoryPolicy().num_resources_limit; |
| } |
| bool BrowserViewRenderer::OnDraw(jobject java_canvas, |
| @@ -106,10 +234,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, false); |
| // 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, false); |
| + |
| + return did_draw_gl; |
| } |
| // Perform a software draw |
| return DrawSWInternal(java_canvas, clip); |
| @@ -230,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, true); |
|
boliu
2014/05/02 20:28:34
Hmm, right now we don't need effective_immediately
hush (inactive)
2014/05/02 22:07:40
Done.
|
| + 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 +416,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) { |