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.
5 #include "gpu/command_buffer/client/gl_in_process_context.h"
11 #include <GLES2/gl2.h>
12 #ifndef GL_GLEXT_PROTOTYPES
13 #define GL_GLEXT_PROTOTYPES 1
15 #include <GLES2/gl2ext.h>
16 #include <GLES2/gl2extchromium.h>
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_cmd_helper.h"
26 #include "gpu/command_buffer/client/gles2_implementation.h"
27 #include "gpu/command_buffer/client/transfer_buffer.h"
28 #include "gpu/command_buffer/common/command_buffer.h"
29 #include "gpu/command_buffer/common/constants.h"
30 #include "ui/gfx/geometry/size.h"
31 #include "ui/gl/gl_image.h"
33 #if defined(OS_ANDROID)
34 #include "ui/gl/android/surface_texture.h"
41 const int32 kDefaultCommandBufferSize
= 1024 * 1024;
42 const unsigned int kDefaultStartTransferBufferSize
= 4 * 1024 * 1024;
43 const unsigned int kDefaultMinTransferBufferSize
= 1 * 256 * 1024;
44 const unsigned int kDefaultMaxTransferBufferSize
= 16 * 1024 * 1024;
46 class GLInProcessContextImpl
47 : public GLInProcessContext
,
48 public base::SupportsWeakPtr
<GLInProcessContextImpl
> {
50 explicit GLInProcessContextImpl(
51 const GLInProcessContextSharedMemoryLimits
& mem_limits
);
52 ~GLInProcessContextImpl() override
;
54 bool Initialize(scoped_refptr
<gfx::GLSurface
> surface
,
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 GpuMemoryBufferManager
* gpu_memory_buffer_manager
,
64 ImageFactory
* image_factory
);
66 // GLInProcessContext implementation:
67 void SetContextLostCallback(const base::Closure
& callback
) override
;
68 gles2::GLES2Implementation
* GetImplementation() override
;
69 size_t GetMappedMemoryLimit() override
;
70 void SetLock(base::Lock
* lock
) override
;
72 #if defined(OS_ANDROID)
73 scoped_refptr
<gfx::SurfaceTexture
> GetSurfaceTexture(
74 uint32 stream_id
) override
;
80 void OnSignalSyncPoint(const base::Closure
& callback
);
82 scoped_ptr
<gles2::GLES2CmdHelper
> gles2_helper_
;
83 scoped_ptr
<TransferBuffer
> transfer_buffer_
;
84 scoped_ptr
<gles2::GLES2Implementation
> gles2_implementation_
;
85 scoped_ptr
<InProcessCommandBuffer
> command_buffer_
;
87 const GLInProcessContextSharedMemoryLimits mem_limits_
;
89 base::Closure context_lost_callback_
;
92 DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl
);
95 base::LazyInstance
<base::Lock
> g_all_shared_contexts_lock
=
96 LAZY_INSTANCE_INITIALIZER
;
97 base::LazyInstance
<std::set
<GLInProcessContextImpl
*> > g_all_shared_contexts
=
98 LAZY_INSTANCE_INITIALIZER
;
100 GLInProcessContextImpl::GLInProcessContextImpl(
101 const GLInProcessContextSharedMemoryLimits
& mem_limits
)
102 : mem_limits_(mem_limits
), context_lost_(false), lock_(nullptr) {
105 GLInProcessContextImpl::~GLInProcessContextImpl() {
107 base::AutoLock
lock(g_all_shared_contexts_lock
.Get());
108 g_all_shared_contexts
.Get().erase(this);
113 gles2::GLES2Implementation
* GLInProcessContextImpl::GetImplementation() {
114 return gles2_implementation_
.get();
117 size_t GLInProcessContextImpl::GetMappedMemoryLimit() {
118 return mem_limits_
.mapped_memory_reclaim_limit
;
121 void GLInProcessContextImpl::SetLock(base::Lock
* lock
) {
122 command_buffer_
->SetLock(lock
);
126 void GLInProcessContextImpl::SetContextLostCallback(
127 const base::Closure
& callback
) {
128 context_lost_callback_
= callback
;
131 void GLInProcessContextImpl::OnContextLost() {
132 scoped_ptr
<base::AutoLock
> lock
;
134 lock
.reset(new base::AutoLock(*lock_
));
135 context_lost_
= true;
136 if (!context_lost_callback_
.is_null()) {
137 context_lost_callback_
.Run();
141 bool GLInProcessContextImpl::Initialize(
142 scoped_refptr
<gfx::GLSurface
> surface
,
144 bool use_global_share_group
,
145 GLInProcessContext
* share_context
,
146 gfx::AcceleratedWidget window
,
147 const gfx::Size
& size
,
148 const gles2::ContextCreationAttribHelper
& attribs
,
149 gfx::GpuPreference gpu_preference
,
150 const scoped_refptr
<InProcessCommandBuffer::Service
>& service
,
151 GpuMemoryBufferManager
* gpu_memory_buffer_manager
,
152 ImageFactory
* image_factory
) {
153 DCHECK(!use_global_share_group
|| !share_context
);
154 DCHECK(size
.width() >= 0 && size
.height() >= 0);
156 std::vector
<int32
> attrib_vector
;
157 attribs
.Serialize(&attrib_vector
);
159 base::Closure wrapped_callback
=
160 base::Bind(&GLInProcessContextImpl::OnContextLost
, AsWeakPtr());
161 command_buffer_
.reset(new InProcessCommandBuffer(service
));
163 scoped_ptr
<base::AutoLock
> scoped_shared_context_lock
;
164 scoped_refptr
<gles2::ShareGroup
> share_group
;
165 InProcessCommandBuffer
* share_command_buffer
= NULL
;
166 if (use_global_share_group
) {
167 scoped_shared_context_lock
.reset(
168 new base::AutoLock(g_all_shared_contexts_lock
.Get()));
169 for (std::set
<GLInProcessContextImpl
*>::const_iterator it
=
170 g_all_shared_contexts
.Get().begin();
171 it
!= g_all_shared_contexts
.Get().end();
173 const GLInProcessContextImpl
* context
= *it
;
174 if (!context
->context_lost_
) {
175 share_group
= context
->gles2_implementation_
->share_group();
176 share_command_buffer
= context
->command_buffer_
.get();
177 DCHECK(share_group
.get());
178 DCHECK(share_command_buffer
);
182 } else if (share_context
) {
183 GLInProcessContextImpl
* impl
=
184 static_cast<GLInProcessContextImpl
*>(share_context
);
185 share_group
= impl
->gles2_implementation_
->share_group();
186 share_command_buffer
= impl
->command_buffer_
.get();
187 DCHECK(share_group
.get());
188 DCHECK(share_command_buffer
);
191 if (!command_buffer_
->Initialize(surface
,
198 share_command_buffer
,
199 gpu_memory_buffer_manager
,
201 LOG(ERROR
) << "Failed to initialize InProcessCommmandBuffer";
205 // Create the GLES2 helper, which writes the command buffer protocol.
206 gles2_helper_
.reset(new gles2::GLES2CmdHelper(command_buffer_
.get()));
207 if (!gles2_helper_
->Initialize(mem_limits_
.command_buffer_size
)) {
208 LOG(ERROR
) << "Failed to initialize GLES2CmdHelper";
213 // Create a transfer buffer.
214 transfer_buffer_
.reset(new TransferBuffer(gles2_helper_
.get()));
216 // Check for consistency.
217 DCHECK(!attribs
.bind_generates_resource
);
218 const bool bind_generates_resource
= false;
219 const bool support_client_side_arrays
= false;
221 // Create the object exposing the OpenGL API.
222 gles2_implementation_
.reset(
223 new gles2::GLES2Implementation(gles2_helper_
.get(),
225 transfer_buffer_
.get(),
226 bind_generates_resource
,
227 attribs
.lose_context_when_out_of_memory
,
228 support_client_side_arrays
,
229 command_buffer_
.get()));
231 if (use_global_share_group
) {
232 g_all_shared_contexts
.Get().insert(this);
233 scoped_shared_context_lock
.reset();
236 if (!gles2_implementation_
->Initialize(
237 mem_limits_
.start_transfer_buffer_size
,
238 mem_limits_
.min_transfer_buffer_size
,
239 mem_limits_
.max_transfer_buffer_size
,
240 mem_limits_
.mapped_memory_reclaim_limit
)) {
247 void GLInProcessContextImpl::Destroy() {
248 if (gles2_implementation_
) {
249 // First flush the context to ensure that any pending frees of resources
250 // are completed. Otherwise, if this context is part of a share group,
251 // those resources might leak. Also, any remaining side effects of commands
252 // issued on this context might not be visible to other contexts in the
254 gles2_implementation_
->Flush();
256 gles2_implementation_
.reset();
259 transfer_buffer_
.reset();
260 gles2_helper_
.reset();
261 command_buffer_
.reset();
264 #if defined(OS_ANDROID)
265 scoped_refptr
<gfx::SurfaceTexture
>
266 GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id
) {
267 return command_buffer_
->GetSurfaceTexture(stream_id
);
271 } // anonymous namespace
273 GLInProcessContextSharedMemoryLimits::GLInProcessContextSharedMemoryLimits()
274 : command_buffer_size(kDefaultCommandBufferSize
),
275 start_transfer_buffer_size(kDefaultStartTransferBufferSize
),
276 min_transfer_buffer_size(kDefaultMinTransferBufferSize
),
277 max_transfer_buffer_size(kDefaultMaxTransferBufferSize
),
278 mapped_memory_reclaim_limit(gles2::GLES2Implementation::kNoLimit
) {
282 GLInProcessContext
* GLInProcessContext::Create(
283 scoped_refptr
<gpu::InProcessCommandBuffer::Service
> service
,
284 scoped_refptr
<gfx::GLSurface
> surface
,
286 gfx::AcceleratedWidget window
,
287 const gfx::Size
& size
,
288 GLInProcessContext
* share_context
,
289 bool use_global_share_group
,
290 const ::gpu::gles2::ContextCreationAttribHelper
& attribs
,
291 gfx::GpuPreference gpu_preference
,
292 const GLInProcessContextSharedMemoryLimits
& memory_limits
,
293 GpuMemoryBufferManager
* gpu_memory_buffer_manager
,
294 ImageFactory
* image_factory
) {
295 DCHECK(!use_global_share_group
|| !share_context
);
297 DCHECK_EQ(surface
->IsOffscreen(), is_offscreen
);
298 DCHECK(surface
->GetSize() == size
);
299 DCHECK_EQ(gfx::kNullAcceleratedWidget
, window
);
302 scoped_ptr
<GLInProcessContextImpl
> context(
303 new GLInProcessContextImpl(memory_limits
));
304 if (!context
->Initialize(surface
,
306 use_global_share_group
,
313 gpu_memory_buffer_manager
,
317 return context
.release();