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"
31 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
33 int GetInProcessRendererId() {
34 content::RenderProcessHost::iterator it =
35 content::RenderProcessHost::AllHostsIterator();
37 // There should always be one RPH in single process mode.
42 int id = it.GetCurrentValue()->GetID();
44 DCHECK(it.IsAtEnd()); // Not multiprocess compatible.
48 class VideoContextProvider
49 : public StreamTextureFactorySynchronousImpl::ContextProvider {
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();
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 {
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,
124 attributes.shareResources,
128 wrapped_gl_context_for_main_thread_ = 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();
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();
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_ptr<StreamTextureFactorySynchronousImpl> factory(
182 new StreamTextureFactorySynchronousImpl(
183 base::Bind(&SynchronousCompositorFactoryImpl::
184 TryCreateStreamTextureFactory,
185 base::Unretained(this)),
187 return factory.PassAs<StreamTextureFactory>();
190 void CompositorInitializedHardwareDraw(SynchronousCompositorImpl* compositor);
191 void CompositorReleasedHardwareDraw(SynchronousCompositorImpl* compositor);
194 void ReleaseGlobalHardwareResources();
195 bool CanCreateMainThreadContext();
196 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
197 TryCreateStreamTextureFactory();
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
245 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
246 base::AutoLock lock(num_hardware_compositor_lock_);
247 return num_hardware_compositors_ > 0;
250 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
251 SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
252 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
254 if (CanCreateMainThreadContext() && offscreen_context_for_main_thread_) {
255 DCHECK(wrapped_gl_context_for_main_thread_);
257 new VideoContextProvider(offscreen_context_for_main_thread_,
258 wrapped_gl_context_for_main_thread_);
260 return context_provider;
263 base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
264 LAZY_INSTANCE_INITIALIZER;
268 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl);
271 SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
273 if (g_factory == NULL)
275 RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
278 WebContents* contents = WebContents::FromRenderViewHost(rvh);
281 return FromWebContents(contents);
284 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
286 return FromID(GetInProcessRendererId(), routing_id);
289 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
290 : compositor_client_(NULL),
291 output_surface_(NULL),
293 input_handler_(NULL) {
297 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
298 if (compositor_client_)
299 compositor_client_->DidDestroyCompositor(this);
300 SetInputHandler(NULL);
303 void SynchronousCompositorImpl::SetClient(
304 SynchronousCompositorClient* compositor_client) {
305 DCHECK(CalledOnValidThread());
306 compositor_client_ = compositor_client;
309 bool SynchronousCompositorImpl::InitializeHwDraw(
310 scoped_refptr<gfx::GLSurface> surface) {
311 DCHECK(CalledOnValidThread());
312 DCHECK(output_surface_);
313 bool success = output_surface_->InitializeHwDraw(
315 g_factory.Get().GetOffscreenContextProviderForCompositorThread());
317 g_factory.Get().CompositorInitializedHardwareDraw(this);
321 void SynchronousCompositorImpl::ReleaseHwDraw() {
322 DCHECK(CalledOnValidThread());
323 DCHECK(output_surface_);
324 output_surface_->ReleaseHwDraw();
325 g_factory.Get().CompositorReleasedHardwareDraw(this);
328 bool SynchronousCompositorImpl::DemandDrawHw(
329 gfx::Size surface_size,
330 const gfx::Transform& transform,
333 bool stencil_enabled) {
334 DCHECK(CalledOnValidThread());
335 DCHECK(output_surface_);
337 return output_surface_->DemandDrawHw(
338 surface_size, transform, viewport, clip, stencil_enabled);
341 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
342 DCHECK(CalledOnValidThread());
343 DCHECK(output_surface_);
345 return output_surface_->DemandDrawSw(canvas);
348 void SynchronousCompositorImpl::SetMemoryPolicy(
349 const SynchronousCompositorMemoryPolicy& policy) {
350 DCHECK(CalledOnValidThread());
351 DCHECK(output_surface_);
353 return output_surface_->SetMemoryPolicy(policy);
356 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
358 input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
361 void SynchronousCompositorImpl::DidBindOutputSurface(
362 SynchronousCompositorOutputSurface* output_surface) {
363 DCHECK(CalledOnValidThread());
364 output_surface_ = output_surface;
365 if (compositor_client_)
366 compositor_client_->DidInitializeCompositor(this);
369 void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface(
370 SynchronousCompositorOutputSurface* output_surface) {
371 DCHECK(CalledOnValidThread());
373 // Allow for transient hand-over when two output surfaces may refer to
374 // a single delegate.
375 if (output_surface_ == output_surface) {
376 output_surface_ = NULL;
377 if (compositor_client_)
378 compositor_client_->DidDestroyCompositor(this);
379 compositor_client_ = NULL;
383 void SynchronousCompositorImpl::SetInputHandler(
384 cc::InputHandler* input_handler) {
385 DCHECK(CalledOnValidThread());
388 input_handler_->SetRootLayerScrollOffsetDelegate(NULL);
390 input_handler_ = input_handler;
393 input_handler_->SetRootLayerScrollOffsetDelegate(this);
396 void SynchronousCompositorImpl::DidOverscroll(
397 const cc::DidOverscrollParams& params) {
398 if (compositor_client_) {
399 compositor_client_->DidOverscroll(params.accumulated_overscroll,
400 params.latest_overscroll_delta,
401 params.current_fling_velocity);
405 void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) {
406 DCHECK(CalledOnValidThread());
407 if (compositor_client_)
408 compositor_client_->SetContinuousInvalidate(enable);
411 InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
412 const WebKit::WebInputEvent& input_event) {
413 DCHECK(CalledOnValidThread());
414 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
415 contents_->GetRoutingID(), input_event);
418 void SynchronousCompositorImpl::UpdateFrameMetaData(
419 const cc::CompositorFrameMetadata& frame_metadata) {
420 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
421 contents_->GetRenderWidgetHostView());
423 rwhv->SynchronousFrameMetadata(frame_metadata);
426 void SynchronousCompositorImpl::DidActivatePendingTree() {
427 if (compositor_client_)
428 compositor_client_->DidUpdateContent();
431 void SynchronousCompositorImpl::SetMaxScrollOffset(
432 gfx::Vector2dF max_scroll_offset) {
433 DCHECK(CalledOnValidThread());
434 if (compositor_client_)
435 compositor_client_->SetMaxRootLayerScrollOffset(max_scroll_offset);
438 void SynchronousCompositorImpl::SetTotalScrollOffset(gfx::Vector2dF new_value) {
439 DCHECK(CalledOnValidThread());
440 if (compositor_client_)
441 compositor_client_->SetTotalRootLayerScrollOffset(new_value);
444 gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() {
445 DCHECK(CalledOnValidThread());
446 if (compositor_client_)
447 return compositor_client_->GetTotalRootLayerScrollOffset();
448 return gfx::Vector2dF();
451 bool SynchronousCompositorImpl::IsExternalFlingActive() const {
452 DCHECK(CalledOnValidThread());
453 if (compositor_client_)
454 return compositor_client_->IsExternalFlingActive();
458 void SynchronousCompositorImpl::SetTotalPageScaleFactor(
459 float page_scale_factor) {
460 DCHECK(CalledOnValidThread());
461 if (compositor_client_)
462 compositor_client_->SetRootLayerPageScaleFactor(page_scale_factor);
465 void SynchronousCompositorImpl::SetScrollableSize(gfx::SizeF scrollable_size) {
466 DCHECK(CalledOnValidThread());
467 if (compositor_client_)
468 compositor_client_->SetRootLayerScrollableSize(scrollable_size);
471 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
472 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
473 bool SynchronousCompositorImpl::CalledOnValidThread() const {
474 return BrowserThread::CurrentlyOn(BrowserThread::UI);
478 void SynchronousCompositor::SetClientForWebContents(
479 WebContents* contents,
480 SynchronousCompositorClient* client) {
483 g_factory.Get(); // Ensure it's initialized.
484 SynchronousCompositorImpl::CreateForWebContents(contents);
486 if (SynchronousCompositorImpl* instance =
487 SynchronousCompositorImpl::FromWebContents(contents)) {
488 instance->SetClient(client);
492 } // namespace content