Home | History | Annotate | Download | only in in_process
      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_bridge.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::SurfaceTextureBridge> 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   scoped_refptr<cc::ContextProvider> context_provider_;
     68   gpu::GLInProcessContext* gl_in_process_context_;
     69 
     70   DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
     71 };
     72 
     73 class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
     74  public:
     75   SynchronousCompositorFactoryImpl()
     76       : wrapped_gl_context_for_main_thread_(NULL),
     77         num_hardware_compositors_(0) {
     78     SynchronousCompositorFactory::SetInstance(this);
     79   }
     80 
     81   // SynchronousCompositorFactory
     82   virtual scoped_refptr<base::MessageLoopProxy>
     83       GetCompositorMessageLoop() OVERRIDE {
     84     return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
     85   }
     86 
     87   virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
     88       int routing_id) OVERRIDE {
     89     scoped_ptr<SynchronousCompositorOutputSurface> output_surface(
     90         new SynchronousCompositorOutputSurface(routing_id));
     91     return output_surface.PassAs<cc::OutputSurface>();
     92   }
     93 
     94   virtual InputHandlerManagerClient* GetInputHandlerManagerClient() OVERRIDE {
     95     return synchronous_input_event_filter();
     96   }
     97 
     98   SynchronousInputEventFilter* synchronous_input_event_filter() {
     99     return &synchronous_input_event_filter_;
    100   }
    101 
    102   scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
    103   CreateOffscreenContext() {
    104     if (!gfx::GLSurface::InitializeOneOff())
    105       return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
    106 
    107     const char* allowed_extensions = "*";
    108     const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
    109 
    110     WebKit::WebGraphicsContext3D::Attributes attributes;
    111     attributes.antialias = false;
    112     attributes.shareResources = true;
    113     attributes.noAutomaticFlushes = true;
    114 
    115     gpu::GLInProcessContextAttribs in_process_attribs;
    116     WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
    117         attributes, &in_process_attribs);
    118     scoped_ptr<gpu::GLInProcessContext> context(
    119         gpu::GLInProcessContext::CreateContext(true,
    120                                                NULL,
    121                                                gfx::Size(1, 1),
    122                                                attributes.shareResources,
    123                                                allowed_extensions,
    124                                                in_process_attribs,
    125                                                gpu_preference));
    126 
    127     wrapped_gl_context_for_main_thread_ = context.get();
    128     if (!context.get())
    129       return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
    130 
    131     return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
    132         WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
    133             context.Pass(), attributes));
    134   }
    135 
    136   virtual scoped_refptr<cc::ContextProvider>
    137   GetOffscreenContextProviderForMainThread() OVERRIDE {
    138     // This check only guarantees the main thread context is created after
    139     // a compositor did successfully initialize hardware draw in the past.
    140     // In particular this does not guarantee that the main thread context
    141     // will fail creation when all compositors release hardware draw.
    142     bool failed = !CanCreateMainThreadContext();
    143     if (!failed &&
    144         (!offscreen_context_for_main_thread_.get() ||
    145          offscreen_context_for_main_thread_->DestroyedOnMainThread())) {
    146       offscreen_context_for_main_thread_ =
    147           webkit::gpu::ContextProviderInProcess::Create(base::Bind(
    148               &SynchronousCompositorFactoryImpl::CreateOffscreenContext,
    149               base::Unretained(this)));
    150       failed = !offscreen_context_for_main_thread_.get() ||
    151                !offscreen_context_for_main_thread_->BindToCurrentThread();
    152     }
    153 
    154     if (failed) {
    155       offscreen_context_for_main_thread_ = NULL;
    156       wrapped_gl_context_for_main_thread_ = NULL;
    157     }
    158     return offscreen_context_for_main_thread_;
    159   }
    160 
    161   // This is called on both renderer main thread (offscreen context creation
    162   // path shared between cross-process and in-process platforms) and renderer
    163   // compositor impl thread (InitializeHwDraw) in order to support Android
    164   // WebView synchronously enable and disable hardware mode multiple times in
    165   // the same task. This is ok because in-process WGC3D creation may happen on
    166   // any thread and is lightweight.
    167   virtual scoped_refptr<cc::ContextProvider>
    168       GetOffscreenContextProviderForCompositorThread() OVERRIDE {
    169     base::AutoLock lock(offscreen_context_for_compositor_thread_lock_);
    170     if (!offscreen_context_for_compositor_thread_.get() ||
    171         offscreen_context_for_compositor_thread_->DestroyedOnMainThread()) {
    172       offscreen_context_for_compositor_thread_ =
    173           webkit::gpu::ContextProviderInProcess::CreateOffscreen();
    174     }
    175     return offscreen_context_for_compositor_thread_;
    176   }
    177 
    178   virtual scoped_ptr<StreamTextureFactory> CreateStreamTextureFactory(
    179       int view_id) OVERRIDE {
    180     scoped_ptr<StreamTextureFactorySynchronousImpl> factory(
    181         new StreamTextureFactorySynchronousImpl(
    182             base::Bind(&SynchronousCompositorFactoryImpl::
    183                             TryCreateStreamTextureFactory,
    184                        base::Unretained(this)),
    185             view_id));
    186     return factory.PassAs<StreamTextureFactory>();
    187   }
    188 
    189   void CompositorInitializedHardwareDraw(SynchronousCompositorImpl* compositor);
    190   void CompositorReleasedHardwareDraw(SynchronousCompositorImpl* compositor);
    191 
    192  private:
    193   void ReleaseGlobalHardwareResources();
    194   bool CanCreateMainThreadContext();
    195   scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
    196       TryCreateStreamTextureFactory();
    197 
    198   SynchronousInputEventFilter synchronous_input_event_filter_;
    199 
    200   // Only guards construction and destruction of
    201   // |offscreen_context_for_compositor_thread_|, not usage.
    202   base::Lock offscreen_context_for_compositor_thread_lock_;
    203   scoped_refptr<cc::ContextProvider> offscreen_context_for_main_thread_;
    204   // This is a pointer to the context owned by
    205   // |offscreen_context_for_main_thread_|.
    206   gpu::GLInProcessContext* wrapped_gl_context_for_main_thread_;
    207   scoped_refptr<cc::ContextProvider> offscreen_context_for_compositor_thread_;
    208 
    209   // |num_hardware_compositor_lock_| is updated on UI thread only but can be
    210   // read on renderer main thread.
    211   base::Lock num_hardware_compositor_lock_;
    212   unsigned int num_hardware_compositors_;
    213 };
    214 
    215 void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw(
    216     SynchronousCompositorImpl* compositor) {
    217   base::AutoLock lock(num_hardware_compositor_lock_);
    218   num_hardware_compositors_++;
    219 }
    220 
    221 void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw(
    222     SynchronousCompositorImpl* compositor) {
    223   bool should_release_resources = false;
    224   {
    225     base::AutoLock lock(num_hardware_compositor_lock_);
    226     DCHECK_GT(num_hardware_compositors_, 0u);
    227     num_hardware_compositors_--;
    228     should_release_resources = num_hardware_compositors_ == 0u;
    229   }
    230   if (should_release_resources)
    231     ReleaseGlobalHardwareResources();
    232 }
    233 
    234 void SynchronousCompositorFactoryImpl::ReleaseGlobalHardwareResources() {
    235   {
    236     base::AutoLock lock(offscreen_context_for_compositor_thread_lock_);
    237     offscreen_context_for_compositor_thread_ = NULL;
    238   }
    239 
    240   // TODO(boliu): Properly clean up command buffer server of main thread
    241   // context here.
    242 }
    243 
    244 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
    245   base::AutoLock lock(num_hardware_compositor_lock_);
    246   return num_hardware_compositors_ > 0;
    247 }
    248 
    249 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
    250 SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
    251   scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
    252       context_provider;
    253   if (CanCreateMainThreadContext() &&
    254       GetOffscreenContextProviderForMainThread()) {
    255     DCHECK(offscreen_context_for_main_thread_);
    256     DCHECK(wrapped_gl_context_for_main_thread_);
    257     context_provider =
    258         new VideoContextProvider(offscreen_context_for_main_thread_,
    259                                  wrapped_gl_context_for_main_thread_);
    260   }
    261   return context_provider;
    262 }
    263 
    264 base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
    265     LAZY_INSTANCE_INITIALIZER;
    266 
    267 }  // namespace
    268 
    269 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl);
    270 
    271 // static
    272 SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
    273                                                              int routing_id) {
    274   if (g_factory == NULL)
    275     return NULL;
    276   RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
    277   if (!rvh)
    278     return NULL;
    279   WebContents* contents = WebContents::FromRenderViewHost(rvh);
    280   if (!contents)
    281     return NULL;
    282   return FromWebContents(contents);
    283 }
    284 
    285 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
    286     int routing_id) {
    287   return FromID(GetInProcessRendererId(), routing_id);
    288 }
    289 
    290 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
    291     : compositor_client_(NULL),
    292       output_surface_(NULL),
    293       contents_(contents),
    294       input_handler_(NULL) {
    295   DCHECK(contents);
    296 }
    297 
    298 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
    299   if (compositor_client_)
    300     compositor_client_->DidDestroyCompositor(this);
    301   SetInputHandler(NULL);
    302 }
    303 
    304 void SynchronousCompositorImpl::SetClient(
    305     SynchronousCompositorClient* compositor_client) {
    306   DCHECK(CalledOnValidThread());
    307   compositor_client_ = compositor_client;
    308 }
    309 
    310 bool SynchronousCompositorImpl::InitializeHwDraw(
    311     scoped_refptr<gfx::GLSurface> surface) {
    312   DCHECK(CalledOnValidThread());
    313   DCHECK(output_surface_);
    314   bool success = output_surface_->InitializeHwDraw(
    315       surface,
    316       g_factory.Get().GetOffscreenContextProviderForCompositorThread());
    317   if (success)
    318     g_factory.Get().CompositorInitializedHardwareDraw(this);
    319   return success;
    320 }
    321 
    322 void SynchronousCompositorImpl::ReleaseHwDraw() {
    323   DCHECK(CalledOnValidThread());
    324   DCHECK(output_surface_);
    325   output_surface_->ReleaseHwDraw();
    326   g_factory.Get().CompositorReleasedHardwareDraw(this);
    327 }
    328 
    329 bool SynchronousCompositorImpl::DemandDrawHw(
    330       gfx::Size surface_size,
    331       const gfx::Transform& transform,
    332       gfx::Rect viewport,
    333       gfx::Rect clip,
    334       bool stencil_enabled) {
    335   DCHECK(CalledOnValidThread());
    336   DCHECK(output_surface_);
    337 
    338   return output_surface_->DemandDrawHw(
    339       surface_size, transform, viewport, clip, stencil_enabled);
    340 }
    341 
    342 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
    343   DCHECK(CalledOnValidThread());
    344   DCHECK(output_surface_);
    345 
    346   return output_surface_->DemandDrawSw(canvas);
    347 }
    348 
    349 void SynchronousCompositorImpl::SetMemoryPolicy(
    350     const SynchronousCompositorMemoryPolicy& policy) {
    351   DCHECK(CalledOnValidThread());
    352   DCHECK(output_surface_);
    353 
    354   return output_surface_->SetMemoryPolicy(policy);
    355 }
    356 
    357 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
    358   if (input_handler_)
    359     input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
    360 }
    361 
    362 void SynchronousCompositorImpl::DidBindOutputSurface(
    363       SynchronousCompositorOutputSurface* output_surface) {
    364   DCHECK(CalledOnValidThread());
    365   output_surface_ = output_surface;
    366   if (compositor_client_)
    367     compositor_client_->DidInitializeCompositor(this);
    368 }
    369 
    370 void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface(
    371        SynchronousCompositorOutputSurface* output_surface) {
    372   DCHECK(CalledOnValidThread());
    373 
    374   // Allow for transient hand-over when two output surfaces may refer to
    375   // a single delegate.
    376   if (output_surface_ == output_surface) {
    377     output_surface_ = NULL;
    378     if (compositor_client_)
    379       compositor_client_->DidDestroyCompositor(this);
    380     compositor_client_ = NULL;
    381   }
    382 }
    383 
    384 void SynchronousCompositorImpl::SetInputHandler(
    385     cc::InputHandler* input_handler) {
    386   DCHECK(CalledOnValidThread());
    387 
    388   if (input_handler_)
    389     input_handler_->SetRootLayerScrollOffsetDelegate(NULL);
    390 
    391   input_handler_ = input_handler;
    392 
    393   if (input_handler_)
    394     input_handler_->SetRootLayerScrollOffsetDelegate(this);
    395 }
    396 
    397 void SynchronousCompositorImpl::DidOverscroll(
    398     const cc::DidOverscrollParams& params) {
    399   if (compositor_client_) {
    400     compositor_client_->DidOverscroll(params.accumulated_overscroll,
    401                                       params.latest_overscroll_delta,
    402                                       params.current_fling_velocity);
    403   }
    404 }
    405 
    406 void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) {
    407   DCHECK(CalledOnValidThread());
    408   if (compositor_client_)
    409     compositor_client_->SetContinuousInvalidate(enable);
    410 }
    411 
    412 InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
    413     const WebKit::WebInputEvent& input_event) {
    414   DCHECK(CalledOnValidThread());
    415   return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
    416       contents_->GetRoutingID(), input_event);
    417 }
    418 
    419 void SynchronousCompositorImpl::UpdateFrameMetaData(
    420     const cc::CompositorFrameMetadata& frame_metadata) {
    421   RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
    422       contents_->GetRenderWidgetHostView());
    423   if (rwhv)
    424     rwhv->SynchronousFrameMetadata(frame_metadata);
    425 }
    426 
    427 void SynchronousCompositorImpl::DidActivatePendingTree() {
    428   if (compositor_client_)
    429     compositor_client_->DidUpdateContent();
    430 }
    431 
    432 void SynchronousCompositorImpl::SetMaxScrollOffset(
    433     gfx::Vector2dF max_scroll_offset) {
    434   DCHECK(CalledOnValidThread());
    435   if (compositor_client_)
    436     compositor_client_->SetMaxRootLayerScrollOffset(max_scroll_offset);
    437 }
    438 
    439 void SynchronousCompositorImpl::SetTotalScrollOffset(gfx::Vector2dF new_value) {
    440   DCHECK(CalledOnValidThread());
    441   if (compositor_client_)
    442     compositor_client_->SetTotalRootLayerScrollOffset(new_value);
    443 }
    444 
    445 gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() {
    446   DCHECK(CalledOnValidThread());
    447   if (compositor_client_)
    448     return compositor_client_->GetTotalRootLayerScrollOffset();
    449   return gfx::Vector2dF();
    450 }
    451 
    452 bool SynchronousCompositorImpl::IsExternalFlingActive() const {
    453   DCHECK(CalledOnValidThread());
    454   if (compositor_client_)
    455     return compositor_client_->IsExternalFlingActive();
    456   return false;
    457 }
    458 
    459 void SynchronousCompositorImpl::SetTotalPageScaleFactor(
    460     float page_scale_factor) {
    461   DCHECK(CalledOnValidThread());
    462   if (compositor_client_)
    463     compositor_client_->SetRootLayerPageScaleFactor(page_scale_factor);
    464 }
    465 
    466 void SynchronousCompositorImpl::SetScrollableSize(gfx::SizeF scrollable_size) {
    467   DCHECK(CalledOnValidThread());
    468   if (compositor_client_)
    469     compositor_client_->SetRootLayerScrollableSize(scrollable_size);
    470 }
    471 
    472 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
    473 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
    474 bool SynchronousCompositorImpl::CalledOnValidThread() const {
    475   return BrowserThread::CurrentlyOn(BrowserThread::UI);
    476 }
    477 
    478 // static
    479 void SynchronousCompositor::SetClientForWebContents(
    480     WebContents* contents,
    481     SynchronousCompositorClient* client) {
    482   DCHECK(contents);
    483   if (client) {
    484     g_factory.Get();  // Ensure it's initialized.
    485     SynchronousCompositorImpl::CreateForWebContents(contents);
    486   }
    487   if (SynchronousCompositorImpl* instance =
    488       SynchronousCompositorImpl::FromWebContents(contents)) {
    489     instance->SetClient(client);
    490   }
    491 }
    492 
    493 }  // namespace content
    494