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"
15 #include "base/trace_event/trace_event_argument.h"
17 namespace android_webview
{
21 class RequestDrawGLTracker
{
23 RequestDrawGLTracker();
24 bool ShouldRequestOnNonUiThread(SharedRendererState
* state
);
25 bool ShouldRequestOnUiThread(SharedRendererState
* state
);
27 void SetQueuedFunctorOnUi(SharedRendererState
* state
);
31 SharedRendererState
* pending_ui_
;
32 SharedRendererState
* pending_non_ui_
;
35 RequestDrawGLTracker::RequestDrawGLTracker()
36 : pending_ui_(NULL
), pending_non_ui_(NULL
) {
39 bool RequestDrawGLTracker::ShouldRequestOnNonUiThread(
40 SharedRendererState
* state
) {
41 base::AutoLock
lock(lock_
);
42 if (pending_ui_
|| pending_non_ui_
)
44 pending_non_ui_
= state
;
48 bool RequestDrawGLTracker::ShouldRequestOnUiThread(SharedRendererState
* state
) {
49 base::AutoLock
lock(lock_
);
50 if (pending_non_ui_
) {
51 pending_non_ui_
->ResetRequestDrawGLCallback();
52 pending_non_ui_
= NULL
;
54 // At this time, we could have already called RequestDrawGL on the UI thread,
55 // but the corresponding GL mode process hasn't happened yet. In this case,
56 // don't schedule another requestDrawGL on the UI thread.
63 void RequestDrawGLTracker::ResetPending() {
64 base::AutoLock
lock(lock_
);
65 pending_non_ui_
= NULL
;
69 void RequestDrawGLTracker::SetQueuedFunctorOnUi(SharedRendererState
* state
) {
70 base::AutoLock
lock(lock_
);
73 pending_non_ui_
= NULL
;
76 } // namespace internal
80 base::LazyInstance
<internal::RequestDrawGLTracker
> g_request_draw_gl_tracker
=
81 LAZY_INSTANCE_INITIALIZER
;
85 SharedRendererState::SharedRendererState(
86 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_loop
,
87 BrowserViewRenderer
* browser_view_renderer
)
89 browser_view_renderer_(browser_view_renderer
),
90 renderer_manager_key_(GLViewRendererManager::GetInstance()->NullKey()),
92 inside_hardware_release_(false),
93 needs_force_invalidate_on_next_draw_gl_(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() {
107 if (ui_loop_
->BelongsToCurrentThread()) {
108 if (!g_request_draw_gl_tracker
.Get().ShouldRequestOnUiThread(this))
110 ClientRequestDrawGLOnUI();
112 if (!g_request_draw_gl_tracker
.Get().ShouldRequestOnNonUiThread(this))
114 base::Closure callback
;
116 base::AutoLock
lock(lock_
);
117 callback
= request_draw_gl_closure_
;
119 ui_loop_
->PostTask(FROM_HERE
, callback
);
123 void SharedRendererState::DidDrawGLProcess() {
124 g_request_draw_gl_tracker
.Get().ResetPending();
127 void SharedRendererState::ResetRequestDrawGLCallback() {
128 DCHECK(ui_loop_
->BelongsToCurrentThread());
129 base::AutoLock
lock(lock_
);
130 request_draw_gl_cancelable_closure_
.Reset(base::Bind(
131 &SharedRendererState::ClientRequestDrawGLOnUI
, base::Unretained(this)));
132 request_draw_gl_closure_
= request_draw_gl_cancelable_closure_
.callback();
135 void SharedRendererState::ClientRequestDrawGLOnUI() {
136 DCHECK(ui_loop_
->BelongsToCurrentThread());
137 ResetRequestDrawGLCallback();
138 g_request_draw_gl_tracker
.Get().SetQueuedFunctorOnUi(this);
139 if (!browser_view_renderer_
->RequestDrawGL(false)) {
140 g_request_draw_gl_tracker
.Get().ResetPending();
141 LOG(ERROR
) << "Failed to request GL process. Deadlock likely";
145 void SharedRendererState::UpdateParentDrawConstraintsOnUI() {
146 DCHECK(ui_loop_
->BelongsToCurrentThread());
147 browser_view_renderer_
->UpdateParentDrawConstraints();
150 void SharedRendererState::SetScrollOffsetOnUI(gfx::Vector2d scroll_offset
) {
151 base::AutoLock
lock(lock_
);
152 scroll_offset_
= scroll_offset
;
155 gfx::Vector2d
SharedRendererState::GetScrollOffsetOnRT() {
156 base::AutoLock
lock(lock_
);
157 return scroll_offset_
;
160 bool SharedRendererState::HasCompositorFrameOnUI() const {
161 base::AutoLock
lock(lock_
);
162 return compositor_frame_
.get();
165 void SharedRendererState::SetCompositorFrameOnUI(
166 scoped_ptr
<cc::CompositorFrame
> frame
,
168 base::AutoLock
lock(lock_
);
169 DCHECK(!compositor_frame_
.get());
170 compositor_frame_
= frame
.Pass();
171 force_commit_
= force_commit
;
174 scoped_ptr
<cc::CompositorFrame
> SharedRendererState::PassCompositorFrameOnRT() {
175 base::AutoLock
lock(lock_
);
176 return compositor_frame_
.Pass();
179 scoped_ptr
<cc::CompositorFrame
>
180 SharedRendererState::PassUncommittedFrameOnUI() {
181 base::AutoLock
lock(lock_
);
182 return compositor_frame_
.Pass();
185 bool SharedRendererState::ForceCommitOnRT() const {
186 base::AutoLock
lock(lock_
);
187 return force_commit_
;
190 bool SharedRendererState::UpdateDrawConstraintsOnRT(
191 const ParentCompositorDrawConstraints
& parent_draw_constraints
) {
192 base::AutoLock
lock(lock_
);
193 if (needs_force_invalidate_on_next_draw_gl_
||
194 !parent_draw_constraints_
.Equals(parent_draw_constraints
)) {
195 parent_draw_constraints_
= parent_draw_constraints
;
202 void SharedRendererState::PostExternalDrawConstraintsToChildCompositorOnRT(
203 const ParentCompositorDrawConstraints
& parent_draw_constraints
) {
204 if (UpdateDrawConstraintsOnRT(parent_draw_constraints
)) {
205 // No need to hold the lock_ during the post task.
208 base::Bind(&SharedRendererState::UpdateParentDrawConstraintsOnUI
,
209 ui_thread_weak_ptr_
));
213 void SharedRendererState::DidSkipCommitFrameOnRT() {
214 ui_loop_
->PostTask(FROM_HERE
,
215 base::Bind(&SharedRendererState::DidSkipCommitFrameOnUI
,
216 ui_thread_weak_ptr_
));
219 void SharedRendererState::DidSkipCommitFrameOnUI() {
220 DCHECK(ui_loop_
->BelongsToCurrentThread());
221 browser_view_renderer_
->DidSkipCommitFrame();
224 ParentCompositorDrawConstraints
225 SharedRendererState::GetParentDrawConstraintsOnUI() const {
226 base::AutoLock
lock(lock_
);
227 return parent_draw_constraints_
;
230 void SharedRendererState::SetForceInvalidateOnNextDrawGLOnUI(
231 bool needs_force_invalidate_on_next_draw_gl
) {
232 base::AutoLock
lock(lock_
);
233 needs_force_invalidate_on_next_draw_gl_
=
234 needs_force_invalidate_on_next_draw_gl
;
237 bool SharedRendererState::NeedsForceInvalidateOnNextDrawGLOnUI() const {
238 base::AutoLock
lock(lock_
);
239 return needs_force_invalidate_on_next_draw_gl_
;
242 void SharedRendererState::SetInsideHardwareRelease(bool inside
) {
243 base::AutoLock
lock(lock_
);
244 inside_hardware_release_
= inside
;
247 bool SharedRendererState::IsInsideHardwareRelease() const {
248 base::AutoLock
lock(lock_
);
249 return inside_hardware_release_
;
252 void SharedRendererState::InsertReturnedResourcesOnRT(
253 const cc::ReturnedResourceArray
& resources
) {
254 base::AutoLock
lock(lock_
);
255 returned_resources_
.insert(
256 returned_resources_
.end(), resources
.begin(), resources
.end());
259 void SharedRendererState::SwapReturnedResourcesOnUI(
260 cc::ReturnedResourceArray
* resources
) {
261 DCHECK(resources
->empty());
262 base::AutoLock
lock(lock_
);
263 resources
->swap(returned_resources_
);
266 bool SharedRendererState::ReturnedResourcesEmptyOnUI() const {
267 base::AutoLock
lock(lock_
);
268 return returned_resources_
.empty();
271 void SharedRendererState::DrawGL(AwDrawGLInfo
* draw_info
) {
272 TRACE_EVENT0("android_webview", "DrawFunctor");
273 if (draw_info
->mode
== AwDrawGLInfo::kModeSync
) {
274 TRACE_EVENT_INSTANT0("android_webview", "kModeSync",
275 TRACE_EVENT_SCOPE_THREAD
);
276 if (hardware_renderer_
)
277 hardware_renderer_
->CommitFrame();
281 // kModeProcessNoContext should never happen because we tear down hardware
282 // in onTrimMemory. However that guarantee is maintained outside of chromium
283 // code. Not notifying shared state in kModeProcessNoContext can lead to
284 // immediate deadlock, which is slightly more catastrophic than leaks or
286 if (draw_info
->mode
== AwDrawGLInfo::kModeProcess
||
287 draw_info
->mode
== AwDrawGLInfo::kModeProcessNoContext
) {
292 GLViewRendererManager
* manager
= GLViewRendererManager::GetInstance();
293 base::AutoLock
lock(lock_
);
294 if (renderer_manager_key_
!= manager
->NullKey()) {
295 manager
->DidDrawGL(renderer_manager_key_
);
299 ScopedAppGLStateRestore
state_restore(
300 draw_info
->mode
== AwDrawGLInfo::kModeDraw
301 ? ScopedAppGLStateRestore::MODE_DRAW
302 : ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
);
303 ScopedAllowGL allow_gl
;
305 if (draw_info
->mode
== AwDrawGLInfo::kModeProcessNoContext
) {
306 LOG(ERROR
) << "Received unexpected kModeProcessNoContext";
309 if (IsInsideHardwareRelease()) {
310 hardware_renderer_
.reset();
311 // Flush the idle queue in tear down.
312 DeferredGpuCommandService::GetInstance()->PerformAllIdleWork();
316 if (draw_info
->mode
!= AwDrawGLInfo::kModeDraw
) {
317 if (draw_info
->mode
== AwDrawGLInfo::kModeProcess
) {
318 DeferredGpuCommandService::GetInstance()->PerformIdleWork(true);
323 if (!hardware_renderer_
) {
324 hardware_renderer_
.reset(new HardwareRenderer(this));
325 hardware_renderer_
->CommitFrame();
328 hardware_renderer_
->DrawGL(state_restore
.stencil_enabled(),
329 state_restore
.framebuffer_binding_ext(),
331 DeferredGpuCommandService::GetInstance()->PerformIdleWork(false);
334 void SharedRendererState::ReleaseHardwareDrawIfNeededOnUI() {
335 DCHECK(ui_loop_
->BelongsToCurrentThread());
336 InsideHardwareReleaseReset
auto_inside_hardware_release_reset(this);
338 browser_view_renderer_
->DetachFunctorFromView();
339 bool hardware_initialized
= browser_view_renderer_
->hardware_enabled();
340 if (hardware_initialized
) {
341 bool draw_functor_succeeded
= browser_view_renderer_
->RequestDrawGL(true);
342 if (!draw_functor_succeeded
) {
343 LOG(ERROR
) << "Unable to free GL resources. Has the Window leaked?";
344 // Calling release on wrong thread intentionally.
346 info
.mode
= AwDrawGLInfo::kModeProcess
;
350 browser_view_renderer_
->ReleaseHardware();
353 GLViewRendererManager
* manager
= GLViewRendererManager::GetInstance();
356 base::AutoLock
lock(lock_
);
357 if (renderer_manager_key_
!= manager
->NullKey()) {
358 manager
->Remove(renderer_manager_key_
);
359 renderer_manager_key_
= manager
->NullKey();
363 if (hardware_initialized
) {
364 // Flush any invoke functors that's caused by ReleaseHardware.
365 browser_view_renderer_
->RequestDrawGL(true);
369 void SharedRendererState::InitializeHardwareDrawIfNeededOnUI() {
370 DCHECK(ui_loop_
->BelongsToCurrentThread());
371 GLViewRendererManager
* manager
= GLViewRendererManager::GetInstance();
373 base::AutoLock
lock(lock_
);
374 if (renderer_manager_key_
== manager
->NullKey()) {
375 renderer_manager_key_
= manager
->PushBack(this);
376 DeferredGpuCommandService::SetInstance();
380 SharedRendererState::InsideHardwareReleaseReset::InsideHardwareReleaseReset(
381 SharedRendererState
* shared_renderer_state
)
382 : shared_renderer_state_(shared_renderer_state
) {
383 DCHECK(!shared_renderer_state_
->IsInsideHardwareRelease());
384 shared_renderer_state_
->SetInsideHardwareRelease(true);
387 SharedRendererState::InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
388 shared_renderer_state_
->SetInsideHardwareRelease(false);
391 } // namespace android_webview