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/deferred_gpu_command_service.h"
9 #include "android_webview/browser/hardware_renderer.h"
10 #include "android_webview/browser/scoped_app_gl_state_restore.h"
11 #include "android_webview/public/browser/draw_gl.h"
12 #include "base/bind.h"
13 #include "base/lazy_instance.h"
14 #include "base/location.h"
16 namespace android_webview {
20 class RequestDrawGLTracker {
22 RequestDrawGLTracker();
23 bool ShouldRequestOnNonUiThread(SharedRendererState* state);
24 bool ShouldRequestOnUiThread(SharedRendererState* state);
25 void DidRequestOnUiThread();
30 SharedRendererState* pending_ui_;
31 SharedRendererState* pending_non_ui_;
34 RequestDrawGLTracker::RequestDrawGLTracker()
35 : pending_ui_(NULL), pending_non_ui_(NULL) {
38 bool RequestDrawGLTracker::ShouldRequestOnNonUiThread(
39 SharedRendererState* state) {
40 base::AutoLock lock(lock_);
41 if (pending_ui_ || pending_non_ui_)
43 pending_non_ui_ = state;
47 bool RequestDrawGLTracker::ShouldRequestOnUiThread(SharedRendererState* state) {
48 base::AutoLock lock(lock_);
49 if (pending_non_ui_) {
50 pending_non_ui_->ResetRequestDrawGLCallback();
51 pending_non_ui_ = NULL;
59 void RequestDrawGLTracker::ResetPending() {
60 base::AutoLock lock(lock_);
61 pending_non_ui_ = NULL;
65 } // namespace internal
69 base::LazyInstance<internal::RequestDrawGLTracker> g_request_draw_gl_tracker =
70 LAZY_INSTANCE_INITIALIZER;
74 SharedRendererState::SharedRendererState(
75 const scoped_refptr<base::SingleThreadTaskRunner>& ui_loop,
76 BrowserViewRenderer* browser_view_renderer)
78 browser_view_renderer_(browser_view_renderer),
79 renderer_manager_key_(GLViewRendererManager::GetInstance()->NullKey()),
81 inside_hardware_release_(false),
82 needs_force_invalidate_on_next_draw_gl_(false),
83 weak_factory_on_ui_thread_(this) {
84 DCHECK(ui_loop_->BelongsToCurrentThread());
85 DCHECK(browser_view_renderer_);
86 ui_thread_weak_ptr_ = weak_factory_on_ui_thread_.GetWeakPtr();
87 ResetRequestDrawGLCallback();
90 SharedRendererState::~SharedRendererState() {
91 DCHECK(ui_loop_->BelongsToCurrentThread());
92 DCHECK(!hardware_renderer_.get());
95 void SharedRendererState::ClientRequestDrawGL() {
96 if (ui_loop_->BelongsToCurrentThread()) {
97 if (!g_request_draw_gl_tracker.Get().ShouldRequestOnUiThread(this))
99 ClientRequestDrawGLOnUI();
101 if (!g_request_draw_gl_tracker.Get().ShouldRequestOnNonUiThread(this))
103 base::Closure callback;
105 base::AutoLock lock(lock_);
106 callback = request_draw_gl_closure_;
108 ui_loop_->PostTask(FROM_HERE, callback);
112 void SharedRendererState::DidDrawGLProcess() {
113 g_request_draw_gl_tracker.Get().ResetPending();
116 void SharedRendererState::ResetRequestDrawGLCallback() {
117 DCHECK(ui_loop_->BelongsToCurrentThread());
118 base::AutoLock lock(lock_);
119 request_draw_gl_cancelable_closure_.Reset(base::Bind(
120 &SharedRendererState::ClientRequestDrawGLOnUI, base::Unretained(this)));
121 request_draw_gl_closure_ = request_draw_gl_cancelable_closure_.callback();
124 void SharedRendererState::ClientRequestDrawGLOnUI() {
125 DCHECK(ui_loop_->BelongsToCurrentThread());
126 ResetRequestDrawGLCallback();
127 if (!browser_view_renderer_->RequestDrawGL(false)) {
128 g_request_draw_gl_tracker.Get().ResetPending();
129 LOG(ERROR) << "Failed to request GL process. Deadlock likely";
133 void SharedRendererState::UpdateParentDrawConstraintsOnUI() {
134 DCHECK(ui_loop_->BelongsToCurrentThread());
135 browser_view_renderer_->UpdateParentDrawConstraints();
138 void SharedRendererState::SetScrollOffsetOnUI(gfx::Vector2d scroll_offset) {
139 base::AutoLock lock(lock_);
140 scroll_offset_ = scroll_offset;
143 gfx::Vector2d SharedRendererState::GetScrollOffsetOnRT() {
144 base::AutoLock lock(lock_);
145 return scroll_offset_;
148 bool SharedRendererState::HasCompositorFrameOnUI() const {
149 base::AutoLock lock(lock_);
150 return compositor_frame_.get();
153 void SharedRendererState::SetCompositorFrameOnUI(
154 scoped_ptr<cc::CompositorFrame> frame,
156 base::AutoLock lock(lock_);
157 DCHECK(!compositor_frame_.get());
158 compositor_frame_ = frame.Pass();
159 force_commit_ = force_commit;
162 scoped_ptr<cc::CompositorFrame> SharedRendererState::PassCompositorFrameOnRT() {
163 base::AutoLock lock(lock_);
164 return compositor_frame_.Pass();
167 scoped_ptr<cc::CompositorFrame>
168 SharedRendererState::PassUncommittedFrameOnUI() {
169 base::AutoLock lock(lock_);
170 return compositor_frame_.Pass();
173 bool SharedRendererState::ForceCommitOnRT() const {
174 base::AutoLock lock(lock_);
175 return force_commit_;
178 bool SharedRendererState::UpdateDrawConstraintsOnRT(
179 const ParentCompositorDrawConstraints& parent_draw_constraints) {
180 base::AutoLock lock(lock_);
181 if (needs_force_invalidate_on_next_draw_gl_ ||
182 !parent_draw_constraints_.Equals(parent_draw_constraints)) {
183 parent_draw_constraints_ = parent_draw_constraints;
190 void SharedRendererState::PostExternalDrawConstraintsToChildCompositorOnRT(
191 const ParentCompositorDrawConstraints& parent_draw_constraints) {
192 if (UpdateDrawConstraintsOnRT(parent_draw_constraints)) {
193 // No need to hold the lock_ during the post task.
196 base::Bind(&SharedRendererState::UpdateParentDrawConstraintsOnUI,
197 ui_thread_weak_ptr_));
201 void SharedRendererState::DidSkipCommitFrameOnRT() {
202 ui_loop_->PostTask(FROM_HERE,
203 base::Bind(&SharedRendererState::DidSkipCommitFrameOnUI,
204 ui_thread_weak_ptr_));
207 void SharedRendererState::DidSkipCommitFrameOnUI() {
208 DCHECK(ui_loop_->BelongsToCurrentThread());
209 browser_view_renderer_->DidSkipCommitFrame();
212 ParentCompositorDrawConstraints
213 SharedRendererState::GetParentDrawConstraintsOnUI() const {
214 base::AutoLock lock(lock_);
215 return parent_draw_constraints_;
218 void SharedRendererState::SetForceInvalidateOnNextDrawGLOnUI(
219 bool needs_force_invalidate_on_next_draw_gl) {
220 base::AutoLock lock(lock_);
221 needs_force_invalidate_on_next_draw_gl_ =
222 needs_force_invalidate_on_next_draw_gl;
225 bool SharedRendererState::NeedsForceInvalidateOnNextDrawGLOnUI() const {
226 base::AutoLock lock(lock_);
227 return needs_force_invalidate_on_next_draw_gl_;
230 void SharedRendererState::SetInsideHardwareRelease(bool inside) {
231 base::AutoLock lock(lock_);
232 inside_hardware_release_ = inside;
235 bool SharedRendererState::IsInsideHardwareRelease() const {
236 base::AutoLock lock(lock_);
237 return inside_hardware_release_;
240 void SharedRendererState::InsertReturnedResourcesOnRT(
241 const cc::ReturnedResourceArray& resources) {
242 base::AutoLock lock(lock_);
243 returned_resources_.insert(
244 returned_resources_.end(), resources.begin(), resources.end());
247 void SharedRendererState::SwapReturnedResourcesOnUI(
248 cc::ReturnedResourceArray* resources) {
249 DCHECK(resources->empty());
250 base::AutoLock lock(lock_);
251 resources->swap(returned_resources_);
254 bool SharedRendererState::ReturnedResourcesEmptyOnUI() const {
255 base::AutoLock lock(lock_);
256 return returned_resources_.empty();
259 void SharedRendererState::DrawGL(AwDrawGLInfo* draw_info) {
260 if (draw_info->mode == AwDrawGLInfo::kModeSync) {
261 if (hardware_renderer_)
262 hardware_renderer_->CommitFrame();
267 GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
268 base::AutoLock lock(lock_);
269 if (renderer_manager_key_ != manager->NullKey()) {
270 manager->DidDrawGL(renderer_manager_key_);
274 ScopedAppGLStateRestore state_restore(
275 draw_info->mode == AwDrawGLInfo::kModeDraw
276 ? ScopedAppGLStateRestore::MODE_DRAW
277 : ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
278 ScopedAllowGL allow_gl;
280 if (draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
281 LOG(ERROR) << "Received unexpected kModeProcessNoContext";
284 // kModeProcessNoContext should never happen because we tear down hardware
285 // in onTrimMemory. However that guarantee is maintained outside of chromium
286 // code. Not notifying shared state in kModeProcessNoContext can lead to
287 // immediate deadlock, which is slightly more catastrophic than leaks or
289 if (draw_info->mode == AwDrawGLInfo::kModeProcess ||
290 draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
294 if (IsInsideHardwareRelease()) {
295 hardware_renderer_.reset();
296 // Flush the idle queue in tear down.
297 DeferredGpuCommandService::GetInstance()->PerformAllIdleWork();
301 if (draw_info->mode != AwDrawGLInfo::kModeDraw) {
302 if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
303 DeferredGpuCommandService::GetInstance()->PerformIdleWork(true);
308 if (!hardware_renderer_) {
309 hardware_renderer_.reset(new HardwareRenderer(this));
310 hardware_renderer_->CommitFrame();
313 hardware_renderer_->DrawGL(state_restore.stencil_enabled(),
314 state_restore.framebuffer_binding_ext(),
316 DeferredGpuCommandService::GetInstance()->PerformIdleWork(false);
319 void SharedRendererState::ReleaseHardwareDrawIfNeededOnUI() {
320 DCHECK(ui_loop_->BelongsToCurrentThread());
321 InsideHardwareReleaseReset auto_inside_hardware_release_reset(this);
323 browser_view_renderer_->InvalidateOnFunctorDestroy();
324 bool hardware_initialized = browser_view_renderer_->hardware_enabled();
325 if (hardware_initialized) {
326 bool draw_functor_succeeded = browser_view_renderer_->RequestDrawGL(true);
327 if (!draw_functor_succeeded) {
328 LOG(ERROR) << "Unable to free GL resources. Has the Window leaked?";
329 // Calling release on wrong thread intentionally.
331 info.mode = AwDrawGLInfo::kModeProcess;
335 browser_view_renderer_->ReleaseHardware();
338 GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
341 base::AutoLock lock(lock_);
342 if (renderer_manager_key_ != manager->NullKey()) {
343 manager->Remove(renderer_manager_key_);
344 renderer_manager_key_ = manager->NullKey();
348 if (hardware_initialized) {
349 // Flush any invoke functors that's caused by ReleaseHardware.
350 browser_view_renderer_->RequestDrawGL(true);
354 void SharedRendererState::InitializeHardwareDrawIfNeededOnUI() {
355 DCHECK(ui_loop_->BelongsToCurrentThread());
356 GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
358 base::AutoLock lock(lock_);
359 if (renderer_manager_key_ == manager->NullKey()) {
360 renderer_manager_key_ = manager->PushBack(this);
361 DeferredGpuCommandService::SetInstance();
365 SharedRendererState::InsideHardwareReleaseReset::InsideHardwareReleaseReset(
366 SharedRendererState* shared_renderer_state)
367 : shared_renderer_state_(shared_renderer_state) {
368 DCHECK(!shared_renderer_state_->IsInsideHardwareRelease());
369 shared_renderer_state_->SetInsideHardwareRelease(true);
372 SharedRendererState::InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
373 shared_renderer_state_->SetInsideHardwareRelease(false);
376 } // namespace android_webview