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