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_refptr
<VideoContextProvider
> context_provider
;
182 if (CanCreateMainThreadContext()) {
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
);
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
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
;
255 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl
);
258 SynchronousCompositorImpl
* SynchronousCompositorImpl::FromID(int process_id
,
260 if (g_factory
== NULL
)
262 RenderViewHost
* rvh
= RenderViewHost::FromID(process_id
, routing_id
);
265 WebContents
* contents
= WebContents::FromRenderViewHost(rvh
);
268 return FromWebContents(contents
);
271 SynchronousCompositorImpl
* SynchronousCompositorImpl::FromRoutingID(
273 return FromID(GetInProcessRendererId(), routing_id
);
276 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents
* contents
)
277 : compositor_client_(NULL
),
278 output_surface_(NULL
),
280 input_handler_(NULL
) {
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(
302 g_factory
.Get().GetOffscreenContextProviderForCompositorThread());
304 g_factory
.Get().CompositorInitializedHardwareDraw(this);
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
,
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() {
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());
375 input_handler_
->SetRootLayerScrollOffsetDelegate(NULL
);
377 input_handler_
= 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());
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
);
457 void SynchronousCompositor::SetClientForWebContents(
458 WebContents
* contents
,
459 SynchronousCompositorClient
* 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