Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / service / buffer_manager.cc
blob7b1c90dfbb35d5c633987094b3e75d02b286f87a
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.
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"
16 namespace gpu {
17 namespace gles2 {
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) {
33 BufferManager::~BufferManager() {
34 DCHECK(buffers_.empty());
35 CHECK_EQ(buffer_count_, 0u);
38 void BufferManager::Destroy(bool have_context) {
39 have_context_ = have_context;
40 buffers_.clear();
41 DCHECK_EQ(0u, memory_tracker_->GetMemRepresented());
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);
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;
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);
66 void BufferManager::StartTracking(Buffer* /* buffer */) {
67 ++buffer_count_;
70 void BufferManager::StopTracking(Buffer* buffer) {
71 memory_tracker_->TrackMemFree(buffer->size());
72 --buffer_count_;
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);
87 Buffer::~Buffer() {
88 if (manager_) {
89 if (manager_->have_context_) {
90 GLuint id = service_id();
91 glDeleteBuffersARB(1, &id);
93 manager_->StopTracking(this);
94 manager_ = NULL;
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();
113 if (shadowed_) {
114 if (data) {
115 memcpy(shadow_.get(), data, size);
116 } else {
117 memset(shadow_.get(), 0, size);
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_;
131 bool Buffer::SetRange(
132 GLintptr offset, GLsizeiptr size, const GLvoid * data) {
133 if (!CheckRange(offset, size)) {
134 return false;
136 if (shadowed_) {
137 memcpy(shadow_.get() + offset, data, size);
138 ClearCache();
140 return true;
143 const void* Buffer::GetRange(
144 GLintptr offset, GLsizeiptr size) const {
145 if (!shadowed_) {
146 return NULL;
148 if (!CheckRange(offset, size)) {
149 return NULL;
151 return shadow_.get() + offset;
154 void Buffer::ClearCache() {
155 range_set_.clear();
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;
169 return max_value;
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;
181 uint32 size;
182 if (!SafeMultiplyUint32(
183 count, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type), &size)) {
184 return false;
187 if (!SafeAddUint32(offset, size, &size)) {
188 return false;
191 if (size > static_cast<uint32>(size_)) {
192 return false;
195 if (!shadowed_) {
196 return false;
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;
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;
217 max_v = GetMaxValue<uint32>(shadow_.get(), offset, count);
218 break;
219 default:
220 NOTREACHED(); // should never get here by validation.
221 break;
223 range_set_.insert(std::make_pair(range, max_v));
224 *max_value = max_v;
225 return true;
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;
237 return false;
240 bool BufferManager::IsUsageClientSideArray(GLenum usage) {
241 return usage == GL_STREAM_DRAW && use_client_side_arrays_for_stream_buffers_;
244 bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() {
245 return feature_info_.get() &&
246 feature_info_->workarounds()
247 .use_non_zero_size_for_client_side_stream_buffers;
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());
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;
271 if (!feature_info_->validators()->buffer_usage.IsValid(usage)) {
272 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
273 error_state, "glBufferData", usage, "usage");
274 return;
276 if (size < 0) {
277 ERRORSTATE_SET_GL_ERROR(
278 error_state, GL_INVALID_VALUE, "glBufferData", "size < 0");
279 return;
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;
289 if (!memory_tracker_->EnsureGPUMemoryAvailable(size)) {
290 ERRORSTATE_SET_GL_ERROR(
291 error_state, GL_OUT_OF_MEMORY, "glBufferData", "out of memory");
292 return;
295 DoBufferData(error_state, buffer, size, usage, data);
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();
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);
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);
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;
339 DoBufferSubData(error_state, buffer, offset, size, data);
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;
354 if (!buffer->IsClientSideArray()) {
355 glBufferSubData(buffer->target(), offset, size, data);
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;
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();
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;
386 if (buffer->target() == 0) {
387 buffer->set_target(target);
389 return true;
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();
404 } // namespace gles2
405 } // namespace gpu