Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / android_webview / browser / shared_renderer_state.cc
blob69a41e53d3d0d33f621e93cee5bf714e0a277a1b
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
3 // found in the LICENSE file.
5 #include "android_webview/browser/shared_renderer_state.h"
7 #include "android_webview/browser/browser_view_renderer.h"
8 #include "android_webview/browser/child_frame.h"
9 #include "android_webview/browser/deferred_gpu_command_service.h"
10 #include "android_webview/browser/hardware_renderer.h"
11 #include "android_webview/browser/scoped_app_gl_state_restore.h"
12 #include "android_webview/public/browser/draw_gl.h"
13 #include "base/bind.h"
14 #include "base/lazy_instance.h"
15 #include "base/location.h"
16 #include "base/time/time.h"
17 #include "base/trace_event/trace_event_argument.h"
19 namespace android_webview {
21 namespace internal {
23 class RequestDrawGLTracker {
24 public:
25 RequestDrawGLTracker();
26 bool ShouldRequestOnNonUiThread(SharedRendererState* state);
27 bool ShouldRequestOnUiThread(SharedRendererState* state);
28 void ResetPending();
29 void SetQueuedFunctorOnUi(SharedRendererState* state);
31 private:
32 base::Lock lock_;
33 SharedRendererState* pending_ui_;
34 SharedRendererState* pending_non_ui_;
37 RequestDrawGLTracker::RequestDrawGLTracker()
38 : pending_ui_(NULL), pending_non_ui_(NULL) {
41 bool RequestDrawGLTracker::ShouldRequestOnNonUiThread(
42 SharedRendererState* state) {
43 base::AutoLock lock(lock_);
44 if (pending_ui_ || pending_non_ui_)
45 return false;
46 pending_non_ui_ = state;
47 return true;
50 bool RequestDrawGLTracker::ShouldRequestOnUiThread(SharedRendererState* state) {
51 base::AutoLock lock(lock_);
52 if (pending_non_ui_) {
53 pending_non_ui_->ResetRequestDrawGLCallback();
54 pending_non_ui_ = NULL;
56 // At this time, we could have already called RequestDrawGL on the UI thread,
57 // but the corresponding GL mode process hasn't happened yet. In this case,
58 // don't schedule another requestDrawGL on the UI thread.
59 if (pending_ui_)
60 return false;
61 pending_ui_ = state;
62 return true;
65 void RequestDrawGLTracker::ResetPending() {
66 base::AutoLock lock(lock_);
67 pending_non_ui_ = NULL;
68 pending_ui_ = NULL;
71 void RequestDrawGLTracker::SetQueuedFunctorOnUi(SharedRendererState* state) {
72 base::AutoLock lock(lock_);
73 DCHECK(state);
74 pending_ui_ = state;
75 pending_non_ui_ = NULL;
78 } // namespace internal
80 namespace {
82 base::LazyInstance<internal::RequestDrawGLTracker> g_request_draw_gl_tracker =
83 LAZY_INSTANCE_INITIALIZER;
87 SharedRendererState::SharedRendererState(
88 const scoped_refptr<base::SingleThreadTaskRunner>& ui_loop,
89 BrowserViewRenderer* browser_view_renderer)
90 : ui_loop_(ui_loop),
91 browser_view_renderer_(browser_view_renderer),
92 renderer_manager_key_(GLViewRendererManager::GetInstance()->NullKey()),
93 inside_hardware_release_(false),
94 weak_factory_on_ui_thread_(this) {
95 DCHECK(ui_loop_->BelongsToCurrentThread());
96 DCHECK(browser_view_renderer_);
97 ui_thread_weak_ptr_ = weak_factory_on_ui_thread_.GetWeakPtr();
98 ResetRequestDrawGLCallback();
101 SharedRendererState::~SharedRendererState() {
102 DCHECK(ui_loop_->BelongsToCurrentThread());
103 DCHECK(!hardware_renderer_.get());
106 void SharedRendererState::ClientRequestDrawGL(bool for_idle) {
107 if (ui_loop_->BelongsToCurrentThread()) {
108 if (!g_request_draw_gl_tracker.Get().ShouldRequestOnUiThread(this))
109 return;
110 ClientRequestDrawGLOnUI();
111 } else {
112 if (!g_request_draw_gl_tracker.Get().ShouldRequestOnNonUiThread(this))
113 return;
114 base::Closure callback;
116 base::AutoLock lock(lock_);
117 callback = request_draw_gl_closure_;
119 // 17ms is slightly longer than a frame, hoping that it will come
120 // after the next frame so that the idle work is taken care off by
121 // the next frame instead.
122 ui_loop_->PostDelayedTask(
123 FROM_HERE, callback,
124 for_idle ? base::TimeDelta::FromMilliseconds(17) : base::TimeDelta());
128 void SharedRendererState::DidDrawGLProcess() {
129 g_request_draw_gl_tracker.Get().ResetPending();
132 void SharedRendererState::ResetRequestDrawGLCallback() {
133 DCHECK(ui_loop_->BelongsToCurrentThread());
134 base::AutoLock lock(lock_);
135 request_draw_gl_cancelable_closure_.Reset(base::Bind(
136 &SharedRendererState::ClientRequestDrawGLOnUI, base::Unretained(this)));
137 request_draw_gl_closure_ = request_draw_gl_cancelable_closure_.callback();
140 void SharedRendererState::ClientRequestDrawGLOnUI() {
141 DCHECK(ui_loop_->BelongsToCurrentThread());
142 ResetRequestDrawGLCallback();
143 g_request_draw_gl_tracker.Get().SetQueuedFunctorOnUi(this);
144 if (!browser_view_renderer_->RequestDrawGL(false)) {
145 g_request_draw_gl_tracker.Get().ResetPending();
146 LOG(ERROR) << "Failed to request GL process. Deadlock likely";
150 void SharedRendererState::UpdateParentDrawConstraintsOnUI() {
151 DCHECK(ui_loop_->BelongsToCurrentThread());
152 browser_view_renderer_->UpdateParentDrawConstraints();
155 void SharedRendererState::SetScrollOffsetOnUI(gfx::Vector2d scroll_offset) {
156 base::AutoLock lock(lock_);
157 scroll_offset_ = scroll_offset;
160 gfx::Vector2d SharedRendererState::GetScrollOffsetOnRT() {
161 base::AutoLock lock(lock_);
162 return scroll_offset_;
165 void SharedRendererState::SetCompositorFrameOnUI(scoped_ptr<ChildFrame> frame) {
166 base::AutoLock lock(lock_);
167 DCHECK(!child_frame_.get());
168 child_frame_ = frame.Pass();
171 scoped_ptr<ChildFrame> SharedRendererState::PassCompositorFrameOnRT() {
172 base::AutoLock lock(lock_);
173 return child_frame_.Pass();
176 scoped_ptr<ChildFrame> SharedRendererState::PassUncommittedFrameOnUI() {
177 base::AutoLock lock(lock_);
178 return child_frame_.Pass();
181 void SharedRendererState::PostExternalDrawConstraintsToChildCompositorOnRT(
182 const ParentCompositorDrawConstraints& parent_draw_constraints) {
184 base::AutoLock lock(lock_);
185 parent_draw_constraints_ = parent_draw_constraints;
188 // No need to hold the lock_ during the post task.
189 ui_loop_->PostTask(
190 FROM_HERE,
191 base::Bind(&SharedRendererState::UpdateParentDrawConstraintsOnUI,
192 ui_thread_weak_ptr_));
195 ParentCompositorDrawConstraints
196 SharedRendererState::GetParentDrawConstraintsOnUI() const {
197 base::AutoLock lock(lock_);
198 return parent_draw_constraints_;
201 void SharedRendererState::SetInsideHardwareRelease(bool inside) {
202 base::AutoLock lock(lock_);
203 inside_hardware_release_ = inside;
206 bool SharedRendererState::IsInsideHardwareRelease() const {
207 base::AutoLock lock(lock_);
208 return inside_hardware_release_;
211 void SharedRendererState::InsertReturnedResourcesOnRT(
212 const cc::ReturnedResourceArray& resources) {
213 base::AutoLock lock(lock_);
214 returned_resources_.insert(
215 returned_resources_.end(), resources.begin(), resources.end());
218 void SharedRendererState::SwapReturnedResourcesOnUI(
219 cc::ReturnedResourceArray* resources) {
220 DCHECK(resources->empty());
221 base::AutoLock lock(lock_);
222 resources->swap(returned_resources_);
225 bool SharedRendererState::ReturnedResourcesEmptyOnUI() const {
226 base::AutoLock lock(lock_);
227 return returned_resources_.empty();
230 void SharedRendererState::DrawGL(AwDrawGLInfo* draw_info) {
231 TRACE_EVENT0("android_webview", "DrawFunctor");
232 if (draw_info->mode == AwDrawGLInfo::kModeSync) {
233 TRACE_EVENT_INSTANT0("android_webview", "kModeSync",
234 TRACE_EVENT_SCOPE_THREAD);
235 if (hardware_renderer_)
236 hardware_renderer_->CommitFrame();
237 return;
240 // kModeProcessNoContext should never happen because we tear down hardware
241 // in onTrimMemory. However that guarantee is maintained outside of chromium
242 // code. Not notifying shared state in kModeProcessNoContext can lead to
243 // immediate deadlock, which is slightly more catastrophic than leaks or
244 // corruption.
245 if (draw_info->mode == AwDrawGLInfo::kModeProcess ||
246 draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
247 DidDrawGLProcess();
251 GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
252 base::AutoLock lock(lock_);
253 if (renderer_manager_key_ != manager->NullKey()) {
254 manager->DidDrawGL(renderer_manager_key_);
258 ScopedAppGLStateRestore state_restore(
259 draw_info->mode == AwDrawGLInfo::kModeDraw
260 ? ScopedAppGLStateRestore::MODE_DRAW
261 : ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
262 // Set the correct FBO before kModeDraw. The GL commands run in kModeDraw
263 // require a correctly bound FBO. The FBO remains until the next kModeDraw.
264 // So kModeProcess between kModeDraws has correctly bound FBO, too.
265 if (draw_info->mode == AwDrawGLInfo::kModeDraw) {
266 if (!hardware_renderer_) {
267 hardware_renderer_.reset(new HardwareRenderer(this));
268 hardware_renderer_->CommitFrame();
270 hardware_renderer_->SetBackingFrameBufferObject(
271 state_restore.framebuffer_binding_ext());
274 ScopedAllowGL allow_gl;
276 if (draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
277 LOG(ERROR) << "Received unexpected kModeProcessNoContext";
280 if (IsInsideHardwareRelease()) {
281 hardware_renderer_.reset();
282 // Flush the idle queue in tear down.
283 DeferredGpuCommandService::GetInstance()->PerformAllIdleWork();
284 return;
287 if (draw_info->mode != AwDrawGLInfo::kModeDraw) {
288 if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
289 DeferredGpuCommandService::GetInstance()->PerformIdleWork(true);
291 return;
294 hardware_renderer_->DrawGL(state_restore.stencil_enabled(), draw_info);
295 DeferredGpuCommandService::GetInstance()->PerformIdleWork(false);
298 void SharedRendererState::ReleaseHardwareDrawIfNeededOnUI() {
299 ReleaseCompositorResourcesIfNeededOnUI(true);
302 void SharedRendererState::DeleteHardwareRendererOnUI() {
303 ReleaseCompositorResourcesIfNeededOnUI(false);
306 void SharedRendererState::ReleaseCompositorResourcesIfNeededOnUI(
307 bool release_hardware_draw) {
308 DCHECK(ui_loop_->BelongsToCurrentThread());
309 InsideHardwareReleaseReset auto_inside_hardware_release_reset(this);
311 browser_view_renderer_->DetachFunctorFromView();
312 bool hardware_initialized = browser_view_renderer_->hardware_enabled();
313 // If the WebView gets onTrimMemory >= MODERATE twice in a row, the 2nd
314 // onTrimMemory will result in an unnecessary Render Thread DrawGL call.
315 if (hardware_initialized) {
316 bool draw_functor_succeeded = browser_view_renderer_->RequestDrawGL(true);
317 if (!draw_functor_succeeded) {
318 LOG(ERROR) << "Unable to free GL resources. Has the Window leaked?";
319 // Calling release on wrong thread intentionally.
320 AwDrawGLInfo info;
321 info.mode = AwDrawGLInfo::kModeProcess;
322 DrawGL(&info);
325 if (release_hardware_draw)
326 browser_view_renderer_->ReleaseHardware();
329 GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
332 base::AutoLock lock(lock_);
333 if (renderer_manager_key_ != manager->NullKey()) {
334 manager->Remove(renderer_manager_key_);
335 renderer_manager_key_ = manager->NullKey();
339 if (hardware_initialized) {
340 // Flush any invoke functors that's caused by ReleaseHardware.
341 browser_view_renderer_->RequestDrawGL(true);
345 void SharedRendererState::InitializeHardwareDrawIfNeededOnUI() {
346 DCHECK(ui_loop_->BelongsToCurrentThread());
347 GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
349 base::AutoLock lock(lock_);
350 if (renderer_manager_key_ == manager->NullKey()) {
351 renderer_manager_key_ = manager->PushBack(this);
355 SharedRendererState::InsideHardwareReleaseReset::InsideHardwareReleaseReset(
356 SharedRendererState* shared_renderer_state)
357 : shared_renderer_state_(shared_renderer_state) {
358 DCHECK(!shared_renderer_state_->IsInsideHardwareRelease());
359 shared_renderer_state_->SetInsideHardwareRelease(true);
362 SharedRendererState::InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
363 shared_renderer_state_->SetInsideHardwareRelease(false);
366 } // namespace android_webview