• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GLInProcessContextImpl(const GLInProcessContextSharedMemoryLimits & mem_limits)96 GLInProcessContextImpl::GLInProcessContextImpl(
97     const GLInProcessContextSharedMemoryLimits& mem_limits)
98     : mem_limits_(mem_limits), context_lost_(false) {
99 }
100 
~GLInProcessContextImpl()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 
GetImplementation()109 gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() {
110   return gles2_implementation_.get();
111 }
112 
GetMappedMemoryLimit()113 size_t GLInProcessContextImpl::GetMappedMemoryLimit() {
114   return mem_limits_.mapped_memory_reclaim_limit;
115 }
116 
SetContextLostCallback(const base::Closure & callback)117 void GLInProcessContextImpl::SetContextLostCallback(
118     const base::Closure& callback) {
119   context_lost_callback_ = callback;
120 }
121 
OnContextLost()122 void GLInProcessContextImpl::OnContextLost() {
123   context_lost_ = true;
124   if (!context_lost_callback_.is_null()) {
125     context_lost_callback_.Run();
126   }
127 }
128 
Initialize(scoped_refptr<gfx::GLSurface> surface,bool is_offscreen,bool use_global_share_group,GLInProcessContext * share_context,gfx::AcceleratedWidget window,const gfx::Size & size,const gles2::ContextCreationAttribHelper & attribs,gfx::GpuPreference gpu_preference,const scoped_refptr<InProcessCommandBuffer::Service> & service)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 
Destroy()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>
GetSurfaceTexture(uint32 stream_id)248 GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id) {
249   return command_buffer_->GetSurfaceTexture(stream_id);
250 }
251 #endif
252 
253 }  // anonymous namespace
254 
GLInProcessContextSharedMemoryLimits()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
Create(scoped_refptr<gpu::InProcessCommandBuffer::Service> service,scoped_refptr<gfx::GLSurface> surface,bool is_offscreen,gfx::AcceleratedWidget window,const gfx::Size & size,GLInProcessContext * share_context,bool use_global_share_group,const::gpu::gles2::ContextCreationAttribHelper & attribs,gfx::GpuPreference gpu_preference,const GLInProcessContextSharedMemoryLimits & memory_limits)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