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/service/vertex_attrib_manager.h" 6 7 #include <list> 8 9 #include "base/logging.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "build/build_config.h" 13 #define GLES2_GPU_SERVICE 1 14 #include "gpu/command_buffer/common/gles2_cmd_format.h" 15 #include "gpu/command_buffer/common/gles2_cmd_utils.h" 16 #include "gpu/command_buffer/service/buffer_manager.h" 17 #include "gpu/command_buffer/service/error_state.h" 18 #include "gpu/command_buffer/service/feature_info.h" 19 #include "gpu/command_buffer/service/gl_utils.h" 20 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" 21 #include "gpu/command_buffer/service/gpu_switches.h" 22 #include "gpu/command_buffer/service/program_manager.h" 23 #include "gpu/command_buffer/service/vertex_array_manager.h" 24 25 namespace gpu { 26 namespace gles2 { 27 28 VertexAttrib::VertexAttrib() 29 : index_(0), 30 enabled_(false), 31 size_(4), 32 type_(GL_FLOAT), 33 offset_(0), 34 normalized_(GL_FALSE), 35 gl_stride_(0), 36 real_stride_(16), 37 divisor_(0), 38 is_client_side_array_(false), 39 list_(NULL) { 40 } 41 42 VertexAttrib::~VertexAttrib() { 43 } 44 45 void VertexAttrib::SetInfo( 46 Buffer* buffer, 47 GLint size, 48 GLenum type, 49 GLboolean normalized, 50 GLsizei gl_stride, 51 GLsizei real_stride, 52 GLsizei offset) { 53 DCHECK_GT(real_stride, 0); 54 buffer_ = buffer; 55 size_ = size; 56 type_ = type; 57 normalized_ = normalized; 58 gl_stride_ = gl_stride; 59 real_stride_ = real_stride; 60 offset_ = offset; 61 } 62 63 void VertexAttrib::Unbind(Buffer* buffer) { 64 if (buffer_.get() == buffer) { 65 buffer_ = NULL; 66 } 67 } 68 69 bool VertexAttrib::CanAccess(GLuint index) const { 70 if (!enabled_) { 71 return true; 72 } 73 74 if (!buffer_.get() || buffer_->IsDeleted()) { 75 return false; 76 } 77 78 // The number of elements that can be accessed. 79 GLsizeiptr buffer_size = buffer_->size(); 80 if (offset_ > buffer_size || real_stride_ == 0) { 81 return false; 82 } 83 84 uint32 usable_size = buffer_size - offset_; 85 GLuint num_elements = usable_size / real_stride_ + 86 ((usable_size % real_stride_) >= 87 (GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type_) * size_) ? 1 : 0); 88 return index < num_elements; 89 } 90 91 VertexAttribManager::VertexAttribManager() 92 : num_fixed_attribs_(0), 93 element_array_buffer_(NULL), 94 manager_(NULL), 95 deleted_(false), 96 service_id_(0) { 97 } 98 99 VertexAttribManager::VertexAttribManager( 100 VertexArrayManager* manager, GLuint service_id, uint32 num_vertex_attribs) 101 : num_fixed_attribs_(0), 102 element_array_buffer_(NULL), 103 manager_(manager), 104 deleted_(false), 105 service_id_(service_id) { 106 manager_->StartTracking(this); 107 Initialize(num_vertex_attribs, false); 108 } 109 110 VertexAttribManager::~VertexAttribManager() { 111 if (manager_) { 112 if (manager_->have_context_) { 113 if (service_id_ != 0) // 0 indicates an emulated VAO 114 glDeleteVertexArraysOES(1, &service_id_); 115 } 116 manager_->StopTracking(this); 117 manager_ = NULL; 118 } 119 } 120 121 void VertexAttribManager::Initialize( 122 uint32 max_vertex_attribs, bool init_attribs) { 123 vertex_attribs_.resize(max_vertex_attribs); 124 125 for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) { 126 vertex_attribs_[vv].set_index(vv); 127 vertex_attribs_[vv].SetList(&disabled_vertex_attribs_); 128 129 if (init_attribs) { 130 glVertexAttrib4f(vv, 0.0f, 0.0f, 0.0f, 1.0f); 131 } 132 } 133 } 134 135 void VertexAttribManager::SetElementArrayBuffer(Buffer* buffer) { 136 element_array_buffer_ = buffer; 137 } 138 139 bool VertexAttribManager::Enable(GLuint index, bool enable) { 140 if (index >= vertex_attribs_.size()) { 141 return false; 142 } 143 VertexAttrib& info = vertex_attribs_[index]; 144 if (info.enabled() != enable) { 145 info.set_enabled(enable); 146 info.SetList(enable ? &enabled_vertex_attribs_ : &disabled_vertex_attribs_); 147 } 148 return true; 149 } 150 151 void VertexAttribManager::Unbind(Buffer* buffer) { 152 if (element_array_buffer_.get() == buffer) { 153 element_array_buffer_ = NULL; 154 } 155 for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) { 156 vertex_attribs_[vv].Unbind(buffer); 157 } 158 } 159 160 bool VertexAttribManager::ValidateBindings( 161 const char* function_name, 162 GLES2Decoder* decoder, 163 FeatureInfo* feature_info, 164 Program* current_program, 165 GLuint max_vertex_accessed, 166 GLsizei primcount) { 167 ErrorState* error_state = decoder->GetErrorState(); 168 // true if any enabled, used divisor is zero 169 bool divisor0 = false; 170 const GLuint kInitialBufferId = 0xFFFFFFFFU; 171 GLuint current_buffer_id = kInitialBufferId; 172 bool use_client_side_arrays_for_stream_buffers = feature_info->workarounds( 173 ).use_client_side_arrays_for_stream_buffers; 174 // Validate all attribs currently enabled. If they are used by the current 175 // program then check that they have enough elements to handle the draw call. 176 // If they are not used by the current program check that they have a buffer 177 // assigned. 178 for (VertexAttribList::iterator it = enabled_vertex_attribs_.begin(); 179 it != enabled_vertex_attribs_.end(); ++it) { 180 VertexAttrib* attrib = *it; 181 const Program::VertexAttrib* attrib_info = 182 current_program->GetAttribInfoByLocation(attrib->index()); 183 if (attrib_info) { 184 divisor0 |= (attrib->divisor() == 0); 185 GLuint count = attrib->MaxVertexAccessed(primcount, max_vertex_accessed); 186 // This attrib is used in the current program. 187 if (!attrib->CanAccess(count)) { 188 ERRORSTATE_SET_GL_ERROR( 189 error_state, GL_INVALID_OPERATION, function_name, 190 (std::string( 191 "attempt to access out of range vertices in attribute ") + 192 base::IntToString(attrib->index())).c_str()); 193 return false; 194 } 195 if (use_client_side_arrays_for_stream_buffers) { 196 Buffer* buffer = attrib->buffer(); 197 glEnableVertexAttribArray(attrib->index()); 198 if (buffer->IsClientSideArray()) { 199 if (current_buffer_id != 0) { 200 current_buffer_id = 0; 201 glBindBuffer(GL_ARRAY_BUFFER, 0); 202 } 203 attrib->set_is_client_side_array(true); 204 const void* ptr = buffer->GetRange(attrib->offset(), 0); 205 DCHECK(ptr); 206 glVertexAttribPointer( 207 attrib->index(), 208 attrib->size(), 209 attrib->type(), 210 attrib->normalized(), 211 attrib->gl_stride(), 212 ptr); 213 } else if (attrib->is_client_side_array()) { 214 attrib->set_is_client_side_array(false); 215 GLuint new_buffer_id = buffer->service_id(); 216 if (new_buffer_id != current_buffer_id) { 217 current_buffer_id = new_buffer_id; 218 glBindBuffer(GL_ARRAY_BUFFER, current_buffer_id); 219 } 220 const void* ptr = reinterpret_cast<const void*>(attrib->offset()); 221 glVertexAttribPointer( 222 attrib->index(), 223 attrib->size(), 224 attrib->type(), 225 attrib->normalized(), 226 attrib->gl_stride(), 227 ptr); 228 } 229 } 230 } else { 231 // This attrib is not used in the current program. 232 if (!attrib->buffer()) { 233 ERRORSTATE_SET_GL_ERROR( 234 error_state, GL_INVALID_OPERATION, function_name, 235 (std::string( 236 "attempt to render with no buffer attached to " 237 "enabled attribute ") + 238 base::IntToString(attrib->index())).c_str()); 239 return false; 240 } else if (use_client_side_arrays_for_stream_buffers) { 241 Buffer* buffer = attrib->buffer(); 242 // Disable client side arrays for unused attributes else we'll 243 // read bad memory 244 if (buffer->IsClientSideArray()) { 245 // Don't disable attrib 0 since it's special. 246 if (attrib->index() > 0) { 247 glDisableVertexAttribArray(attrib->index()); 248 } 249 } 250 } 251 } 252 } 253 254 if (primcount && !divisor0) { 255 ERRORSTATE_SET_GL_ERROR( 256 error_state, GL_INVALID_OPERATION, function_name, 257 "attempt instanced render with all attributes having " 258 "non-zero divisors"); 259 return false; 260 } 261 262 if (current_buffer_id != kInitialBufferId) { 263 // Restore the buffer binding. 264 decoder->RestoreBufferBindings(); 265 } 266 267 return true; 268 } 269 270 } // namespace gles2 271 } // namespace gpu 272