Home | History | Annotate | Download | only in in_process
      1 // Copyright 2014 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_factory_impl.h"
      6 
      7 #include "base/observer_list.h"
      8 #include "content/browser/android/in_process/synchronous_compositor_output_surface.h"
      9 #include "content/public/browser/browser_thread.h"
     10 #include "gpu/command_buffer/client/gl_in_process_context.h"
     11 #include "ui/gl/android/surface_texture.h"
     12 #include "ui/gl/gl_surface.h"
     13 #include "ui/gl/gl_surface_stub.h"
     14 #include "webkit/common/gpu/context_provider_in_process.h"
     15 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
     16 
     17 using webkit::gpu::ContextProviderWebContext;
     18 
     19 namespace content {
     20 
     21 namespace {
     22 
     23 blink::WebGraphicsContext3D::Attributes GetDefaultAttribs() {
     24   blink::WebGraphicsContext3D::Attributes attributes;
     25   attributes.antialias = false;
     26   attributes.depth = false;
     27   attributes.stencil = false;
     28   attributes.shareResources = true;
     29   attributes.noAutomaticFlushes = true;
     30 
     31   return attributes;
     32 }
     33 
     34 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
     35 
     36 scoped_ptr<gpu::GLInProcessContext> CreateOffscreenContext(
     37     const blink::WebGraphicsContext3D::Attributes& attributes) {
     38   const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
     39 
     40   gpu::GLInProcessContextAttribs in_process_attribs;
     41   WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
     42       attributes, &in_process_attribs);
     43   in_process_attribs.lose_context_when_out_of_memory = 1;
     44 
     45   scoped_ptr<gpu::GLInProcessContext> context(
     46       gpu::GLInProcessContext::Create(NULL /* service */,
     47                                       NULL /* surface */,
     48                                       true /* is_offscreen */,
     49                                       gfx::kNullAcceleratedWidget,
     50                                       gfx::Size(1, 1),
     51                                       NULL /* share_context */,
     52                                       false /* share_resources */,
     53                                       in_process_attribs,
     54                                       gpu_preference));
     55   return context.Pass();
     56 }
     57 
     58 scoped_ptr<gpu::GLInProcessContext> CreateContext(
     59     scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
     60     gpu::GLInProcessContext* share_context) {
     61   const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
     62   gpu::GLInProcessContextAttribs in_process_attribs;
     63   WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
     64       GetDefaultAttribs(), &in_process_attribs);
     65   in_process_attribs.lose_context_when_out_of_memory = 1;
     66 
     67   scoped_ptr<gpu::GLInProcessContext> context(
     68       gpu::GLInProcessContext::Create(service,
     69                                       NULL /* surface */,
     70                                       false /* is_offscreen */,
     71                                       gfx::kNullAcceleratedWidget,
     72                                       gfx::Size(1, 1),
     73                                       share_context,
     74                                       false /* share_resources */,
     75                                       in_process_attribs,
     76                                       gpu_preference));
     77   return context.Pass();
     78 }
     79 
     80 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> WrapContext(
     81     scoped_ptr<gpu::GLInProcessContext> context) {
     82   if (!context.get())
     83     return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
     84 
     85   return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
     86       WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
     87           context.Pass(), GetDefaultAttribs()));
     88 }
     89 
     90 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
     91 WrapContextWithAttributes(
     92     scoped_ptr<gpu::GLInProcessContext> context,
     93     const blink::WebGraphicsContext3D::Attributes& attributes) {
     94   if (!context.get())
     95     return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
     96 
     97   return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
     98       WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
     99           context.Pass(), attributes));
    100 }
    101 
    102 }  // namespace
    103 
    104 class SynchronousCompositorFactoryImpl::VideoContextProvider
    105     : public StreamTextureFactorySynchronousImpl::ContextProvider {
    106  public:
    107   VideoContextProvider(
    108       scoped_ptr<gpu::GLInProcessContext> gl_in_process_context)
    109       : gl_in_process_context_(gl_in_process_context.get()) {
    110 
    111     context_provider_ = webkit::gpu::ContextProviderInProcess::Create(
    112         WrapContext(gl_in_process_context.Pass()),
    113         "Video-Offscreen-main-thread");
    114     context_provider_->BindToCurrentThread();
    115   }
    116 
    117   virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
    118       uint32 stream_id) OVERRIDE {
    119     return gl_in_process_context_->GetSurfaceTexture(stream_id);
    120   }
    121 
    122   virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE {
    123     return context_provider_->ContextGL();
    124   }
    125 
    126   virtual void AddObserver(StreamTextureFactoryContextObserver* obs) OVERRIDE {
    127     observer_list_.AddObserver(obs);
    128   }
    129 
    130   virtual void RemoveObserver(
    131       StreamTextureFactoryContextObserver* obs) OVERRIDE {
    132     observer_list_.RemoveObserver(obs);
    133   }
    134 
    135   void RestoreContext() {
    136     FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver,
    137                       observer_list_,
    138                       ResetStreamTextureProxy());
    139   }
    140 
    141  private:
    142   friend class base::RefCountedThreadSafe<VideoContextProvider>;
    143   virtual ~VideoContextProvider() {}
    144 
    145   scoped_refptr<cc::ContextProvider> context_provider_;
    146   gpu::GLInProcessContext* gl_in_process_context_;
    147   ObserverList<StreamTextureFactoryContextObserver> observer_list_;
    148 
    149   DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
    150 };
    151 
    152 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
    153 
    154 SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl()
    155     : record_full_layer_(true),
    156       num_hardware_compositors_(0) {
    157   SynchronousCompositorFactory::SetInstance(this);
    158 }
    159 
    160 SynchronousCompositorFactoryImpl::~SynchronousCompositorFactoryImpl() {}
    161 
    162 scoped_refptr<base::MessageLoopProxy>
    163 SynchronousCompositorFactoryImpl::GetCompositorMessageLoop() {
    164   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
    165 }
    166 
    167 bool
    168 SynchronousCompositorFactoryImpl::RecordFullLayer() {
    169   return record_full_layer_;
    170 }
    171 
    172 scoped_ptr<cc::OutputSurface>
    173 SynchronousCompositorFactoryImpl::CreateOutputSurface(int routing_id) {
    174   scoped_ptr<SynchronousCompositorOutputSurface> output_surface(
    175       new SynchronousCompositorOutputSurface(routing_id));
    176   return output_surface.PassAs<cc::OutputSurface>();
    177 }
    178 
    179 InputHandlerManagerClient*
    180 SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() {
    181   return synchronous_input_event_filter();
    182 }
    183 
    184 scoped_refptr<ContextProviderWebContext> SynchronousCompositorFactoryImpl::
    185     GetSharedOffscreenContextProviderForMainThread() {
    186   bool failed = false;
    187   if ((!offscreen_context_for_main_thread_.get() ||
    188        offscreen_context_for_main_thread_->DestroyedOnMainThread())) {
    189     scoped_ptr<gpu::GLInProcessContext> context =
    190         CreateOffscreenContext(GetDefaultAttribs());
    191     offscreen_context_for_main_thread_ =
    192         webkit::gpu::ContextProviderInProcess::Create(
    193             WrapContext(context.Pass()),
    194             "Compositor-Offscreen-main-thread");
    195     failed = !offscreen_context_for_main_thread_.get() ||
    196              !offscreen_context_for_main_thread_->BindToCurrentThread();
    197   }
    198 
    199   if (failed) {
    200     offscreen_context_for_main_thread_ = NULL;
    201   }
    202   return offscreen_context_for_main_thread_;
    203 }
    204 
    205 scoped_refptr<cc::ContextProvider> SynchronousCompositorFactoryImpl::
    206     CreateOnscreenContextProviderForCompositorThread() {
    207   DCHECK(service_);
    208 
    209   if (!share_context_.get())
    210     share_context_ = CreateContext(service_, NULL);
    211   return webkit::gpu::ContextProviderInProcess::Create(
    212       WrapContext(CreateContext(service_, share_context_.get())),
    213       "Child-Compositor");
    214 }
    215 
    216 gpu::GLInProcessContext* SynchronousCompositorFactoryImpl::GetShareContext() {
    217   DCHECK(share_context_.get());
    218   return share_context_.get();
    219 }
    220 
    221 scoped_refptr<StreamTextureFactory>
    222 SynchronousCompositorFactoryImpl::CreateStreamTextureFactory(int frame_id) {
    223   scoped_refptr<StreamTextureFactorySynchronousImpl> factory(
    224       StreamTextureFactorySynchronousImpl::Create(
    225           base::Bind(
    226               &SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory,
    227               base::Unretained(this)),
    228           frame_id));
    229   return factory;
    230 }
    231 
    232 blink::WebGraphicsContext3D*
    233 SynchronousCompositorFactoryImpl::CreateOffscreenGraphicsContext3D(
    234     const blink::WebGraphicsContext3D::Attributes& attributes) {
    235   return WrapContextWithAttributes(CreateOffscreenContext(attributes),
    236                                    attributes).release();
    237 }
    238 
    239 void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw() {
    240   base::AutoLock lock(num_hardware_compositor_lock_);
    241   num_hardware_compositors_++;
    242   if (num_hardware_compositors_ == 1 && main_thread_proxy_) {
    243     main_thread_proxy_->PostTask(
    244         FROM_HERE,
    245         base::Bind(
    246             &SynchronousCompositorFactoryImpl::RestoreContextOnMainThread,
    247             base::Unretained(this)));
    248   }
    249 }
    250 
    251 void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw() {
    252   base::AutoLock lock(num_hardware_compositor_lock_);
    253   DCHECK_GT(num_hardware_compositors_, 0u);
    254   num_hardware_compositors_--;
    255 }
    256 
    257 void SynchronousCompositorFactoryImpl::RestoreContextOnMainThread() {
    258   if (CanCreateMainThreadContext() && video_context_provider_ )
    259     video_context_provider_->RestoreContext();
    260 }
    261 
    262 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
    263   base::AutoLock lock(num_hardware_compositor_lock_);
    264   return num_hardware_compositors_ > 0;
    265 }
    266 
    267 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
    268 SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
    269   {
    270     base::AutoLock lock(num_hardware_compositor_lock_);
    271     main_thread_proxy_ = base::MessageLoopProxy::current();
    272   }
    273 
    274   // Always fail creation even if |video_context_provider_| is not NULL.
    275   // This is to avoid synchronous calls that may deadlock. Setting
    276   // |video_context_provider_| to null is also not safe since it makes
    277   // synchronous destruction uncontrolled and possibly deadlock.
    278   if (!CanCreateMainThreadContext()) {
    279     return
    280         scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>();
    281   }
    282 
    283   if (!video_context_provider_) {
    284     DCHECK(service_);
    285     DCHECK(share_context_.get());
    286 
    287     video_context_provider_ = new VideoContextProvider(
    288         CreateContext(service_, share_context_.get()));
    289   }
    290   return video_context_provider_;
    291 }
    292 
    293 void SynchronousCompositorFactoryImpl::SetDeferredGpuService(
    294     scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
    295   DCHECK(!service_);
    296   service_ = service;
    297 }
    298 
    299 void SynchronousCompositorFactoryImpl::SetRecordFullDocument(
    300     bool record_full_document) {
    301   record_full_layer_ = record_full_document;
    302 }
    303 
    304 }  // namespace content
    305