blob: cdbfc9f47c3f8828899a4f96f5011cb4f536353e [file] [log] [blame]
Ben Murdocheb525c52013-07-10 11:40:50 +01001// 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
Ben Murdoch28390f62013-08-01 12:44:22 +01007#include <set>
Ben Murdocheb525c52013-07-10 11:40:50 +01008#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"
Ben Murdocheb525c52013-07-10 11:40:50 +010020#include "base/lazy_instance.h"
21#include "base/logging.h"
22#include "base/memory/scoped_ptr.h"
23#include "base/memory/weak_ptr.h"
Ben Murdoch9ab55632013-07-18 11:57:30 +010024#include "base/message_loop/message_loop.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010025#include "gpu/command_buffer/client/gles2_implementation.h"
Ben Murdoch558790d2013-07-30 15:19:42 +010026#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010027#include "gpu/command_buffer/client/image_factory.h"
28#include "gpu/command_buffer/client/transfer_buffer.h"
Ben Murdoch28390f62013-08-01 12:44:22 +010029#include "gpu/command_buffer/common/command_buffer.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010030#include "gpu/command_buffer/common/constants.h"
Ben Murdoch28390f62013-08-01 12:44:22 +010031#include "gpu/command_buffer/service/in_process_command_buffer.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010032#include "ui/gfx/size.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010033#include "ui/gl/gl_image.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010034
35namespace gpu {
36
Ben Murdocheb525c52013-07-10 11:40:50 +010037namespace {
38
39const int32 kCommandBufferSize = 1024 * 1024;
40// TODO(kbr): make the transfer buffer size configurable via context
41// creation attributes.
42const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
43const size_t kMinTransferBufferSize = 1 * 256 * 1024;
44const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
45
Ben Murdoch558790d2013-07-30 15:19:42 +010046static GpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL;
Ben Murdocheb525c52013-07-10 11:40:50 +010047
Ben Murdocheb525c52013-07-10 11:40:50 +010048class GLInProcessContextImpl
49 : public GLInProcessContext,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010050 public gles2::ImageFactory,
Ben Murdocheb525c52013-07-10 11:40:50 +010051 public base::SupportsWeakPtr<GLInProcessContextImpl> {
52 public:
Ben Murdoch28390f62013-08-01 12:44:22 +010053 explicit GLInProcessContextImpl();
Ben Murdocheb525c52013-07-10 11:40:50 +010054 virtual ~GLInProcessContextImpl();
55
Ben Murdochbb1529c2013-08-08 10:24:53 +010056 bool Initialize(scoped_refptr<gfx::GLSurface> surface,
57 bool is_offscreen,
Ben Murdoch28390f62013-08-01 12:44:22 +010058 bool share_resources,
Ben Murdocheb525c52013-07-10 11:40:50 +010059 gfx::AcceleratedWidget window,
60 const gfx::Size& size,
61 const char* allowed_extensions,
Ben Murdochbb1529c2013-08-08 10:24:53 +010062 const GLInProcessContextAttribs& attribs,
63 gfx::GpuPreference gpu_preference);
Ben Murdocheb525c52013-07-10 11:40:50 +010064
65 // GLInProcessContext implementation:
Ben Murdochbb1529c2013-08-08 10:24:53 +010066 virtual void SetContextLostCallback(const base::Closure& callback) OVERRIDE;
Ben Murdocheb525c52013-07-10 11:40:50 +010067 virtual void SignalSyncPoint(unsigned sync_point,
68 const base::Closure& callback) OVERRIDE;
69 virtual void SignalQuery(unsigned query, const base::Closure& callback)
70 OVERRIDE;
71 virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE;
72
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010073 // ImageFactory implementation:
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010074 virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010075 int width, int height, GLenum internalformat,
76 unsigned* image_id) OVERRIDE;
77 virtual void DeleteGpuMemoryBuffer(unsigned image_id) OVERRIDE;
78
Ben Murdocheb525c52013-07-10 11:40:50 +010079 private:
80 void Destroy();
Ben Murdocheb525c52013-07-10 11:40:50 +010081 void PollQueryCallbacks();
82 void CallQueryCallback(size_t index);
Ben Murdochbb1529c2013-08-08 10:24:53 +010083 void OnContextLost();
Ben Murdoch28390f62013-08-01 12:44:22 +010084 void OnSignalSyncPoint(const base::Closure& callback);
Ben Murdocheb525c52013-07-10 11:40:50 +010085
Ben Murdocheb525c52013-07-10 11:40:50 +010086 scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_;
87 scoped_ptr<TransferBuffer> transfer_buffer_;
88 scoped_ptr<gles2::GLES2Implementation> gles2_implementation_;
Ben Murdoch28390f62013-08-01 12:44:22 +010089 scoped_ptr<InProcessCommandBuffer> command_buffer_;
Ben Murdocheb525c52013-07-10 11:40:50 +010090
91 typedef std::pair<unsigned, base::Closure> QueryCallback;
92 std::vector<QueryCallback> query_callbacks_;
93
Ben Murdoch28390f62013-08-01 12:44:22 +010094 unsigned int share_group_id_;
95 bool context_lost_;
Ben Murdochbb1529c2013-08-08 10:24:53 +010096 base::Closure context_lost_callback_;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010097
Ben Murdocheb525c52013-07-10 11:40:50 +010098 DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl);
99};
100
Ben Murdoch28390f62013-08-01 12:44:22 +0100101base::LazyInstance<base::Lock> g_all_shared_contexts_lock =
102 LAZY_INSTANCE_INITIALIZER;
103base::LazyInstance<std::set<GLInProcessContextImpl*> > g_all_shared_contexts =
104 LAZY_INSTANCE_INITIALIZER;
Ben Murdocheb525c52013-07-10 11:40:50 +0100105
Ben Murdoch28390f62013-08-01 12:44:22 +0100106size_t SharedContextCount() {
107 base::AutoLock lock(g_all_shared_contexts_lock.Get());
108 return g_all_shared_contexts.Get().size();
Ben Murdocheb525c52013-07-10 11:40:50 +0100109}
110
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100111scoped_ptr<gfx::GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer(
Ben Murdocheb525c52013-07-10 11:40:50 +0100112 int width, int height, GLenum internalformat, unsigned int* image_id) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100113 scoped_ptr<gfx::GpuMemoryBuffer> buffer(
Ben Murdoch558790d2013-07-30 15:19:42 +0100114 g_gpu_memory_buffer_factory->CreateGpuMemoryBuffer(width,
115 height,
116 internalformat));
117 if (!buffer)
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100118 return scoped_ptr<gfx::GpuMemoryBuffer>();
Ben Murdocheb525c52013-07-10 11:40:50 +0100119
Ben Murdoch28390f62013-08-01 12:44:22 +0100120 *image_id = command_buffer_->CreateImageForGpuMemoryBuffer(
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100121 buffer->GetHandle(), gfx::Size(width, height));
Ben Murdocheb525c52013-07-10 11:40:50 +0100122 return buffer.Pass();
123}
124
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100125void GLInProcessContextImpl::DeleteGpuMemoryBuffer(unsigned int image_id) {
Ben Murdoch28390f62013-08-01 12:44:22 +0100126 command_buffer_->RemoveImage(image_id);
Ben Murdocheb525c52013-07-10 11:40:50 +0100127}
128
Ben Murdoch28390f62013-08-01 12:44:22 +0100129GLInProcessContextImpl::GLInProcessContextImpl()
130 : share_group_id_(0), context_lost_(false) {}
Ben Murdocheb525c52013-07-10 11:40:50 +0100131
132GLInProcessContextImpl::~GLInProcessContextImpl() {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100133 {
Ben Murdoch28390f62013-08-01 12:44:22 +0100134 base::AutoLock lock(g_all_shared_contexts_lock.Get());
135 g_all_shared_contexts.Get().erase(this);
Ben Murdocheb525c52013-07-10 11:40:50 +0100136 }
Ben Murdoch28390f62013-08-01 12:44:22 +0100137 Destroy();
Ben Murdocheb525c52013-07-10 11:40:50 +0100138}
139
140void GLInProcessContextImpl::SignalSyncPoint(unsigned sync_point,
141 const base::Closure& callback) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100142 DCHECK(!callback.is_null());
Ben Murdoch28390f62013-08-01 12:44:22 +0100143 base::Closure wrapped_callback = base::Bind(
144 &GLInProcessContextImpl::OnSignalSyncPoint, AsWeakPtr(), callback);
145 command_buffer_->SignalSyncPoint(sync_point, wrapped_callback);
Ben Murdocheb525c52013-07-10 11:40:50 +0100146}
147
148gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() {
149 return gles2_implementation_.get();
150}
151
Ben Murdochbb1529c2013-08-08 10:24:53 +0100152void GLInProcessContextImpl::SetContextLostCallback(
153 const base::Closure& callback) {
154 context_lost_callback_ = callback;
155}
156
157void GLInProcessContextImpl::OnContextLost() {
Ben Murdoch28390f62013-08-01 12:44:22 +0100158 context_lost_ = true;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100159 if (!context_lost_callback_.is_null()) {
160 context_lost_callback_.Run();
161 }
Ben Murdoch28390f62013-08-01 12:44:22 +0100162}
163
164void GLInProcessContextImpl::OnSignalSyncPoint(const base::Closure& callback) {
165 // TODO: Should it always trigger callbacks?
166 if (!context_lost_)
167 callback.Run();
Ben Murdocheb525c52013-07-10 11:40:50 +0100168}
169
170bool GLInProcessContextImpl::Initialize(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100171 scoped_refptr<gfx::GLSurface> surface,
Ben Murdocheb525c52013-07-10 11:40:50 +0100172 bool is_offscreen,
Ben Murdoch28390f62013-08-01 12:44:22 +0100173 bool share_resources,
Ben Murdocheb525c52013-07-10 11:40:50 +0100174 gfx::AcceleratedWidget window,
175 const gfx::Size& size,
176 const char* allowed_extensions,
Ben Murdochbb1529c2013-08-08 10:24:53 +0100177 const GLInProcessContextAttribs& attribs,
178 gfx::GpuPreference gpu_preference) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100179 DCHECK(size.width() >= 0 && size.height() >= 0);
180
Ben Murdochbb1529c2013-08-08 10:24:53 +0100181 const int32 ALPHA_SIZE = 0x3021;
182 const int32 BLUE_SIZE = 0x3022;
183 const int32 GREEN_SIZE = 0x3023;
184 const int32 RED_SIZE = 0x3024;
185 const int32 DEPTH_SIZE = 0x3025;
186 const int32 STENCIL_SIZE = 0x3026;
187 const int32 SAMPLES = 0x3031;
188 const int32 SAMPLE_BUFFERS = 0x3032;
189 const int32 NONE = 0x3038;
190
191 std::vector<int32> attrib_vector;
192 if (attribs.alpha_size >= 0) {
193 attrib_vector.push_back(ALPHA_SIZE);
194 attrib_vector.push_back(attribs.alpha_size);
Ben Murdocheb525c52013-07-10 11:40:50 +0100195 }
Ben Murdochbb1529c2013-08-08 10:24:53 +0100196 if (attribs.blue_size >= 0) {
197 attrib_vector.push_back(BLUE_SIZE);
198 attrib_vector.push_back(attribs.blue_size);
199 }
200 if (attribs.green_size >= 0) {
201 attrib_vector.push_back(GREEN_SIZE);
202 attrib_vector.push_back(attribs.green_size);
203 }
204 if (attribs.red_size >= 0) {
205 attrib_vector.push_back(RED_SIZE);
206 attrib_vector.push_back(attribs.red_size);
207 }
208 if (attribs.depth_size >= 0) {
209 attrib_vector.push_back(DEPTH_SIZE);
210 attrib_vector.push_back(attribs.depth_size);
211 }
212 if (attribs.stencil_size >= 0) {
213 attrib_vector.push_back(STENCIL_SIZE);
214 attrib_vector.push_back(attribs.stencil_size);
215 }
216 if (attribs.samples >= 0) {
217 attrib_vector.push_back(SAMPLES);
218 attrib_vector.push_back(attribs.samples);
219 }
220 if (attribs.sample_buffers >= 0) {
221 attrib_vector.push_back(SAMPLE_BUFFERS);
222 attrib_vector.push_back(attribs.sample_buffers);
223 }
224 attrib_vector.push_back(NONE);
Ben Murdocheb525c52013-07-10 11:40:50 +0100225
Ben Murdoch28390f62013-08-01 12:44:22 +0100226 base::Closure wrapped_callback =
Ben Murdochbb1529c2013-08-08 10:24:53 +0100227 base::Bind(&GLInProcessContextImpl::OnContextLost, AsWeakPtr());
Ben Murdoch28390f62013-08-01 12:44:22 +0100228 command_buffer_.reset(new InProcessCommandBuffer());
229
230 scoped_ptr<base::AutoLock> scoped_shared_context_lock;
231 scoped_refptr<gles2::ShareGroup> share_group;
232 if (share_resources) {
233 scoped_shared_context_lock.reset(
234 new base::AutoLock(g_all_shared_contexts_lock.Get()));
235 for (std::set<GLInProcessContextImpl*>::const_iterator it =
236 g_all_shared_contexts.Get().begin();
237 it != g_all_shared_contexts.Get().end();
238 it++) {
239 const GLInProcessContextImpl* context = *it;
240 if (!context->context_lost_) {
241 share_group = context->gles2_implementation_->share_group();
242 DCHECK(share_group);
243 share_group_id_ = context->share_group_id_;
244 break;
245 }
246 share_group_id_ = std::max(share_group_id_, context->share_group_id_);
247 }
248 if (!share_group && !++share_group_id_)
249 ++share_group_id_;
Ben Murdocheb525c52013-07-10 11:40:50 +0100250 }
Ben Murdochbb1529c2013-08-08 10:24:53 +0100251 if (!command_buffer_->Initialize(surface,
252 is_offscreen,
253 share_resources,
254 window,
255 size,
256 allowed_extensions,
257 attrib_vector,
258 gpu_preference,
259 wrapped_callback,
260 share_group_id_)) {
Ben Murdoch28390f62013-08-01 12:44:22 +0100261 LOG(INFO) << "Failed to initialize InProcessCommmandBuffer";
262 return false;
Ben Murdocheb525c52013-07-10 11:40:50 +0100263 }
264
265 // Create the GLES2 helper, which writes the command buffer protocol.
266 gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
267 if (!gles2_helper_->Initialize(kCommandBufferSize)) {
Ben Murdoch28390f62013-08-01 12:44:22 +0100268 LOG(INFO) << "Failed to initialize GLES2CmdHelper";
Ben Murdocheb525c52013-07-10 11:40:50 +0100269 Destroy();
270 return false;
271 }
272
273 // Create a transfer buffer.
274 transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get()));
275
Ben Murdocheb525c52013-07-10 11:40:50 +0100276 // Create the object exposing the OpenGL API.
277 gles2_implementation_.reset(new gles2::GLES2Implementation(
278 gles2_helper_.get(),
Ben Murdoch28390f62013-08-01 12:44:22 +0100279 share_group,
Ben Murdocheb525c52013-07-10 11:40:50 +0100280 transfer_buffer_.get(),
Ben Murdocheb525c52013-07-10 11:40:50 +0100281 false,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100282 this));
Ben Murdocheb525c52013-07-10 11:40:50 +0100283
Ben Murdoch28390f62013-08-01 12:44:22 +0100284 if (share_resources) {
285 g_all_shared_contexts.Get().insert(this);
286 scoped_shared_context_lock.reset();
287 }
288
Ben Murdocheb525c52013-07-10 11:40:50 +0100289 if (!gles2_implementation_->Initialize(
290 kStartTransferBufferSize,
291 kMinTransferBufferSize,
292 kMaxTransferBufferSize)) {
293 return false;
294 }
295
Ben Murdocheb525c52013-07-10 11:40:50 +0100296 return true;
297}
298
299void GLInProcessContextImpl::Destroy() {
300 while (!query_callbacks_.empty()) {
301 CallQueryCallback(0);
302 }
303
Ben Murdocheb525c52013-07-10 11:40:50 +0100304 if (gles2_implementation_) {
305 // First flush the context to ensure that any pending frees of resources
306 // are completed. Otherwise, if this context is part of a share group,
307 // those resources might leak. Also, any remaining side effects of commands
308 // issued on this context might not be visible to other contexts in the
309 // share group.
310 gles2_implementation_->Flush();
311
312 gles2_implementation_.reset();
313 }
314
315 transfer_buffer_.reset();
316 gles2_helper_.reset();
317 command_buffer_.reset();
Ben Murdocheb525c52013-07-10 11:40:50 +0100318}
319
320void GLInProcessContextImpl::CallQueryCallback(size_t index) {
321 DCHECK_LT(index, query_callbacks_.size());
322 QueryCallback query_callback = query_callbacks_[index];
323 query_callbacks_[index] = query_callbacks_.back();
324 query_callbacks_.pop_back();
325 query_callback.second.Run();
326}
327
Ben Murdoch28390f62013-08-01 12:44:22 +0100328// TODO(sievers): Move this to the service side
Ben Murdocheb525c52013-07-10 11:40:50 +0100329void GLInProcessContextImpl::PollQueryCallbacks() {
330 for (size_t i = 0; i < query_callbacks_.size();) {
331 unsigned query = query_callbacks_[i].first;
332 GLuint param = 0;
333 gles2::GLES2Implementation* gl = GetImplementation();
334 if (gl->IsQueryEXT(query)) {
335 gl->GetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &param);
336 } else {
337 param = 1;
338 }
339 if (param) {
340 CallQueryCallback(i);
341 } else {
342 i++;
343 }
344 }
345 if (!query_callbacks_.empty()) {
346 base::MessageLoop::current()->PostDelayedTask(
347 FROM_HERE,
348 base::Bind(&GLInProcessContextImpl::PollQueryCallbacks,
349 this->AsWeakPtr()),
350 base::TimeDelta::FromMilliseconds(5));
351 }
352}
353
354void GLInProcessContextImpl::SignalQuery(
355 unsigned query,
356 const base::Closure& callback) {
357 query_callbacks_.push_back(std::make_pair(query, callback));
358 // If size > 1, there is already a poll callback pending.
359 if (query_callbacks_.size() == 1) {
360 PollQueryCallbacks();
361 }
362}
363
364} // anonymous namespace
365
Ben Murdochbb1529c2013-08-08 10:24:53 +0100366GLInProcessContextAttribs::GLInProcessContextAttribs()
367 : alpha_size(-1),
368 blue_size(-1),
369 green_size(-1),
370 red_size(-1),
371 depth_size(-1),
372 stencil_size(-1),
373 samples(-1),
374 sample_buffers(-1) {}
375
Ben Murdocheb525c52013-07-10 11:40:50 +0100376// static
377GLInProcessContext* GLInProcessContext::CreateContext(
378 bool is_offscreen,
379 gfx::AcceleratedWidget window,
380 const gfx::Size& size,
381 bool share_resources,
382 const char* allowed_extensions,
Ben Murdochbb1529c2013-08-08 10:24:53 +0100383 const GLInProcessContextAttribs& attribs,
384 gfx::GpuPreference gpu_preference) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100385 scoped_ptr<GLInProcessContextImpl> context(
Ben Murdoch28390f62013-08-01 12:44:22 +0100386 new GLInProcessContextImpl());
Ben Murdocheb525c52013-07-10 11:40:50 +0100387 if (!context->Initialize(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100388 NULL /* surface */,
Ben Murdocheb525c52013-07-10 11:40:50 +0100389 is_offscreen,
Ben Murdoch28390f62013-08-01 12:44:22 +0100390 share_resources,
Ben Murdocheb525c52013-07-10 11:40:50 +0100391 window,
392 size,
393 allowed_extensions,
Ben Murdochbb1529c2013-08-08 10:24:53 +0100394 attribs,
395 gpu_preference))
396 return NULL;
397
398 return context.release();
399}
400
401// static
402GLInProcessContext* GLInProcessContext::CreateWithSurface(
403 scoped_refptr<gfx::GLSurface> surface,
404 bool share_resources,
405 const char* allowed_extensions,
406 const GLInProcessContextAttribs& attribs,
407 gfx::GpuPreference gpu_preference) {
408 scoped_ptr<GLInProcessContextImpl> context(
409 new GLInProcessContextImpl());
410 if (!context->Initialize(
411 surface,
412 surface->IsOffscreen(),
413 share_resources,
414 gfx::kNullAcceleratedWidget,
415 surface->GetSize(),
416 allowed_extensions,
417 attribs,
418 gpu_preference))
Ben Murdocheb525c52013-07-10 11:40:50 +0100419 return NULL;
420
421 return context.release();
422}
423
424// static
Ben Murdoch558790d2013-07-30 15:19:42 +0100425void GLInProcessContext::SetGpuMemoryBufferFactory(
426 GpuMemoryBufferFactory* factory) {
427 DCHECK_EQ(0u, SharedContextCount());
428 g_gpu_memory_buffer_factory = factory;
Ben Murdocheb525c52013-07-10 11:40:50 +0100429}
430
Ben Murdocheb525c52013-07-10 11:40:50 +0100431} // namespace gpu