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. 4 5 #include "android_webview/browser/shared_renderer_state.h" 6 7 #include "android_webview/browser/browser_view_renderer_client.h" 8 #include "base/bind.h" 9 #include "base/lazy_instance.h" 10 #include "base/location.h" 11 12 namespace android_webview { 13 14 namespace internal { 15 16 class RequestDrawGLTracker { 17 public: 18 RequestDrawGLTracker(); 19 bool ShouldRequestOnNoneUiThread(SharedRendererState* state); 20 bool ShouldRequestOnUiThread(SharedRendererState* state); 21 void ResetPending(); 22 void SetQueuedFunctorOnUi(SharedRendererState* state); 23 24 private: 25 base::Lock lock_; 26 SharedRendererState* pending_ui_; 27 SharedRendererState* pending_non_ui_; 28 }; 29 30 RequestDrawGLTracker::RequestDrawGLTracker() 31 : pending_ui_(NULL), pending_non_ui_(NULL) { 32 } 33 34 bool RequestDrawGLTracker::ShouldRequestOnNoneUiThread( 35 SharedRendererState* state) { 36 base::AutoLock lock(lock_); 37 if (pending_ui_ || pending_non_ui_) 38 return false; 39 pending_non_ui_ = state; 40 return true; 41 } 42 43 bool RequestDrawGLTracker::ShouldRequestOnUiThread(SharedRendererState* state) { 44 base::AutoLock lock(lock_); 45 if (pending_non_ui_) { 46 pending_non_ui_->ResetRequestDrawGLCallback(); 47 pending_non_ui_ = NULL; 48 } 49 // At this time, we could have already called RequestDrawGL on the UI thread, 50 // but the corresponding GL mode process hasn't happened yet. In this case, 51 // don't schedule another requestDrawGL on the UI thread. 52 if (pending_ui_) 53 return false; 54 pending_ui_ = state; 55 return true; 56 } 57 58 void RequestDrawGLTracker::ResetPending() { 59 base::AutoLock lock(lock_); 60 pending_non_ui_ = NULL; 61 pending_ui_ = NULL; 62 } 63 64 void RequestDrawGLTracker::SetQueuedFunctorOnUi(SharedRendererState* state) { 65 base::AutoLock lock(lock_); 66 DCHECK(state); 67 DCHECK(pending_ui_ == state || pending_non_ui_ == state); 68 pending_ui_ = state; 69 pending_non_ui_ = NULL; 70 } 71 72 } // namespace internal 73 74 namespace { 75 76 base::LazyInstance<internal::RequestDrawGLTracker> g_request_draw_gl_tracker = 77 LAZY_INSTANCE_INITIALIZER; 78 79 } 80 81 SharedRendererState::SharedRendererState( 82 scoped_refptr<base::MessageLoopProxy> ui_loop, 83 BrowserViewRendererClient* client) 84 : ui_loop_(ui_loop), 85 client_on_ui_(client), 86 force_commit_(false), 87 inside_hardware_release_(false), 88 needs_force_invalidate_on_next_draw_gl_(false), 89 weak_factory_on_ui_thread_(this) { 90 DCHECK(ui_loop_->BelongsToCurrentThread()); 91 DCHECK(client_on_ui_); 92 ui_thread_weak_ptr_ = weak_factory_on_ui_thread_.GetWeakPtr(); 93 ResetRequestDrawGLCallback(); 94 } 95 96 SharedRendererState::~SharedRendererState() { 97 DCHECK(ui_loop_->BelongsToCurrentThread()); 98 } 99 100 void SharedRendererState::ClientRequestDrawGL() { 101 if (ui_loop_->BelongsToCurrentThread()) { 102 if (!g_request_draw_gl_tracker.Get().ShouldRequestOnUiThread(this)) 103 return; 104 ClientRequestDrawGLOnUIThread(); 105 } else { 106 if (!g_request_draw_gl_tracker.Get().ShouldRequestOnNoneUiThread(this)) 107 return; 108 base::Closure callback; 109 { 110 base::AutoLock lock(lock_); 111 callback = request_draw_gl_closure_; 112 } 113 ui_loop_->PostTask(FROM_HERE, callback); 114 } 115 } 116 117 void SharedRendererState::DidDrawGLProcess() { 118 g_request_draw_gl_tracker.Get().ResetPending(); 119 } 120 121 void SharedRendererState::ResetRequestDrawGLCallback() { 122 DCHECK(ui_loop_->BelongsToCurrentThread()); 123 base::AutoLock lock(lock_); 124 request_draw_gl_cancelable_closure_.Reset( 125 base::Bind(&SharedRendererState::ClientRequestDrawGLOnUIThread, 126 base::Unretained(this))); 127 request_draw_gl_closure_ = request_draw_gl_cancelable_closure_.callback(); 128 } 129 130 void SharedRendererState::ClientRequestDrawGLOnUIThread() { 131 DCHECK(ui_loop_->BelongsToCurrentThread()); 132 ResetRequestDrawGLCallback(); 133 g_request_draw_gl_tracker.Get().SetQueuedFunctorOnUi(this); 134 if (!client_on_ui_->RequestDrawGL(NULL, false)) { 135 g_request_draw_gl_tracker.Get().ResetPending(); 136 LOG(ERROR) << "Failed to request GL process. Deadlock likely"; 137 } 138 } 139 140 void SharedRendererState::UpdateParentDrawConstraintsOnUIThread() { 141 DCHECK(ui_loop_->BelongsToCurrentThread()); 142 client_on_ui_->UpdateParentDrawConstraints(); 143 } 144 145 void SharedRendererState::SetScrollOffset(gfx::Vector2d scroll_offset) { 146 base::AutoLock lock(lock_); 147 scroll_offset_ = scroll_offset; 148 } 149 150 gfx::Vector2d SharedRendererState::GetScrollOffset() { 151 base::AutoLock lock(lock_); 152 return scroll_offset_; 153 } 154 155 bool SharedRendererState::HasCompositorFrame() const { 156 base::AutoLock lock(lock_); 157 return compositor_frame_.get(); 158 } 159 160 void SharedRendererState::SetCompositorFrame( 161 scoped_ptr<cc::CompositorFrame> frame, bool force_commit) { 162 base::AutoLock lock(lock_); 163 DCHECK(!compositor_frame_.get()); 164 compositor_frame_ = frame.Pass(); 165 force_commit_ = force_commit; 166 } 167 168 scoped_ptr<cc::CompositorFrame> SharedRendererState::PassCompositorFrame() { 169 base::AutoLock lock(lock_); 170 return compositor_frame_.Pass(); 171 } 172 173 bool SharedRendererState::ForceCommit() const { 174 base::AutoLock lock(lock_); 175 return force_commit_; 176 } 177 178 bool SharedRendererState::UpdateDrawConstraints( 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; 184 return true; 185 } 186 187 return false; 188 } 189 190 void SharedRendererState::PostExternalDrawConstraintsToChildCompositor( 191 const ParentCompositorDrawConstraints& parent_draw_constraints) { 192 if (UpdateDrawConstraints(parent_draw_constraints)) { 193 // No need to hold the lock_ during the post task. 194 ui_loop_->PostTask( 195 FROM_HERE, 196 base::Bind(&SharedRendererState::UpdateParentDrawConstraintsOnUIThread, 197 ui_thread_weak_ptr_)); 198 } 199 } 200 201 void SharedRendererState::DidSkipCommitFrame() { 202 ui_loop_->PostTask( 203 FROM_HERE, 204 base::Bind(&SharedRendererState::DidSkipCommitFrameOnUIThread, 205 ui_thread_weak_ptr_)); 206 } 207 208 void SharedRendererState::DidSkipCommitFrameOnUIThread() { 209 DCHECK(ui_loop_->BelongsToCurrentThread()); 210 client_on_ui_->DidSkipCommitFrame(); 211 } 212 213 const ParentCompositorDrawConstraints 214 SharedRendererState::ParentDrawConstraints() const { 215 base::AutoLock lock(lock_); 216 return parent_draw_constraints_; 217 } 218 219 void SharedRendererState::SetForceInvalidateOnNextDrawGL( 220 bool needs_force_invalidate_on_next_draw_gl) { 221 base::AutoLock lock(lock_); 222 needs_force_invalidate_on_next_draw_gl_ = 223 needs_force_invalidate_on_next_draw_gl; 224 } 225 226 bool SharedRendererState::NeedsForceInvalidateOnNextDrawGL() const { 227 base::AutoLock lock(lock_); 228 return needs_force_invalidate_on_next_draw_gl_; 229 } 230 231 void SharedRendererState::SetInsideHardwareRelease(bool inside) { 232 base::AutoLock lock(lock_); 233 inside_hardware_release_ = inside; 234 } 235 236 bool SharedRendererState::IsInsideHardwareRelease() const { 237 base::AutoLock lock(lock_); 238 return inside_hardware_release_; 239 } 240 241 void SharedRendererState::InsertReturnedResources( 242 const cc::ReturnedResourceArray& resources) { 243 base::AutoLock lock(lock_); 244 returned_resources_.insert( 245 returned_resources_.end(), resources.begin(), resources.end()); 246 } 247 248 void SharedRendererState::SwapReturnedResources( 249 cc::ReturnedResourceArray* resources) { 250 DCHECK(resources->empty()); 251 base::AutoLock lock(lock_); 252 resources->swap(returned_resources_); 253 } 254 255 bool SharedRendererState::ReturnedResourcesEmpty() const { 256 base::AutoLock lock(lock_); 257 return returned_resources_.empty(); 258 } 259 260 InsideHardwareReleaseReset::InsideHardwareReleaseReset( 261 SharedRendererState* shared_renderer_state) 262 : shared_renderer_state_(shared_renderer_state) { 263 DCHECK(!shared_renderer_state_->IsInsideHardwareRelease()); 264 shared_renderer_state_->SetInsideHardwareRelease(true); 265 } 266 267 InsideHardwareReleaseReset::~InsideHardwareReleaseReset() { 268 shared_renderer_state_->SetInsideHardwareRelease(false); 269 } 270 271 } // namespace android_webview 272