Let the browser know about the renderer's page id assignments, even if the renderer...
[chromium-blink-merge.git] / gpu / command_buffer / client / vertex_array_object_manager.cc
blob3e98bd0845041097721afd68dbd156847d2c029e
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/vertex_array_object_manager.h"
7 #include "base/logging.h"
8 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
9 #include "gpu/command_buffer/client/gles2_implementation.h"
11 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
12 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
13 #endif
15 namespace gpu {
16 namespace gles2 {
18 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
20 static GLsizei RoundUpToMultipleOf4(GLsizei size) {
21 return (size + 3) & ~3;
24 #endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
26 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
27 static GLuint ToGLuint(const void* ptr) {
28 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
31 // This class tracks VertexAttribPointers and helps emulate client side buffers.
33 // The way client side buffers work is we shadow all the Vertex Attribs so we
34 // know which ones are pointing to client side buffers.
36 // At Draw time, for any attribs pointing to client side buffers we copy them
37 // to a special VBO and reset the actual vertex attrib pointers to point to this
38 // VBO.
40 // This also means we have to catch calls to query those values so that when
41 // an attrib is a client side buffer we pass the info back the user expects.
43 class GLES2_IMPL_EXPORT VertexArrayObject {
44 public:
45 // Info about Vertex Attributes. This is used to track what the user currently
46 // has bound on each Vertex Attribute so we can simulate client side buffers
47 // at glDrawXXX time.
48 class VertexAttrib {
49 public:
50 VertexAttrib()
51 : enabled_(false),
52 buffer_id_(0),
53 size_(4),
54 type_(GL_FLOAT),
55 normalized_(GL_FALSE),
56 pointer_(NULL),
57 gl_stride_(0),
58 divisor_(0) {
61 bool enabled() const {
62 return enabled_;
65 void set_enabled(bool enabled) {
66 enabled_ = enabled;
69 GLuint buffer_id() const {
70 return buffer_id_;
73 void set_buffer_id(GLuint id) {
74 buffer_id_ = id;
77 GLenum type() const {
78 return type_;
81 GLint size() const {
82 return size_;
85 GLsizei stride() const {
86 return gl_stride_;
89 GLboolean normalized() const {
90 return normalized_;
93 const GLvoid* pointer() const {
94 return pointer_;
97 bool IsClientSide() const {
98 return buffer_id_ == 0;
101 GLuint divisor() const {
102 return divisor_;
105 void SetInfo(
106 GLuint buffer_id,
107 GLint size,
108 GLenum type,
109 GLboolean normalized,
110 GLsizei gl_stride,
111 const GLvoid* pointer) {
112 buffer_id_ = buffer_id;
113 size_ = size;
114 type_ = type;
115 normalized_ = normalized;
116 gl_stride_ = gl_stride;
117 pointer_ = pointer;
120 void SetDivisor(GLuint divisor) {
121 divisor_ = divisor;
124 private:
125 // Whether or not this attribute is enabled.
126 bool enabled_;
128 // The id of the buffer. 0 = client side buffer.
129 GLuint buffer_id_;
131 // Number of components (1, 2, 3, 4).
132 GLint size_;
134 // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer.
135 GLenum type_;
137 // GL_TRUE or GL_FALSE
138 GLboolean normalized_;
140 // The pointer/offset into the buffer.
141 const GLvoid* pointer_;
143 // The stride that will be used to access the buffer. This is the bogus GL
144 // stride where 0 = compute the stride based on size and type.
145 GLsizei gl_stride_;
147 // Divisor, for geometry instancing.
148 GLuint divisor_;
151 typedef std::vector<VertexAttrib> VertexAttribs;
153 explicit VertexArrayObject(GLuint max_vertex_attribs);
155 void UnbindBuffer(GLuint id);
157 bool BindElementArray(GLuint id);
159 bool HaveEnabledClientSideBuffers() const;
161 void SetAttribEnable(GLuint index, bool enabled);
163 void SetAttribPointer(
164 GLuint buffer_id,
165 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
166 const void* ptr);
168 bool GetVertexAttrib(
169 GLuint index, GLenum pname, uint32* param) const;
171 void SetAttribDivisor(GLuint index, GLuint divisor);
173 bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const;
175 const VertexAttribs& vertex_attribs() const {
176 return vertex_attribs_;
179 GLuint bound_element_array_buffer() const {
180 return bound_element_array_buffer_id_;
183 private:
184 const VertexAttrib* GetAttrib(GLuint index) const;
186 int num_client_side_pointers_enabled_;
188 // The currently bound element array buffer.
189 GLuint bound_element_array_buffer_id_;
191 VertexAttribs vertex_attribs_;
193 DISALLOW_COPY_AND_ASSIGN(VertexArrayObject);
196 VertexArrayObject::VertexArrayObject(GLuint max_vertex_attribs)
197 : num_client_side_pointers_enabled_(0),
198 bound_element_array_buffer_id_(0) {
199 vertex_attribs_.resize(max_vertex_attribs);
202 void VertexArrayObject::UnbindBuffer(GLuint id) {
203 if (id == 0) {
204 return;
206 for (size_t ii = 0; ii < vertex_attribs_.size(); ++ii) {
207 VertexAttrib& attrib = vertex_attribs_[ii];
208 if (attrib.buffer_id() == id) {
209 attrib.set_buffer_id(0);
210 if (attrib.enabled()) {
211 ++num_client_side_pointers_enabled_;
215 if (bound_element_array_buffer_id_ == id) {
216 bound_element_array_buffer_id_ = 0;
220 bool VertexArrayObject::BindElementArray(GLuint id) {
221 if (id == bound_element_array_buffer_id_) {
222 return false;
224 bound_element_array_buffer_id_ = id;
225 return true;
227 bool VertexArrayObject::HaveEnabledClientSideBuffers() const {
228 return num_client_side_pointers_enabled_ > 0;
231 void VertexArrayObject::SetAttribEnable(GLuint index, bool enabled) {
232 if (index < vertex_attribs_.size()) {
233 VertexAttrib& attrib = vertex_attribs_[index];
234 if (attrib.enabled() != enabled) {
235 if (attrib.IsClientSide()) {
236 num_client_side_pointers_enabled_ += enabled ? 1 : -1;
237 DCHECK_GE(num_client_side_pointers_enabled_, 0);
239 attrib.set_enabled(enabled);
244 void VertexArrayObject::SetAttribPointer(
245 GLuint buffer_id,
246 GLuint index,
247 GLint size,
248 GLenum type,
249 GLboolean normalized,
250 GLsizei stride,
251 const void* ptr) {
252 if (index < vertex_attribs_.size()) {
253 VertexAttrib& attrib = vertex_attribs_[index];
254 if (attrib.IsClientSide() && attrib.enabled()) {
255 --num_client_side_pointers_enabled_;
256 DCHECK_GE(num_client_side_pointers_enabled_, 0);
259 attrib.SetInfo(buffer_id, size, type, normalized, stride, ptr);
261 if (attrib.IsClientSide() && attrib.enabled()) {
262 ++num_client_side_pointers_enabled_;
267 bool VertexArrayObject::GetVertexAttrib(
268 GLuint index, GLenum pname, uint32* param) const {
269 const VertexAttrib* attrib = GetAttrib(index);
270 if (!attrib) {
271 return false;
274 switch (pname) {
275 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
276 *param = attrib->buffer_id();
277 break;
278 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
279 *param = attrib->enabled();
280 break;
281 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
282 *param = attrib->size();
283 break;
284 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
285 *param = attrib->stride();
286 break;
287 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
288 *param = attrib->type();
289 break;
290 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
291 *param = attrib->normalized();
292 break;
293 default:
294 return false; // pass through to service side.
295 break;
297 return true;
300 void VertexArrayObject::SetAttribDivisor(GLuint index, GLuint divisor) {
301 if (index < vertex_attribs_.size()) {
302 VertexAttrib& attrib = vertex_attribs_[index];
303 attrib.SetDivisor(divisor);
307 // Gets the Attrib pointer for an attrib but only if it's a client side
308 // pointer. Returns true if it got the pointer.
309 bool VertexArrayObject::GetAttribPointer(
310 GLuint index, GLenum pname, void** ptr) const {
311 const VertexAttrib* attrib = GetAttrib(index);
312 if (attrib && pname == GL_VERTEX_ATTRIB_ARRAY_POINTER) {
313 *ptr = const_cast<void*>(attrib->pointer());
314 return true;
316 return false;
319 // Gets an attrib if it's in range and it's client side.
320 const VertexArrayObject::VertexAttrib* VertexArrayObject::GetAttrib(
321 GLuint index) const {
322 if (index < vertex_attribs_.size()) {
323 const VertexAttrib* attrib = &vertex_attribs_[index];
324 return attrib;
326 return NULL;
329 VertexArrayObjectManager::VertexArrayObjectManager(
330 GLuint max_vertex_attribs,
331 GLuint array_buffer_id,
332 GLuint element_array_buffer_id)
333 : max_vertex_attribs_(max_vertex_attribs),
334 array_buffer_id_(array_buffer_id),
335 array_buffer_size_(0),
336 array_buffer_offset_(0),
337 element_array_buffer_id_(element_array_buffer_id),
338 element_array_buffer_size_(0),
339 collection_buffer_size_(0),
340 default_vertex_array_object_(new VertexArrayObject(max_vertex_attribs)),
341 bound_vertex_array_object_(default_vertex_array_object_) {
344 VertexArrayObjectManager::~VertexArrayObjectManager() {
345 for (VertexArrayObjectMap::iterator it = vertex_array_objects_.begin();
346 it != vertex_array_objects_.end(); ++it) {
347 delete it->second;
349 delete default_vertex_array_object_;
352 bool VertexArrayObjectManager::IsReservedId(GLuint id) const {
353 return (id != 0 &&
354 (id == array_buffer_id_ || id == element_array_buffer_id_));
357 GLuint VertexArrayObjectManager::bound_element_array_buffer() const {
358 return bound_vertex_array_object_->bound_element_array_buffer();
361 void VertexArrayObjectManager::UnbindBuffer(GLuint id) {
362 bound_vertex_array_object_->UnbindBuffer(id);
365 bool VertexArrayObjectManager::BindElementArray(GLuint id) {
366 return bound_vertex_array_object_->BindElementArray(id);
369 void VertexArrayObjectManager::GenVertexArrays(
370 GLsizei n, const GLuint* arrays) {
371 DCHECK_GE(n, 0);
372 for (GLsizei i = 0; i < n; ++i) {
373 std::pair<VertexArrayObjectMap::iterator, bool> result =
374 vertex_array_objects_.insert(std::make_pair(
375 arrays[i], new VertexArrayObject(max_vertex_attribs_)));
376 DCHECK(result.second);
380 void VertexArrayObjectManager::DeleteVertexArrays(
381 GLsizei n, const GLuint* arrays) {
382 DCHECK_GE(n, 0);
383 for (GLsizei i = 0; i < n; ++i) {
384 GLuint id = arrays[i];
385 if (id) {
386 VertexArrayObjectMap::iterator it = vertex_array_objects_.find(id);
387 if (it != vertex_array_objects_.end()) {
388 if (bound_vertex_array_object_ == it->second) {
389 bound_vertex_array_object_ = default_vertex_array_object_;
391 delete it->second;
392 vertex_array_objects_.erase(it);
398 bool VertexArrayObjectManager::BindVertexArray(GLuint array, bool* changed) {
399 *changed = false;
400 VertexArrayObject* vertex_array_object = default_vertex_array_object_;
401 if (array != 0) {
402 VertexArrayObjectMap::iterator it = vertex_array_objects_.find(array);
403 if (it == vertex_array_objects_.end()) {
404 return false;
406 vertex_array_object = it->second;
408 *changed = vertex_array_object != bound_vertex_array_object_;
409 bound_vertex_array_object_ = vertex_array_object;
410 return true;
413 bool VertexArrayObjectManager::HaveEnabledClientSideBuffers() const {
414 return bound_vertex_array_object_->HaveEnabledClientSideBuffers();
417 void VertexArrayObjectManager::SetAttribEnable(GLuint index, bool enabled) {
418 bound_vertex_array_object_->SetAttribEnable(index, enabled);
421 bool VertexArrayObjectManager::GetVertexAttrib(
422 GLuint index, GLenum pname, uint32* param) {
423 return bound_vertex_array_object_->GetVertexAttrib(index, pname, param);
426 bool VertexArrayObjectManager::GetAttribPointer(
427 GLuint index, GLenum pname, void** ptr) const {
428 return bound_vertex_array_object_->GetAttribPointer(index, pname, ptr);
431 bool VertexArrayObjectManager::SetAttribPointer(
432 GLuint buffer_id,
433 GLuint index,
434 GLint size,
435 GLenum type,
436 GLboolean normalized,
437 GLsizei stride,
438 const void* ptr) {
439 // Client side arrays are not allowed in vaos.
440 if (buffer_id == 0 && !IsDefaultVAOBound()) {
441 return false;
443 bound_vertex_array_object_->SetAttribPointer(
444 buffer_id, index, size, type, normalized, stride, ptr);
445 return true;
448 void VertexArrayObjectManager::SetAttribDivisor(GLuint index, GLuint divisor) {
449 bound_vertex_array_object_->SetAttribDivisor(index, divisor);
452 // Collects the data into the collection buffer and returns the number of
453 // bytes collected.
454 GLsizei VertexArrayObjectManager::CollectData(
455 const void* data,
456 GLsizei bytes_per_element,
457 GLsizei real_stride,
458 GLsizei num_elements) {
459 GLsizei bytes_needed = bytes_per_element * num_elements;
460 if (collection_buffer_size_ < bytes_needed) {
461 collection_buffer_.reset(new int8[bytes_needed]);
462 collection_buffer_size_ = bytes_needed;
464 const int8* src = static_cast<const int8*>(data);
465 int8* dst = collection_buffer_.get();
466 int8* end = dst + bytes_per_element * num_elements;
467 for (; dst < end; src += real_stride, dst += bytes_per_element) {
468 memcpy(dst, src, bytes_per_element);
470 return bytes_needed;
473 bool VertexArrayObjectManager::IsDefaultVAOBound() const {
474 return bound_vertex_array_object_ == default_vertex_array_object_;
477 // Returns true if buffers were setup.
478 bool VertexArrayObjectManager::SetupSimulatedClientSideBuffers(
479 const char* function_name,
480 GLES2Implementation* gl,
481 GLES2CmdHelper* gl_helper,
482 GLsizei num_elements,
483 GLsizei primcount,
484 bool* simulated) {
485 *simulated = false;
486 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
487 if (!bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
488 return true;
490 if (!IsDefaultVAOBound()) {
491 gl->SetGLError(
492 GL_INVALID_OPERATION, function_name,
493 "client side arrays not allowed with vertex array object");
494 return false;
496 *simulated = true;
497 GLsizei total_size = 0;
498 // Compute the size of the buffer we need.
499 const VertexArrayObject::VertexAttribs& vertex_attribs =
500 bound_vertex_array_object_->vertex_attribs();
501 for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
502 const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
503 if (attrib.IsClientSide() && attrib.enabled()) {
504 size_t bytes_per_element =
505 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
506 attrib.size();
507 GLsizei elements = (primcount && attrib.divisor() > 0) ?
508 ((primcount - 1) / attrib.divisor() + 1) : num_elements;
509 total_size += RoundUpToMultipleOf4(bytes_per_element * elements);
512 gl_helper->BindBuffer(GL_ARRAY_BUFFER, array_buffer_id_);
513 array_buffer_offset_ = 0;
514 if (total_size > array_buffer_size_) {
515 gl->BufferDataHelper(GL_ARRAY_BUFFER, total_size, NULL, GL_DYNAMIC_DRAW);
516 array_buffer_size_ = total_size;
518 for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
519 const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
520 if (attrib.IsClientSide() && attrib.enabled()) {
521 size_t bytes_per_element =
522 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
523 attrib.size();
524 GLsizei real_stride = attrib.stride() ?
525 attrib.stride() : static_cast<GLsizei>(bytes_per_element);
526 GLsizei elements = (primcount && attrib.divisor() > 0) ?
527 ((primcount - 1) / attrib.divisor() + 1) : num_elements;
528 GLsizei bytes_collected = CollectData(
529 attrib.pointer(), bytes_per_element, real_stride, elements);
530 gl->BufferSubDataHelper(
531 GL_ARRAY_BUFFER, array_buffer_offset_, bytes_collected,
532 collection_buffer_.get());
533 gl_helper->VertexAttribPointer(
534 ii, attrib.size(), attrib.type(), attrib.normalized(), 0,
535 array_buffer_offset_);
536 array_buffer_offset_ += RoundUpToMultipleOf4(bytes_collected);
537 DCHECK_LE(array_buffer_offset_, array_buffer_size_);
540 #endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
541 return true;
544 // Copies in indices to the service and returns the highest index accessed + 1
545 bool VertexArrayObjectManager::SetupSimulatedIndexAndClientSideBuffers(
546 const char* function_name,
547 GLES2Implementation* gl,
548 GLES2CmdHelper* gl_helper,
549 GLsizei count,
550 GLenum type,
551 GLsizei primcount,
552 const void* indices,
553 GLuint* offset,
554 bool* simulated) {
555 *simulated = false;
556 *offset = ToGLuint(indices);
557 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
558 GLsizei num_elements = 0;
559 if (bound_vertex_array_object_->bound_element_array_buffer() == 0) {
560 *simulated = true;
561 *offset = 0;
562 GLsizei max_index = -1;
563 switch (type) {
564 case GL_UNSIGNED_BYTE: {
565 const uint8* src = static_cast<const uint8*>(indices);
566 for (GLsizei ii = 0; ii < count; ++ii) {
567 if (src[ii] > max_index) {
568 max_index = src[ii];
571 break;
573 case GL_UNSIGNED_SHORT: {
574 const uint16* src = static_cast<const uint16*>(indices);
575 for (GLsizei ii = 0; ii < count; ++ii) {
576 if (src[ii] > max_index) {
577 max_index = src[ii];
580 break;
582 case GL_UNSIGNED_INT: {
583 uint32 max_glsizei = static_cast<uint32>(
584 std::numeric_limits<GLsizei>::max());
585 const uint32* src = static_cast<const uint32*>(indices);
586 for (GLsizei ii = 0; ii < count; ++ii) {
587 // Other parts of the API use GLsizei (signed) to store limits.
588 // As such, if we encounter a index that cannot be represented with
589 // an unsigned int we need to flag it as an error here.
590 if(src[ii] > max_glsizei) {
591 gl->SetGLError(
592 GL_INVALID_OPERATION, function_name, "index too large.");
593 return false;
595 GLsizei signed_index = static_cast<GLsizei>(src[ii]);
596 if (signed_index > max_index) {
597 max_index = signed_index;
600 break;
602 default:
603 break;
605 gl_helper->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id_);
606 GLsizei bytes_per_element =
607 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type);
608 GLsizei bytes_needed = bytes_per_element * count;
609 if (bytes_needed > element_array_buffer_size_) {
610 element_array_buffer_size_ = bytes_needed;
611 gl->BufferDataHelper(
612 GL_ELEMENT_ARRAY_BUFFER, bytes_needed, NULL, GL_DYNAMIC_DRAW);
614 gl->BufferSubDataHelper(
615 GL_ELEMENT_ARRAY_BUFFER, 0, bytes_needed, indices);
617 num_elements = max_index + 1;
618 } else if (bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
619 // Index buffer is GL buffer. Ask the service for the highest vertex
620 // that will be accessed. Note: It doesn't matter if another context
621 // changes the contents of any of the buffers. The service will still
622 // validate the indices. We just need to know how much to copy across.
623 num_elements = gl->GetMaxValueInBufferCHROMIUMHelper(
624 bound_vertex_array_object_->bound_element_array_buffer(),
625 count, type, ToGLuint(indices)) + 1;
628 bool simulated_client_side_buffers = false;
629 SetupSimulatedClientSideBuffers(
630 function_name, gl, gl_helper, num_elements, primcount,
631 &simulated_client_side_buffers);
632 *simulated = *simulated || simulated_client_side_buffers;
633 #endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
634 return true;
637 } // namespace gles2
638 } // namespace gpu