Roll leveldb 3f7758:803d69 (v1.17 -> v1.18)
[chromium-blink-merge.git] / gpu / command_buffer / client / vertex_array_object_manager.cc
bloba1098e960f2544fd6e99356caf010ef8d3322848
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) {
53 bool enabled() const {
54 return enabled_;
57 void set_enabled(bool enabled) {
58 enabled_ = enabled;
61 GLuint buffer_id() const {
62 return buffer_id_;
65 void set_buffer_id(GLuint id) {
66 buffer_id_ = id;
69 GLenum type() const {
70 return type_;
73 GLint size() const {
74 return size_;
77 GLsizei stride() const {
78 return gl_stride_;
81 GLboolean normalized() const {
82 return normalized_;
85 const GLvoid* pointer() const {
86 return pointer_;
89 bool IsClientSide() const {
90 return buffer_id_ == 0;
93 GLuint divisor() const {
94 return divisor_;
97 void SetInfo(
98 GLuint buffer_id,
99 GLint size,
100 GLenum type,
101 GLboolean normalized,
102 GLsizei gl_stride,
103 const GLvoid* pointer) {
104 buffer_id_ = buffer_id;
105 size_ = size;
106 type_ = type;
107 normalized_ = normalized;
108 gl_stride_ = gl_stride;
109 pointer_ = pointer;
112 void SetDivisor(GLuint divisor) {
113 divisor_ = divisor;
116 private:
117 // Whether or not this attribute is enabled.
118 bool enabled_;
120 // The id of the buffer. 0 = client side buffer.
121 GLuint buffer_id_;
123 // Number of components (1, 2, 3, 4).
124 GLint size_;
126 // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer.
127 GLenum type_;
129 // GL_TRUE or GL_FALSE
130 GLboolean normalized_;
132 // The pointer/offset into the buffer.
133 const GLvoid* pointer_;
135 // The stride that will be used to access the buffer. This is the bogus GL
136 // stride where 0 = compute the stride based on size and type.
137 GLsizei gl_stride_;
139 // Divisor, for geometry instancing.
140 GLuint divisor_;
143 typedef std::vector<VertexAttrib> VertexAttribs;
145 explicit VertexArrayObject(GLuint max_vertex_attribs);
147 void UnbindBuffer(GLuint id);
149 bool BindElementArray(GLuint id);
151 bool HaveEnabledClientSideBuffers() const;
153 void SetAttribEnable(GLuint index, bool enabled);
155 void SetAttribPointer(
156 GLuint buffer_id,
157 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
158 const void* ptr);
160 bool GetVertexAttrib(
161 GLuint index, GLenum pname, uint32* param) const;
163 void SetAttribDivisor(GLuint index, GLuint divisor);
165 bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const;
167 const VertexAttribs& vertex_attribs() const {
168 return vertex_attribs_;
171 GLuint bound_element_array_buffer() const {
172 return bound_element_array_buffer_id_;
175 private:
176 const VertexAttrib* GetAttrib(GLuint index) const;
178 int num_client_side_pointers_enabled_;
180 // The currently bound element array buffer.
181 GLuint bound_element_array_buffer_id_;
183 VertexAttribs vertex_attribs_;
185 DISALLOW_COPY_AND_ASSIGN(VertexArrayObject);
188 VertexArrayObject::VertexArrayObject(GLuint max_vertex_attribs)
189 : num_client_side_pointers_enabled_(0),
190 bound_element_array_buffer_id_(0) {
191 vertex_attribs_.resize(max_vertex_attribs);
194 void VertexArrayObject::UnbindBuffer(GLuint id) {
195 if (id == 0) {
196 return;
198 for (size_t ii = 0; ii < vertex_attribs_.size(); ++ii) {
199 VertexAttrib& attrib = vertex_attribs_[ii];
200 if (attrib.buffer_id() == id) {
201 attrib.set_buffer_id(0);
202 if (attrib.enabled()) {
203 ++num_client_side_pointers_enabled_;
207 if (bound_element_array_buffer_id_ == id) {
208 bound_element_array_buffer_id_ = 0;
212 bool VertexArrayObject::BindElementArray(GLuint id) {
213 if (id == bound_element_array_buffer_id_) {
214 return false;
216 bound_element_array_buffer_id_ = id;
217 return true;
219 bool VertexArrayObject::HaveEnabledClientSideBuffers() const {
220 return num_client_side_pointers_enabled_ > 0;
223 void VertexArrayObject::SetAttribEnable(GLuint index, bool enabled) {
224 if (index < vertex_attribs_.size()) {
225 VertexAttrib& attrib = vertex_attribs_[index];
226 if (attrib.enabled() != enabled) {
227 if (attrib.IsClientSide()) {
228 num_client_side_pointers_enabled_ += enabled ? 1 : -1;
229 DCHECK_GE(num_client_side_pointers_enabled_, 0);
231 attrib.set_enabled(enabled);
236 void VertexArrayObject::SetAttribPointer(
237 GLuint buffer_id,
238 GLuint index,
239 GLint size,
240 GLenum type,
241 GLboolean normalized,
242 GLsizei stride,
243 const void* ptr) {
244 if (index < vertex_attribs_.size()) {
245 VertexAttrib& attrib = vertex_attribs_[index];
246 if (attrib.IsClientSide() && attrib.enabled()) {
247 --num_client_side_pointers_enabled_;
248 DCHECK_GE(num_client_side_pointers_enabled_, 0);
251 attrib.SetInfo(buffer_id, size, type, normalized, stride, ptr);
253 if (attrib.IsClientSide() && attrib.enabled()) {
254 ++num_client_side_pointers_enabled_;
259 bool VertexArrayObject::GetVertexAttrib(
260 GLuint index, GLenum pname, uint32* param) const {
261 const VertexAttrib* attrib = GetAttrib(index);
262 if (!attrib) {
263 return false;
266 switch (pname) {
267 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
268 *param = attrib->buffer_id();
269 break;
270 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
271 *param = attrib->enabled();
272 break;
273 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
274 *param = attrib->size();
275 break;
276 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
277 *param = attrib->stride();
278 break;
279 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
280 *param = attrib->type();
281 break;
282 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
283 *param = attrib->normalized();
284 break;
285 default:
286 return false; // pass through to service side.
287 break;
289 return true;
292 void VertexArrayObject::SetAttribDivisor(GLuint index, GLuint divisor) {
293 if (index < vertex_attribs_.size()) {
294 VertexAttrib& attrib = vertex_attribs_[index];
295 attrib.SetDivisor(divisor);
299 // Gets the Attrib pointer for an attrib but only if it's a client side
300 // pointer. Returns true if it got the pointer.
301 bool VertexArrayObject::GetAttribPointer(
302 GLuint index, GLenum pname, void** ptr) const {
303 const VertexAttrib* attrib = GetAttrib(index);
304 if (attrib && pname == GL_VERTEX_ATTRIB_ARRAY_POINTER) {
305 *ptr = const_cast<void*>(attrib->pointer());
306 return true;
308 return false;
311 // Gets an attrib if it's in range and it's client side.
312 const VertexArrayObject::VertexAttrib* VertexArrayObject::GetAttrib(
313 GLuint index) const {
314 if (index < vertex_attribs_.size()) {
315 const VertexAttrib* attrib = &vertex_attribs_[index];
316 return attrib;
318 return NULL;
321 VertexArrayObjectManager::VertexArrayObjectManager(
322 GLuint max_vertex_attribs,
323 GLuint array_buffer_id,
324 GLuint element_array_buffer_id,
325 bool support_client_side_arrays)
326 : max_vertex_attribs_(max_vertex_attribs),
327 array_buffer_id_(array_buffer_id),
328 array_buffer_size_(0),
329 array_buffer_offset_(0),
330 element_array_buffer_id_(element_array_buffer_id),
331 element_array_buffer_size_(0),
332 collection_buffer_size_(0),
333 default_vertex_array_object_(new VertexArrayObject(max_vertex_attribs)),
334 bound_vertex_array_object_(default_vertex_array_object_),
335 support_client_side_arrays_(support_client_side_arrays) {
338 VertexArrayObjectManager::~VertexArrayObjectManager() {
339 for (VertexArrayObjectMap::iterator it = vertex_array_objects_.begin();
340 it != vertex_array_objects_.end(); ++it) {
341 delete it->second;
343 delete default_vertex_array_object_;
346 bool VertexArrayObjectManager::IsReservedId(GLuint id) const {
347 return (id != 0 &&
348 (id == array_buffer_id_ || id == element_array_buffer_id_));
351 GLuint VertexArrayObjectManager::bound_element_array_buffer() const {
352 return bound_vertex_array_object_->bound_element_array_buffer();
355 void VertexArrayObjectManager::UnbindBuffer(GLuint id) {
356 bound_vertex_array_object_->UnbindBuffer(id);
359 bool VertexArrayObjectManager::BindElementArray(GLuint id) {
360 return bound_vertex_array_object_->BindElementArray(id);
363 void VertexArrayObjectManager::GenVertexArrays(
364 GLsizei n, const GLuint* arrays) {
365 DCHECK_GE(n, 0);
366 for (GLsizei i = 0; i < n; ++i) {
367 std::pair<VertexArrayObjectMap::iterator, bool> result =
368 vertex_array_objects_.insert(std::make_pair(
369 arrays[i], new VertexArrayObject(max_vertex_attribs_)));
370 DCHECK(result.second);
374 void VertexArrayObjectManager::DeleteVertexArrays(
375 GLsizei n, const GLuint* arrays) {
376 DCHECK_GE(n, 0);
377 for (GLsizei i = 0; i < n; ++i) {
378 GLuint id = arrays[i];
379 if (id) {
380 VertexArrayObjectMap::iterator it = vertex_array_objects_.find(id);
381 if (it != vertex_array_objects_.end()) {
382 if (bound_vertex_array_object_ == it->second) {
383 bound_vertex_array_object_ = default_vertex_array_object_;
385 delete it->second;
386 vertex_array_objects_.erase(it);
392 bool VertexArrayObjectManager::BindVertexArray(GLuint array, bool* changed) {
393 *changed = false;
394 VertexArrayObject* vertex_array_object = default_vertex_array_object_;
395 if (array != 0) {
396 VertexArrayObjectMap::iterator it = vertex_array_objects_.find(array);
397 if (it == vertex_array_objects_.end()) {
398 return false;
400 vertex_array_object = it->second;
402 *changed = vertex_array_object != bound_vertex_array_object_;
403 bound_vertex_array_object_ = vertex_array_object;
404 return true;
407 bool VertexArrayObjectManager::HaveEnabledClientSideBuffers() const {
408 return bound_vertex_array_object_->HaveEnabledClientSideBuffers();
411 void VertexArrayObjectManager::SetAttribEnable(GLuint index, bool enabled) {
412 bound_vertex_array_object_->SetAttribEnable(index, enabled);
415 bool VertexArrayObjectManager::GetVertexAttrib(
416 GLuint index, GLenum pname, uint32* param) {
417 return bound_vertex_array_object_->GetVertexAttrib(index, pname, param);
420 bool VertexArrayObjectManager::GetAttribPointer(
421 GLuint index, GLenum pname, void** ptr) const {
422 return bound_vertex_array_object_->GetAttribPointer(index, pname, ptr);
425 bool VertexArrayObjectManager::SetAttribPointer(
426 GLuint buffer_id,
427 GLuint index,
428 GLint size,
429 GLenum type,
430 GLboolean normalized,
431 GLsizei stride,
432 const void* ptr) {
433 // Client side arrays are not allowed in vaos.
434 if (buffer_id == 0 && !IsDefaultVAOBound()) {
435 return false;
437 bound_vertex_array_object_->SetAttribPointer(
438 buffer_id, index, size, type, normalized, stride, ptr);
439 return true;
442 void VertexArrayObjectManager::SetAttribDivisor(GLuint index, GLuint divisor) {
443 bound_vertex_array_object_->SetAttribDivisor(index, divisor);
446 // Collects the data into the collection buffer and returns the number of
447 // bytes collected.
448 GLsizei VertexArrayObjectManager::CollectData(
449 const void* data,
450 GLsizei bytes_per_element,
451 GLsizei real_stride,
452 GLsizei num_elements) {
453 GLsizei bytes_needed = bytes_per_element * num_elements;
454 if (collection_buffer_size_ < bytes_needed) {
455 collection_buffer_.reset(new int8[bytes_needed]);
456 collection_buffer_size_ = bytes_needed;
458 const int8* src = static_cast<const int8*>(data);
459 int8* dst = collection_buffer_.get();
460 int8* end = dst + bytes_per_element * num_elements;
461 for (; dst < end; src += real_stride, dst += bytes_per_element) {
462 memcpy(dst, src, bytes_per_element);
464 return bytes_needed;
467 bool VertexArrayObjectManager::IsDefaultVAOBound() const {
468 return bound_vertex_array_object_ == default_vertex_array_object_;
471 // Returns true if buffers were setup.
472 bool VertexArrayObjectManager::SetupSimulatedClientSideBuffers(
473 const char* function_name,
474 GLES2Implementation* gl,
475 GLES2CmdHelper* gl_helper,
476 GLsizei num_elements,
477 GLsizei primcount,
478 bool* simulated) {
479 *simulated = false;
480 if (!support_client_side_arrays_)
481 return true;
482 if (!bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
483 return true;
485 if (!IsDefaultVAOBound()) {
486 gl->SetGLError(
487 GL_INVALID_OPERATION, function_name,
488 "client side arrays not allowed with vertex array object");
489 return false;
491 *simulated = true;
492 GLsizei total_size = 0;
493 // Compute the size of the buffer we need.
494 const VertexArrayObject::VertexAttribs& vertex_attribs =
495 bound_vertex_array_object_->vertex_attribs();
496 for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
497 const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
498 if (attrib.IsClientSide() && attrib.enabled()) {
499 size_t bytes_per_element =
500 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
501 attrib.size();
502 GLsizei elements = (primcount && attrib.divisor() > 0) ?
503 ((primcount - 1) / attrib.divisor() + 1) : num_elements;
504 total_size += RoundUpToMultipleOf4(bytes_per_element * elements);
507 gl_helper->BindBuffer(GL_ARRAY_BUFFER, array_buffer_id_);
508 array_buffer_offset_ = 0;
509 if (total_size > array_buffer_size_) {
510 gl->BufferDataHelper(GL_ARRAY_BUFFER, total_size, NULL, GL_DYNAMIC_DRAW);
511 array_buffer_size_ = total_size;
513 for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
514 const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
515 if (attrib.IsClientSide() && attrib.enabled()) {
516 size_t bytes_per_element =
517 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
518 attrib.size();
519 GLsizei real_stride = attrib.stride() ?
520 attrib.stride() : static_cast<GLsizei>(bytes_per_element);
521 GLsizei elements = (primcount && attrib.divisor() > 0) ?
522 ((primcount - 1) / attrib.divisor() + 1) : num_elements;
523 GLsizei bytes_collected = CollectData(
524 attrib.pointer(), bytes_per_element, real_stride, elements);
525 gl->BufferSubDataHelper(
526 GL_ARRAY_BUFFER, array_buffer_offset_, bytes_collected,
527 collection_buffer_.get());
528 gl_helper->VertexAttribPointer(
529 ii, attrib.size(), attrib.type(), attrib.normalized(), 0,
530 array_buffer_offset_);
531 array_buffer_offset_ += RoundUpToMultipleOf4(bytes_collected);
532 DCHECK_LE(array_buffer_offset_, array_buffer_size_);
535 return true;
538 // Copies in indices to the service and returns the highest index accessed + 1
539 bool VertexArrayObjectManager::SetupSimulatedIndexAndClientSideBuffers(
540 const char* function_name,
541 GLES2Implementation* gl,
542 GLES2CmdHelper* gl_helper,
543 GLsizei count,
544 GLenum type,
545 GLsizei primcount,
546 const void* indices,
547 GLuint* offset,
548 bool* simulated) {
549 *simulated = false;
550 *offset = ToGLuint(indices);
551 if (!support_client_side_arrays_)
552 return true;
553 GLsizei num_elements = 0;
554 if (bound_vertex_array_object_->bound_element_array_buffer() == 0) {
555 *simulated = true;
556 *offset = 0;
557 GLsizei max_index = -1;
558 switch (type) {
559 case GL_UNSIGNED_BYTE: {
560 const uint8* src = static_cast<const uint8*>(indices);
561 for (GLsizei ii = 0; ii < count; ++ii) {
562 if (src[ii] > max_index) {
563 max_index = src[ii];
566 break;
568 case GL_UNSIGNED_SHORT: {
569 const uint16* src = static_cast<const uint16*>(indices);
570 for (GLsizei ii = 0; ii < count; ++ii) {
571 if (src[ii] > max_index) {
572 max_index = src[ii];
575 break;
577 case GL_UNSIGNED_INT: {
578 uint32 max_glsizei = static_cast<uint32>(
579 std::numeric_limits<GLsizei>::max());
580 const uint32* src = static_cast<const uint32*>(indices);
581 for (GLsizei ii = 0; ii < count; ++ii) {
582 // Other parts of the API use GLsizei (signed) to store limits.
583 // As such, if we encounter a index that cannot be represented with
584 // an unsigned int we need to flag it as an error here.
585 if(src[ii] > max_glsizei) {
586 gl->SetGLError(
587 GL_INVALID_OPERATION, function_name, "index too large.");
588 return false;
590 GLsizei signed_index = static_cast<GLsizei>(src[ii]);
591 if (signed_index > max_index) {
592 max_index = signed_index;
595 break;
597 default:
598 break;
600 gl_helper->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id_);
601 GLsizei bytes_per_element =
602 GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type);
603 GLsizei bytes_needed = bytes_per_element * count;
604 if (bytes_needed > element_array_buffer_size_) {
605 element_array_buffer_size_ = bytes_needed;
606 gl->BufferDataHelper(
607 GL_ELEMENT_ARRAY_BUFFER, bytes_needed, NULL, GL_DYNAMIC_DRAW);
609 gl->BufferSubDataHelper(
610 GL_ELEMENT_ARRAY_BUFFER, 0, bytes_needed, indices);
612 num_elements = max_index + 1;
613 } else if (bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
614 // Index buffer is GL buffer. Ask the service for the highest vertex
615 // that will be accessed. Note: It doesn't matter if another context
616 // changes the contents of any of the buffers. The service will still
617 // validate the indices. We just need to know how much to copy across.
618 num_elements = gl->GetMaxValueInBufferCHROMIUMHelper(
619 bound_vertex_array_object_->bound_element_array_buffer(),
620 count, type, ToGLuint(indices)) + 1;
623 bool simulated_client_side_buffers = false;
624 SetupSimulatedClientSideBuffers(
625 function_name, gl, gl_helper, num_elements, primcount,
626 &simulated_client_side_buffers);
627 *simulated = *simulated || simulated_client_side_buffers;
628 return true;
631 } // namespace gles2
632 } // namespace gpu