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 |