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