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
RequestDrawGLTracker()30 RequestDrawGLTracker::RequestDrawGLTracker()
31 : pending_ui_(NULL), pending_non_ui_(NULL) {
32 }
33
ShouldRequestOnNoneUiThread(SharedRendererState * state)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
ShouldRequestOnUiThread(SharedRendererState * state)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
ResetPending()58 void RequestDrawGLTracker::ResetPending() {
59 base::AutoLock lock(lock_);
60 pending_non_ui_ = NULL;
61 pending_ui_ = NULL;
62 }
63
SetQueuedFunctorOnUi(SharedRendererState * state)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
SharedRendererState(scoped_refptr<base::MessageLoopProxy> ui_loop,BrowserViewRendererClient * client)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
~SharedRendererState()96 SharedRendererState::~SharedRendererState() {
97 DCHECK(ui_loop_->BelongsToCurrentThread());
98 }
99
ClientRequestDrawGL()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
DidDrawGLProcess()117 void SharedRendererState::DidDrawGLProcess() {
118 g_request_draw_gl_tracker.Get().ResetPending();
119 }
120
ResetRequestDrawGLCallback()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
ClientRequestDrawGLOnUIThread()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
UpdateParentDrawConstraintsOnUIThread()140 void SharedRendererState::UpdateParentDrawConstraintsOnUIThread() {
141 DCHECK(ui_loop_->BelongsToCurrentThread());
142 client_on_ui_->UpdateParentDrawConstraints();
143 }
144
SetScrollOffset(gfx::Vector2d scroll_offset)145 void SharedRendererState::SetScrollOffset(gfx::Vector2d scroll_offset) {
146 base::AutoLock lock(lock_);
147 scroll_offset_ = scroll_offset;
148 }
149
GetScrollOffset()150 gfx::Vector2d SharedRendererState::GetScrollOffset() {
151 base::AutoLock lock(lock_);
152 return scroll_offset_;
153 }
154
HasCompositorFrame() const155 bool SharedRendererState::HasCompositorFrame() const {
156 base::AutoLock lock(lock_);
157 return compositor_frame_.get();
158 }
159
SetCompositorFrame(scoped_ptr<cc::CompositorFrame> frame,bool force_commit)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
PassCompositorFrame()168 scoped_ptr<cc::CompositorFrame> SharedRendererState::PassCompositorFrame() {
169 base::AutoLock lock(lock_);
170 return compositor_frame_.Pass();
171 }
172
ForceCommit() const173 bool SharedRendererState::ForceCommit() const {
174 base::AutoLock lock(lock_);
175 return force_commit_;
176 }
177
UpdateDrawConstraints(const ParentCompositorDrawConstraints & parent_draw_constraints)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
PostExternalDrawConstraintsToChildCompositor(const ParentCompositorDrawConstraints & parent_draw_constraints)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
DidSkipCommitFrame()201 void SharedRendererState::DidSkipCommitFrame() {
202 ui_loop_->PostTask(
203 FROM_HERE,
204 base::Bind(&SharedRendererState::DidSkipCommitFrameOnUIThread,
205 ui_thread_weak_ptr_));
206 }
207
DidSkipCommitFrameOnUIThread()208 void SharedRendererState::DidSkipCommitFrameOnUIThread() {
209 DCHECK(ui_loop_->BelongsToCurrentThread());
210 client_on_ui_->DidSkipCommitFrame();
211 }
212
213 const ParentCompositorDrawConstraints
ParentDrawConstraints() const214 SharedRendererState::ParentDrawConstraints() const {
215 base::AutoLock lock(lock_);
216 return parent_draw_constraints_;
217 }
218
SetForceInvalidateOnNextDrawGL(bool needs_force_invalidate_on_next_draw_gl)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
NeedsForceInvalidateOnNextDrawGL() const226 bool SharedRendererState::NeedsForceInvalidateOnNextDrawGL() const {
227 base::AutoLock lock(lock_);
228 return needs_force_invalidate_on_next_draw_gl_;
229 }
230
SetInsideHardwareRelease(bool inside)231 void SharedRendererState::SetInsideHardwareRelease(bool inside) {
232 base::AutoLock lock(lock_);
233 inside_hardware_release_ = inside;
234 }
235
IsInsideHardwareRelease() const236 bool SharedRendererState::IsInsideHardwareRelease() const {
237 base::AutoLock lock(lock_);
238 return inside_hardware_release_;
239 }
240
InsertReturnedResources(const cc::ReturnedResourceArray & resources)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
SwapReturnedResources(cc::ReturnedResourceArray * resources)248 void SharedRendererState::SwapReturnedResources(
249 cc::ReturnedResourceArray* resources) {
250 DCHECK(resources->empty());
251 base::AutoLock lock(lock_);
252 resources->swap(returned_resources_);
253 }
254
ReturnedResourcesEmpty() const255 bool SharedRendererState::ReturnedResourcesEmpty() const {
256 base::AutoLock lock(lock_);
257 return returned_resources_.empty();
258 }
259
InsideHardwareReleaseReset(SharedRendererState * shared_renderer_state)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
~InsideHardwareReleaseReset()267 InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
268 shared_renderer_state_->SetInsideHardwareRelease(false);
269 }
270
271 } // namespace android_webview
272