| Index: gpu/command_buffer/service/vertex_attrib_manager.cc
 | 
| diff --git a/gpu/command_buffer/service/vertex_attrib_manager.cc b/gpu/command_buffer/service/vertex_attrib_manager.cc
 | 
| index 50c2dec6b02b5e949dd0ca15d8dfcfe4ecfb595a..fe346ab04be09471b3c219c07fc90898002322bf 100644
 | 
| --- a/gpu/command_buffer/service/vertex_attrib_manager.cc
 | 
| +++ b/gpu/command_buffer/service/vertex_attrib_manager.cc
 | 
| @@ -9,13 +9,17 @@
 | 
|  #include "base/command_line.h"
 | 
|  #include "base/logging.h"
 | 
|  #include "base/memory/scoped_ptr.h"
 | 
| +#include "base/string_number_conversions.h"
 | 
|  #include "build/build_config.h"
 | 
|  #define GLES2_GPU_SERVICE 1
 | 
|  #include "gpu/command_buffer/common/gles2_cmd_format.h"
 | 
|  #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 | 
|  #include "gpu/command_buffer/service/buffer_manager.h"
 | 
| +#include "gpu/command_buffer/service/feature_info.h"
 | 
|  #include "gpu/command_buffer/service/gl_utils.h"
 | 
| +#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 | 
|  #include "gpu/command_buffer/service/gpu_switches.h"
 | 
| +#include "gpu/command_buffer/service/program_manager.h"
 | 
|  #include "gpu/command_buffer/service/vertex_array_manager.h"
 | 
|  
 | 
|  namespace gpu {
 | 
| @@ -31,6 +35,7 @@ VertexAttrib::VertexAttrib()
 | 
|        gl_stride_(0),
 | 
|        real_stride_(16),
 | 
|        divisor_(0),
 | 
| +      is_client_side_array_(false),
 | 
|        list_(NULL) {
 | 
|  }
 | 
|  
 | 
| @@ -154,5 +159,114 @@ void VertexAttribManager::Unbind(Buffer* buffer) {
 | 
|    }
 | 
|  }
 | 
|  
 | 
| +bool VertexAttribManager::ValidateBindings(
 | 
| +    const char* function_name,
 | 
| +    GLES2Decoder* decoder,
 | 
| +    FeatureInfo* feature_info,
 | 
| +    Program* current_program,
 | 
| +    GLuint max_vertex_accessed,
 | 
| +    GLsizei primcount) {
 | 
| +  // true if any enabled, used divisor is zero
 | 
| +  bool divisor0 = false;
 | 
| +  const GLuint kInitialBufferId = 0xFFFFFFFFU;
 | 
| +  GLuint current_buffer_id = kInitialBufferId;
 | 
| +  bool use_client_side_arrays_for_stream_buffers = feature_info->workarounds(
 | 
| +      ).use_client_side_arrays_for_stream_buffers;
 | 
| +  // Validate all attribs currently enabled. If they are used by the current
 | 
| +  // program then check that they have enough elements to handle the draw call.
 | 
| +  // If they are not used by the current program check that they have a buffer
 | 
| +  // assigned.
 | 
| +  for (VertexAttribInfoList::iterator it = enabled_vertex_attribs_.begin();
 | 
| +       it != enabled_vertex_attribs_.end(); ++it) {
 | 
| +    VertexAttrib* attrib = *it;
 | 
| +    const Program::VertexAttrib* attrib_info =
 | 
| +        current_program->GetAttribInfoByLocation(attrib->index());
 | 
| +    if (attrib_info) {
 | 
| +      divisor0 |= (attrib->divisor() == 0);
 | 
| +      GLuint count = attrib->MaxVertexAccessed(primcount, max_vertex_accessed);
 | 
| +      // This attrib is used in the current program.
 | 
| +      if (!attrib->CanAccess(count)) {
 | 
| +        decoder->SetGLError(
 | 
| +            GL_INVALID_OPERATION, function_name,
 | 
| +            (std::string(
 | 
| +                 "attempt to access out of range vertices in attribute ") +
 | 
| +             base::IntToString(attrib->index())).c_str());
 | 
| +        return false;
 | 
| +      }
 | 
| +      if (use_client_side_arrays_for_stream_buffers) {
 | 
| +        Buffer* buffer = attrib->buffer();
 | 
| +        glEnableVertexAttribArray(attrib->index());
 | 
| +        if (buffer->IsClientSideArray()) {
 | 
| +          if (current_buffer_id != 0) {
 | 
| +            current_buffer_id = 0;
 | 
| +            glBindBuffer(GL_ARRAY_BUFFER, 0);
 | 
| +          }
 | 
| +          attrib->set_is_client_side_array(true);
 | 
| +          const void* ptr = buffer->GetRange(attrib->offset(), 0);
 | 
| +          DCHECK(ptr);
 | 
| +          glVertexAttribPointer(
 | 
| +              attrib->index(),
 | 
| +              attrib->size(),
 | 
| +              attrib->type(),
 | 
| +              attrib->normalized(),
 | 
| +              attrib->gl_stride(),
 | 
| +              ptr);
 | 
| +        } else if (attrib->is_client_side_array()) {
 | 
| +          attrib->set_is_client_side_array(false);
 | 
| +          GLuint new_buffer_id = buffer->service_id();
 | 
| +          if (new_buffer_id != current_buffer_id) {
 | 
| +            current_buffer_id = new_buffer_id;
 | 
| +            glBindBuffer(GL_ARRAY_BUFFER, current_buffer_id);
 | 
| +          }
 | 
| +          const void* ptr = reinterpret_cast<const void*>(attrib->offset());
 | 
| +          glVertexAttribPointer(
 | 
| +              attrib->index(),
 | 
| +              attrib->size(),
 | 
| +              attrib->type(),
 | 
| +              attrib->normalized(),
 | 
| +              attrib->gl_stride(),
 | 
| +              ptr);
 | 
| +        }
 | 
| +      }
 | 
| +    } else {
 | 
| +      // This attrib is not used in the current program.
 | 
| +      if (!attrib->buffer()) {
 | 
| +        decoder->SetGLError(
 | 
| +            GL_INVALID_OPERATION, function_name,
 | 
| +            (std::string(
 | 
| +                 "attempt to render with no buffer attached to "
 | 
| +                 "enabled attribute ") +
 | 
| +                 base::IntToString(attrib->index())).c_str());
 | 
| +        return false;
 | 
| +      } else if (use_client_side_arrays_for_stream_buffers) {
 | 
| +        Buffer* buffer = attrib->buffer();
 | 
| +        // Disable client side arrays for unused attributes else we'll
 | 
| +        // read bad memory
 | 
| +        if (buffer->IsClientSideArray()) {
 | 
| +          // Don't disable attrib 0 since it's special.
 | 
| +          if (attrib->index() > 0) {
 | 
| +            glDisableVertexAttribArray(attrib->index());
 | 
| +          }
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  if (primcount && !divisor0) {
 | 
| +    decoder->SetGLError(
 | 
| +        GL_INVALID_OPERATION, function_name,
 | 
| +        "attempt instanced render with all attributes having "
 | 
| +        "non-zero divisors");
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  if (current_buffer_id != kInitialBufferId) {
 | 
| +    // Restore the buffer binding.
 | 
| +    decoder->RestoreBufferBindings();
 | 
| +  }
 | 
| +
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
|  }  // namespace gles2
 | 
|  }  // namespace gpu
 | 
| 
 |