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