Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / android_webview / browser / shared_renderer_state.cc
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.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"
15
16 namespace android_webview {
17
18 namespace internal {
19
20 class RequestDrawGLTracker {
21  public:
22   RequestDrawGLTracker();
23   bool ShouldRequestOnNonUiThread(SharedRendererState* state);
24   bool ShouldRequestOnUiThread(SharedRendererState* state);
25   void DidRequestOnUiThread();
26   void ResetPending();
27
28  private:
29   base::Lock lock_;
30   SharedRendererState* pending_ui_;
31   SharedRendererState* pending_non_ui_;
32 };
33
34 RequestDrawGLTracker::RequestDrawGLTracker()
35     : pending_ui_(NULL), pending_non_ui_(NULL) {
36 }
37
38 bool RequestDrawGLTracker::ShouldRequestOnNonUiThread(
39     SharedRendererState* state) {
40   base::AutoLock lock(lock_);
41   if (pending_ui_ || pending_non_ui_)
42     return false;
43   pending_non_ui_ = state;
44   return true;
45 }
46
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;
52   }
53   if (pending_ui_)
54     return false;
55   pending_ui_ = state;
56   return true;
57 }
58
59 void RequestDrawGLTracker::ResetPending() {
60   base::AutoLock lock(lock_);
61   pending_non_ui_ = NULL;
62   pending_ui_ = NULL;
63 }
64
65 }  // namespace internal
66
67 namespace {
68
69 base::LazyInstance<internal::RequestDrawGLTracker> g_request_draw_gl_tracker =
70     LAZY_INSTANCE_INITIALIZER;
71
72 }
73
74 SharedRendererState::SharedRendererState(
75     const scoped_refptr<base::SingleThreadTaskRunner>& ui_loop,
76     BrowserViewRenderer* browser_view_renderer)
77     : ui_loop_(ui_loop),
78       browser_view_renderer_(browser_view_renderer),
79       renderer_manager_key_(GLViewRendererManager::GetInstance()->NullKey()),
80       force_commit_(false),
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();
88 }
89
90 SharedRendererState::~SharedRendererState() {
91   DCHECK(ui_loop_->BelongsToCurrentThread());
92   DCHECK(!hardware_renderer_.get());
93 }
94
95 void SharedRendererState::ClientRequestDrawGL() {
96   if (ui_loop_->BelongsToCurrentThread()) {
97     if (!g_request_draw_gl_tracker.Get().ShouldRequestOnUiThread(this))
98       return;
99     ClientRequestDrawGLOnUI();
100   } else {
101     if (!g_request_draw_gl_tracker.Get().ShouldRequestOnNonUiThread(this))
102       return;
103     base::Closure callback;
104     {
105       base::AutoLock lock(lock_);
106       callback = request_draw_gl_closure_;
107     }
108     ui_loop_->PostTask(FROM_HERE, callback);
109   }
110 }
111
112 void SharedRendererState::DidDrawGLProcess() {
113   g_request_draw_gl_tracker.Get().ResetPending();
114 }
115
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();
122 }
123
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";
130   }
131 }
132
133 void SharedRendererState::UpdateParentDrawConstraintsOnUI() {
134   DCHECK(ui_loop_->BelongsToCurrentThread());
135   browser_view_renderer_->UpdateParentDrawConstraints();
136 }
137
138 void SharedRendererState::SetScrollOffsetOnUI(gfx::Vector2d scroll_offset) {
139   base::AutoLock lock(lock_);
140   scroll_offset_ = scroll_offset;
141 }
142
143 gfx::Vector2d SharedRendererState::GetScrollOffsetOnRT() {
144   base::AutoLock lock(lock_);
145   return scroll_offset_;
146 }
147
148 bool SharedRendererState::HasCompositorFrameOnUI() const {
149   base::AutoLock lock(lock_);
150   return compositor_frame_.get();
151 }
152
153 void SharedRendererState::SetCompositorFrameOnUI(
154     scoped_ptr<cc::CompositorFrame> frame,
155     bool force_commit) {
156   base::AutoLock lock(lock_);
157   DCHECK(!compositor_frame_.get());
158   compositor_frame_ = frame.Pass();
159   force_commit_ = force_commit;
160 }
161
162 scoped_ptr<cc::CompositorFrame> SharedRendererState::PassCompositorFrameOnRT() {
163   base::AutoLock lock(lock_);
164   return compositor_frame_.Pass();
165 }
166
167 scoped_ptr<cc::CompositorFrame>
168 SharedRendererState::PassUncommittedFrameOnUI() {
169   base::AutoLock lock(lock_);
170   return compositor_frame_.Pass();
171 }
172
173 bool SharedRendererState::ForceCommitOnRT() const {
174   base::AutoLock lock(lock_);
175   return force_commit_;
176 }
177
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;
184     return true;
185   }
186
187   return false;
188 }
189
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.
194     ui_loop_->PostTask(
195         FROM_HERE,
196         base::Bind(&SharedRendererState::UpdateParentDrawConstraintsOnUI,
197                    ui_thread_weak_ptr_));
198   }
199 }
200
201 void SharedRendererState::DidSkipCommitFrameOnRT() {
202   ui_loop_->PostTask(FROM_HERE,
203                      base::Bind(&SharedRendererState::DidSkipCommitFrameOnUI,
204                                 ui_thread_weak_ptr_));
205 }
206
207 void SharedRendererState::DidSkipCommitFrameOnUI() {
208   DCHECK(ui_loop_->BelongsToCurrentThread());
209   browser_view_renderer_->DidSkipCommitFrame();
210 }
211
212 ParentCompositorDrawConstraints
213 SharedRendererState::GetParentDrawConstraintsOnUI() const {
214   base::AutoLock lock(lock_);
215   return parent_draw_constraints_;
216 }
217
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;
223 }
224
225 bool SharedRendererState::NeedsForceInvalidateOnNextDrawGLOnUI() const {
226   base::AutoLock lock(lock_);
227   return needs_force_invalidate_on_next_draw_gl_;
228 }
229
230 void SharedRendererState::SetInsideHardwareRelease(bool inside) {
231   base::AutoLock lock(lock_);
232   inside_hardware_release_ = inside;
233 }
234
235 bool SharedRendererState::IsInsideHardwareRelease() const {
236   base::AutoLock lock(lock_);
237   return inside_hardware_release_;
238 }
239
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());
245 }
246
247 void SharedRendererState::SwapReturnedResourcesOnUI(
248     cc::ReturnedResourceArray* resources) {
249   DCHECK(resources->empty());
250   base::AutoLock lock(lock_);
251   resources->swap(returned_resources_);
252 }
253
254 bool SharedRendererState::ReturnedResourcesEmptyOnUI() const {
255   base::AutoLock lock(lock_);
256   return returned_resources_.empty();
257 }
258
259 void SharedRendererState::DrawGL(AwDrawGLInfo* draw_info) {
260   if (draw_info->mode == AwDrawGLInfo::kModeSync) {
261     if (hardware_renderer_)
262       hardware_renderer_->CommitFrame();
263     return;
264   }
265
266   {
267     GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
268     base::AutoLock lock(lock_);
269     if (renderer_manager_key_ != manager->NullKey()) {
270       manager->DidDrawGL(renderer_manager_key_);
271     }
272   }
273
274   ScopedAppGLStateRestore state_restore(
275       draw_info->mode == AwDrawGLInfo::kModeDraw
276           ? ScopedAppGLStateRestore::MODE_DRAW
277           : ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
278   ScopedAllowGL allow_gl;
279
280   if (draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
281     LOG(ERROR) << "Received unexpected kModeProcessNoContext";
282   }
283
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
288   // corruption.
289   if (draw_info->mode == AwDrawGLInfo::kModeProcess ||
290       draw_info->mode == AwDrawGLInfo::kModeProcessNoContext) {
291     DidDrawGLProcess();
292   }
293
294   if (IsInsideHardwareRelease()) {
295     hardware_renderer_.reset();
296     // Flush the idle queue in tear down.
297     DeferredGpuCommandService::GetInstance()->PerformAllIdleWork();
298     return;
299   }
300
301   if (draw_info->mode != AwDrawGLInfo::kModeDraw) {
302     if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
303       DeferredGpuCommandService::GetInstance()->PerformIdleWork(true);
304     }
305     return;
306   }
307
308   if (!hardware_renderer_) {
309     hardware_renderer_.reset(new HardwareRenderer(this));
310     hardware_renderer_->CommitFrame();
311   }
312
313   hardware_renderer_->DrawGL(state_restore.stencil_enabled(),
314                              state_restore.framebuffer_binding_ext(),
315                              draw_info);
316   DeferredGpuCommandService::GetInstance()->PerformIdleWork(false);
317 }
318
319 void SharedRendererState::ReleaseHardwareDrawIfNeededOnUI() {
320   DCHECK(ui_loop_->BelongsToCurrentThread());
321   InsideHardwareReleaseReset auto_inside_hardware_release_reset(this);
322
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.
330       AwDrawGLInfo info;
331       info.mode = AwDrawGLInfo::kModeProcess;
332       DrawGL(&info);
333     }
334
335     browser_view_renderer_->ReleaseHardware();
336   }
337
338   GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
339
340   {
341     base::AutoLock lock(lock_);
342     if (renderer_manager_key_ != manager->NullKey()) {
343       manager->Remove(renderer_manager_key_);
344       renderer_manager_key_ = manager->NullKey();
345     }
346   }
347
348   if (hardware_initialized) {
349     // Flush any invoke functors that's caused by ReleaseHardware.
350     browser_view_renderer_->RequestDrawGL(true);
351   }
352 }
353
354 void SharedRendererState::InitializeHardwareDrawIfNeededOnUI() {
355   DCHECK(ui_loop_->BelongsToCurrentThread());
356   GLViewRendererManager* manager = GLViewRendererManager::GetInstance();
357
358   base::AutoLock lock(lock_);
359   if (renderer_manager_key_ == manager->NullKey()) {
360     renderer_manager_key_ = manager->PushBack(this);
361     DeferredGpuCommandService::SetInstance();
362   }
363 }
364
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);
370 }
371
372 SharedRendererState::InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
373   shared_renderer_state_->SetInsideHardwareRelease(false);
374 }
375
376 }  // namespace android_webview