blob: 041511ea0bb65fb22f4d2e5d4a0a7205e0a0d57d [file] [log] [blame]
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001// Copyright 2013 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 "content/browser/android/in_process/synchronous_compositor_impl.h"
6
7#include "base/lazy_instance.h"
Ben Murdoch9ab55632013-07-18 11:57:30 +01008#include "base/message_loop/message_loop.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01009#include "base/synchronization/lock.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010010#include "cc/input/input_handler.h"
11#include "cc/input/layer_scroll_offset_delegate.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010012#include "content/browser/android/in_process/synchronous_input_event_filter.h"
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +010013#include "content/browser/renderer_host/render_widget_host_view_android.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010014#include "content/public/browser/android/synchronous_compositor_client.h"
15#include "content/public/browser/browser_thread.h"
16#include "content/public/browser/render_process_host.h"
17#include "content/public/browser/render_view_host.h"
18#include "content/renderer/android/synchronous_compositor_factory.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010019#include "ui/gl/gl_surface.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010020#include "webkit/common/gpu/context_provider_in_process.h"
21
22namespace content {
23
24namespace {
25
26int GetInProcessRendererId() {
27 content::RenderProcessHost::iterator it =
28 content::RenderProcessHost::AllHostsIterator();
29 if (it.IsAtEnd()) {
30 // There should always be one RPH in single process mode.
31 NOTREACHED();
32 return 0;
33 }
34
35 int id = it.GetCurrentValue()->GetID();
36 it.Advance();
37 DCHECK(it.IsAtEnd()); // Not multiprocess compatible.
38 return id;
39}
40
41class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
42 public:
43 SynchronousCompositorFactoryImpl() {
44 SynchronousCompositorFactory::SetInstance(this);
45 }
46
47 // SynchronousCompositorFactory
48 virtual scoped_refptr<base::MessageLoopProxy>
49 GetCompositorMessageLoop() OVERRIDE {
50 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
51 }
52
53 virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
54 int routing_id) OVERRIDE {
55 scoped_ptr<SynchronousCompositorOutputSurface> output_surface(
56 new SynchronousCompositorOutputSurface(routing_id));
57 return output_surface.PassAs<cc::OutputSurface>();
58 }
59
60 virtual InputHandlerManagerClient* GetInputHandlerManagerClient() OVERRIDE {
61 return synchronous_input_event_filter();
62 }
63
64 SynchronousInputEventFilter* synchronous_input_event_filter() {
65 return &synchronous_input_event_filter_;
66 }
67
68 virtual scoped_refptr<cc::ContextProvider>
69 GetOffscreenContextProviderForMainThread() OVERRIDE {
70 NOTIMPLEMENTED()
71 << "Synchronous compositor does not support main thread context yet.";
72 return scoped_refptr<cc::ContextProvider>();
73 }
74
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010075 // This is called on both renderer main thread (offscreen context creation
76 // path shared between cross-process and in-process platforms) and renderer
77 // compositor impl thread (InitializeHwDraw) in order to support Android
78 // WebView synchronously enable and disable hardware mode multiple times in
79 // the same task. This is ok because in-process WGC3D creation may happen on
80 // any thread and is lightweight.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010081 virtual scoped_refptr<cc::ContextProvider>
82 GetOffscreenContextProviderForCompositorThread() OVERRIDE {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010083 base::AutoLock lock(offscreen_context_for_compositor_thread_creation_lock_);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010084 if (!offscreen_context_for_compositor_thread_.get() ||
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010085 offscreen_context_for_compositor_thread_->DestroyedOnMainThread()) {
86 offscreen_context_for_compositor_thread_ =
87 webkit::gpu::ContextProviderInProcess::Create();
88 }
89 return offscreen_context_for_compositor_thread_;
90 }
91
92 private:
93 SynchronousInputEventFilter synchronous_input_event_filter_;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010094
95 // Only guards construction of |offscreen_context_for_compositor_thread_|,
96 // not usage.
97 base::Lock offscreen_context_for_compositor_thread_creation_lock_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010098 scoped_refptr<cc::ContextProvider> offscreen_context_for_compositor_thread_;
99};
100
101base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
102 LAZY_INSTANCE_INITIALIZER;
103
104} // namespace
105
106DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl);
107
108// static
109SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
110 int routing_id) {
111 if (g_factory == NULL)
112 return NULL;
113 RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
114 if (!rvh)
115 return NULL;
116 WebContents* contents = WebContents::FromRenderViewHost(rvh);
117 if (!contents)
118 return NULL;
119 return FromWebContents(contents);
120}
121
122SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
123 int routing_id) {
124 return FromID(GetInProcessRendererId(), routing_id);
125}
126
127SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
128 : compositor_client_(NULL),
129 output_surface_(NULL),
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100130 contents_(contents),
131 input_handler_(NULL) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100132 DCHECK(contents);
133}
134
135SynchronousCompositorImpl::~SynchronousCompositorImpl() {
136 if (compositor_client_)
137 compositor_client_->DidDestroyCompositor(this);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100138 SetInputHandler(NULL);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100139}
140
141void SynchronousCompositorImpl::SetClient(
142 SynchronousCompositorClient* compositor_client) {
143 DCHECK(CalledOnValidThread());
144 compositor_client_ = compositor_client;
145}
146
Ben Murdochbb1529c2013-08-08 10:24:53 +0100147bool SynchronousCompositorImpl::InitializeHwDraw(
148 scoped_refptr<gfx::GLSurface> surface) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100149 DCHECK(CalledOnValidThread());
150 DCHECK(output_surface_);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100151 return output_surface_->InitializeHwDraw(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100152 surface,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100153 g_factory.Get().GetOffscreenContextProviderForCompositorThread());
154}
155
156void SynchronousCompositorImpl::ReleaseHwDraw() {
157 DCHECK(CalledOnValidThread());
158 DCHECK(output_surface_);
159 return output_surface_->ReleaseHwDraw();
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100160}
161
162bool SynchronousCompositorImpl::DemandDrawHw(
163 gfx::Size view_size,
164 const gfx::Transform& transform,
Ben Murdochfb250652013-07-31 11:42:55 +0100165 gfx::Rect damage_area,
166 bool stencil_enabled) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100167 DCHECK(CalledOnValidThread());
168 DCHECK(output_surface_);
169
Ben Murdochfb250652013-07-31 11:42:55 +0100170 return output_surface_->DemandDrawHw(
171 view_size, transform, damage_area, stencil_enabled);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100172}
173
174bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
175 DCHECK(CalledOnValidThread());
176 DCHECK(output_surface_);
177
178 return output_surface_->DemandDrawSw(canvas);
179}
180
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100181void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
182 if (input_handler_)
183 input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
184}
185
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100186void SynchronousCompositorImpl::DidBindOutputSurface(
187 SynchronousCompositorOutputSurface* output_surface) {
188 DCHECK(CalledOnValidThread());
189 output_surface_ = output_surface;
190 if (compositor_client_)
191 compositor_client_->DidInitializeCompositor(this);
192}
193
194void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface(
195 SynchronousCompositorOutputSurface* output_surface) {
196 DCHECK(CalledOnValidThread());
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100197
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100198 // Allow for transient hand-over when two output surfaces may refer to
199 // a single delegate.
200 if (output_surface_ == output_surface) {
201 output_surface_ = NULL;
202 if (compositor_client_)
203 compositor_client_->DidDestroyCompositor(this);
204 compositor_client_ = NULL;
205 }
206}
207
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100208void SynchronousCompositorImpl::SetInputHandler(
209 cc::InputHandler* input_handler) {
210 DCHECK(CalledOnValidThread());
211
212 if (input_handler_)
213 input_handler_->SetRootLayerScrollOffsetDelegate(NULL);
214
215 input_handler_ = input_handler;
216
217 if (input_handler_)
218 input_handler_->SetRootLayerScrollOffsetDelegate(this);
219}
220
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100221void SynchronousCompositorImpl::DidOverscroll(
Ben Murdoch9ab55632013-07-18 11:57:30 +0100222 const cc::DidOverscrollParams& params) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100223 if (compositor_client_) {
Ben Murdoch9ab55632013-07-18 11:57:30 +0100224 compositor_client_->DidOverscroll(params.latest_overscroll_delta,
225 params.current_fling_velocity);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100226 }
227}
228
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100229void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) {
230 DCHECK(CalledOnValidThread());
231 if (compositor_client_)
232 compositor_client_->SetContinuousInvalidate(enable);
233}
234
235InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
236 const WebKit::WebInputEvent& input_event) {
237 DCHECK(CalledOnValidThread());
238 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
239 contents_->GetRoutingID(), input_event);
240}
241
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +0100242void SynchronousCompositorImpl::UpdateFrameMetaData(
243 const cc::CompositorFrameMetadata& frame_metadata) {
244 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
245 contents_->GetRenderWidgetHostView());
246 if (rwhv)
247 rwhv->SynchronousFrameMetadata(frame_metadata);
248}
249
Ben Murdochca12bfa2013-07-23 11:17:05 +0100250void SynchronousCompositorImpl::DidActivatePendingTree() {
251 if (compositor_client_)
252 compositor_client_->DidUpdateContent();
253}
254
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100255void SynchronousCompositorImpl::SetTotalScrollOffset(gfx::Vector2dF new_value) {
256 DCHECK(CalledOnValidThread());
257 if (compositor_client_)
258 compositor_client_->SetTotalRootLayerScrollOffset(new_value);
259}
260
261gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() {
262 DCHECK(CalledOnValidThread());
263 if (compositor_client_)
264 return compositor_client_->GetTotalRootLayerScrollOffset();
265 return gfx::Vector2dF();
266}
267
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100268// Not using base::NonThreadSafe as we want to enforce a more exacting threading
269// requirement: SynchronousCompositorImpl() must only be used on the UI thread.
270bool SynchronousCompositorImpl::CalledOnValidThread() const {
271 return BrowserThread::CurrentlyOn(BrowserThread::UI);
272}
273
274// static
275void SynchronousCompositor::SetClientForWebContents(
276 WebContents* contents,
277 SynchronousCompositorClient* client) {
278 DCHECK(contents);
279 if (client) {
280 g_factory.Get(); // Ensure it's initialized.
281 SynchronousCompositorImpl::CreateForWebContents(contents);
282 }
283 if (SynchronousCompositorImpl* instance =
284 SynchronousCompositorImpl::FromWebContents(contents)) {
285 instance->SetClient(client);
286 }
287}
288
289} // namespace content