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
12namespace android_webview {
13
14namespace internal {
15
16class 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
30RequestDrawGLTracker::RequestDrawGLTracker()
31    : pending_ui_(NULL), pending_non_ui_(NULL) {
32}
33
34bool 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
43bool 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
58void RequestDrawGLTracker::ResetPending() {
59  base::AutoLock lock(lock_);
60  pending_non_ui_ = NULL;
61  pending_ui_ = NULL;
62}
63
64void 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
74namespace {
75
76base::LazyInstance<internal::RequestDrawGLTracker> g_request_draw_gl_tracker =
77    LAZY_INSTANCE_INITIALIZER;
78
79}
80
81SharedRendererState::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
96SharedRendererState::~SharedRendererState() {
97  DCHECK(ui_loop_->BelongsToCurrentThread());
98}
99
100void 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
117void SharedRendererState::DidDrawGLProcess() {
118  g_request_draw_gl_tracker.Get().ResetPending();
119}
120
121void 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
130void 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
140void SharedRendererState::UpdateParentDrawConstraintsOnUIThread() {
141  DCHECK(ui_loop_->BelongsToCurrentThread());
142  client_on_ui_->UpdateParentDrawConstraints();
143}
144
145void SharedRendererState::SetScrollOffset(gfx::Vector2d scroll_offset) {
146  base::AutoLock lock(lock_);
147  scroll_offset_ = scroll_offset;
148}
149
150gfx::Vector2d SharedRendererState::GetScrollOffset() {
151  base::AutoLock lock(lock_);
152  return scroll_offset_;
153}
154
155bool SharedRendererState::HasCompositorFrame() const {
156  base::AutoLock lock(lock_);
157  return compositor_frame_.get();
158}
159
160void 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
168scoped_ptr<cc::CompositorFrame> SharedRendererState::PassCompositorFrame() {
169  base::AutoLock lock(lock_);
170  return compositor_frame_.Pass();
171}
172
173bool SharedRendererState::ForceCommit() const {
174  base::AutoLock lock(lock_);
175  return force_commit_;
176}
177
178bool 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
190void 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
201void SharedRendererState::DidSkipCommitFrame() {
202  ui_loop_->PostTask(
203      FROM_HERE,
204      base::Bind(&SharedRendererState::DidSkipCommitFrameOnUIThread,
205                 ui_thread_weak_ptr_));
206}
207
208void SharedRendererState::DidSkipCommitFrameOnUIThread() {
209  DCHECK(ui_loop_->BelongsToCurrentThread());
210  client_on_ui_->DidSkipCommitFrame();
211}
212
213const ParentCompositorDrawConstraints
214SharedRendererState::ParentDrawConstraints() const {
215  base::AutoLock lock(lock_);
216  return parent_draw_constraints_;
217}
218
219void 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
226bool SharedRendererState::NeedsForceInvalidateOnNextDrawGL() const {
227  base::AutoLock lock(lock_);
228  return needs_force_invalidate_on_next_draw_gl_;
229}
230
231void SharedRendererState::SetInsideHardwareRelease(bool inside) {
232  base::AutoLock lock(lock_);
233  inside_hardware_release_ = inside;
234}
235
236bool SharedRendererState::IsInsideHardwareRelease() const {
237  base::AutoLock lock(lock_);
238  return inside_hardware_release_;
239}
240
241void 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
248void SharedRendererState::SwapReturnedResources(
249    cc::ReturnedResourceArray* resources) {
250  DCHECK(resources->empty());
251  base::AutoLock lock(lock_);
252  resources->swap(returned_resources_);
253}
254
255bool SharedRendererState::ReturnedResourcesEmpty() const {
256  base::AutoLock lock(lock_);
257  return returned_resources_.empty();
258}
259
260InsideHardwareReleaseReset::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
267InsideHardwareReleaseReset::~InsideHardwareReleaseReset() {
268  shared_renderer_state_->SetInsideHardwareRelease(false);
269}
270
271}  // namespace android_webview
272