Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / gpu / command_buffer / service / buffer_manager.cc
blob6b12f83d71257f4df7c787fa7e77f4ea71f24acc
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/logging.h"
8 #include "base/trace_event/trace_event.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 #include "ui/gl/gl_implementation.h"
17 namespace gpu {
18 namespace gles2 {
20 BufferManager::BufferManager(
21 MemoryTracker* memory_tracker,
22 FeatureInfo* feature_info)
23 : memory_tracker_(
24 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
25 feature_info_(feature_info),
26 allow_buffers_on_multiple_targets_(false),
27 allow_fixed_attribs_(false),
28 buffer_count_(0),
29 have_context_(true),
30 use_client_side_arrays_for_stream_buffers_(
31 feature_info ? feature_info->workarounds(
32 ).use_client_side_arrays_for_stream_buffers : 0) {
35 BufferManager::~BufferManager() {
36 DCHECK(buffers_.empty());
37 CHECK_EQ(buffer_count_, 0u);
40 void BufferManager::Destroy(bool have_context) {
41 have_context_ = have_context;
42 buffers_.clear();
43 DCHECK_EQ(0u, memory_tracker_->GetMemRepresented());
46 void BufferManager::CreateBuffer(GLuint client_id, GLuint service_id) {
47 scoped_refptr<Buffer> buffer(new Buffer(this, service_id));
48 std::pair<BufferMap::iterator, bool> result =
49 buffers_.insert(std::make_pair(client_id, buffer));
50 DCHECK(result.second);
53 Buffer* BufferManager::GetBuffer(
54 GLuint client_id) {
55 BufferMap::iterator it = buffers_.find(client_id);
56 return it != buffers_.end() ? it->second.get() : NULL;
59 void BufferManager::RemoveBuffer(GLuint client_id) {
60 BufferMap::iterator it = buffers_.find(client_id);
61 if (it != buffers_.end()) {
62 Buffer* buffer = it->second.get();
63 buffer->MarkAsDeleted();
64 buffers_.erase(it);
68 void BufferManager::StartTracking(Buffer* /* buffer */) {
69 ++buffer_count_;
72 void BufferManager::StopTracking(Buffer* buffer) {
73 memory_tracker_->TrackMemFree(buffer->size());
74 --buffer_count_;
77 Buffer::MappedRange::MappedRange(
78 GLintptr offset, GLsizeiptr size, GLenum access, void* pointer,
79 scoped_refptr<gpu::Buffer> shm)
80 : offset(offset),
81 size(size),
82 access(access),
83 pointer(pointer),
84 shm(shm) {
85 DCHECK(pointer);
86 DCHECK(shm.get() && GetShmPointer());
89 Buffer::MappedRange::~MappedRange() {
92 void* Buffer::MappedRange::GetShmPointer() const {
93 DCHECK(shm.get());
94 return shm->GetDataAddress(static_cast<unsigned int>(offset),
95 static_cast<unsigned int>(size));
98 Buffer::Buffer(BufferManager* manager, GLuint service_id)
99 : manager_(manager),
100 size_(0),
101 deleted_(false),
102 shadowed_(false),
103 is_client_side_array_(false),
104 service_id_(service_id),
105 initial_target_(0),
106 usage_(GL_STATIC_DRAW) {
107 manager_->StartTracking(this);
110 Buffer::~Buffer() {
111 if (manager_) {
112 if (manager_->have_context_) {
113 GLuint id = service_id();
114 glDeleteBuffersARB(1, &id);
116 manager_->StopTracking(this);
117 manager_ = NULL;
121 void Buffer::SetInfo(
122 GLsizeiptr size, GLenum usage, bool shadow, const GLvoid* data,
123 bool is_client_side_array) {
124 usage_ = usage;
125 is_client_side_array_ = is_client_side_array;
126 ClearCache();
127 if (size != size_ || shadow != shadowed_) {
128 shadowed_ = shadow;
129 size_ = size;
130 if (shadowed_) {
131 shadow_.reset(new int8[size]);
132 } else {
133 shadow_.reset();
136 if (shadowed_) {
137 if (data) {
138 memcpy(shadow_.get(), data, size);
139 } else {
140 memset(shadow_.get(), 0, size);
143 mapped_range_.reset(nullptr);
146 bool Buffer::CheckRange(
147 GLintptr offset, GLsizeiptr size) const {
148 int32 end = 0;
149 return offset >= 0 && size >= 0 &&
150 offset <= std::numeric_limits<int32>::max() &&
151 size <= std::numeric_limits<int32>::max() &&
152 SafeAddInt32(offset, size, &end) && end <= size_;
155 bool Buffer::SetRange(
156 GLintptr offset, GLsizeiptr size, const GLvoid * data) {
157 if (!CheckRange(offset, size)) {
158 return false;
160 if (shadowed_) {
161 memcpy(shadow_.get() + offset, data, size);
162 ClearCache();
164 return true;
167 const void* Buffer::GetRange(
168 GLintptr offset, GLsizeiptr size) const {
169 if (!shadowed_) {
170 return NULL;
172 if (!CheckRange(offset, size)) {
173 return NULL;
175 return shadow_.get() + offset;
178 void Buffer::ClearCache() {
179 range_set_.clear();
182 template <typename T>
183 GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count) {
184 GLuint max_value = 0;
185 const T* element = reinterpret_cast<const T*>(
186 static_cast<const int8*>(data) + offset);
187 const T* end = element + count;
188 for (; element < end; ++element) {
189 if (*element > max_value) {
190 max_value = *element;
193 return max_value;
196 bool Buffer::GetMaxValueForRange(
197 GLuint offset, GLsizei count, GLenum type, GLuint* max_value) {
198 Range range(offset, count, type);
199 RangeToMaxValueMap::iterator it = range_set_.find(range);
200 if (it != range_set_.end()) {
201 *max_value = it->second;
202 return true;
205 uint32 size;
206 if (!SafeMultiplyUint32(
207 count, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type), &size)) {
208 return false;
211 if (!SafeAddUint32(offset, size, &size)) {
212 return false;
215 if (size > static_cast<uint32>(size_)) {
216 return false;
219 if (!shadowed_) {
220 return false;
223 // Scan the range for the max value and store
224 GLuint max_v = 0;
225 switch (type) {
226 case GL_UNSIGNED_BYTE:
227 max_v = GetMaxValue<uint8>(shadow_.get(), offset, count);
228 break;
229 case GL_UNSIGNED_SHORT:
230 // Check we are not accessing an odd byte for a 2 byte value.
231 if ((offset & 1) != 0) {
232 return false;
234 max_v = GetMaxValue<uint16>(shadow_.get(), offset, count);
235 break;
236 case GL_UNSIGNED_INT:
237 // Check we are not accessing a non aligned address for a 4 byte value.
238 if ((offset & 3) != 0) {
239 return false;
241 max_v = GetMaxValue<uint32>(shadow_.get(), offset, count);
242 break;
243 default:
244 NOTREACHED(); // should never get here by validation.
245 break;
247 range_set_.insert(std::make_pair(range, max_v));
248 *max_value = max_v;
249 return true;
252 bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const {
253 // This doesn't need to be fast. It's only used during slow queries.
254 for (BufferMap::const_iterator it = buffers_.begin();
255 it != buffers_.end(); ++it) {
256 if (it->second->service_id() == service_id) {
257 *client_id = it->first;
258 return true;
261 return false;
264 bool BufferManager::IsUsageClientSideArray(GLenum usage) {
265 return usage == GL_STREAM_DRAW && use_client_side_arrays_for_stream_buffers_;
268 bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() {
269 return feature_info_.get() &&
270 feature_info_->workarounds()
271 .use_non_zero_size_for_client_side_stream_buffers;
274 void BufferManager::SetInfo(Buffer* buffer, GLenum target, GLsizeiptr size,
275 GLenum usage, const GLvoid* data) {
276 DCHECK(buffer);
277 memory_tracker_->TrackMemFree(buffer->size());
278 const bool is_client_side_array = IsUsageClientSideArray(usage);
279 const bool support_fixed_attribs =
280 gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
281 // TODO(zmo): Don't shadow buffer data on ES3. crbug.com/491002.
282 const bool shadow = target == GL_ELEMENT_ARRAY_BUFFER ||
283 allow_buffers_on_multiple_targets_ ||
284 (allow_fixed_attribs_ && !support_fixed_attribs) ||
285 is_client_side_array;
286 buffer->SetInfo(size, usage, shadow, data, is_client_side_array);
287 memory_tracker_->TrackMemAlloc(buffer->size());
290 void BufferManager::ValidateAndDoBufferData(
291 ContextState* context_state, GLenum target, GLsizeiptr size,
292 const GLvoid* data, GLenum usage) {
293 ErrorState* error_state = context_state->GetErrorState();
294 if (!feature_info_->validators()->buffer_target.IsValid(target)) {
295 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
296 error_state, "glBufferData", target, "target");
297 return;
299 if (!feature_info_->validators()->buffer_usage.IsValid(usage)) {
300 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
301 error_state, "glBufferData", usage, "usage");
302 return;
304 if (size < 0) {
305 ERRORSTATE_SET_GL_ERROR(
306 error_state, GL_INVALID_VALUE, "glBufferData", "size < 0");
307 return;
310 Buffer* buffer = GetBufferInfoForTarget(context_state, target);
311 if (!buffer) {
312 ERRORSTATE_SET_GL_ERROR(
313 error_state, GL_INVALID_VALUE, "glBufferData", "unknown buffer");
314 return;
317 if (!memory_tracker_->EnsureGPUMemoryAvailable(size)) {
318 ERRORSTATE_SET_GL_ERROR(
319 error_state, GL_OUT_OF_MEMORY, "glBufferData", "out of memory");
320 return;
323 DoBufferData(error_state, buffer, target, size, usage, data);
327 void BufferManager::DoBufferData(
328 ErrorState* error_state,
329 Buffer* buffer,
330 GLenum target,
331 GLsizeiptr size,
332 GLenum usage,
333 const GLvoid* data) {
334 // Clear the buffer to 0 if no initial data was passed in.
335 scoped_ptr<int8[]> zero;
336 if (!data) {
337 zero.reset(new int8[size]);
338 memset(zero.get(), 0, size);
339 data = zero.get();
342 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData");
343 if (IsUsageClientSideArray(usage)) {
344 GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0;
345 glBufferData(target, empty_size, NULL, usage);
346 } else {
347 glBufferData(target, size, data, usage);
349 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData");
350 if (error == GL_NO_ERROR) {
351 SetInfo(buffer, target, size, usage, data);
352 } else {
353 SetInfo(buffer, target, 0, usage, NULL);
357 void BufferManager::ValidateAndDoBufferSubData(
358 ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size,
359 const GLvoid * data) {
360 ErrorState* error_state = context_state->GetErrorState();
361 Buffer* buffer = GetBufferInfoForTarget(context_state, target);
362 if (!buffer) {
363 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, "glBufferSubData",
364 "unknown buffer");
365 return;
368 DoBufferSubData(error_state, buffer, target, offset, size, data);
371 void BufferManager::DoBufferSubData(
372 ErrorState* error_state,
373 Buffer* buffer,
374 GLenum target,
375 GLintptr offset,
376 GLsizeiptr size,
377 const GLvoid* data) {
378 if (!buffer->SetRange(offset, size, data)) {
379 ERRORSTATE_SET_GL_ERROR(
380 error_state, GL_INVALID_VALUE, "glBufferSubData", "out of range");
381 return;
384 if (!buffer->IsClientSideArray()) {
385 glBufferSubData(target, offset, size, data);
389 void BufferManager::ValidateAndDoGetBufferParameteriv(
390 ContextState* context_state, GLenum target, GLenum pname, GLint* params) {
391 Buffer* buffer = GetBufferInfoForTarget(context_state, target);
392 if (!buffer) {
393 ERRORSTATE_SET_GL_ERROR(
394 context_state->GetErrorState(), GL_INVALID_OPERATION,
395 "glGetBufferParameteriv", "no buffer bound for target");
396 return;
398 switch (pname) {
399 case GL_BUFFER_SIZE:
400 *params = buffer->size();
401 break;
402 case GL_BUFFER_USAGE:
403 *params = buffer->usage();
404 break;
405 default:
406 NOTREACHED();
410 bool BufferManager::SetTarget(Buffer* buffer, GLenum target) {
411 if (!allow_buffers_on_multiple_targets_) {
412 // After being bound to ELEMENT_ARRAY_BUFFER target, a buffer cannot be
413 // bound to any other targets except for COPY_READ/WRITE_BUFFER target;
414 // After being bound to non ELEMENT_ARRAY_BUFFER target, a buffer cannot
415 // be bound to ELEMENT_ARRAY_BUFFER target.
417 // Note that we don't force the WebGL 2 rule that a buffer bound to
418 // TRANSFORM_FEEDBACK_BUFFER target should not be bound to any other
419 // targets, because that is not a security threat, so we only enforce it
420 // in the WebGL2RenderingContextBase.
421 switch (buffer->initial_target()) {
422 case GL_ELEMENT_ARRAY_BUFFER:
423 switch (target) {
424 case GL_ARRAY_BUFFER:
425 case GL_PIXEL_PACK_BUFFER:
426 case GL_PIXEL_UNPACK_BUFFER:
427 case GL_TRANSFORM_FEEDBACK_BUFFER:
428 case GL_UNIFORM_BUFFER:
429 return false;
430 default:
431 break;
433 break;
434 case GL_ARRAY_BUFFER:
435 case GL_COPY_READ_BUFFER:
436 case GL_COPY_WRITE_BUFFER:
437 case GL_PIXEL_PACK_BUFFER:
438 case GL_PIXEL_UNPACK_BUFFER:
439 case GL_TRANSFORM_FEEDBACK_BUFFER:
440 case GL_UNIFORM_BUFFER:
441 if (target == GL_ELEMENT_ARRAY_BUFFER) {
442 return false;
444 break;
445 default:
446 break;
449 if (buffer->initial_target() == 0)
450 buffer->set_initial_target(target);
451 return true;
454 // Since one BufferManager can be shared by multiple decoders, ContextState is
455 // passed in each time and not just passed in during initialization.
456 Buffer* BufferManager::GetBufferInfoForTarget(
457 ContextState* state, GLenum target) const {
458 switch (target) {
459 case GL_ARRAY_BUFFER:
460 return state->bound_array_buffer.get();
461 case GL_ELEMENT_ARRAY_BUFFER:
462 return state->vertex_attrib_manager->element_array_buffer();
463 case GL_COPY_READ_BUFFER:
464 return state->bound_copy_read_buffer.get();
465 case GL_COPY_WRITE_BUFFER:
466 return state->bound_copy_write_buffer.get();
467 case GL_PIXEL_PACK_BUFFER:
468 return state->bound_pixel_pack_buffer.get();
469 case GL_PIXEL_UNPACK_BUFFER:
470 return state->bound_pixel_unpack_buffer.get();
471 case GL_TRANSFORM_FEEDBACK_BUFFER:
472 return state->bound_transform_feedback_buffer.get();
473 case GL_UNIFORM_BUFFER:
474 return state->bound_uniform_buffer.get();
475 default:
476 NOTREACHED();
477 return nullptr;
481 } // namespace gles2
482 } // namespace gpu