- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / android / in_process / synchronous_compositor_impl.cc
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.
4
5 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
6
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"
26
27 namespace content {
28
29 namespace {
30
31 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
32
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;
40   }
41
42   int id = it.GetCurrentValue()->GetID();
43   it.Advance();
44   DCHECK(it.IsAtEnd());  // Not multiprocess compatible.
45   return id;
46 }
47
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) {}
56
57   virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
58       uint32 stream_id) OVERRIDE {
59     return gl_in_process_context_->GetSurfaceTexture(stream_id);
60   }
61
62   virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
63     return context_provider_->Context3d();
64   }
65
66  private:
67   friend class base::RefCountedThreadSafe<VideoContextProvider>;
68   virtual ~VideoContextProvider() {}
69
70   scoped_refptr<cc::ContextProvider> context_provider_;
71   gpu::GLInProcessContext* gl_in_process_context_;
72
73   DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
74 };
75
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);
82   }
83
84   // SynchronousCompositorFactory
85   virtual scoped_refptr<base::MessageLoopProxy>
86       GetCompositorMessageLoop() OVERRIDE {
87     return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
88   }
89
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>();
95   }
96
97   virtual InputHandlerManagerClient* GetInputHandlerManagerClient() OVERRIDE {
98     return synchronous_input_event_filter();
99   }
100
101   SynchronousInputEventFilter* synchronous_input_event_filter() {
102     return &synchronous_input_event_filter_;
103   }
104
105   scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
106   CreateOffscreenContext() {
107     if (!gfx::GLSurface::InitializeOneOff())
108       return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
109
110     const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
111
112     WebKit::WebGraphicsContext3D::Attributes attributes;
113     attributes.antialias = false;
114     attributes.shareResources = true;
115     attributes.noAutomaticFlushes = true;
116
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));
127
128     wrapped_gl_context_for_main_thread_ = context.get();
129     if (!context.get())
130       return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
131
132     return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
133         WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
134             context.Pass(), attributes));
135   }
136
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();
153     }
154
155     if (failed) {
156       offscreen_context_for_main_thread_ = NULL;
157       wrapped_gl_context_for_main_thread_ = NULL;
158     }
159     return offscreen_context_for_main_thread_;
160   }
161
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();
175     }
176     return offscreen_context_for_compositor_thread_;
177   }
178
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)),
186             view_id));
187     return factory.PassAs<StreamTextureFactory>();
188   }
189
190   void CompositorInitializedHardwareDraw(SynchronousCompositorImpl* compositor);
191   void CompositorReleasedHardwareDraw(SynchronousCompositorImpl* compositor);
192
193  private:
194   void ReleaseGlobalHardwareResources();
195   bool CanCreateMainThreadContext();
196   scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
197       TryCreateStreamTextureFactory();
198
199   SynchronousInputEventFilter synchronous_input_event_filter_;
200
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_;
209
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_;
214 };
215
216 void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw(
217     SynchronousCompositorImpl* compositor) {
218   base::AutoLock lock(num_hardware_compositor_lock_);
219   num_hardware_compositors_++;
220 }
221
222 void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw(
223     SynchronousCompositorImpl* compositor) {
224   bool should_release_resources = false;
225   {
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;
230   }
231   if (should_release_resources)
232     ReleaseGlobalHardwareResources();
233 }
234
235 void SynchronousCompositorFactoryImpl::ReleaseGlobalHardwareResources() {
236   {
237     base::AutoLock lock(offscreen_context_for_compositor_thread_lock_);
238     offscreen_context_for_compositor_thread_ = NULL;
239   }
240
241   // TODO(boliu): Properly clean up command buffer server of main thread
242   // context here.
243 }
244
245 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
246   base::AutoLock lock(num_hardware_compositor_lock_);
247   return num_hardware_compositors_ > 0;
248 }
249
250 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
251 SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
252   scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
253       context_provider;
254   if (CanCreateMainThreadContext() && offscreen_context_for_main_thread_) {
255     DCHECK(wrapped_gl_context_for_main_thread_);
256     context_provider =
257         new VideoContextProvider(offscreen_context_for_main_thread_,
258                                  wrapped_gl_context_for_main_thread_);
259   }
260   return context_provider;
261 }
262
263 base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
264     LAZY_INSTANCE_INITIALIZER;
265
266 }  // namespace
267
268 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl);
269
270 // static
271 SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
272                                                              int routing_id) {
273   if (g_factory == NULL)
274     return NULL;
275   RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
276   if (!rvh)
277     return NULL;
278   WebContents* contents = WebContents::FromRenderViewHost(rvh);
279   if (!contents)
280     return NULL;
281   return FromWebContents(contents);
282 }
283
284 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
285     int routing_id) {
286   return FromID(GetInProcessRendererId(), routing_id);
287 }
288
289 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
290     : compositor_client_(NULL),
291       output_surface_(NULL),
292       contents_(contents),
293       input_handler_(NULL) {
294   DCHECK(contents);
295 }
296
297 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
298   if (compositor_client_)
299     compositor_client_->DidDestroyCompositor(this);
300   SetInputHandler(NULL);
301 }
302
303 void SynchronousCompositorImpl::SetClient(
304     SynchronousCompositorClient* compositor_client) {
305   DCHECK(CalledOnValidThread());
306   compositor_client_ = compositor_client;
307 }
308
309 bool SynchronousCompositorImpl::InitializeHwDraw(
310     scoped_refptr<gfx::GLSurface> surface) {
311   DCHECK(CalledOnValidThread());
312   DCHECK(output_surface_);
313   bool success = output_surface_->InitializeHwDraw(
314       surface,
315       g_factory.Get().GetOffscreenContextProviderForCompositorThread());
316   if (success)
317     g_factory.Get().CompositorInitializedHardwareDraw(this);
318   return success;
319 }
320
321 void SynchronousCompositorImpl::ReleaseHwDraw() {
322   DCHECK(CalledOnValidThread());
323   DCHECK(output_surface_);
324   output_surface_->ReleaseHwDraw();
325   g_factory.Get().CompositorReleasedHardwareDraw(this);
326 }
327
328 bool SynchronousCompositorImpl::DemandDrawHw(
329       gfx::Size surface_size,
330       const gfx::Transform& transform,
331       gfx::Rect viewport,
332       gfx::Rect clip,
333       bool stencil_enabled) {
334   DCHECK(CalledOnValidThread());
335   DCHECK(output_surface_);
336
337   return output_surface_->DemandDrawHw(
338       surface_size, transform, viewport, clip, stencil_enabled);
339 }
340
341 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
342   DCHECK(CalledOnValidThread());
343   DCHECK(output_surface_);
344
345   return output_surface_->DemandDrawSw(canvas);
346 }
347
348 void SynchronousCompositorImpl::SetMemoryPolicy(
349     const SynchronousCompositorMemoryPolicy& policy) {
350   DCHECK(CalledOnValidThread());
351   DCHECK(output_surface_);
352
353   return output_surface_->SetMemoryPolicy(policy);
354 }
355
356 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
357   if (input_handler_)
358     input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
359 }
360
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);
367 }
368
369 void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface(
370        SynchronousCompositorOutputSurface* output_surface) {
371   DCHECK(CalledOnValidThread());
372
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;
380   }
381 }
382
383 void SynchronousCompositorImpl::SetInputHandler(
384     cc::InputHandler* input_handler) {
385   DCHECK(CalledOnValidThread());
386
387   if (input_handler_)
388     input_handler_->SetRootLayerScrollOffsetDelegate(NULL);
389
390   input_handler_ = input_handler;
391
392   if (input_handler_)
393     input_handler_->SetRootLayerScrollOffsetDelegate(this);
394 }
395
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);
402   }
403 }
404
405 void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) {
406   DCHECK(CalledOnValidThread());
407   if (compositor_client_)
408     compositor_client_->SetContinuousInvalidate(enable);
409 }
410
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);
416 }
417
418 void SynchronousCompositorImpl::UpdateFrameMetaData(
419     const cc::CompositorFrameMetadata& frame_metadata) {
420   RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
421       contents_->GetRenderWidgetHostView());
422   if (rwhv)
423     rwhv->SynchronousFrameMetadata(frame_metadata);
424 }
425
426 void SynchronousCompositorImpl::DidActivatePendingTree() {
427   if (compositor_client_)
428     compositor_client_->DidUpdateContent();
429 }
430
431 void SynchronousCompositorImpl::SetMaxScrollOffset(
432     gfx::Vector2dF max_scroll_offset) {
433   DCHECK(CalledOnValidThread());
434   if (compositor_client_)
435     compositor_client_->SetMaxRootLayerScrollOffset(max_scroll_offset);
436 }
437
438 void SynchronousCompositorImpl::SetTotalScrollOffset(gfx::Vector2dF new_value) {
439   DCHECK(CalledOnValidThread());
440   if (compositor_client_)
441     compositor_client_->SetTotalRootLayerScrollOffset(new_value);
442 }
443
444 gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() {
445   DCHECK(CalledOnValidThread());
446   if (compositor_client_)
447     return compositor_client_->GetTotalRootLayerScrollOffset();
448   return gfx::Vector2dF();
449 }
450
451 bool SynchronousCompositorImpl::IsExternalFlingActive() const {
452   DCHECK(CalledOnValidThread());
453   if (compositor_client_)
454     return compositor_client_->IsExternalFlingActive();
455   return false;
456 }
457
458 void SynchronousCompositorImpl::SetTotalPageScaleFactor(
459     float page_scale_factor) {
460   DCHECK(CalledOnValidThread());
461   if (compositor_client_)
462     compositor_client_->SetRootLayerPageScaleFactor(page_scale_factor);
463 }
464
465 void SynchronousCompositorImpl::SetScrollableSize(gfx::SizeF scrollable_size) {
466   DCHECK(CalledOnValidThread());
467   if (compositor_client_)
468     compositor_client_->SetRootLayerScrollableSize(scrollable_size);
469 }
470
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);
475 }
476
477 // static
478 void SynchronousCompositor::SetClientForWebContents(
479     WebContents* contents,
480     SynchronousCompositorClient* client) {
481   DCHECK(contents);
482   if (client) {
483     g_factory.Get();  // Ensure it's initialized.
484     SynchronousCompositorImpl::CreateForWebContents(contents);
485   }
486   if (SynchronousCompositorImpl* instance =
487       SynchronousCompositorImpl::FromWebContents(contents)) {
488     instance->SetClient(client);
489   }
490 }
491
492 }  // namespace content