Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / gpu / command_buffer / client / vertex_array_object_manager.cc
blob415abe610cef1750cf53318d222474f89519f03c
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 namespace gpu {
12 namespace gles2 {
14 static GLsizei RoundUpToMultipleOf4(GLsizei size) {
15 return (size + 3) & ~3;
18 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
19 static GLuint ToGLuint(const void* ptr) {
20 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
23 // This class tracks VertexAttribPointers and helps emulate client side buffers.
25 // The way client side buffers work is we shadow all the Vertex Attribs so we
26 // know which ones are pointing to client side buffers.
28 // At Draw time, for any attribs pointing to client side buffers we copy them
29 // to a special VBO and reset the actual vertex attrib pointers to point to this
30 // VBO.
32 // This also means we have to catch calls to query those values so that when
33 // an attrib is a client side buffer we pass the info back the user expects.
35 class GLES2_IMPL_EXPORT VertexArrayObject {
36 public:
37 // Info about Vertex Attributes. This is used to track what the user currently
38 // has bound on each Vertex Attribute so we can simulate client side buffers
39 // at glDrawXXX time.
40 class VertexAttrib {
41 public:
42 VertexAttrib()
43 : enabled_(false),
44 buffer_id_(0),
45 size_(4),
46 type_(GL_FLOAT),
47 normalized_(GL_FALSE),
48 pointer_(NULL),
49 gl_stride_(0),
50 divisor_(0),
51 integer_(GL_FALSE) {
54 bool enabled() const {
55 return enabled_;
58 void set_enabled(bool enabled) {
59 enabled_ = enabled;
62 GLuint buffer_id() const {
63 return buffer_id_;
66 void set_buffer_id(GLuint id) {
67 buffer_id_ = id;
70 GLenum type() const {
71 return type_;
74 GLint size() const {
75 return size_;
78 GLsizei stride() const {
79 return gl_stride_;
82 GLboolean normalized() const {
83 return normalized_;
86 const GLvoid* pointer() const {
87 return pointer_;
90 bool IsClientSide() const {
91 return buffer_id_ == 0;
94 GLuint divisor() const {
95 return divisor_;
98 GLboolean integer() const {
99 return integer_;
102 void SetInfo(
103 GLuint buffer_id,
104 GLint size,
105 GLenum type,
106 GLboolean normalized,
107 GLsizei gl_stride,
108 const GLvoid* pointer,
109 GLboolean integer) {
110 buffer_id_ = buffer_id;
111 size_ = size;
112 type_ = type;
113 normalized_ = normalized;
114 gl_stride_ = gl_stride;
115 pointer_ = pointer;
116 integer_ = integer;
119 void SetDivisor(GLuint divisor) {
120 divisor_ = divisor;
123 private:
124 // Whether or not this attribute is enabled.
125 bool enabled_;
127 // The id of the buffer. 0 = client side buffer.
128 GLuint buffer_id_;
130 // Number of components (1, 2, 3, 4).
131 GLint size_;
133 // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer.
134 GLenum type_;
136 // GL_TRUE or GL_FALSE
137 GLboolean normalized_;
139 // The pointer/offset into the buffer.
140 const GLvoid* pointer_;
142 // The stride that will be used to access the buffer. This is the bogus GL
143 // stride where 0 = compute the stride based on size and type.
144 GLsizei gl_stride_;
146 // Divisor, for geometry instancing.
147 GLuint divisor_;
149 GLboolean integer_;
152 typedef std::vector<VertexAttrib> VertexAttribs;
154 explicit VertexArrayObject(GLuint max_vertex_attribs);
156 void UnbindBuffer(GLuint id);
158 bool BindElementArray(GLuint id);
160 bool HaveEnabledClientSideBuffers() const;
162 void SetAttribEnable(GLuint index, bool enabled);
164 void SetAttribPointer(
165 GLuint buffer_id,
166 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
167 const void* ptr, GLboolean integer);
169 bool GetVertexAttrib(
170 GLuint index, GLenum pname, uint32* param) const;
172 void SetAttribDivisor(GLuint index, GLuint divisor);
174 bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const;
176 const VertexAttribs& vertex_attribs() const {
177 return vertex_attribs_;
180 GLuint bound_element_array_buffer() const {
181 return bound_element_array_buffer_id_;
184 private:
185 const VertexAttrib* GetAttrib(GLuint index) const;
187 int num_client_side_pointers_enabled_;
189 // The currently bound element array buffer.
190 GLuint bound_element_array_buffer_id_;
192 VertexAttribs vertex_attribs_;
194 DISALLOW_COPY_AND_ASSIGN(VertexArrayObject);
197 VertexArrayObject::VertexArrayObject(GLuint max_vertex_attribs)
198 : num_client_side_pointers_enabled_(0),
199 bound_element_array_buffer_id_(0) {
200 vertex_attribs_.resize(max_vertex_attribs);
203 void VertexArrayObject::UnbindBuffer(GLuint id) {
204 if (id == 0) {
205 return;
207 for (size_t ii = 0; ii < vertex_attribs_.size(); ++ii) {
208 VertexAttrib& attrib = vertex_attribs_[ii];
209 if (attrib.buffer_id() == id) {
210 attrib.set_buffer_id(0);
211 if (attrib.enabled()) {
212 ++num_client_side_pointers_enabled_;
216 if (bound_element_array_buffer_id_ == id) {
217 bound_element_array_buffer_id_ = 0;
221 bool VertexArrayObject::BindElementArray(GLuint id) {
222 if (id == bound_element_array_buffer_id_) {
223 return false;
225 bound_element_array_buffer_id_ = id;
226 return true;
228 bool VertexArrayObject::HaveEnabledClientSideBuffers() const {
229 return num_client_side_pointers_enabled_ > 0;
232 void VertexArrayObject::SetAttribEnable(GLuint index, bool enabled) {
233 if (index < vertex_attribs_.size()) {
234 VertexAttrib& attrib = vertex_attribs_[index];
235 if (attrib.enabled() != enabled) {
236 if (attrib.IsClientSide()) {
237 num_client_side_pointers_enabled_ += enabled ? 1 : -1;
238 DCHECK_GE(num_client_side_pointers_enabled_, 0);
240 attrib.set_enabled(enabled);
245 void VertexArrayObject::SetAttribPointer(
246 GLuint buffer_id,
247 GLuint index,
248 GLint size,
249 GLenum type,
250 GLboolean normalized,
251 GLsizei stride,
252 const void* ptr,
253 GLboolean integer) {
254 if (index < vertex_attribs_.size()) {
255 VertexAttrib& attrib = vertex_attribs_[index];
256 if (attrib.IsClientSide() && attrib.enabled()) {
257 --num_client_side_pointers_enabled_;
258 DCHECK_GE(num_client_side_pointers_enabled_, 0);
261 attrib.SetInfo(buffer_id, size, type, normalized, stride, ptr, integer);
263 if (attrib.IsClientSide() && attrib.enabled()) {
264 ++num_client_side_pointers_enabled_;
269 bool VertexArrayObject::GetVertexAttrib(
270 GLuint index, GLenum pname, uint32* param) const {
271 const VertexAttrib* attrib = GetAttrib(index);
272 if (!attrib) {
273 return false;
276 switch (pname) {
277 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
278 *param = attrib->buffer_id();
279 break;
280 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
281 *param = attrib->enabled();
282 break;
283 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
284 *param = attrib->size();
285 break;
286 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
287 *param = attrib->stride();
288 break;
289 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
290 *param = attrib->type();
291 break;
292 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
293 *param = attrib->normalized();
294 break;
295 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
296 *param = attrib->integer();
297 break;
298 default:
299 return false; // pass through to service side.
301 return true;
304 void VertexArrayObject::SetAttribDivisor(GLuint index, GLuint divisor) {
305 if (index < vertex_attribs_.size()) {
306 VertexAttrib& attrib = vertex_attribs_[index];
307 attrib.SetDivisor(divisor);
311 // Gets the Attrib pointer for an attrib but only if it's a client side
312 // pointer. Returns true if it got the pointer.
313 bool VertexArrayObject::GetAttribPointer(
314 GLuint index, GLenum pname, void** ptr) const {
315 const VertexAttrib* attrib = GetAttrib(index);
316 if (attrib && pname == GL_VERTEX_ATTRIB_ARRAY_POINTER) {
317 *ptr = const_cast<void*>(attrib->pointer());
318 return true;
320 return false;
323 // Gets an attrib if it's in range and it's client side.
324 const VertexArrayObject::VertexAttrib* VertexArrayObject::GetAttrib(
325 GLuint index) const {
326 if (index < vertex_attribs_.size()) {
327 const VertexAttrib* attrib = &vertex_attribs_[index];
328 return attrib;
330 return NULL;
333 VertexArrayObjectManager::VertexArrayObjectManager(
334 GLuint max_vertex_attribs,
335 GLuint array_buffer_id,
336 GLuint element_array_buffer_id,
337 bool support_client_side_arrays)
338 : max_vertex_attribs_(max_vertex_attribs),
339 array_buffer_id_(array_buffer_id),
340 array_buffer_size_(0),
341 array_buffer_offset_(0),
342 element_array_buffer_id_(element_array_buffer_id),
343 element_array_buffer_size_(0),
344 collection_buffer_size_(0),
345 default_vertex_array_object_(new VertexArrayObject(max_vertex_attribs)),
346 bound_vertex_array_object_(default_vertex_array_object_),
347 support_client_side_arrays_(support_client_side_arrays) {
350 VertexArrayObjectManager::~VertexArrayObjectManager() {
351 for (VertexArrayObjectMap::iterator it = vertex_array_objects_.begin();
352 it != vertex_array_objects_.end(); ++it) {
353 delete it->second;
355 delete default_vertex_array_object_;
358 bool VertexArrayObjectManager::IsReservedId(GLuint id) const {
359 return (id != 0 &&
360 (id == array_buffer_id_ || id == element_array_buffer_id_));
363 GLuint VertexArrayObjectManager::bound_element_array_buffer() const {
364 return bound_vertex_array_object_->bound_element_array_buffer();
367 void VertexArrayObjectManager::UnbindBuffer(GLuint id) {
368 bound_vertex_array_object_->UnbindBuffer(id);
371 bool VertexArrayObjectManager::BindElementArray(GLuint id) {
372 return bound_vertex_array_object_->BindElementArray(id);
375 void VertexArrayObjectManager::GenVertexArrays(
376 GLsizei n, const GLuint* arrays) {
377 DCHECK_GE(n, 0);
378 for (GLsizei i = 0; i < n; ++i) {
379 std::pair<VertexArrayObjectMap::iterator, bool> result =
380 vertex_array_objects_.insert(std::make_pair(
381 arrays[i], new VertexArrayObject(max_vertex_attribs_)));
382 DCHECK(result.second);
386 void VertexArrayObjectManager::DeleteVertexArrays(
387 GLsizei n, const GLuint* arrays) {
388 DCHECK_GE(n, 0);
389 for (GLsizei i = 0; i < n; ++i) {
390 GLuint id = arrays[i];
391 if (id) {
392 VertexArrayObjectMap::iterator it = vertex_array_objects_.find(id);
393 if (it != vertex_array_objects_.end()) {
394 if (bound_vertex_array_object_ == it->second) {
395 bound_vertex_array_object_ = default_vertex_array_object_;
397 delete it->second;
398 vertex_array_objects_.erase(it);
404 bool VertexArrayObjectManager::BindVertexArray(GLuint array, bool* changed) {
405 *changed = false;
406 VertexArrayObject* vertex_array_object = default_vertex_array_object_;
407 if (array != 0) {
408 VertexArrayObjectMap::iterator it = vertex_array_objects_.find(array);
409 if (it == vertex_array_objects_.end()) {
410 return false;
412 vertex_array_object = it->second;
414 *changed = vertex_array_object != bound_vertex_array_object_;
415 bound_vertex_array_object_ = vertex_array_object;
416 return true;
419 bool VertexArrayObjectManager::HaveEnabledClientSideBuffers() const {
420 return bound_vertex_array_object_->HaveEnabledClientSideBuffers();
423 void VertexArrayObjectManager::SetAttribEnable(GLuint index, bool enabled) {
424 bound_vertex_array_object_->SetAttribEnable(index, enabled);
427 bool VertexArrayObjectManager::GetVertexAttrib(
428 GLuint index, GLenum pname, uint32* param) {
429 return bound_vertex_array_object_->GetVertexAttrib(index, pname, param);
432 bool VertexArrayObjectManager::GetAttribPointer(
433 GLuint index, GLenum pname, void** ptr) const {
434 return bound_vertex_array_object_->GetAttribPointer(index, pname, ptr);
437 bool VertexArrayObjectManager::SetAttribPointer(
438 GLuint buffer_id,
439 GLuint index,
440 GLint size,
441 GLenum type,
442 GLboolean normalized,
443 GLsizei stride,
444 const void* ptr,
445 GLboolean integer) {
446 // Client side arrays are not allowed in vaos.
447 if (buffer_id == 0 && !IsDefaultVAOBound()) {
448 return false;
450 bound_vertex_array_object_->SetAttribPointer(
451 buffer_id, index, size, type, normalized, stride, ptr, integer);
452 return true;
455 void VertexArrayObjectManager::SetAttribDivisor(GLuint index, GLuint divisor) {
456 bound_vertex_array_object_->SetAttribDivisor(index, divisor);
459 // Collects the data into the collection buffer and returns the number of
460 // bytes collected.
461 GLsizei VertexArrayObjectManager::CollectData(
462 const void* data,
463 GLsizei bytes_per_element,
464 GLsizei real_stride,
465 GLsizei num_elements) {
466 GLsizei bytes_needed = bytes_per_element * num_elements;
467 if (collection_buffer_size_ < bytes_needed) {
468 collection_buffer_.reset(new int8[bytes_needed]);
469 collection_buffer_size_ = bytes_needed;
471 const int8* src = static_cast<const int8*>(data);
472 int8* dst = collection_buffer_.get();
473 int8* end = dst + bytes_per_element * num_elements;
474 for (; dst < end; src += real_stride, dst += bytes_per_element) {
475 memcpy(dst, src, bytes_per_element);
477 return bytes_needed;
480 bool VertexArrayObjectManager::IsDefaultVAOBound() const {
481 return bound_vertex_array_object_ == default_vertex_array_object_;
484 // Returns true if buffers were setup.
485 bool VertexArrayObjectManager::SetupSimulatedClientSideBuffers(
486 const char* function_name,
487 GLES2Implementation* gl,
488 GLES2CmdHelper* gl_helper,
489 GLsizei num_elements,
490 GLsizei primcount,
491 bool* simulated) {
492 *simulated = false;
493 if (!support_client_side_arrays_)
494 return true;
495 if (!bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
496 return true;
498 if (!IsDefaultVAOBound()) {
499 gl->SetGLError(
500 GL_INVALID_OPERATION, function_name,
501 "client side arrays not allowed with vertex array object");
502 return false;
504 *simulated = true;
505 GLsizei total_size = 0;
506 // Compute the size of the buffer we need.
507 const VertexArrayObject::VertexAttribs& vertex_attribs =
508 bound_vertex_array_object_->vertex_attribs();
509 for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
510 const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
511 if (attrib.IsClientSide() && attrib.enabled()) {
512 size_t bytes_per_element =
513 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
514 attrib.size();
515 GLsizei elements = (primcount && attrib.divisor() > 0) ?
516 ((primcount - 1) / attrib.divisor() + 1) : num_elements;
517 total_size += RoundUpToMultipleOf4(bytes_per_element * elements);
520 gl_helper->BindBuffer(GL_ARRAY_BUFFER, array_buffer_id_);
521 array_buffer_offset_ = 0;
522 if (total_size > array_buffer_size_) {
523 gl->BufferDataHelper(GL_ARRAY_BUFFER, total_size, NULL, GL_DYNAMIC_DRAW);
524 array_buffer_size_ = total_size;
526 for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
527 const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
528 if (attrib.IsClientSide() && attrib.enabled()) {
529 size_t bytes_per_element =
530 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
531 attrib.size();
532 GLsizei real_stride = attrib.stride() ?
533 attrib.stride() : static_cast<GLsizei>(bytes_per_element);
534 GLsizei elements = (primcount && attrib.divisor() > 0) ?
535 ((primcount - 1) / attrib.divisor() + 1) : num_elements;
536 GLsizei bytes_collected = CollectData(
537 attrib.pointer(), bytes_per_element, real_stride, elements);
538 gl->BufferSubDataHelper(
539 GL_ARRAY_BUFFER, array_buffer_offset_, bytes_collected,
540 collection_buffer_.get());
541 gl_helper->VertexAttribPointer(
542 ii, attrib.size(), attrib.type(), attrib.normalized(), 0,
543 array_buffer_offset_);
544 array_buffer_offset_ += RoundUpToMultipleOf4(bytes_collected);
545 DCHECK_LE(array_buffer_offset_, array_buffer_size_);
548 return true;
551 // Copies in indices to the service and returns the highest index accessed + 1
552 bool VertexArrayObjectManager::SetupSimulatedIndexAndClientSideBuffers(
553 const char* function_name,
554 GLES2Implementation* gl,
555 GLES2CmdHelper* gl_helper,
556 GLsizei count,
557 GLenum type,
558 GLsizei primcount,
559 const void* indices,
560 GLuint* offset,
561 bool* simulated) {
562 *simulated = false;
563 *offset = ToGLuint(indices);
564 if (!support_client_side_arrays_)
565 return true;
566 GLsizei num_elements = 0;
567 if (bound_vertex_array_object_->bound_element_array_buffer() == 0) {
568 *simulated = true;
569 *offset = 0;
570 GLsizei max_index = -1;
571 switch (type) {
572 case GL_UNSIGNED_BYTE: {
573 const uint8* src = static_cast<const uint8*>(indices);
574 for (GLsizei ii = 0; ii < count; ++ii) {
575 if (src[ii] > max_index) {
576 max_index = src[ii];
579 break;
581 case GL_UNSIGNED_SHORT: {
582 const uint16* src = static_cast<const uint16*>(indices);
583 for (GLsizei ii = 0; ii < count; ++ii) {
584 if (src[ii] > max_index) {
585 max_index = src[ii];
588 break;
590 case GL_UNSIGNED_INT: {
591 uint32 max_glsizei = static_cast<uint32>(
592 std::numeric_limits<GLsizei>::max());
593 const uint32* src = static_cast<const uint32*>(indices);
594 for (GLsizei ii = 0; ii < count; ++ii) {
595 // Other parts of the API use GLsizei (signed) to store limits.
596 // As such, if we encounter a index that cannot be represented with
597 // an unsigned int we need to flag it as an error here.
598 if(src[ii] > max_glsizei) {
599 gl->SetGLError(
600 GL_INVALID_OPERATION, function_name, "index too large.");
601 return false;
603 GLsizei signed_index = static_cast<GLsizei>(src[ii]);
604 if (signed_index > max_index) {
605 max_index = signed_index;
608 break;
610 default:
611 break;
613 gl_helper->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id_);
614 GLsizei bytes_per_element =
615 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type);
616 GLsizei bytes_needed = bytes_per_element * count;
617 if (bytes_needed > element_array_buffer_size_) {
618 element_array_buffer_size_ = bytes_needed;
619 gl->BufferDataHelper(
620 GL_ELEMENT_ARRAY_BUFFER, bytes_needed, NULL, GL_DYNAMIC_DRAW);
622 gl->BufferSubDataHelper(
623 GL_ELEMENT_ARRAY_BUFFER, 0, bytes_needed, indices);
625 num_elements = max_index + 1;
626 } else if (bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
627 // Index buffer is GL buffer. Ask the service for the highest vertex
628 // that will be accessed. Note: It doesn't matter if another context
629 // changes the contents of any of the buffers. The service will still
630 // validate the indices. We just need to know how much to copy across.
631 num_elements = gl->GetMaxValueInBufferCHROMIUMHelper(
632 bound_vertex_array_object_->bound_element_array_buffer(),
633 count, type, ToGLuint(indices)) + 1;
636 bool simulated_client_side_buffers = false;
637 SetupSimulatedClientSideBuffers(
638 function_name, gl, gl_helper, num_elements, primcount,
639 &simulated_client_side_buffers);
640 *simulated = *simulated || simulated_client_side_buffers;
641 return true;
644 } // namespace gles2
645 } // namespace gpu