Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "android_webview/browser/browser_view_renderer.h" | 5 #include "android_webview/browser/browser_view_renderer.h" |
| 6 | 6 |
| 7 #include "android_webview/browser/browser_view_renderer_client.h" | 7 #include "android_webview/browser/browser_view_renderer_client.h" |
| 8 #include "android_webview/browser/shared_renderer_state.h" | 8 #include "android_webview/browser/shared_renderer_state.h" |
| 9 #include "android_webview/public/browser/draw_gl.h" | 9 #include "android_webview/public/browser/draw_gl.h" |
| 10 #include "base/android/jni_android.h" | 10 #include "base/android/jni_android.h" |
| 11 #include "base/auto_reset.h" | 11 #include "base/auto_reset.h" |
| 12 #include "base/debug/trace_event.h" | 12 #include "base/debug/trace_event.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
| 15 #include "content/public/browser/android/synchronous_compositor.h" | 15 #include "content/public/browser/android/synchronous_compositor.h" |
| 16 #include "content/public/browser/browser_thread.h" | |
| 16 #include "content/public/browser/web_contents.h" | 17 #include "content/public/browser/web_contents.h" |
| 17 #include "third_party/skia/include/core/SkBitmap.h" | 18 #include "third_party/skia/include/core/SkBitmap.h" |
| 18 #include "third_party/skia/include/core/SkCanvas.h" | 19 #include "third_party/skia/include/core/SkCanvas.h" |
| 19 #include "third_party/skia/include/core/SkPicture.h" | 20 #include "third_party/skia/include/core/SkPicture.h" |
| 20 #include "ui/gfx/vector2d_conversions.h" | 21 #include "ui/gfx/vector2d_conversions.h" |
| 21 | 22 |
| 22 using base::android::AttachCurrentThread; | 23 using base::android::AttachCurrentThread; |
| 23 using base::android::JavaRef; | 24 using base::android::JavaRef; |
| 24 using base::android::ScopedJavaLocalRef; | 25 using base::android::ScopedJavaLocalRef; |
| 25 | 26 using content::BrowserThread; |
| 26 namespace android_webview { | 27 namespace android_webview { |
| 27 | 28 |
| 28 namespace { | 29 namespace { |
| 29 | 30 |
| 30 const int64 kFallbackTickTimeoutInMilliseconds = 20; | 31 const int64 kFallbackTickTimeoutInMilliseconds = 20; |
| 31 | 32 |
| 33 // Used to calculate memory and resource allocation. Determined experimentally. | |
| 34 const size_t kMemoryMultiplier = 10; | |
| 35 const size_t kNumGrallocLimit = 150; | |
| 36 const size_t kBytesPerPixel = 4; | |
| 37 const size_t kMemoryAllocationStep = 5 * 1024 * 1024; | |
| 38 // Needs |kNumGrallocLimit| tiles to draw quickly, but it will be resource | |
| 39 // hungry if it only gets allocated less than |kGrallocHungryLimit|. | |
| 40 const size_t kGrallocHungryLimit = 100; | |
| 41 // Becomes starved if the resource request cannot be granted kStarvedTimes in a | |
|
boliu
2014/04/28 22:22:15
heh, hungry -> starved, actually makes sense
| |
| 42 // row. | |
| 43 const size_t kStarvedTimes = 5; | |
| 44 | |
| 45 typedef content::SynchronousCompositorMemoryPolicy Policy; | |
|
boliu
2014/04/28 22:22:15
Never do this. This is just confusing. If you want
hush (inactive)
2014/04/30 20:50:17
Done.
| |
| 32 class AutoResetWithLock { | 46 class AutoResetWithLock { |
| 33 public: | 47 public: |
| 34 AutoResetWithLock(gfx::Vector2dF* scoped_variable, | 48 AutoResetWithLock(gfx::Vector2dF* scoped_variable, |
| 35 gfx::Vector2dF new_value, | 49 gfx::Vector2dF new_value, |
| 36 base::Lock& lock) | 50 base::Lock& lock) |
| 37 : scoped_variable_(scoped_variable), | 51 : scoped_variable_(scoped_variable), |
| 38 original_value_(*scoped_variable), | 52 original_value_(*scoped_variable), |
| 39 lock_(lock) { | 53 lock_(lock) { |
| 40 base::AutoLock auto_lock(lock_); | 54 base::AutoLock auto_lock(lock_); |
| 41 *scoped_variable_ = new_value; | 55 *scoped_variable_ = new_value; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 72 view_visible_(false), | 86 view_visible_(false), |
| 73 window_visible_(false), | 87 window_visible_(false), |
| 74 attached_to_window_(false), | 88 attached_to_window_(false), |
| 75 dip_scale_(0.0), | 89 dip_scale_(0.0), |
| 76 page_scale_factor_(1.0), | 90 page_scale_factor_(1.0), |
| 77 on_new_picture_enable_(false), | 91 on_new_picture_enable_(false), |
| 78 clear_view_(false), | 92 clear_view_(false), |
| 79 compositor_needs_continuous_invalidate_(false), | 93 compositor_needs_continuous_invalidate_(false), |
| 80 block_invalidates_(false), | 94 block_invalidates_(false), |
| 81 width_(0), | 95 width_(0), |
| 82 height_(0) { | 96 height_(0), |
| 97 num_hungry_(0) { | |
| 83 CHECK(web_contents_); | 98 CHECK(web_contents_); |
| 84 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this); | 99 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this); |
| 85 | |
| 86 // Currently the logic in this class relies on |has_compositor_| remaining | 100 // Currently the logic in this class relies on |has_compositor_| remaining |
| 87 // false until the DidInitializeCompositor() call, hence it is not set here. | 101 // false until the DidInitializeCompositor() call, hence it is not set here. |
| 88 } | 102 } |
| 89 | 103 |
| 90 BrowserViewRenderer::~BrowserViewRenderer() { | 104 BrowserViewRenderer::~BrowserViewRenderer() { |
| 91 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL); | 105 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL); |
| 106 Policy zero_policy; | |
| 107 SetMemoryPolicy(zero_policy); | |
|
boliu
2014/04/28 22:22:15
This should already happen in OnDetached, not need
hush (inactive)
2014/04/30 20:50:17
I'm just being safe here.
Why is OnDetached guaran
boliu
2014/05/01 00:37:40
First, webview is never gc-ed before it is detache
| |
| 108 } | |
| 109 | |
| 110 // This function is supposed to be called after HardwareRenderer trims the | |
| 111 // memory of the compositor. | |
| 112 // It will update the cached memory policy in shared renderer state, as well as | |
| 113 // the tile resource allocation in GlobalTileManager. | |
| 114 void BrowserViewRenderer::TrimMemory() { | |
|
boliu
2014/04/28 22:22:15
Is TileManager aware that we are dropping tiles on
hush (inactive)
2014/04/30 20:50:17
You mean global tile manager?
Yes it is aware of i
| |
| 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 116 Policy zero_policy; | |
| 117 SetMemoryPolicy(zero_policy); | |
| 118 ForceFakeCompositeSW(); | |
| 119 ForceDropTiles(); | |
|
boliu
2014/04/28 22:22:15
Isn't ForceDropTiles enough? Why both?
hush (inactive)
2014/04/30 20:50:17
Yes it is enough. Removed.
On 2014/04/28 22:22:15,
| |
| 120 } | |
| 121 | |
| 122 Policy BrowserViewRenderer::CalculateMemoryPolicy() { | |
|
boliu
2014/04/28 22:22:15
IdealPolicy? Or DesiredPolicy?
hush (inactive)
2014/04/30 20:50:17
I changed the function name to CalculateDesiredMem
| |
| 123 Policy policy; | |
| 124 policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel * | |
| 125 draw_gl_input_.global_visible_rect.width() * | |
| 126 draw_gl_input_.global_visible_rect.height(); | |
| 127 // Round up to a multiple of kMemoryAllocationStep. | |
| 128 policy.bytes_limit = | |
| 129 (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep; | |
| 130 policy.num_resources_limit = CalculateTileRequest(); | |
| 131 return policy; | |
| 132 } | |
| 133 | |
| 134 // This function updates the cached memory policy in shared renderer state, as | |
| 135 // well as the tile resource allocation in GlobalTileManager. | |
| 136 void BrowserViewRenderer::SetMemoryPolicy(Policy& new_policy) { | |
|
boliu
2014/04/28 22:22:15
SetMemoryPolicy sounds like a simple setter, this
hush (inactive)
2014/04/30 20:50:17
Good point (although I put some comments there to
| |
| 137 Policy current_policy = shared_renderer_state_->GetMemoryPolicy(); | |
| 138 GlobalTileManager* manager = GlobalTileManager::GetInstance(); | |
| 139 | |
| 140 size_t num_tiles = manager->RequestTiles(current_policy.num_resources_limit, | |
| 141 new_policy.num_resources_limit, IsStarved(), tile_manager_key_); | |
| 142 if (num_tiles < | |
| 143 std::min(kGrallocHungryLimit, new_policy.num_resources_limit)) { | |
| 144 num_hungry_++; | |
|
boliu
2014/04/28 22:22:15
this should only be modified in OnDraw. Too easy t
hush (inactive)
2014/04/30 20:50:17
SetMemoryPolicy is called in 3 places: OnDraw, Tri
| |
| 145 } else { | |
| 146 num_hungry_ = 0; | |
| 147 } | |
| 148 | |
| 149 new_policy.num_resources_limit = num_tiles; | |
| 150 shared_renderer_state_->SetMemoryPolicy(new_policy); | |
| 151 } | |
| 152 | |
| 153 size_t BrowserViewRenderer::CalculateTileRequest() { | |
| 154 return kNumGrallocLimit; | |
| 155 } | |
| 156 | |
| 157 bool BrowserViewRenderer::IsStarved() { | |
| 158 // If the hardware renderer is hungry for kStarvedTimes in a row, this | |
| 159 // hardware renderer is considered starved. | |
| 160 return num_hungry_ >= kStarvedTimes; | |
| 161 } | |
| 162 | |
| 163 size_t BrowserViewRenderer::ForceDropTiles() { | |
| 164 size_t dropped_tiles = | |
| 165 shared_renderer_state_->GetMemoryPolicy().num_resources_limit; | |
| 166 Policy zero_policy; | |
| 167 | |
| 168 shared_renderer_state_->SetMemoryPolicy(zero_policy); | |
| 169 shared_renderer_state_->GetCompositor()-> | |
| 170 SetMemoryPolicy(zero_policy); | |
| 171 | |
| 172 // Now force a fake SW draw to make sure the tiles are dropped because the | |
| 173 // tile manager only manages tiles after a Draw. | |
| 174 // Making a fake SW draw is a hacky way to forcibly drop tiles. Maybe we can | |
| 175 // find better implementations. | |
| 176 ForceFakeCompositeSW(); | |
| 177 return dropped_tiles; | |
| 92 } | 178 } |
| 93 | 179 |
| 94 bool BrowserViewRenderer::OnDraw(jobject java_canvas, | 180 bool BrowserViewRenderer::OnDraw(jobject java_canvas, |
| 95 bool is_hardware_canvas, | 181 bool is_hardware_canvas, |
| 96 const gfx::Vector2d& scroll, | 182 const gfx::Vector2d& scroll, |
| 97 const gfx::Rect& global_visible_rect, | 183 const gfx::Rect& global_visible_rect, |
| 98 const gfx::Rect& clip) { | 184 const gfx::Rect& clip) { |
| 99 draw_gl_input_.frame_id++; | 185 draw_gl_input_.frame_id++; |
| 100 draw_gl_input_.scroll_offset = scroll; | 186 draw_gl_input_.scroll_offset = scroll; |
| 101 draw_gl_input_.global_visible_rect = global_visible_rect; | 187 draw_gl_input_.global_visible_rect = global_visible_rect; |
| 102 draw_gl_input_.width = width_; | 188 draw_gl_input_.width = width_; |
| 103 draw_gl_input_.height = height_; | 189 draw_gl_input_.height = height_; |
| 104 if (clear_view_) | 190 if (clear_view_) |
| 105 return false; | 191 return false; |
| 106 if (is_hardware_canvas && attached_to_window_) { | 192 if (is_hardware_canvas && attached_to_window_) { |
| 107 shared_renderer_state_->SetDrawGLInput(draw_gl_input_); | 193 shared_renderer_state_->SetDrawGLInput(draw_gl_input_); |
| 194 | |
| 195 Policy old_policy = shared_renderer_state_->GetMemoryPolicy(); | |
| 196 Policy new_policy = CalculateMemoryPolicy(); | |
| 197 SetMemoryPolicy(new_policy); | |
| 108 // We should be performing a hardware draw here. If we don't have the | 198 // We should be performing a hardware draw here. If we don't have the |
| 109 // compositor yet or if RequestDrawGL fails, it means we failed this draw | 199 // compositor yet or if RequestDrawGL fails, it means we failed this draw |
| 110 // and thus return false here to clear to background color for this draw. | 200 // and thus return false here to clear to background color for this draw. |
| 111 return has_compositor_ && client_->RequestDrawGL(java_canvas); | 201 bool did_draw_gl = has_compositor_ && client_->RequestDrawGL(java_canvas); |
| 202 if (did_draw_gl) | |
| 203 GlobalTileManager::GetInstance()->DidDrawGL(tile_manager_key_); | |
|
boliu
2014/04/28 22:22:15
Hmm, why do You you need to condition this on did_
hush (inactive)
2014/04/30 20:50:17
I want to be accurate about the MRU inside GlobalT
| |
| 204 else | |
| 205 SetMemoryPolicy(old_policy); | |
|
boliu
2014/04/28 22:22:15
Why set back to old policy?
hush (inactive)
2014/04/30 20:50:17
The memory policy is supposedly read by HardwareRe
boliu
2014/05/01 00:37:40
Let's assume that never happens, that if HardwareR
| |
| 206 | |
| 207 return did_draw_gl; | |
| 112 } | 208 } |
| 113 // Perform a software draw | 209 // Perform a software draw |
| 114 return DrawSWInternal(java_canvas, clip); | 210 return DrawSWInternal(java_canvas, clip); |
| 115 } | 211 } |
| 116 | 212 |
| 117 void BrowserViewRenderer::DidDrawGL(const DrawGLResult& result) { | 213 void BrowserViewRenderer::DidDrawGL(const DrawGLResult& result) { |
| 118 DidComposite(!result.clip_contains_visible_rect); | 214 DidComposite(!result.clip_contains_visible_rect); |
| 119 } | 215 } |
| 120 | 216 |
| 121 bool BrowserViewRenderer::DrawSWInternal(jobject java_canvas, | 217 bool BrowserViewRenderer::DrawSWInternal(jobject java_canvas, |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) { | 319 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) { |
| 224 TRACE_EVENT2("android_webview", | 320 TRACE_EVENT2("android_webview", |
| 225 "BrowserViewRenderer::OnAttachedToWindow", | 321 "BrowserViewRenderer::OnAttachedToWindow", |
| 226 "width", | 322 "width", |
| 227 width, | 323 width, |
| 228 "height", | 324 "height", |
| 229 height); | 325 height); |
| 230 attached_to_window_ = true; | 326 attached_to_window_ = true; |
| 231 width_ = width; | 327 width_ = width; |
| 232 height_ = height; | 328 height_ = height; |
| 329 tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this); | |
| 330 num_hungry_ = 0; | |
| 233 } | 331 } |
| 234 | 332 |
| 235 void BrowserViewRenderer::OnDetachedFromWindow() { | 333 void BrowserViewRenderer::OnDetachedFromWindow() { |
| 236 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow"); | 334 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow"); |
| 237 attached_to_window_ = false; | 335 attached_to_window_ = false; |
| 336 Policy zero_policy; | |
| 337 SetMemoryPolicy(zero_policy); | |
| 338 GlobalTileManager::GetInstance()->Remove(tile_manager_key_); | |
| 339 num_hungry_ = 0; | |
| 340 // The hardware resources are released in the destructor of hardware renderer, | |
| 341 // so we don't need to do it here. | |
| 342 // See AwContents::ReleaseHardwareDrawOnRenderThread(JNIEnv*, jobject). | |
| 238 } | 343 } |
| 239 | 344 |
| 240 bool BrowserViewRenderer::IsAttachedToWindow() const { | 345 bool BrowserViewRenderer::IsAttachedToWindow() const { |
| 241 return attached_to_window_; | 346 return attached_to_window_; |
| 242 } | 347 } |
| 243 | 348 |
| 244 bool BrowserViewRenderer::IsVisible() const { | 349 bool BrowserViewRenderer::IsVisible() const { |
| 245 // Ignore |window_visible_| if |attached_to_window_| is false. | 350 // Ignore |window_visible_| if |attached_to_window_| is false. |
| 246 return view_visible_ && (!attached_to_window_ || window_visible_); | 351 return view_visible_ && (!attached_to_window_ || window_visible_); |
| 247 } | 352 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 260 has_compositor_ = true; | 365 has_compositor_ = true; |
| 261 shared_renderer_state_->SetCompositorOnUiThread(compositor); | 366 shared_renderer_state_->SetCompositorOnUiThread(compositor); |
| 262 } | 367 } |
| 263 | 368 |
| 264 void BrowserViewRenderer::DidDestroyCompositor( | 369 void BrowserViewRenderer::DidDestroyCompositor( |
| 265 content::SynchronousCompositor* compositor) { | 370 content::SynchronousCompositor* compositor) { |
| 266 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor"); | 371 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor"); |
| 267 DCHECK(has_compositor_); | 372 DCHECK(has_compositor_); |
| 268 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 373 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 269 has_compositor_ = false; | 374 has_compositor_ = false; |
| 270 shared_renderer_state_->SetCompositorOnUiThread(NULL); | 375 shared_renderer_state_->SetCompositorOnUiThread(NULL); |
|
boliu
2014/04/28 22:22:15
DCHECK here memory policy is 0, (this should only
hush (inactive)
2014/04/30 20:50:17
Yeah. That makes sense.
On 2014/04/28 22:22:15, bo
| |
| 271 } | 376 } |
| 272 | 377 |
| 273 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) { | 378 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) { |
| 274 if (!ui_task_runner_->BelongsToCurrentThread()) { | 379 if (!ui_task_runner_->BelongsToCurrentThread()) { |
| 275 ui_task_runner_->PostTask( | 380 ui_task_runner_->PostTask( |
| 276 FROM_HERE, | 381 FROM_HERE, |
| 277 base::Bind(&BrowserViewRenderer::SetContinuousInvalidate, | 382 base::Bind(&BrowserViewRenderer::SetContinuousInvalidate, |
| 278 ui_thread_weak_ptr_, | 383 ui_thread_weak_ptr_, |
| 279 invalidate)); | 384 invalidate)); |
| 280 return; | 385 return; |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 598 base::StringAppendF(&str, | 703 base::StringAppendF(&str, |
| 599 "surface width height: [%d %d] ", | 704 "surface width height: [%d %d] ", |
| 600 draw_info->width, | 705 draw_info->width, |
| 601 draw_info->height); | 706 draw_info->height); |
| 602 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer); | 707 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer); |
| 603 } | 708 } |
| 604 return str; | 709 return str; |
| 605 } | 710 } |
| 606 | 711 |
| 607 } // namespace android_webview | 712 } // namespace android_webview |
| OLD | NEW |