Home | History | Annotate | Download | only in client
      1 // Copyright (c) 2012 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 "gpu/command_buffer/client/gl_in_process_context.h"
      6 
      7 #include <set>
      8 #include <utility>
      9 #include <vector>
     10 
     11 #include <GLES2/gl2.h>
     12 #ifndef GL_GLEXT_PROTOTYPES
     13 #define GL_GLEXT_PROTOTYPES 1
     14 #endif
     15 #include <GLES2/gl2ext.h>
     16 #include <GLES2/gl2extchromium.h>
     17 
     18 #include "base/bind.h"
     19 #include "base/bind_helpers.h"
     20 #include "base/lazy_instance.h"
     21 #include "base/logging.h"
     22 #include "base/memory/scoped_ptr.h"
     23 #include "base/memory/weak_ptr.h"
     24 #include "base/message_loop/message_loop.h"
     25 #include "gpu/command_buffer/client/gles2_implementation.h"
     26 #include "gpu/command_buffer/client/transfer_buffer.h"
     27 #include "gpu/command_buffer/common/command_buffer.h"
     28 #include "gpu/command_buffer/common/constants.h"
     29 #include "ui/gfx/size.h"
     30 #include "ui/gl/gl_image.h"
     31 
     32 #if defined(OS_ANDROID)
     33 #include "ui/gl/android/surface_texture.h"
     34 #endif
     35 
     36 namespace gpu {
     37 
     38 namespace {
     39 
     40 const int32 kDefaultCommandBufferSize = 1024 * 1024;
     41 const unsigned int kDefaultStartTransferBufferSize = 4 * 1024 * 1024;
     42 const unsigned int kDefaultMinTransferBufferSize = 1 * 256 * 1024;
     43 const unsigned int kDefaultMaxTransferBufferSize = 16 * 1024 * 1024;
     44 
     45 class GLInProcessContextImpl
     46     : public GLInProcessContext,
     47       public base::SupportsWeakPtr<GLInProcessContextImpl> {
     48  public:
     49   explicit GLInProcessContextImpl(
     50       const GLInProcessContextSharedMemoryLimits& mem_limits);
     51   virtual ~GLInProcessContextImpl();
     52 
     53   bool Initialize(
     54       scoped_refptr<gfx::GLSurface> surface,
     55       bool is_offscreen,
     56       bool use_global_share_group,
     57       GLInProcessContext* share_context,
     58       gfx::AcceleratedWidget window,
     59       const gfx::Size& size,
     60       const gpu::gles2::ContextCreationAttribHelper& attribs,
     61       gfx::GpuPreference gpu_preference,
     62       const scoped_refptr<InProcessCommandBuffer::Service>& service);
     63 
     64   // GLInProcessContext implementation:
     65   virtual void SetContextLostCallback(const base::Closure& callback) OVERRIDE;
     66   virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE;
     67   virtual size_t GetMappedMemoryLimit() OVERRIDE;
     68 
     69 #if defined(OS_ANDROID)
     70   virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
     71       uint32 stream_id) OVERRIDE;
     72 #endif
     73 
     74  private:
     75   void Destroy();
     76   void OnContextLost();
     77   void OnSignalSyncPoint(const base::Closure& callback);
     78 
     79   scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_;
     80   scoped_ptr<TransferBuffer> transfer_buffer_;
     81   scoped_ptr<gles2::GLES2Implementation> gles2_implementation_;
     82   scoped_ptr<InProcessCommandBuffer> command_buffer_;
     83 
     84   const GLInProcessContextSharedMemoryLimits mem_limits_;
     85   bool context_lost_;
     86   base::Closure context_lost_callback_;
     87 
     88   DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl);
     89 };
     90 
     91 base::LazyInstance<base::Lock> g_all_shared_contexts_lock =
     92     LAZY_INSTANCE_INITIALIZER;
     93 base::LazyInstance<std::set<GLInProcessContextImpl*> > g_all_shared_contexts =
     94     LAZY_INSTANCE_INITIALIZER;
     95 
     96 GLInProcessContextImpl::GLInProcessContextImpl(
     97     const GLInProcessContextSharedMemoryLimits& mem_limits)
     98     : mem_limits_(mem_limits), context_lost_(false) {
     99 }
    100 
    101 GLInProcessContextImpl::~GLInProcessContextImpl() {
    102   {
    103     base::AutoLock lock(g_all_shared_contexts_lock.Get());
    104     g_all_shared_contexts.Get().erase(this);
    105   }
    106   Destroy();
    107 }
    108 
    109 gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() {
    110   return gles2_implementation_.get();
    111 }
    112 
    113 size_t GLInProcessContextImpl::GetMappedMemoryLimit() {
    114   return mem_limits_.mapped_memory_reclaim_limit;
    115 }
    116 
    117 void GLInProcessContextImpl::SetContextLostCallback(
    118     const base::Closure& callback) {
    119   context_lost_callback_ = callback;
    120 }
    121 
    122 void GLInProcessContextImpl::OnContextLost() {
    123   context_lost_ = true;
    124   if (!context_lost_callback_.is_null()) {
    125     context_lost_callback_.Run();
    126   }
    127 }
    128 
    129 bool GLInProcessContextImpl::Initialize(
    130     scoped_refptr<gfx::GLSurface> surface,
    131     bool is_offscreen,
    132     bool use_global_share_group,
    133     GLInProcessContext* share_context,
    134     gfx::AcceleratedWidget window,
    135     const gfx::Size& size,
    136     const gles2::ContextCreationAttribHelper& attribs,
    137     gfx::GpuPreference gpu_preference,
    138     const scoped_refptr<InProcessCommandBuffer::Service>& service) {
    139   DCHECK(!use_global_share_group || !share_context);
    140   DCHECK(size.width() >= 0 && size.height() >= 0);
    141 
    142   std::vector<int32> attrib_vector;
    143   attribs.Serialize(&attrib_vector);
    144 
    145   base::Closure wrapped_callback =
    146       base::Bind(&GLInProcessContextImpl::OnContextLost, AsWeakPtr());
    147   command_buffer_.reset(new InProcessCommandBuffer(service));
    148 
    149   scoped_ptr<base::AutoLock> scoped_shared_context_lock;
    150   scoped_refptr<gles2::ShareGroup> share_group;
    151   InProcessCommandBuffer* share_command_buffer = NULL;
    152   if (use_global_share_group) {
    153     scoped_shared_context_lock.reset(
    154         new base::AutoLock(g_all_shared_contexts_lock.Get()));
    155     for (std::set<GLInProcessContextImpl*>::const_iterator it =
    156              g_all_shared_contexts.Get().begin();
    157          it != g_all_shared_contexts.Get().end();
    158          it++) {
    159       const GLInProcessContextImpl* context = *it;
    160       if (!context->context_lost_) {
    161         share_group = context->gles2_implementation_->share_group();
    162         share_command_buffer = context->command_buffer_.get();
    163         DCHECK(share_group.get());
    164         DCHECK(share_command_buffer);
    165         break;
    166       }
    167     }
    168   } else if (share_context) {
    169     GLInProcessContextImpl* impl =
    170         static_cast<GLInProcessContextImpl*>(share_context);
    171     share_group = impl->gles2_implementation_->share_group();
    172     share_command_buffer = impl->command_buffer_.get();
    173     DCHECK(share_group.get());
    174     DCHECK(share_command_buffer);
    175   }
    176 
    177   if (!command_buffer_->Initialize(surface,
    178                                    is_offscreen,
    179                                    window,
    180                                    size,
    181                                    attrib_vector,
    182                                    gpu_preference,
    183                                    wrapped_callback,
    184                                    share_command_buffer)) {
    185     LOG(ERROR) << "Failed to initialize InProcessCommmandBuffer";
    186     return false;
    187   }
    188 
    189   // Create the GLES2 helper, which writes the command buffer protocol.
    190   gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
    191   if (!gles2_helper_->Initialize(mem_limits_.command_buffer_size)) {
    192     LOG(ERROR) << "Failed to initialize GLES2CmdHelper";
    193     Destroy();
    194     return false;
    195   }
    196 
    197   // Create a transfer buffer.
    198   transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get()));
    199 
    200   // Check for consistency.
    201   DCHECK(!attribs.bind_generates_resource);
    202   bool bind_generates_resource = false;
    203 
    204   // Create the object exposing the OpenGL API.
    205   gles2_implementation_.reset(
    206       new gles2::GLES2Implementation(gles2_helper_.get(),
    207                                      share_group.get(),
    208                                      transfer_buffer_.get(),
    209                                      bind_generates_resource,
    210                                      attribs.lose_context_when_out_of_memory,
    211                                      command_buffer_.get()));
    212 
    213   if (use_global_share_group) {
    214     g_all_shared_contexts.Get().insert(this);
    215     scoped_shared_context_lock.reset();
    216   }
    217 
    218   if (!gles2_implementation_->Initialize(
    219           mem_limits_.start_transfer_buffer_size,
    220           mem_limits_.min_transfer_buffer_size,
    221           mem_limits_.max_transfer_buffer_size,
    222           mem_limits_.mapped_memory_reclaim_limit)) {
    223     return false;
    224   }
    225 
    226   return true;
    227 }
    228 
    229 void GLInProcessContextImpl::Destroy() {
    230   if (gles2_implementation_) {
    231     // First flush the context to ensure that any pending frees of resources
    232     // are completed. Otherwise, if this context is part of a share group,
    233     // those resources might leak. Also, any remaining side effects of commands
    234     // issued on this context might not be visible to other contexts in the
    235     // share group.
    236     gles2_implementation_->Flush();
    237 
    238     gles2_implementation_.reset();
    239   }
    240 
    241   transfer_buffer_.reset();
    242   gles2_helper_.reset();
    243   command_buffer_.reset();
    244 }
    245 
    246 #if defined(OS_ANDROID)
    247 scoped_refptr<gfx::SurfaceTexture>
    248 GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id) {
    249   return command_buffer_->GetSurfaceTexture(stream_id);
    250 }
    251 #endif
    252 
    253 }  // anonymous namespace
    254 
    255 GLInProcessContextSharedMemoryLimits::GLInProcessContextSharedMemoryLimits()
    256     : command_buffer_size(kDefaultCommandBufferSize),
    257       start_transfer_buffer_size(kDefaultStartTransferBufferSize),
    258       min_transfer_buffer_size(kDefaultMinTransferBufferSize),
    259       max_transfer_buffer_size(kDefaultMaxTransferBufferSize),
    260       mapped_memory_reclaim_limit(gles2::GLES2Implementation::kNoLimit) {
    261 }
    262 
    263 // static
    264 GLInProcessContext* GLInProcessContext::Create(
    265     scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
    266     scoped_refptr<gfx::GLSurface> surface,
    267     bool is_offscreen,
    268     gfx::AcceleratedWidget window,
    269     const gfx::Size& size,
    270     GLInProcessContext* share_context,
    271     bool use_global_share_group,
    272     const ::gpu::gles2::ContextCreationAttribHelper& attribs,
    273     gfx::GpuPreference gpu_preference,
    274     const GLInProcessContextSharedMemoryLimits& memory_limits) {
    275   DCHECK(!use_global_share_group || !share_context);
    276   if (surface.get()) {
    277     DCHECK_EQ(surface->IsOffscreen(), is_offscreen);
    278     DCHECK(surface->GetSize() == size);
    279     DCHECK_EQ(gfx::kNullAcceleratedWidget, window);
    280   }
    281 
    282   scoped_ptr<GLInProcessContextImpl> context(
    283       new GLInProcessContextImpl(memory_limits));
    284   if (!context->Initialize(surface,
    285                            is_offscreen,
    286                            use_global_share_group,
    287                            share_context,
    288                            window,
    289                            size,
    290                            attribs,
    291                            gpu_preference,
    292                            service))
    293     return NULL;
    294 
    295   return context.release();
    296 }
    297 
    298 }  // namespace gpu
    299