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. 4 5 #include "gpu/command_buffer/client/vertex_array_object_manager.h" 6 7 #include "base/logging.h" 8 #include "gpu/command_buffer/client/gles2_cmd_helper.h" 9 #include "gpu/command_buffer/client/gles2_implementation.h" 10 11 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) 12 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS 13 #endif 14 15 namespace gpu { 16 namespace gles2 { 17 18 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) 19 20 static GLsizei RoundUpToMultipleOf4(GLsizei size) { 21 return (size + 3) & ~3; 22 } 23 24 #endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) 25 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)); 29 } 30 31 // This class tracks VertexAttribPointers and helps emulate client side buffers. 32 // 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. 35 // 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. 39 // 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. 42 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) { 59 } 60 61 bool enabled() const { 62 return enabled_; 63 } 64 65 void set_enabled(bool enabled) { 66 enabled_ = enabled; 67 } 68 69 GLuint buffer_id() const { 70 return buffer_id_; 71 } 72 73 void set_buffer_id(GLuint id) { 74 buffer_id_ = id; 75 } 76 77 GLenum type() const { 78 return type_; 79 } 80 81 GLint size() const { 82 return size_; 83 } 84 85 GLsizei stride() const { 86 return gl_stride_; 87 } 88 89 GLboolean normalized() const { 90 return normalized_; 91 } 92 93 const GLvoid* pointer() const { 94 return pointer_; 95 } 96 97 bool IsClientSide() const { 98 return buffer_id_ == 0; 99 } 100 101 GLuint divisor() const { 102 return divisor_; 103 } 104 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; 118 } 119 120 void SetDivisor(GLuint divisor) { 121 divisor_ = divisor; 122 } 123 124 private: 125 // Whether or not this attribute is enabled. 126 bool enabled_; 127 128 // The id of the buffer. 0 = client side buffer. 129 GLuint buffer_id_; 130 131 // Number of components (1, 2, 3, 4). 132 GLint size_; 133 134 // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer. 135 GLenum type_; 136 137 // GL_TRUE or GL_FALSE 138 GLboolean normalized_; 139 140 // The pointer/offset into the buffer. 141 const GLvoid* pointer_; 142 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_; 146 147 // Divisor, for geometry instancing. 148 GLuint divisor_; 149 }; 150 151 typedef std::vector<VertexAttrib> VertexAttribs; 152 153 explicit VertexArrayObject(GLuint max_vertex_attribs); 154 155 void UnbindBuffer(GLuint id); 156 157 bool BindElementArray(GLuint id); 158 159 bool HaveEnabledClientSideBuffers() const; 160 161 void SetAttribEnable(GLuint index, bool enabled); 162 163 void SetAttribPointer( 164 GLuint buffer_id, 165 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, 166 const void* ptr); 167 168 bool GetVertexAttrib( 169 GLuint index, GLenum pname, uint32* param) const; 170 171 void SetAttribDivisor(GLuint index, GLuint divisor); 172 173 bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const; 174 175 const VertexAttribs& vertex_attribs() const { 176 return vertex_attribs_; 177 } 178 179 GLuint bound_element_array_buffer() const { 180 return bound_element_array_buffer_id_; 181 } 182 183 private: 184 const VertexAttrib* GetAttrib(GLuint index) const; 185 186 int num_client_side_pointers_enabled_; 187 188 // The currently bound element array buffer. 189 GLuint bound_element_array_buffer_id_; 190 191 VertexAttribs vertex_attribs_; 192 193 DISALLOW_COPY_AND_ASSIGN(VertexArrayObject); 194 }; 195 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); 200 } 201 202 void VertexArrayObject::UnbindBuffer(GLuint id) { 203 if (id == 0) { 204 return; 205 } 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_; 212 } 213 } 214 } 215 if (bound_element_array_buffer_id_ == id) { 216 bound_element_array_buffer_id_ = 0; 217 } 218 } 219 220 bool VertexArrayObject::BindElementArray(GLuint id) { 221 if (id == bound_element_array_buffer_id_) { 222 return false; 223 } 224 bound_element_array_buffer_id_ = id; 225 return true; 226 } 227 bool VertexArrayObject::HaveEnabledClientSideBuffers() const { 228 return num_client_side_pointers_enabled_ > 0; 229 } 230 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); 238 } 239 attrib.set_enabled(enabled); 240 } 241 } 242 } 243 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); 257 } 258 259 attrib.SetInfo(buffer_id, size, type, normalized, stride, ptr); 260 261 if (attrib.IsClientSide() && attrib.enabled()) { 262 ++num_client_side_pointers_enabled_; 263 } 264 } 265 } 266 267 bool VertexArrayObject::GetVertexAttrib( 268 GLuint index, GLenum pname, uint32* param) const { 269 const VertexAttrib* attrib = GetAttrib(index); 270 if (!attrib) { 271 return false; 272 } 273 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; 296 } 297 return true; 298 } 299 300 void VertexArrayObject::SetAttribDivisor(GLuint index, GLuint divisor) { 301 if (index < vertex_attribs_.size()) { 302 VertexAttrib& attrib = vertex_attribs_[index]; 303 attrib.SetDivisor(divisor); 304 } 305 } 306 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; 315 } 316 return false; 317 } 318 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; 325 } 326 return NULL; 327 } 328 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_) { 342 } 343 344 VertexArrayObjectManager::~VertexArrayObjectManager() { 345 for (VertexArrayObjectMap::iterator it = vertex_array_objects_.begin(); 346 it != vertex_array_objects_.end(); ++it) { 347 delete it->second; 348 } 349 delete default_vertex_array_object_; 350 } 351 352 bool VertexArrayObjectManager::IsReservedId(GLuint id) const { 353 return (id != 0 && 354 (id == array_buffer_id_ || id == element_array_buffer_id_)); 355 } 356 357 GLuint VertexArrayObjectManager::bound_element_array_buffer() const { 358 return bound_vertex_array_object_->bound_element_array_buffer(); 359 } 360 361 void VertexArrayObjectManager::UnbindBuffer(GLuint id) { 362 bound_vertex_array_object_->UnbindBuffer(id); 363 } 364 365 bool VertexArrayObjectManager::BindElementArray(GLuint id) { 366 return bound_vertex_array_object_->BindElementArray(id); 367 } 368 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); 377 } 378 } 379 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_; 390 } 391 delete it->second; 392 vertex_array_objects_.erase(it); 393 } 394 } 395 } 396 } 397 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; 405 } 406 vertex_array_object = it->second; 407 } 408 *changed = vertex_array_object != bound_vertex_array_object_; 409 bound_vertex_array_object_ = vertex_array_object; 410 return true; 411 } 412 413 bool VertexArrayObjectManager::HaveEnabledClientSideBuffers() const { 414 return bound_vertex_array_object_->HaveEnabledClientSideBuffers(); 415 } 416 417 void VertexArrayObjectManager::SetAttribEnable(GLuint index, bool enabled) { 418 bound_vertex_array_object_->SetAttribEnable(index, enabled); 419 } 420 421 bool VertexArrayObjectManager::GetVertexAttrib( 422 GLuint index, GLenum pname, uint32* param) { 423 return bound_vertex_array_object_->GetVertexAttrib(index, pname, param); 424 } 425 426 bool VertexArrayObjectManager::GetAttribPointer( 427 GLuint index, GLenum pname, void** ptr) const { 428 return bound_vertex_array_object_->GetAttribPointer(index, pname, ptr); 429 } 430 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; 442 } 443 bound_vertex_array_object_->SetAttribPointer( 444 buffer_id, index, size, type, normalized, stride, ptr); 445 return true; 446 } 447 448 void VertexArrayObjectManager::SetAttribDivisor(GLuint index, GLuint divisor) { 449 bound_vertex_array_object_->SetAttribDivisor(index, divisor); 450 } 451 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; 463 } 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); 469 } 470 return bytes_needed; 471 } 472 473 bool VertexArrayObjectManager::IsDefaultVAOBound() const { 474 return bound_vertex_array_object_ == default_vertex_array_object_; 475 } 476 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; 489 } 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; 495 } 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); 510 } 511 } 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; 517 } 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_); 538 } 539 } 540 #endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) 541 return true; 542 } 543 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]; 569 } 570 } 571 break; 572 } 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]; 578 } 579 } 580 break; 581 } 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; 594 } 595 GLsizei signed_index = static_cast<GLsizei>(src[ii]); 596 if (signed_index > max_index) { 597 max_index = signed_index; 598 } 599 } 600 break; 601 } 602 default: 603 break; 604 } 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); 613 } 614 gl->BufferSubDataHelper( 615 GL_ELEMENT_ARRAY_BUFFER, 0, bytes_needed, indices); 616 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; 626 } 627 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; 635 } 636 637 } // namespace gles2 638 } // namespace gpu 639 640 641