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/buffer_manager.h" 6 #include <limits> 7 #include "base/debug/trace_event.h" 8 #include "base/logging.h" 9 #include "gpu/command_buffer/common/gles2_cmd_utils.h" 10 #include "gpu/command_buffer/service/context_state.h" 11 #include "gpu/command_buffer/service/error_state.h" 12 #include "gpu/command_buffer/service/feature_info.h" 13 #include "gpu/command_buffer/service/memory_tracking.h" 14 #include "ui/gl/gl_bindings.h" 15 16 namespace gpu { 17 namespace gles2 { 18 19 BufferManager::BufferManager( 20 MemoryTracker* memory_tracker, 21 FeatureInfo* feature_info) 22 : memory_tracker_( 23 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)), 24 feature_info_(feature_info), 25 allow_buffers_on_multiple_targets_(false), 26 buffer_count_(0), 27 have_context_(true), 28 use_client_side_arrays_for_stream_buffers_( 29 feature_info ? feature_info->workarounds( 30 ).use_client_side_arrays_for_stream_buffers : 0) { 31 } 32 33 BufferManager::~BufferManager() { 34 DCHECK(buffers_.empty()); 35 CHECK_EQ(buffer_count_, 0u); 36 } 37 38 void BufferManager::Destroy(bool have_context) { 39 have_context_ = have_context; 40 buffers_.clear(); 41 DCHECK_EQ(0u, memory_tracker_->GetMemRepresented()); 42 } 43 44 void BufferManager::CreateBuffer(GLuint client_id, GLuint service_id) { 45 scoped_refptr<Buffer> buffer(new Buffer(this, service_id)); 46 std::pair<BufferMap::iterator, bool> result = 47 buffers_.insert(std::make_pair(client_id, buffer)); 48 DCHECK(result.second); 49 } 50 51 Buffer* BufferManager::GetBuffer( 52 GLuint client_id) { 53 BufferMap::iterator it = buffers_.find(client_id); 54 return it != buffers_.end() ? it->second.get() : NULL; 55 } 56 57 void BufferManager::RemoveBuffer(GLuint client_id) { 58 BufferMap::iterator it = buffers_.find(client_id); 59 if (it != buffers_.end()) { 60 Buffer* buffer = it->second.get(); 61 buffer->MarkAsDeleted(); 62 buffers_.erase(it); 63 } 64 } 65 66 void BufferManager::StartTracking(Buffer* /* buffer */) { 67 ++buffer_count_; 68 } 69 70 void BufferManager::StopTracking(Buffer* buffer) { 71 memory_tracker_->TrackMemFree(buffer->size()); 72 --buffer_count_; 73 } 74 75 Buffer::Buffer(BufferManager* manager, GLuint service_id) 76 : manager_(manager), 77 size_(0), 78 deleted_(false), 79 shadowed_(false), 80 is_client_side_array_(false), 81 service_id_(service_id), 82 target_(0), 83 usage_(GL_STATIC_DRAW) { 84 manager_->StartTracking(this); 85 } 86 87 Buffer::~Buffer() { 88 if (manager_) { 89 if (manager_->have_context_) { 90 GLuint id = service_id(); 91 glDeleteBuffersARB(1, &id); 92 } 93 manager_->StopTracking(this); 94 manager_ = NULL; 95 } 96 } 97 98 void Buffer::SetInfo( 99 GLsizeiptr size, GLenum usage, bool shadow, const GLvoid* data, 100 bool is_client_side_array) { 101 usage_ = usage; 102 is_client_side_array_ = is_client_side_array; 103 ClearCache(); 104 if (size != size_ || shadow != shadowed_) { 105 shadowed_ = shadow; 106 size_ = size; 107 if (shadowed_) { 108 shadow_.reset(new int8[size]); 109 } else { 110 shadow_.reset(); 111 } 112 } 113 if (shadowed_) { 114 if (data) { 115 memcpy(shadow_.get(), data, size); 116 } else { 117 memset(shadow_.get(), 0, size); 118 } 119 } 120 } 121 122 bool Buffer::CheckRange( 123 GLintptr offset, GLsizeiptr size) const { 124 int32 end = 0; 125 return offset >= 0 && size >= 0 && 126 offset <= std::numeric_limits<int32>::max() && 127 size <= std::numeric_limits<int32>::max() && 128 SafeAddInt32(offset, size, &end) && end <= size_; 129 } 130 131 bool Buffer::SetRange( 132 GLintptr offset, GLsizeiptr size, const GLvoid * data) { 133 if (!CheckRange(offset, size)) { 134 return false; 135 } 136 if (shadowed_) { 137 memcpy(shadow_.get() + offset, data, size); 138 ClearCache(); 139 } 140 return true; 141 } 142 143 const void* Buffer::GetRange( 144 GLintptr offset, GLsizeiptr size) const { 145 if (!shadowed_) { 146 return NULL; 147 } 148 if (!CheckRange(offset, size)) { 149 return NULL; 150 } 151 return shadow_.get() + offset; 152 } 153 154 void Buffer::ClearCache() { 155 range_set_.clear(); 156 } 157 158 template <typename T> 159 GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count) { 160 GLuint max_value = 0; 161 const T* element = reinterpret_cast<const T*>( 162 static_cast<const int8*>(data) + offset); 163 const T* end = element + count; 164 for (; element < end; ++element) { 165 if (*element > max_value) { 166 max_value = *element; 167 } 168 } 169 return max_value; 170 } 171 172 bool Buffer::GetMaxValueForRange( 173 GLuint offset, GLsizei count, GLenum type, GLuint* max_value) { 174 Range range(offset, count, type); 175 RangeToMaxValueMap::iterator it = range_set_.find(range); 176 if (it != range_set_.end()) { 177 *max_value = it->second; 178 return true; 179 } 180 181 uint32 size; 182 if (!SafeMultiplyUint32( 183 count, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type), &size)) { 184 return false; 185 } 186 187 if (!SafeAddUint32(offset, size, &size)) { 188 return false; 189 } 190 191 if (size > static_cast<uint32>(size_)) { 192 return false; 193 } 194 195 if (!shadowed_) { 196 return false; 197 } 198 199 // Scan the range for the max value and store 200 GLuint max_v = 0; 201 switch (type) { 202 case GL_UNSIGNED_BYTE: 203 max_v = GetMaxValue<uint8>(shadow_.get(), offset, count); 204 break; 205 case GL_UNSIGNED_SHORT: 206 // Check we are not accessing an odd byte for a 2 byte value. 207 if ((offset & 1) != 0) { 208 return false; 209 } 210 max_v = GetMaxValue<uint16>(shadow_.get(), offset, count); 211 break; 212 case GL_UNSIGNED_INT: 213 // Check we are not accessing a non aligned address for a 4 byte value. 214 if ((offset & 3) != 0) { 215 return false; 216 } 217 max_v = GetMaxValue<uint32>(shadow_.get(), offset, count); 218 break; 219 default: 220 NOTREACHED(); // should never get here by validation. 221 break; 222 } 223 range_set_.insert(std::make_pair(range, max_v)); 224 *max_value = max_v; 225 return true; 226 } 227 228 bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const { 229 // This doesn't need to be fast. It's only used during slow queries. 230 for (BufferMap::const_iterator it = buffers_.begin(); 231 it != buffers_.end(); ++it) { 232 if (it->second->service_id() == service_id) { 233 *client_id = it->first; 234 return true; 235 } 236 } 237 return false; 238 } 239 240 bool BufferManager::IsUsageClientSideArray(GLenum usage) { 241 return usage == GL_STREAM_DRAW && use_client_side_arrays_for_stream_buffers_; 242 } 243 244 bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() { 245 return feature_info_.get() && 246 feature_info_->workarounds() 247 .use_non_zero_size_for_client_side_stream_buffers; 248 } 249 250 void BufferManager::SetInfo( 251 Buffer* buffer, GLsizeiptr size, GLenum usage, const GLvoid* data) { 252 DCHECK(buffer); 253 memory_tracker_->TrackMemFree(buffer->size()); 254 bool is_client_side_array = IsUsageClientSideArray(usage); 255 bool shadow = buffer->target() == GL_ELEMENT_ARRAY_BUFFER || 256 allow_buffers_on_multiple_targets_ || 257 is_client_side_array; 258 buffer->SetInfo(size, usage, shadow, data, is_client_side_array); 259 memory_tracker_->TrackMemAlloc(buffer->size()); 260 } 261 262 void BufferManager::ValidateAndDoBufferData( 263 ContextState* context_state, GLenum target, GLsizeiptr size, 264 const GLvoid * data, GLenum usage) { 265 ErrorState* error_state = context_state->GetErrorState(); 266 if (!feature_info_->validators()->buffer_target.IsValid(target)) { 267 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( 268 error_state, "glBufferData", target, "target"); 269 return; 270 } 271 if (!feature_info_->validators()->buffer_usage.IsValid(usage)) { 272 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( 273 error_state, "glBufferData", usage, "usage"); 274 return; 275 } 276 if (size < 0) { 277 ERRORSTATE_SET_GL_ERROR( 278 error_state, GL_INVALID_VALUE, "glBufferData", "size < 0"); 279 return; 280 } 281 282 Buffer* buffer = GetBufferInfoForTarget(context_state, target); 283 if (!buffer) { 284 ERRORSTATE_SET_GL_ERROR( 285 error_state, GL_INVALID_VALUE, "glBufferData", "unknown buffer"); 286 return; 287 } 288 289 if (!memory_tracker_->EnsureGPUMemoryAvailable(size)) { 290 ERRORSTATE_SET_GL_ERROR( 291 error_state, GL_OUT_OF_MEMORY, "glBufferData", "out of memory"); 292 return; 293 } 294 295 DoBufferData(error_state, buffer, size, usage, data); 296 } 297 298 299 void BufferManager::DoBufferData( 300 ErrorState* error_state, 301 Buffer* buffer, 302 GLsizeiptr size, 303 GLenum usage, 304 const GLvoid* data) { 305 // Clear the buffer to 0 if no initial data was passed in. 306 scoped_ptr<int8[]> zero; 307 if (!data) { 308 zero.reset(new int8[size]); 309 memset(zero.get(), 0, size); 310 data = zero.get(); 311 } 312 313 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData"); 314 if (IsUsageClientSideArray(usage)) { 315 GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0; 316 glBufferData(buffer->target(), empty_size, NULL, usage); 317 } else { 318 glBufferData(buffer->target(), size, data, usage); 319 } 320 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData"); 321 if (error == GL_NO_ERROR) { 322 SetInfo(buffer, size, usage, data); 323 } else { 324 SetInfo(buffer, 0, usage, NULL); 325 } 326 } 327 328 void BufferManager::ValidateAndDoBufferSubData( 329 ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size, 330 const GLvoid * data) { 331 ErrorState* error_state = context_state->GetErrorState(); 332 Buffer* buffer = GetBufferInfoForTarget(context_state, target); 333 if (!buffer) { 334 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, "glBufferSubData", 335 "unknown buffer"); 336 return; 337 } 338 339 DoBufferSubData(error_state, buffer, offset, size, data); 340 } 341 342 void BufferManager::DoBufferSubData( 343 ErrorState* error_state, 344 Buffer* buffer, 345 GLintptr offset, 346 GLsizeiptr size, 347 const GLvoid* data) { 348 if (!buffer->SetRange(offset, size, data)) { 349 ERRORSTATE_SET_GL_ERROR( 350 error_state, GL_INVALID_VALUE, "glBufferSubData", "out of range"); 351 return; 352 } 353 354 if (!buffer->IsClientSideArray()) { 355 glBufferSubData(buffer->target(), offset, size, data); 356 } 357 } 358 359 void BufferManager::ValidateAndDoGetBufferParameteriv( 360 ContextState* context_state, GLenum target, GLenum pname, GLint* params) { 361 Buffer* buffer = GetBufferInfoForTarget(context_state, target); 362 if (!buffer) { 363 ERRORSTATE_SET_GL_ERROR( 364 context_state->GetErrorState(), GL_INVALID_OPERATION, 365 "glGetBufferParameteriv", "no buffer bound for target"); 366 return; 367 } 368 switch (pname) { 369 case GL_BUFFER_SIZE: 370 *params = buffer->size(); 371 break; 372 case GL_BUFFER_USAGE: 373 *params = buffer->usage(); 374 break; 375 default: 376 NOTREACHED(); 377 } 378 } 379 380 bool BufferManager::SetTarget(Buffer* buffer, GLenum target) { 381 // Check that we are not trying to bind it to a different target. 382 if (buffer->target() != 0 && buffer->target() != target && 383 !allow_buffers_on_multiple_targets_) { 384 return false; 385 } 386 if (buffer->target() == 0) { 387 buffer->set_target(target); 388 } 389 return true; 390 } 391 392 // Since one BufferManager can be shared by multiple decoders, ContextState is 393 // passed in each time and not just passed in during initialization. 394 Buffer* BufferManager::GetBufferInfoForTarget( 395 ContextState* state, GLenum target) { 396 DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER); 397 if (target == GL_ARRAY_BUFFER) { 398 return state->bound_array_buffer.get(); 399 } else { 400 return state->vertex_attrib_manager->element_array_buffer(); 401 } 402 } 403 404 } // namespace gles2 405 } // namespace gpu 406 407 408