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_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 "gpu/command_buffer/service/in_process_command_buffer.h"
30 #include "ui/gfx/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 kCommandBufferSize
= 1024 * 1024;
42 // TODO(kbr): make the transfer buffer size configurable via context
43 // creation attributes.
44 const size_t kStartTransferBufferSize
= 4 * 1024 * 1024;
45 const size_t kMinTransferBufferSize
= 1 * 256 * 1024;
46 const size_t kMaxTransferBufferSize
= 16 * 1024 * 1024;
48 class GLInProcessContextImpl
49 : public GLInProcessContext
,
50 public base::SupportsWeakPtr
<GLInProcessContextImpl
> {
52 explicit GLInProcessContextImpl();
53 virtual ~GLInProcessContextImpl();
55 bool Initialize(scoped_refptr
<gfx::GLSurface
> surface
,
58 gfx::AcceleratedWidget window
,
59 const gfx::Size
& size
,
60 const GLInProcessContextAttribs
& attribs
,
61 gfx::GpuPreference gpu_preference
);
63 // GLInProcessContext implementation:
64 virtual void SetContextLostCallback(const base::Closure
& callback
) OVERRIDE
;
65 virtual gles2::GLES2Implementation
* GetImplementation() OVERRIDE
;
67 #if defined(OS_ANDROID)
68 virtual scoped_refptr
<gfx::SurfaceTexture
> GetSurfaceTexture(
69 uint32 stream_id
) OVERRIDE
;
75 void OnSignalSyncPoint(const base::Closure
& callback
);
77 scoped_ptr
<gles2::GLES2CmdHelper
> gles2_helper_
;
78 scoped_ptr
<TransferBuffer
> transfer_buffer_
;
79 scoped_ptr
<gles2::GLES2Implementation
> gles2_implementation_
;
80 scoped_ptr
<InProcessCommandBuffer
> command_buffer_
;
82 unsigned int share_group_id_
;
84 base::Closure context_lost_callback_
;
86 DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl
);
89 base::LazyInstance
<base::Lock
> g_all_shared_contexts_lock
=
90 LAZY_INSTANCE_INITIALIZER
;
91 base::LazyInstance
<std::set
<GLInProcessContextImpl
*> > g_all_shared_contexts
=
92 LAZY_INSTANCE_INITIALIZER
;
94 GLInProcessContextImpl::GLInProcessContextImpl()
95 : share_group_id_(0), context_lost_(false) {}
97 GLInProcessContextImpl::~GLInProcessContextImpl() {
99 base::AutoLock
lock(g_all_shared_contexts_lock
.Get());
100 g_all_shared_contexts
.Get().erase(this);
105 gles2::GLES2Implementation
* GLInProcessContextImpl::GetImplementation() {
106 return gles2_implementation_
.get();
109 void GLInProcessContextImpl::SetContextLostCallback(
110 const base::Closure
& callback
) {
111 context_lost_callback_
= callback
;
114 void GLInProcessContextImpl::OnContextLost() {
115 context_lost_
= true;
116 if (!context_lost_callback_
.is_null()) {
117 context_lost_callback_
.Run();
121 bool GLInProcessContextImpl::Initialize(
122 scoped_refptr
<gfx::GLSurface
> surface
,
124 bool share_resources
,
125 gfx::AcceleratedWidget window
,
126 const gfx::Size
& size
,
127 const GLInProcessContextAttribs
& attribs
,
128 gfx::GpuPreference gpu_preference
) {
129 DCHECK(size
.width() >= 0 && size
.height() >= 0);
131 // Changes to these values should also be copied to
132 // gpu/command_buffer/client/gl_in_process_context.cc and to
133 // content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
134 const int32 ALPHA_SIZE
= 0x3021;
135 const int32 BLUE_SIZE
= 0x3022;
136 const int32 GREEN_SIZE
= 0x3023;
137 const int32 RED_SIZE
= 0x3024;
138 const int32 DEPTH_SIZE
= 0x3025;
139 const int32 STENCIL_SIZE
= 0x3026;
140 const int32 SAMPLES
= 0x3031;
141 const int32 SAMPLE_BUFFERS
= 0x3032;
142 const int32 NONE
= 0x3038;
144 // Chromium-specific attributes
145 const int32 FAIL_IF_MAJOR_PERF_CAVEAT
= 0x10002;
147 std::vector
<int32
> attrib_vector
;
148 if (attribs
.alpha_size
>= 0) {
149 attrib_vector
.push_back(ALPHA_SIZE
);
150 attrib_vector
.push_back(attribs
.alpha_size
);
152 if (attribs
.blue_size
>= 0) {
153 attrib_vector
.push_back(BLUE_SIZE
);
154 attrib_vector
.push_back(attribs
.blue_size
);
156 if (attribs
.green_size
>= 0) {
157 attrib_vector
.push_back(GREEN_SIZE
);
158 attrib_vector
.push_back(attribs
.green_size
);
160 if (attribs
.red_size
>= 0) {
161 attrib_vector
.push_back(RED_SIZE
);
162 attrib_vector
.push_back(attribs
.red_size
);
164 if (attribs
.depth_size
>= 0) {
165 attrib_vector
.push_back(DEPTH_SIZE
);
166 attrib_vector
.push_back(attribs
.depth_size
);
168 if (attribs
.stencil_size
>= 0) {
169 attrib_vector
.push_back(STENCIL_SIZE
);
170 attrib_vector
.push_back(attribs
.stencil_size
);
172 if (attribs
.samples
>= 0) {
173 attrib_vector
.push_back(SAMPLES
);
174 attrib_vector
.push_back(attribs
.samples
);
176 if (attribs
.sample_buffers
>= 0) {
177 attrib_vector
.push_back(SAMPLE_BUFFERS
);
178 attrib_vector
.push_back(attribs
.sample_buffers
);
180 if (attribs
.fail_if_major_perf_caveat
> 0) {
181 attrib_vector
.push_back(FAIL_IF_MAJOR_PERF_CAVEAT
);
182 attrib_vector
.push_back(attribs
.fail_if_major_perf_caveat
);
184 attrib_vector
.push_back(NONE
);
186 base::Closure wrapped_callback
=
187 base::Bind(&GLInProcessContextImpl::OnContextLost
, AsWeakPtr());
188 command_buffer_
.reset(new InProcessCommandBuffer());
190 scoped_ptr
<base::AutoLock
> scoped_shared_context_lock
;
191 scoped_refptr
<gles2::ShareGroup
> share_group
;
192 if (share_resources
) {
193 scoped_shared_context_lock
.reset(
194 new base::AutoLock(g_all_shared_contexts_lock
.Get()));
195 for (std::set
<GLInProcessContextImpl
*>::const_iterator it
=
196 g_all_shared_contexts
.Get().begin();
197 it
!= g_all_shared_contexts
.Get().end();
199 const GLInProcessContextImpl
* context
= *it
;
200 if (!context
->context_lost_
) {
201 share_group
= context
->gles2_implementation_
->share_group();
203 share_group_id_
= context
->share_group_id_
;
206 share_group_id_
= std::max(share_group_id_
, context
->share_group_id_
);
208 if (!share_group
&& !++share_group_id_
)
211 if (!command_buffer_
->Initialize(surface
,
220 LOG(ERROR
) << "Failed to initialize InProcessCommmandBuffer";
224 // Create the GLES2 helper, which writes the command buffer protocol.
225 gles2_helper_
.reset(new gles2::GLES2CmdHelper(command_buffer_
.get()));
226 if (!gles2_helper_
->Initialize(kCommandBufferSize
)) {
227 LOG(ERROR
) << "Failed to initialize GLES2CmdHelper";
232 // Create a transfer buffer.
233 transfer_buffer_
.reset(new TransferBuffer(gles2_helper_
.get()));
235 bool bind_generates_resources
= false;
236 bool free_everything_when_invisible
= false;
238 // Create the object exposing the OpenGL API.
239 gles2_implementation_
.reset(new gles2::GLES2Implementation(
242 transfer_buffer_
.get(),
243 bind_generates_resources
,
244 free_everything_when_invisible
,
245 command_buffer_
.get()));
247 if (share_resources
) {
248 g_all_shared_contexts
.Get().insert(this);
249 scoped_shared_context_lock
.reset();
252 if (!gles2_implementation_
->Initialize(
253 kStartTransferBufferSize
,
254 kMinTransferBufferSize
,
255 kMaxTransferBufferSize
,
256 gles2::GLES2Implementation::kNoLimit
)) {
263 void GLInProcessContextImpl::Destroy() {
264 if (gles2_implementation_
) {
265 // First flush the context to ensure that any pending frees of resources
266 // are completed. Otherwise, if this context is part of a share group,
267 // those resources might leak. Also, any remaining side effects of commands
268 // issued on this context might not be visible to other contexts in the
270 gles2_implementation_
->Flush();
272 gles2_implementation_
.reset();
275 transfer_buffer_
.reset();
276 gles2_helper_
.reset();
277 command_buffer_
.reset();
280 #if defined(OS_ANDROID)
281 scoped_refptr
<gfx::SurfaceTexture
>
282 GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id
) {
283 return command_buffer_
->GetSurfaceTexture(stream_id
);
287 } // anonymous namespace
289 GLInProcessContextAttribs::GLInProcessContextAttribs()
297 sample_buffers(-1) {}
300 GLInProcessContext
* GLInProcessContext::CreateContext(
302 gfx::AcceleratedWidget window
,
303 const gfx::Size
& size
,
304 bool share_resources
,
305 const GLInProcessContextAttribs
& attribs
,
306 gfx::GpuPreference gpu_preference
) {
307 scoped_ptr
<GLInProcessContextImpl
> context(
308 new GLInProcessContextImpl());
309 if (!context
->Initialize(
319 return context
.release();
323 GLInProcessContext
* GLInProcessContext::CreateWithSurface(
324 scoped_refptr
<gfx::GLSurface
> surface
,
325 bool share_resources
,
326 const GLInProcessContextAttribs
& attribs
,
327 gfx::GpuPreference gpu_preference
) {
328 scoped_ptr
<GLInProcessContextImpl
> context(
329 new GLInProcessContextImpl());
330 if (!context
->Initialize(
332 surface
->IsOffscreen(),
334 gfx::kNullAcceleratedWidget
,
340 return context
.release();