[android_webview] Use a fraction to calculate scroll offset.
[chromium-blink-merge.git] / content / browser / android / in_process / synchronous_compositor_impl.cc
blobe9092f8c918a78e6f5969e5e2b85ce7b418baf1e
1 // 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.
5 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
7 #include "base/lazy_instance.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/synchronization/lock.h"
10 #include "cc/input/input_handler.h"
11 #include "cc/input/layer_scroll_offset_delegate.h"
12 #include "content/browser/android/in_process/synchronous_input_event_filter.h"
13 #include "content/browser/renderer_host/render_widget_host_view_android.h"
14 #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"
19 #include "content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h"
20 #include "gpu/command_buffer/client/gl_in_process_context.h"
21 #include "gpu/command_buffer/service/stream_texture_manager_in_process_android.h"
22 #include "ui/gl/android/surface_texture.h"
23 #include "ui/gl/gl_surface.h"
24 #include "webkit/common/gpu/context_provider_in_process.h"
25 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
27 namespace content {
29 namespace {
31 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
33 int GetInProcessRendererId() {
34 content::RenderProcessHost::iterator it =
35 content::RenderProcessHost::AllHostsIterator();
36 if (it.IsAtEnd()) {
37 // There should always be one RPH in single process mode.
38 NOTREACHED();
39 return 0;
42 int id = it.GetCurrentValue()->GetID();
43 it.Advance();
44 DCHECK(it.IsAtEnd()); // Not multiprocess compatible.
45 return id;
48 class VideoContextProvider
49 : public StreamTextureFactorySynchronousImpl::ContextProvider {
50 public:
51 VideoContextProvider(
52 const scoped_refptr<cc::ContextProvider>& context_provider,
53 gpu::GLInProcessContext* gl_in_process_context)
54 : context_provider_(context_provider),
55 gl_in_process_context_(gl_in_process_context) {}
57 virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
58 uint32 stream_id) OVERRIDE {
59 return gl_in_process_context_->GetSurfaceTexture(stream_id);
62 virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
63 return context_provider_->Context3d();
66 private:
67 friend class base::RefCountedThreadSafe<VideoContextProvider>;
68 virtual ~VideoContextProvider() {}
70 scoped_refptr<cc::ContextProvider> context_provider_;
71 gpu::GLInProcessContext* gl_in_process_context_;
73 DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
76 class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
77 public:
78 SynchronousCompositorFactoryImpl()
79 : wrapped_gl_context_for_main_thread_(NULL),
80 num_hardware_compositors_(0) {
81 SynchronousCompositorFactory::SetInstance(this);
84 // SynchronousCompositorFactory
85 virtual scoped_refptr<base::MessageLoopProxy>
86 GetCompositorMessageLoop() OVERRIDE {
87 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
90 virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
91 int routing_id) OVERRIDE {
92 scoped_ptr<SynchronousCompositorOutputSurface> output_surface(
93 new SynchronousCompositorOutputSurface(routing_id));
94 return output_surface.PassAs<cc::OutputSurface>();
97 virtual InputHandlerManagerClient* GetInputHandlerManagerClient() OVERRIDE {
98 return synchronous_input_event_filter();
101 SynchronousInputEventFilter* synchronous_input_event_filter() {
102 return &synchronous_input_event_filter_;
105 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
106 CreateOffscreenContext() {
107 if (!gfx::GLSurface::InitializeOneOff())
108 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
110 const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
112 WebKit::WebGraphicsContext3D::Attributes attributes;
113 attributes.antialias = false;
114 attributes.shareResources = true;
115 attributes.noAutomaticFlushes = true;
117 gpu::GLInProcessContextAttribs in_process_attribs;
118 WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
119 attributes, &in_process_attribs);
120 scoped_ptr<gpu::GLInProcessContext> context(
121 gpu::GLInProcessContext::CreateContext(true,
122 NULL,
123 gfx::Size(1, 1),
124 attributes.shareResources,
125 in_process_attribs,
126 gpu_preference));
128 wrapped_gl_context_for_main_thread_ = context.get();
129 if (!context.get())
130 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
132 return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
133 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
134 context.Pass(), attributes));
137 virtual scoped_refptr<cc::ContextProvider>
138 GetOffscreenContextProviderForMainThread() OVERRIDE {
139 // This check only guarantees the main thread context is created after
140 // a compositor did successfully initialize hardware draw in the past.
141 // In particular this does not guarantee that the main thread context
142 // will fail creation when all compositors release hardware draw.
143 bool failed = !CanCreateMainThreadContext();
144 if (!failed &&
145 (!offscreen_context_for_main_thread_.get() ||
146 offscreen_context_for_main_thread_->DestroyedOnMainThread())) {
147 offscreen_context_for_main_thread_ =
148 webkit::gpu::ContextProviderInProcess::Create(
149 CreateOffscreenContext(),
150 "Compositor-Offscreen");
151 failed = !offscreen_context_for_main_thread_.get() ||
152 !offscreen_context_for_main_thread_->BindToCurrentThread();
155 if (failed) {
156 offscreen_context_for_main_thread_ = NULL;
157 wrapped_gl_context_for_main_thread_ = NULL;
159 return offscreen_context_for_main_thread_;
162 // This is called on both renderer main thread (offscreen context creation
163 // path shared between cross-process and in-process platforms) and renderer
164 // compositor impl thread (InitializeHwDraw) in order to support Android
165 // WebView synchronously enable and disable hardware mode multiple times in
166 // the same task. This is ok because in-process WGC3D creation may happen on
167 // any thread and is lightweight.
168 virtual scoped_refptr<cc::ContextProvider>
169 GetOffscreenContextProviderForCompositorThread() OVERRIDE {
170 base::AutoLock lock(offscreen_context_for_compositor_thread_lock_);
171 if (!offscreen_context_for_compositor_thread_.get() ||
172 offscreen_context_for_compositor_thread_->DestroyedOnMainThread()) {
173 offscreen_context_for_compositor_thread_ =
174 webkit::gpu::ContextProviderInProcess::CreateOffscreen();
176 return offscreen_context_for_compositor_thread_;
179 virtual scoped_ptr<StreamTextureFactory> CreateStreamTextureFactory(
180 int view_id) OVERRIDE {
181 scoped_refptr<VideoContextProvider> context_provider;
182 if (CanCreateMainThreadContext()) {
183 context_provider =
184 new VideoContextProvider(offscreen_context_for_main_thread_,
185 wrapped_gl_context_for_main_thread_);
187 return make_scoped_ptr(new StreamTextureFactorySynchronousImpl(
188 context_provider.get(), view_id))
189 .PassAs<StreamTextureFactory>();
192 void CompositorInitializedHardwareDraw(SynchronousCompositorImpl* compositor);
193 void CompositorReleasedHardwareDraw(SynchronousCompositorImpl* compositor);
195 private:
196 void ReleaseGlobalHardwareResources();
197 bool CanCreateMainThreadContext();
199 SynchronousInputEventFilter synchronous_input_event_filter_;
201 // Only guards construction and destruction of
202 // |offscreen_context_for_compositor_thread_|, not usage.
203 base::Lock offscreen_context_for_compositor_thread_lock_;
204 scoped_refptr<cc::ContextProvider> offscreen_context_for_main_thread_;
205 // This is a pointer to the context owned by
206 // |offscreen_context_for_main_thread_|.
207 gpu::GLInProcessContext* wrapped_gl_context_for_main_thread_;
208 scoped_refptr<cc::ContextProvider> offscreen_context_for_compositor_thread_;
210 // |num_hardware_compositor_lock_| is updated on UI thread only but can be
211 // read on renderer main thread.
212 base::Lock num_hardware_compositor_lock_;
213 unsigned int num_hardware_compositors_;
216 void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw(
217 SynchronousCompositorImpl* compositor) {
218 base::AutoLock lock(num_hardware_compositor_lock_);
219 num_hardware_compositors_++;
222 void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw(
223 SynchronousCompositorImpl* compositor) {
224 bool should_release_resources = false;
226 base::AutoLock lock(num_hardware_compositor_lock_);
227 DCHECK_GT(num_hardware_compositors_, 0u);
228 num_hardware_compositors_--;
229 should_release_resources = num_hardware_compositors_ == 0u;
231 if (should_release_resources)
232 ReleaseGlobalHardwareResources();
235 void SynchronousCompositorFactoryImpl::ReleaseGlobalHardwareResources() {
237 base::AutoLock lock(offscreen_context_for_compositor_thread_lock_);
238 offscreen_context_for_compositor_thread_ = NULL;
241 // TODO(boliu): Properly clean up command buffer server of main thread
242 // context here.
245 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
246 base::AutoLock lock(num_hardware_compositor_lock_);
247 return num_hardware_compositors_ > 0;
250 base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
251 LAZY_INSTANCE_INITIALIZER;
253 } // namespace
255 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl);
257 // static
258 SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
259 int routing_id) {
260 if (g_factory == NULL)
261 return NULL;
262 RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
263 if (!rvh)
264 return NULL;
265 WebContents* contents = WebContents::FromRenderViewHost(rvh);
266 if (!contents)
267 return NULL;
268 return FromWebContents(contents);
271 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
272 int routing_id) {
273 return FromID(GetInProcessRendererId(), routing_id);
276 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
277 : compositor_client_(NULL),
278 output_surface_(NULL),
279 contents_(contents),
280 input_handler_(NULL) {
281 DCHECK(contents);
284 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
285 if (compositor_client_)
286 compositor_client_->DidDestroyCompositor(this);
287 SetInputHandler(NULL);
290 void SynchronousCompositorImpl::SetClient(
291 SynchronousCompositorClient* compositor_client) {
292 DCHECK(CalledOnValidThread());
293 compositor_client_ = compositor_client;
296 bool SynchronousCompositorImpl::InitializeHwDraw(
297 scoped_refptr<gfx::GLSurface> surface) {
298 DCHECK(CalledOnValidThread());
299 DCHECK(output_surface_);
300 bool success = output_surface_->InitializeHwDraw(
301 surface,
302 g_factory.Get().GetOffscreenContextProviderForCompositorThread());
303 if (success)
304 g_factory.Get().CompositorInitializedHardwareDraw(this);
305 return success;
308 void SynchronousCompositorImpl::ReleaseHwDraw() {
309 DCHECK(CalledOnValidThread());
310 DCHECK(output_surface_);
311 output_surface_->ReleaseHwDraw();
312 g_factory.Get().CompositorReleasedHardwareDraw(this);
315 bool SynchronousCompositorImpl::DemandDrawHw(
316 gfx::Size surface_size,
317 const gfx::Transform& transform,
318 gfx::Rect viewport,
319 gfx::Rect clip,
320 bool stencil_enabled) {
321 DCHECK(CalledOnValidThread());
322 DCHECK(output_surface_);
324 return output_surface_->DemandDrawHw(
325 surface_size, transform, viewport, clip, stencil_enabled);
328 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
329 DCHECK(CalledOnValidThread());
330 DCHECK(output_surface_);
332 return output_surface_->DemandDrawSw(canvas);
335 void SynchronousCompositorImpl::SetMemoryPolicy(
336 const SynchronousCompositorMemoryPolicy& policy) {
337 DCHECK(CalledOnValidThread());
338 DCHECK(output_surface_);
340 return output_surface_->SetMemoryPolicy(policy);
343 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
344 if (input_handler_)
345 input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
348 void SynchronousCompositorImpl::DidBindOutputSurface(
349 SynchronousCompositorOutputSurface* output_surface) {
350 DCHECK(CalledOnValidThread());
351 output_surface_ = output_surface;
352 if (compositor_client_)
353 compositor_client_->DidInitializeCompositor(this);
356 void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface(
357 SynchronousCompositorOutputSurface* output_surface) {
358 DCHECK(CalledOnValidThread());
360 // Allow for transient hand-over when two output surfaces may refer to
361 // a single delegate.
362 if (output_surface_ == output_surface) {
363 output_surface_ = NULL;
364 if (compositor_client_)
365 compositor_client_->DidDestroyCompositor(this);
366 compositor_client_ = NULL;
370 void SynchronousCompositorImpl::SetInputHandler(
371 cc::InputHandler* input_handler) {
372 DCHECK(CalledOnValidThread());
374 if (input_handler_)
375 input_handler_->SetRootLayerScrollOffsetDelegate(NULL);
377 input_handler_ = input_handler;
379 if (input_handler_)
380 input_handler_->SetRootLayerScrollOffsetDelegate(this);
383 void SynchronousCompositorImpl::DidOverscroll(
384 const cc::DidOverscrollParams& params) {
385 if (compositor_client_) {
386 compositor_client_->DidOverscroll(params.accumulated_overscroll,
387 params.latest_overscroll_delta,
388 params.current_fling_velocity);
392 void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) {
393 DCHECK(CalledOnValidThread());
394 if (compositor_client_)
395 compositor_client_->SetContinuousInvalidate(enable);
398 InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
399 const WebKit::WebInputEvent& input_event) {
400 DCHECK(CalledOnValidThread());
401 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
402 contents_->GetRoutingID(), input_event);
405 void SynchronousCompositorImpl::UpdateFrameMetaData(
406 const cc::CompositorFrameMetadata& frame_metadata) {
407 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
408 contents_->GetRenderWidgetHostView());
409 if (rwhv)
410 rwhv->SynchronousFrameMetadata(frame_metadata);
413 void SynchronousCompositorImpl::DidActivatePendingTree() {
414 if (compositor_client_)
415 compositor_client_->DidUpdateContent();
418 void SynchronousCompositorImpl::SetMaxScrollOffset(
419 gfx::Vector2dF max_scroll_offset) {
420 DCHECK(CalledOnValidThread());
421 if (compositor_client_)
422 compositor_client_->SetMaxRootLayerScrollOffset(max_scroll_offset);
425 void SynchronousCompositorImpl::SetTotalScrollOffset(gfx::Vector2dF new_value) {
426 DCHECK(CalledOnValidThread());
427 if (compositor_client_)
428 compositor_client_->SetTotalRootLayerScrollOffset(new_value);
431 gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() {
432 DCHECK(CalledOnValidThread());
433 if (compositor_client_)
434 return compositor_client_->GetTotalRootLayerScrollOffset();
435 return gfx::Vector2dF();
438 void SynchronousCompositorImpl::SetPageScaleFactor(float page_scale_factor) {
439 DCHECK(CalledOnValidThread());
440 if (compositor_client_)
441 compositor_client_->SetRootLayerPageScaleFactor(page_scale_factor);
444 void SynchronousCompositorImpl::SetScrollableSize(gfx::SizeF scrollable_size) {
445 DCHECK(CalledOnValidThread());
446 if (compositor_client_)
447 compositor_client_->SetRootLayerScrollableSize(scrollable_size);
450 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
451 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
452 bool SynchronousCompositorImpl::CalledOnValidThread() const {
453 return BrowserThread::CurrentlyOn(BrowserThread::UI);
456 // static
457 void SynchronousCompositor::SetClientForWebContents(
458 WebContents* contents,
459 SynchronousCompositorClient* client) {
460 DCHECK(contents);
461 if (client) {
462 g_factory.Get(); // Ensure it's initialized.
463 SynchronousCompositorImpl::CreateForWebContents(contents);
465 if (SynchronousCompositorImpl* instance =
466 SynchronousCompositorImpl::FromWebContents(contents)) {
467 instance->SetClient(client);
471 } // namespace content