This source file includes following definitions.
- RoundUpToMultipleOf4
 
- ToGLuint
 
- divisor_
 
- enabled
 
- set_enabled
 
- buffer_id
 
- set_buffer_id
 
- type
 
- size
 
- stride
 
- normalized
 
- pointer
 
- IsClientSide
 
- divisor
 
- SetInfo
 
- SetDivisor
 
- vertex_attribs
 
- bound_element_array_buffer
 
- bound_element_array_buffer_id_
 
- UnbindBuffer
 
- BindElementArray
 
- HaveEnabledClientSideBuffers
 
- SetAttribEnable
 
- SetAttribPointer
 
- GetVertexAttrib
 
- SetAttribDivisor
 
- GetAttribPointer
 
- GetAttrib
 
- bound_vertex_array_object_
 
- IsReservedId
 
- bound_element_array_buffer
 
- UnbindBuffer
 
- BindElementArray
 
- GenVertexArrays
 
- DeleteVertexArrays
 
- BindVertexArray
 
- HaveEnabledClientSideBuffers
 
- SetAttribEnable
 
- GetVertexAttrib
 
- GetAttribPointer
 
- SetAttribPointer
 
- SetAttribDivisor
 
- CollectData
 
- IsDefaultVAOBound
 
- SetupSimulatedClientSideBuffers
 
- SetupSimulatedIndexAndClientSideBuffers
 
#include "gpu/command_buffer/client/vertex_array_object_manager.h"
#include "base/logging.h"
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
#include "gpu/command_buffer/client/gles2_implementation.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  
static GLuint ToGLuint(const void* ptr) {
  return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
}
class GLES2_IMPL_EXPORT VertexArrayObject {
 public:
  
  
  
  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:
    
    bool enabled_;
    
    GLuint buffer_id_;
    
    GLint size_;
    
    GLenum type_;
    
    GLboolean normalized_;
    
    const GLvoid* pointer_;
    
    
    GLsizei gl_stride_;
    
    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;
  int num_client_side_pointers_enabled_;
  
  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) {
  if (id == 0) {
    return;
  }
  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_;
      }
    }
  }
  if (bound_element_array_buffer_id_ == id) {
    bound_element_array_buffer_id_ = 0;
  }
}
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;
        DCHECK_GE(num_client_side_pointers_enabled_, 0);
      }
      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_;
      DCHECK_GE(num_client_side_pointers_enabled_, 0);
    }
    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;  
      break;
  }
  return true;
}
void VertexArrayObject::SetAttribDivisor(GLuint index, GLuint divisor) {
  if (index < vertex_attribs_.size()) {
    VertexAttrib& attrib = vertex_attribs_[index];
    attrib.SetDivisor(divisor);
  }
}
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;
}
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 != 0 &&
          (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) {
  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_)));
    DCHECK(result.second);
  }
}
void VertexArrayObjectManager::DeleteVertexArrays(
    GLsizei n, const GLuint* arrays) {
  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) {
  
  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);
}
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_;
}
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;
  
  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);
      DCHECK_LE(array_buffer_offset_, array_buffer_size_);
    }
  }
#endif  
  return true;
}
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) {
          
          
          
          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()) {
    
    
    
    
    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  
  return true;
}
}  
}