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 char* allowed_extensions
,
61 const GLInProcessContextAttribs
& attribs
,
62 gfx::GpuPreference gpu_preference
);
64 // GLInProcessContext implementation:
65 virtual void SetContextLostCallback(const base::Closure
& callback
) OVERRIDE
;
66 virtual void SignalSyncPoint(unsigned sync_point
,
67 const base::Closure
& callback
) OVERRIDE
;
68 virtual void SignalQuery(unsigned query
, const base::Closure
& callback
)
70 virtual gles2::GLES2Implementation
* GetImplementation() OVERRIDE
;
72 #if defined(OS_ANDROID)
73 virtual scoped_refptr
<gfx::SurfaceTexture
> GetSurfaceTexture(
74 uint32 stream_id
) OVERRIDE
;
79 void PollQueryCallbacks();
80 void CallQueryCallback(size_t index
);
82 void OnSignalSyncPoint(const base::Closure
& callback
);
84 scoped_ptr
<gles2::GLES2CmdHelper
> gles2_helper_
;
85 scoped_ptr
<TransferBuffer
> transfer_buffer_
;
86 scoped_ptr
<gles2::GLES2Implementation
> gles2_implementation_
;
87 scoped_ptr
<InProcessCommandBuffer
> command_buffer_
;
89 typedef std::pair
<unsigned, base::Closure
> QueryCallback
;
90 std::vector
<QueryCallback
> query_callbacks_
;
92 unsigned int share_group_id_
;
94 base::Closure context_lost_callback_
;
96 DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl
);
99 base::LazyInstance
<base::Lock
> g_all_shared_contexts_lock
=
100 LAZY_INSTANCE_INITIALIZER
;
101 base::LazyInstance
<std::set
<GLInProcessContextImpl
*> > g_all_shared_contexts
=
102 LAZY_INSTANCE_INITIALIZER
;
104 size_t SharedContextCount() {
105 base::AutoLock
lock(g_all_shared_contexts_lock
.Get());
106 return g_all_shared_contexts
.Get().size();
109 GLInProcessContextImpl::GLInProcessContextImpl()
110 : share_group_id_(0), context_lost_(false) {}
112 GLInProcessContextImpl::~GLInProcessContextImpl() {
114 base::AutoLock
lock(g_all_shared_contexts_lock
.Get());
115 g_all_shared_contexts
.Get().erase(this);
120 void GLInProcessContextImpl::SignalSyncPoint(unsigned sync_point
,
121 const base::Closure
& callback
) {
122 DCHECK(!callback
.is_null());
123 base::Closure wrapped_callback
= base::Bind(
124 &GLInProcessContextImpl::OnSignalSyncPoint
, AsWeakPtr(), callback
);
125 command_buffer_
->SignalSyncPoint(sync_point
, wrapped_callback
);
128 gles2::GLES2Implementation
* GLInProcessContextImpl::GetImplementation() {
129 return gles2_implementation_
.get();
132 void GLInProcessContextImpl::SetContextLostCallback(
133 const base::Closure
& callback
) {
134 context_lost_callback_
= callback
;
137 void GLInProcessContextImpl::OnContextLost() {
138 context_lost_
= true;
139 if (!context_lost_callback_
.is_null()) {
140 context_lost_callback_
.Run();
144 void GLInProcessContextImpl::OnSignalSyncPoint(const base::Closure
& callback
) {
145 // TODO: Should it always trigger callbacks?
150 bool GLInProcessContextImpl::Initialize(
151 scoped_refptr
<gfx::GLSurface
> surface
,
153 bool share_resources
,
154 gfx::AcceleratedWidget window
,
155 const gfx::Size
& size
,
156 const char* allowed_extensions
,
157 const GLInProcessContextAttribs
& attribs
,
158 gfx::GpuPreference gpu_preference
) {
159 DCHECK(size
.width() >= 0 && size
.height() >= 0);
161 const int32 ALPHA_SIZE
= 0x3021;
162 const int32 BLUE_SIZE
= 0x3022;
163 const int32 GREEN_SIZE
= 0x3023;
164 const int32 RED_SIZE
= 0x3024;
165 const int32 DEPTH_SIZE
= 0x3025;
166 const int32 STENCIL_SIZE
= 0x3026;
167 const int32 SAMPLES
= 0x3031;
168 const int32 SAMPLE_BUFFERS
= 0x3032;
169 const int32 NONE
= 0x3038;
171 std::vector
<int32
> attrib_vector
;
172 if (attribs
.alpha_size
>= 0) {
173 attrib_vector
.push_back(ALPHA_SIZE
);
174 attrib_vector
.push_back(attribs
.alpha_size
);
176 if (attribs
.blue_size
>= 0) {
177 attrib_vector
.push_back(BLUE_SIZE
);
178 attrib_vector
.push_back(attribs
.blue_size
);
180 if (attribs
.green_size
>= 0) {
181 attrib_vector
.push_back(GREEN_SIZE
);
182 attrib_vector
.push_back(attribs
.green_size
);
184 if (attribs
.red_size
>= 0) {
185 attrib_vector
.push_back(RED_SIZE
);
186 attrib_vector
.push_back(attribs
.red_size
);
188 if (attribs
.depth_size
>= 0) {
189 attrib_vector
.push_back(DEPTH_SIZE
);
190 attrib_vector
.push_back(attribs
.depth_size
);
192 if (attribs
.stencil_size
>= 0) {
193 attrib_vector
.push_back(STENCIL_SIZE
);
194 attrib_vector
.push_back(attribs
.stencil_size
);
196 if (attribs
.samples
>= 0) {
197 attrib_vector
.push_back(SAMPLES
);
198 attrib_vector
.push_back(attribs
.samples
);
200 if (attribs
.sample_buffers
>= 0) {
201 attrib_vector
.push_back(SAMPLE_BUFFERS
);
202 attrib_vector
.push_back(attribs
.sample_buffers
);
204 attrib_vector
.push_back(NONE
);
206 base::Closure wrapped_callback
=
207 base::Bind(&GLInProcessContextImpl::OnContextLost
, AsWeakPtr());
208 command_buffer_
.reset(new InProcessCommandBuffer());
210 scoped_ptr
<base::AutoLock
> scoped_shared_context_lock
;
211 scoped_refptr
<gles2::ShareGroup
> share_group
;
212 if (share_resources
) {
213 scoped_shared_context_lock
.reset(
214 new base::AutoLock(g_all_shared_contexts_lock
.Get()));
215 for (std::set
<GLInProcessContextImpl
*>::const_iterator it
=
216 g_all_shared_contexts
.Get().begin();
217 it
!= g_all_shared_contexts
.Get().end();
219 const GLInProcessContextImpl
* context
= *it
;
220 if (!context
->context_lost_
) {
221 share_group
= context
->gles2_implementation_
->share_group();
223 share_group_id_
= context
->share_group_id_
;
226 share_group_id_
= std::max(share_group_id_
, context
->share_group_id_
);
228 if (!share_group
&& !++share_group_id_
)
231 if (!command_buffer_
->Initialize(surface
,
241 LOG(INFO
) << "Failed to initialize InProcessCommmandBuffer";
245 // Create the GLES2 helper, which writes the command buffer protocol.
246 gles2_helper_
.reset(new gles2::GLES2CmdHelper(command_buffer_
.get()));
247 if (!gles2_helper_
->Initialize(kCommandBufferSize
)) {
248 LOG(INFO
) << "Failed to initialize GLES2CmdHelper";
253 // Create a transfer buffer.
254 transfer_buffer_
.reset(new TransferBuffer(gles2_helper_
.get()));
256 // Create the object exposing the OpenGL API.
257 gles2_implementation_
.reset(new gles2::GLES2Implementation(
260 transfer_buffer_
.get(),
262 command_buffer_
.get()));
264 if (share_resources
) {
265 g_all_shared_contexts
.Get().insert(this);
266 scoped_shared_context_lock
.reset();
269 if (!gles2_implementation_
->Initialize(
270 kStartTransferBufferSize
,
271 kMinTransferBufferSize
,
272 kMaxTransferBufferSize
,
273 gles2::GLES2Implementation::kNoLimit
)) {
280 void GLInProcessContextImpl::Destroy() {
281 while (!query_callbacks_
.empty()) {
282 CallQueryCallback(0);
285 if (gles2_implementation_
) {
286 // First flush the context to ensure that any pending frees of resources
287 // are completed. Otherwise, if this context is part of a share group,
288 // those resources might leak. Also, any remaining side effects of commands
289 // issued on this context might not be visible to other contexts in the
291 gles2_implementation_
->Flush();
293 gles2_implementation_
.reset();
296 transfer_buffer_
.reset();
297 gles2_helper_
.reset();
298 command_buffer_
.reset();
301 void GLInProcessContextImpl::CallQueryCallback(size_t index
) {
302 DCHECK_LT(index
, query_callbacks_
.size());
303 QueryCallback query_callback
= query_callbacks_
[index
];
304 query_callbacks_
[index
] = query_callbacks_
.back();
305 query_callbacks_
.pop_back();
306 query_callback
.second
.Run();
309 // TODO(sievers): Move this to the service side
310 void GLInProcessContextImpl::PollQueryCallbacks() {
311 for (size_t i
= 0; i
< query_callbacks_
.size();) {
312 unsigned query
= query_callbacks_
[i
].first
;
314 gles2::GLES2Implementation
* gl
= GetImplementation();
315 if (gl
->IsQueryEXT(query
)) {
316 gl
->GetQueryObjectuivEXT(query
, GL_QUERY_RESULT_AVAILABLE_EXT
, ¶m
);
321 CallQueryCallback(i
);
326 if (!query_callbacks_
.empty()) {
327 base::MessageLoop::current()->PostDelayedTask(
329 base::Bind(&GLInProcessContextImpl::PollQueryCallbacks
,
331 base::TimeDelta::FromMilliseconds(5));
335 void GLInProcessContextImpl::SignalQuery(
337 const base::Closure
& callback
) {
338 query_callbacks_
.push_back(std::make_pair(query
, callback
));
339 // If size > 1, there is already a poll callback pending.
340 if (query_callbacks_
.size() == 1) {
341 PollQueryCallbacks();
345 #if defined(OS_ANDROID)
346 scoped_refptr
<gfx::SurfaceTexture
>
347 GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id
) {
348 return command_buffer_
->GetSurfaceTexture(stream_id
);
352 } // anonymous namespace
354 GLInProcessContextAttribs::GLInProcessContextAttribs()
362 sample_buffers(-1) {}
365 GLInProcessContext
* GLInProcessContext::CreateContext(
367 gfx::AcceleratedWidget window
,
368 const gfx::Size
& size
,
369 bool share_resources
,
370 const char* allowed_extensions
,
371 const GLInProcessContextAttribs
& attribs
,
372 gfx::GpuPreference gpu_preference
) {
373 scoped_ptr
<GLInProcessContextImpl
> context(
374 new GLInProcessContextImpl());
375 if (!context
->Initialize(
386 return context
.release();
390 GLInProcessContext
* GLInProcessContext::CreateWithSurface(
391 scoped_refptr
<gfx::GLSurface
> surface
,
392 bool share_resources
,
393 const char* allowed_extensions
,
394 const GLInProcessContextAttribs
& attribs
,
395 gfx::GpuPreference gpu_preference
) {
396 scoped_ptr
<GLInProcessContextImpl
> context(
397 new GLInProcessContextImpl());
398 if (!context
->Initialize(
400 surface
->IsOffscreen(),
402 gfx::kNullAcceleratedWidget
,
409 return context
.release();