| Index: gpu/command_buffer/client/vertex_array_object_manager.cc
|
| diff --git a/gpu/command_buffer/client/vertex_array_object_manager.cc b/gpu/command_buffer/client/vertex_array_object_manager.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..822a22763f5c2a749d7d2c8a6ae7496a6971231e
|
| --- /dev/null
|
| +++ b/gpu/command_buffer/client/vertex_array_object_manager.cc
|
| @@ -0,0 +1,631 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "../client/vertex_array_object_manager.h"
|
| +
|
| +#include "../client/gles2_cmd_helper.h"
|
| +#include "../client/gles2_implementation.h"
|
| +#include "../common/logging.h"
|
| +
|
| +#if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
|
| +#define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
|
| +#endif
|
| +
|
| +namespace gpu {
|
| +namespace gles2 {
|
| +
|
| +#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
|
| +
|
| +static GLsizei RoundUpToMultipleOf4(GLsizei size) {
|
| + return (size + 3) & ~3;
|
| +}
|
| +
|
| +#endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
|
| +
|
| +// A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
|
| +static GLuint ToGLuint(const void* ptr) {
|
| + return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
|
| +}
|
| +
|
| +// This class tracks VertexAttribPointers and helps emulate client side buffers.
|
| +//
|
| +// The way client side buffers work is we shadow all the Vertex Attribs so we
|
| +// know which ones are pointing to client side buffers.
|
| +//
|
| +// At Draw time, for any attribs pointing to client side buffers we copy them
|
| +// to a special VBO and reset the actual vertex attrib pointers to point to this
|
| +// VBO.
|
| +//
|
| +// This also means we have to catch calls to query those values so that when
|
| +// an attrib is a client side buffer we pass the info back the user expects.
|
| +
|
| +class GLES2_IMPL_EXPORT VertexArrayObject {
|
| + public:
|
| + // Info about Vertex Attributes. This is used to track what the user currently
|
| + // has bound on each Vertex Attribute so we can simulate client side buffers
|
| + // at glDrawXXX time.
|
| + class VertexAttrib {
|
| + public:
|
| + VertexAttrib()
|
| + : enabled_(false),
|
| + buffer_id_(0),
|
| + size_(4),
|
| + type_(GL_FLOAT),
|
| + normalized_(GL_FALSE),
|
| + pointer_(NULL),
|
| + gl_stride_(0),
|
| + divisor_(0) {
|
| + }
|
| +
|
| + bool enabled() const {
|
| + return enabled_;
|
| + }
|
| +
|
| + void set_enabled(bool enabled) {
|
| + enabled_ = enabled;
|
| + }
|
| +
|
| + GLuint buffer_id() const {
|
| + return buffer_id_;
|
| + }
|
| +
|
| + void set_buffer_id(GLuint id) {
|
| + buffer_id_ = id;
|
| + }
|
| +
|
| + GLenum type() const {
|
| + return type_;
|
| + }
|
| +
|
| + GLint size() const {
|
| + return size_;
|
| + }
|
| +
|
| + GLsizei stride() const {
|
| + return gl_stride_;
|
| + }
|
| +
|
| + GLboolean normalized() const {
|
| + return normalized_;
|
| + }
|
| +
|
| + const GLvoid* pointer() const {
|
| + return pointer_;
|
| + }
|
| +
|
| + bool IsClientSide() const {
|
| + return buffer_id_ == 0;
|
| + }
|
| +
|
| + GLuint divisor() const {
|
| + return divisor_;
|
| + }
|
| +
|
| + void SetInfo(
|
| + GLuint buffer_id,
|
| + GLint size,
|
| + GLenum type,
|
| + GLboolean normalized,
|
| + GLsizei gl_stride,
|
| + const GLvoid* pointer) {
|
| + buffer_id_ = buffer_id;
|
| + size_ = size;
|
| + type_ = type;
|
| + normalized_ = normalized;
|
| + gl_stride_ = gl_stride;
|
| + pointer_ = pointer;
|
| + }
|
| +
|
| + void SetDivisor(GLuint divisor) {
|
| + divisor_ = divisor;
|
| + }
|
| +
|
| + private:
|
| + // Whether or not this attribute is enabled.
|
| + bool enabled_;
|
| +
|
| + // The id of the buffer. 0 = client side buffer.
|
| + GLuint buffer_id_;
|
| +
|
| + // Number of components (1, 2, 3, 4).
|
| + GLint size_;
|
| +
|
| + // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer.
|
| + GLenum type_;
|
| +
|
| + // GL_TRUE or GL_FALSE
|
| + GLboolean normalized_;
|
| +
|
| + // The pointer/offset into the buffer.
|
| + const GLvoid* pointer_;
|
| +
|
| + // The stride that will be used to access the buffer. This is the bogus GL
|
| + // stride where 0 = compute the stride based on size and type.
|
| + GLsizei gl_stride_;
|
| +
|
| + // Divisor, for geometry instancing.
|
| + GLuint divisor_;
|
| + };
|
| +
|
| + typedef std::vector<VertexAttrib> VertexAttribs;
|
| +
|
| + explicit VertexArrayObject(GLuint max_vertex_attribs);
|
| +
|
| + void UnbindBuffer(GLuint id);
|
| +
|
| + bool BindElementArray(GLuint id);
|
| +
|
| + bool HaveEnabledClientSideBuffers() const;
|
| +
|
| + void SetAttribEnable(GLuint index, bool enabled);
|
| +
|
| + void SetAttribPointer(
|
| + GLuint buffer_id,
|
| + GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
|
| + const void* ptr);
|
| +
|
| + bool GetVertexAttrib(
|
| + GLuint index, GLenum pname, uint32* param) const;
|
| +
|
| + void SetAttribDivisor(GLuint index, GLuint divisor);
|
| +
|
| + bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const;
|
| +
|
| + const VertexAttribs& vertex_attribs() const {
|
| + return vertex_attribs_;
|
| + }
|
| +
|
| + GLuint bound_element_array_buffer() const {
|
| + return bound_element_array_buffer_id_;
|
| + }
|
| +
|
| + private:
|
| + const VertexAttrib* GetAttrib(GLuint index) const;
|
| +
|
| + GLuint num_client_side_pointers_enabled_;
|
| +
|
| + // The currently bound element array buffer.
|
| + GLuint bound_element_array_buffer_id_;
|
| +
|
| + VertexAttribs vertex_attribs_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(VertexArrayObject);
|
| +};
|
| +
|
| +VertexArrayObject::VertexArrayObject(GLuint max_vertex_attribs)
|
| + : num_client_side_pointers_enabled_(0),
|
| + bound_element_array_buffer_id_(0) {
|
| + vertex_attribs_.resize(max_vertex_attribs);
|
| +}
|
| +
|
| +void VertexArrayObject::UnbindBuffer(GLuint id) {
|
| + for (size_t ii = 0; ii < vertex_attribs_.size(); ++ii) {
|
| + VertexAttrib& attrib = vertex_attribs_[ii];
|
| + if (attrib.buffer_id() == id) {
|
| + attrib.set_buffer_id(0);
|
| + if (attrib.enabled()) {
|
| + ++num_client_side_pointers_enabled_;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +bool VertexArrayObject::BindElementArray(GLuint id) {
|
| + if (id == bound_element_array_buffer_id_) {
|
| + return false;
|
| + }
|
| + bound_element_array_buffer_id_ = id;
|
| + return true;
|
| +}
|
| +bool VertexArrayObject::HaveEnabledClientSideBuffers() const {
|
| + return num_client_side_pointers_enabled_ > 0;
|
| +}
|
| +
|
| +void VertexArrayObject::SetAttribEnable(GLuint index, bool enabled) {
|
| + if (index < vertex_attribs_.size()) {
|
| + VertexAttrib& attrib = vertex_attribs_[index];
|
| + if (attrib.enabled() != enabled) {
|
| + if (attrib.IsClientSide()) {
|
| + num_client_side_pointers_enabled_ += enabled ? 1 : -1;
|
| + }
|
| + attrib.set_enabled(enabled);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void VertexArrayObject::SetAttribPointer(
|
| + GLuint buffer_id,
|
| + GLuint index,
|
| + GLint size,
|
| + GLenum type,
|
| + GLboolean normalized,
|
| + GLsizei stride,
|
| + const void* ptr) {
|
| + if (index < vertex_attribs_.size()) {
|
| + VertexAttrib& attrib = vertex_attribs_[index];
|
| + if (attrib.IsClientSide() && attrib.enabled()) {
|
| + --num_client_side_pointers_enabled_;
|
| + }
|
| +
|
| + attrib.SetInfo(buffer_id, size, type, normalized, stride, ptr);
|
| +
|
| + if (attrib.IsClientSide() && attrib.enabled()) {
|
| + ++num_client_side_pointers_enabled_;
|
| + }
|
| + }
|
| +}
|
| +
|
| +bool VertexArrayObject::GetVertexAttrib(
|
| + GLuint index, GLenum pname, uint32* param) const {
|
| + const VertexAttrib* attrib = GetAttrib(index);
|
| + if (!attrib) {
|
| + return false;
|
| + }
|
| +
|
| + switch (pname) {
|
| + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
|
| + *param = attrib->buffer_id();
|
| + break;
|
| + case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
|
| + *param = attrib->enabled();
|
| + break;
|
| + case GL_VERTEX_ATTRIB_ARRAY_SIZE:
|
| + *param = attrib->size();
|
| + break;
|
| + case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
|
| + *param = attrib->stride();
|
| + break;
|
| + case GL_VERTEX_ATTRIB_ARRAY_TYPE:
|
| + *param = attrib->type();
|
| + break;
|
| + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
|
| + *param = attrib->normalized();
|
| + break;
|
| + default:
|
| + return false; // pass through to service side.
|
| + break;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void VertexArrayObject::SetAttribDivisor(GLuint index, GLuint divisor) {
|
| + if (index < vertex_attribs_.size()) {
|
| + VertexAttrib& attrib = vertex_attribs_[index];
|
| + attrib.SetDivisor(divisor);
|
| + }
|
| +}
|
| +
|
| +// Gets the Attrib pointer for an attrib but only if it's a client side
|
| +// pointer. Returns true if it got the pointer.
|
| +bool VertexArrayObject::GetAttribPointer(
|
| + GLuint index, GLenum pname, void** ptr) const {
|
| + const VertexAttrib* attrib = GetAttrib(index);
|
| + if (attrib && pname == GL_VERTEX_ATTRIB_ARRAY_POINTER) {
|
| + *ptr = const_cast<void*>(attrib->pointer());
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +// Gets an attrib if it's in range and it's client side.
|
| +const VertexArrayObject::VertexAttrib* VertexArrayObject::GetAttrib(
|
| + GLuint index) const {
|
| + if (index < vertex_attribs_.size()) {
|
| + const VertexAttrib* attrib = &vertex_attribs_[index];
|
| + return attrib;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +VertexArrayObjectManager::VertexArrayObjectManager(
|
| + GLuint max_vertex_attribs,
|
| + GLuint array_buffer_id,
|
| + GLuint element_array_buffer_id)
|
| + : max_vertex_attribs_(max_vertex_attribs),
|
| + array_buffer_id_(array_buffer_id),
|
| + array_buffer_size_(0),
|
| + array_buffer_offset_(0),
|
| + element_array_buffer_id_(element_array_buffer_id),
|
| + element_array_buffer_size_(0),
|
| + collection_buffer_size_(0),
|
| + default_vertex_array_object_(new VertexArrayObject(max_vertex_attribs)),
|
| + bound_vertex_array_object_(default_vertex_array_object_) {
|
| +}
|
| +
|
| +VertexArrayObjectManager::~VertexArrayObjectManager() {
|
| + for (VertexArrayObjectMap::iterator it = vertex_array_objects_.begin();
|
| + it != vertex_array_objects_.end(); ++it) {
|
| + delete it->second;
|
| + }
|
| + delete default_vertex_array_object_;
|
| +}
|
| +
|
| +bool VertexArrayObjectManager::IsReservedId(GLuint id) const {
|
| + return (id == array_buffer_id_ || id == element_array_buffer_id_);
|
| +}
|
| +
|
| +GLuint VertexArrayObjectManager::bound_element_array_buffer() const {
|
| + return bound_vertex_array_object_->bound_element_array_buffer();
|
| +}
|
| +
|
| +void VertexArrayObjectManager::UnbindBuffer(GLuint id) {
|
| + bound_vertex_array_object_->UnbindBuffer(id);
|
| +}
|
| +
|
| +bool VertexArrayObjectManager::BindElementArray(GLuint id) {
|
| + return bound_vertex_array_object_->BindElementArray(id);
|
| +}
|
| +
|
| +void VertexArrayObjectManager::GenVertexArrays(
|
| + GLsizei n, const GLuint* arrays) {
|
| + GPU_DCHECK_GE(n, 0);
|
| + for (GLsizei i = 0; i < n; ++i) {
|
| + std::pair<VertexArrayObjectMap::iterator, bool> result =
|
| + vertex_array_objects_.insert(std::make_pair(
|
| + arrays[i], new VertexArrayObject(max_vertex_attribs_)));
|
| + GPU_DCHECK(result.second);
|
| + }
|
| +}
|
| +
|
| +void VertexArrayObjectManager::DeleteVertexArrays(
|
| + GLsizei n, const GLuint* arrays) {
|
| + GPU_DCHECK_GE(n, 0);
|
| + for (GLsizei i = 0; i < n; ++i) {
|
| + GLuint id = arrays[i];
|
| + if (id) {
|
| + VertexArrayObjectMap::iterator it = vertex_array_objects_.find(id);
|
| + if (it != vertex_array_objects_.end()) {
|
| + if (bound_vertex_array_object_ == it->second) {
|
| + bound_vertex_array_object_ = default_vertex_array_object_;
|
| + }
|
| + delete it->second;
|
| + vertex_array_objects_.erase(it);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +bool VertexArrayObjectManager::BindVertexArray(GLuint array, bool* changed) {
|
| + *changed = false;
|
| + VertexArrayObject* vertex_array_object = default_vertex_array_object_;
|
| + if (array != 0) {
|
| + VertexArrayObjectMap::iterator it = vertex_array_objects_.find(array);
|
| + if (it == vertex_array_objects_.end()) {
|
| + return false;
|
| + }
|
| + vertex_array_object = it->second;
|
| + }
|
| + *changed = vertex_array_object != bound_vertex_array_object_;
|
| + bound_vertex_array_object_ = vertex_array_object;
|
| + return true;
|
| +}
|
| +
|
| +bool VertexArrayObjectManager::HaveEnabledClientSideBuffers() const {
|
| + return bound_vertex_array_object_->HaveEnabledClientSideBuffers();
|
| +}
|
| +
|
| +void VertexArrayObjectManager::SetAttribEnable(GLuint index, bool enabled) {
|
| + bound_vertex_array_object_->SetAttribEnable(index, enabled);
|
| +}
|
| +
|
| +bool VertexArrayObjectManager::GetVertexAttrib(
|
| + GLuint index, GLenum pname, uint32* param) {
|
| + return bound_vertex_array_object_->GetVertexAttrib(index, pname, param);
|
| +}
|
| +
|
| +bool VertexArrayObjectManager::GetAttribPointer(
|
| + GLuint index, GLenum pname, void** ptr) const {
|
| + return bound_vertex_array_object_->GetAttribPointer(index, pname, ptr);
|
| +}
|
| +
|
| +bool VertexArrayObjectManager::SetAttribPointer(
|
| + GLuint buffer_id,
|
| + GLuint index,
|
| + GLint size,
|
| + GLenum type,
|
| + GLboolean normalized,
|
| + GLsizei stride,
|
| + const void* ptr) {
|
| + // Client side arrays are not allowed in vaos.
|
| + if (buffer_id == 0 && !IsDefaultVAOBound()) {
|
| + return false;
|
| + }
|
| + bound_vertex_array_object_->SetAttribPointer(
|
| + buffer_id, index, size, type, normalized, stride, ptr);
|
| + return true;
|
| +}
|
| +
|
| +void VertexArrayObjectManager::SetAttribDivisor(GLuint index, GLuint divisor) {
|
| + bound_vertex_array_object_->SetAttribDivisor(index, divisor);
|
| +}
|
| +
|
| +// Collects the data into the collection buffer and returns the number of
|
| +// bytes collected.
|
| +GLsizei VertexArrayObjectManager::CollectData(
|
| + const void* data,
|
| + GLsizei bytes_per_element,
|
| + GLsizei real_stride,
|
| + GLsizei num_elements) {
|
| + GLsizei bytes_needed = bytes_per_element * num_elements;
|
| + if (collection_buffer_size_ < bytes_needed) {
|
| + collection_buffer_.reset(new int8[bytes_needed]);
|
| + collection_buffer_size_ = bytes_needed;
|
| + }
|
| + const int8* src = static_cast<const int8*>(data);
|
| + int8* dst = collection_buffer_.get();
|
| + int8* end = dst + bytes_per_element * num_elements;
|
| + for (; dst < end; src += real_stride, dst += bytes_per_element) {
|
| + memcpy(dst, src, bytes_per_element);
|
| + }
|
| + return bytes_needed;
|
| +}
|
| +
|
| +bool VertexArrayObjectManager::IsDefaultVAOBound() const {
|
| + return bound_vertex_array_object_ == default_vertex_array_object_;
|
| +}
|
| +
|
| +// Returns true if buffers were setup.
|
| +bool VertexArrayObjectManager::SetupSimulatedClientSideBuffers(
|
| + const char* function_name,
|
| + GLES2Implementation* gl,
|
| + GLES2CmdHelper* gl_helper,
|
| + GLsizei num_elements,
|
| + GLsizei primcount,
|
| + bool* simulated) {
|
| + *simulated = false;
|
| +#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
|
| + if (!bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
|
| + return true;
|
| + }
|
| + if (!IsDefaultVAOBound()) {
|
| + gl->SetGLError(
|
| + GL_INVALID_OPERATION, function_name,
|
| + "client side arrays not allowed with vertex array object");
|
| + return false;
|
| + }
|
| + *simulated = true;
|
| + GLsizei total_size = 0;
|
| + // Compute the size of the buffer we need.
|
| + const VertexArrayObject::VertexAttribs& vertex_attribs =
|
| + bound_vertex_array_object_->vertex_attribs();
|
| + for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
|
| + const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
|
| + if (attrib.IsClientSide() && attrib.enabled()) {
|
| + size_t bytes_per_element =
|
| + GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
|
| + attrib.size();
|
| + GLsizei elements = (primcount && attrib.divisor() > 0) ?
|
| + ((primcount - 1) / attrib.divisor() + 1) : num_elements;
|
| + total_size += RoundUpToMultipleOf4(bytes_per_element * elements);
|
| + }
|
| + }
|
| + gl_helper->BindBuffer(GL_ARRAY_BUFFER, array_buffer_id_);
|
| + array_buffer_offset_ = 0;
|
| + if (total_size > array_buffer_size_) {
|
| + gl->BufferDataHelper(GL_ARRAY_BUFFER, total_size, NULL, GL_DYNAMIC_DRAW);
|
| + array_buffer_size_ = total_size;
|
| + }
|
| + for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
|
| + const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
|
| + if (attrib.IsClientSide() && attrib.enabled()) {
|
| + size_t bytes_per_element =
|
| + GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
|
| + attrib.size();
|
| + GLsizei real_stride = attrib.stride() ?
|
| + attrib.stride() : static_cast<GLsizei>(bytes_per_element);
|
| + GLsizei elements = (primcount && attrib.divisor() > 0) ?
|
| + ((primcount - 1) / attrib.divisor() + 1) : num_elements;
|
| + GLsizei bytes_collected = CollectData(
|
| + attrib.pointer(), bytes_per_element, real_stride, elements);
|
| + gl->BufferSubDataHelper(
|
| + GL_ARRAY_BUFFER, array_buffer_offset_, bytes_collected,
|
| + collection_buffer_.get());
|
| + gl_helper->VertexAttribPointer(
|
| + ii, attrib.size(), attrib.type(), attrib.normalized(), 0,
|
| + array_buffer_offset_);
|
| + array_buffer_offset_ += RoundUpToMultipleOf4(bytes_collected);
|
| + GPU_DCHECK_LE(array_buffer_offset_, array_buffer_size_);
|
| + }
|
| + }
|
| +#endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
|
| + return true;
|
| +}
|
| +
|
| +// Copies in indices to the service and returns the highest index accessed + 1
|
| +bool VertexArrayObjectManager::SetupSimulatedIndexAndClientSideBuffers(
|
| + const char* function_name,
|
| + GLES2Implementation* gl,
|
| + GLES2CmdHelper* gl_helper,
|
| + GLsizei count,
|
| + GLenum type,
|
| + GLsizei primcount,
|
| + const void* indices,
|
| + GLuint* offset,
|
| + bool* simulated) {
|
| + *simulated = false;
|
| + *offset = ToGLuint(indices);
|
| +#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
|
| + GLsizei num_elements = 0;
|
| + if (bound_vertex_array_object_->bound_element_array_buffer() == 0) {
|
| + *simulated = true;
|
| + *offset = 0;
|
| + GLsizei max_index = -1;
|
| + switch (type) {
|
| + case GL_UNSIGNED_BYTE: {
|
| + const uint8* src = static_cast<const uint8*>(indices);
|
| + for (GLsizei ii = 0; ii < count; ++ii) {
|
| + if (src[ii] > max_index) {
|
| + max_index = src[ii];
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + case GL_UNSIGNED_SHORT: {
|
| + const uint16* src = static_cast<const uint16*>(indices);
|
| + for (GLsizei ii = 0; ii < count; ++ii) {
|
| + if (src[ii] > max_index) {
|
| + max_index = src[ii];
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + case GL_UNSIGNED_INT: {
|
| + uint32 max_glsizei = static_cast<uint32>(
|
| + std::numeric_limits<GLsizei>::max());
|
| + const uint32* src = static_cast<const uint32*>(indices);
|
| + for (GLsizei ii = 0; ii < count; ++ii) {
|
| + // Other parts of the API use GLsizei (signed) to store limits.
|
| + // As such, if we encounter a index that cannot be represented with
|
| + // an unsigned int we need to flag it as an error here.
|
| + if(src[ii] > max_glsizei) {
|
| + gl->SetGLError(
|
| + GL_INVALID_OPERATION, function_name, "index too large.");
|
| + return false;
|
| + }
|
| + GLsizei signed_index = static_cast<GLsizei>(src[ii]);
|
| + if (signed_index > max_index) {
|
| + max_index = signed_index;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + break;
|
| + }
|
| + gl_helper->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id_);
|
| + GLsizei bytes_per_element =
|
| + GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type);
|
| + GLsizei bytes_needed = bytes_per_element * count;
|
| + if (bytes_needed > element_array_buffer_size_) {
|
| + element_array_buffer_size_ = bytes_needed;
|
| + gl->BufferDataHelper(
|
| + GL_ELEMENT_ARRAY_BUFFER, bytes_needed, NULL, GL_DYNAMIC_DRAW);
|
| + }
|
| + gl->BufferSubDataHelper(
|
| + GL_ELEMENT_ARRAY_BUFFER, 0, bytes_needed, indices);
|
| +
|
| + num_elements = max_index + 1;
|
| + } else if (bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
|
| + // Index buffer is GL buffer. Ask the service for the highest vertex
|
| + // that will be accessed. Note: It doesn't matter if another context
|
| + // changes the contents of any of the buffers. The service will still
|
| + // validate the indices. We just need to know how much to copy across.
|
| + num_elements = gl->GetMaxValueInBufferCHROMIUMHelper(
|
| + bound_vertex_array_object_->bound_element_array_buffer(),
|
| + count, type, ToGLuint(indices)) + 1;
|
| + }
|
| +
|
| + bool simulated_client_side_buffers = false;
|
| + SetupSimulatedClientSideBuffers(
|
| + function_name, gl, gl_helper, num_elements, primcount,
|
| + &simulated_client_side_buffers);
|
| + *simulated = *simulated || simulated_client_side_buffers;
|
| +#endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
|
| + return true;
|
| +}
|
| +
|
| +} // namespace gles2
|
| +} // namespace gpu
|
| +
|
| +
|
|
|