Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / gpu / command_buffer / service / buffer_manager.cc
blobe5fb1fe78964fe471abf79f915e453ed563a338a
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/strings/stringprintf.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "base/trace_event/memory_dump_manager.h"
11 #include "base/trace_event/trace_event.h"
12 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
13 #include "gpu/command_buffer/service/context_state.h"
14 #include "gpu/command_buffer/service/error_state.h"
15 #include "gpu/command_buffer/service/feature_info.h"
16 #include "gpu/command_buffer/service/memory_tracking.h"
17 #include "ui/gl/gl_bindings.h"
18 #include "ui/gl/gl_implementation.h"
19 #include "ui/gl/trace_util.h"
21 namespace gpu {
22 namespace gles2 {
24 BufferManager::BufferManager(MemoryTracker* memory_tracker,
25 FeatureInfo* feature_info)
26 : memory_type_tracker_(
27 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
28 memory_tracker_(memory_tracker),
29 feature_info_(feature_info),
30 allow_buffers_on_multiple_targets_(false),
31 allow_fixed_attribs_(false),
32 buffer_count_(0),
33 have_context_(true),
34 use_client_side_arrays_for_stream_buffers_(
35 feature_info
36 ? feature_info->workarounds()
37 .use_client_side_arrays_for_stream_buffers
38 : 0) {
39 // When created from InProcessCommandBuffer, we won't have a |memory_tracker_|
40 // so don't register a dump provider.
41 if (memory_tracker_) {
42 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
43 this, base::ThreadTaskRunnerHandle::Get());
47 BufferManager::~BufferManager() {
48 DCHECK(buffers_.empty());
49 CHECK_EQ(buffer_count_, 0u);
51 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
52 this);
55 void BufferManager::Destroy(bool have_context) {
56 have_context_ = have_context;
57 buffers_.clear();
58 DCHECK_EQ(0u, memory_type_tracker_->GetMemRepresented());
61 void BufferManager::CreateBuffer(GLuint client_id, GLuint service_id) {
62 scoped_refptr<Buffer> buffer(new Buffer(this, service_id));
63 std::pair<BufferMap::iterator, bool> result =
64 buffers_.insert(std::make_pair(client_id, buffer));
65 DCHECK(result.second);
68 Buffer* BufferManager::GetBuffer(
69 GLuint client_id) {
70 BufferMap::iterator it = buffers_.find(client_id);
71 return it != buffers_.end() ? it->second.get() : NULL;
74 void BufferManager::RemoveBuffer(GLuint client_id) {
75 BufferMap::iterator it = buffers_.find(client_id);
76 if (it != buffers_.end()) {
77 Buffer* buffer = it->second.get();
78 buffer->MarkAsDeleted();
79 buffers_.erase(it);
83 void BufferManager::StartTracking(Buffer* /* buffer */) {
84 ++buffer_count_;
87 void BufferManager::StopTracking(Buffer* buffer) {
88 memory_type_tracker_->TrackMemFree(buffer->size());
89 --buffer_count_;
92 Buffer::MappedRange::MappedRange(
93 GLintptr offset, GLsizeiptr size, GLenum access, void* pointer,
94 scoped_refptr<gpu::Buffer> shm)
95 : offset(offset),
96 size(size),
97 access(access),
98 pointer(pointer),
99 shm(shm) {
100 DCHECK(pointer);
101 DCHECK(shm.get() && GetShmPointer());
104 Buffer::MappedRange::~MappedRange() {
107 void* Buffer::MappedRange::GetShmPointer() const {
108 DCHECK(shm.get());
109 return shm->GetDataAddress(static_cast<unsigned int>(offset),
110 static_cast<unsigned int>(size));
113 Buffer::Buffer(BufferManager* manager, GLuint service_id)
114 : manager_(manager),
115 size_(0),
116 deleted_(false),
117 shadowed_(false),
118 is_client_side_array_(false),
119 service_id_(service_id),
120 initial_target_(0),
121 usage_(GL_STATIC_DRAW) {
122 manager_->StartTracking(this);
125 Buffer::~Buffer() {
126 if (manager_) {
127 if (manager_->have_context_) {
128 GLuint id = service_id();
129 glDeleteBuffersARB(1, &id);
131 manager_->StopTracking(this);
132 manager_ = NULL;
136 void Buffer::SetInfo(
137 GLsizeiptr size, GLenum usage, bool shadow, const GLvoid* data,
138 bool is_client_side_array) {
139 usage_ = usage;
140 is_client_side_array_ = is_client_side_array;
141 ClearCache();
142 if (size != size_ || shadow != shadowed_) {
143 shadowed_ = shadow;
144 size_ = size;
145 if (shadowed_) {
146 shadow_.reset(new int8[size]);
147 } else {
148 shadow_.reset();
151 if (shadowed_) {
152 if (data) {
153 memcpy(shadow_.get(), data, size);
154 } else {
155 memset(shadow_.get(), 0, size);
158 mapped_range_.reset(nullptr);
161 bool Buffer::CheckRange(
162 GLintptr offset, GLsizeiptr size) const {
163 int32 end = 0;
164 return offset >= 0 && size >= 0 &&
165 offset <= std::numeric_limits<int32>::max() &&
166 size <= std::numeric_limits<int32>::max() &&
167 SafeAddInt32(offset, size, &end) && end <= size_;
170 bool Buffer::SetRange(
171 GLintptr offset, GLsizeiptr size, const GLvoid * data) {
172 if (!CheckRange(offset, size)) {
173 return false;
175 if (shadowed_) {
176 memcpy(shadow_.get() + offset, data, size);
177 ClearCache();
179 return true;
182 const void* Buffer::GetRange(
183 GLintptr offset, GLsizeiptr size) const {
184 if (!shadowed_) {
185 return NULL;
187 if (!CheckRange(offset, size)) {
188 return NULL;
190 return shadow_.get() + offset;
193 void Buffer::ClearCache() {
194 range_set_.clear();
197 template <typename T>
198 GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count) {
199 GLuint max_value = 0;
200 const T* element = reinterpret_cast<const T*>(
201 static_cast<const int8*>(data) + offset);
202 const T* end = element + count;
203 for (; element < end; ++element) {
204 if (*element > max_value) {
205 max_value = *element;
208 return max_value;
211 bool Buffer::GetMaxValueForRange(
212 GLuint offset, GLsizei count, GLenum type, GLuint* max_value) {
213 Range range(offset, count, type);
214 RangeToMaxValueMap::iterator it = range_set_.find(range);
215 if (it != range_set_.end()) {
216 *max_value = it->second;
217 return true;
220 uint32 size;
221 if (!SafeMultiplyUint32(
222 count, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type), &size)) {
223 return false;
226 if (!SafeAddUint32(offset, size, &size)) {
227 return false;
230 if (size > static_cast<uint32>(size_)) {
231 return false;
234 if (!shadowed_) {
235 return false;
238 // Scan the range for the max value and store
239 GLuint max_v = 0;
240 switch (type) {
241 case GL_UNSIGNED_BYTE:
242 max_v = GetMaxValue<uint8>(shadow_.get(), offset, count);
243 break;
244 case GL_UNSIGNED_SHORT:
245 // Check we are not accessing an odd byte for a 2 byte value.
246 if ((offset & 1) != 0) {
247 return false;
249 max_v = GetMaxValue<uint16>(shadow_.get(), offset, count);
250 break;
251 case GL_UNSIGNED_INT:
252 // Check we are not accessing a non aligned address for a 4 byte value.
253 if ((offset & 3) != 0) {
254 return false;
256 max_v = GetMaxValue<uint32>(shadow_.get(), offset, count);
257 break;
258 default:
259 NOTREACHED(); // should never get here by validation.
260 break;
262 range_set_.insert(std::make_pair(range, max_v));
263 *max_value = max_v;
264 return true;
267 bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const {
268 // This doesn't need to be fast. It's only used during slow queries.
269 for (BufferMap::const_iterator it = buffers_.begin();
270 it != buffers_.end(); ++it) {
271 if (it->second->service_id() == service_id) {
272 *client_id = it->first;
273 return true;
276 return false;
279 bool BufferManager::IsUsageClientSideArray(GLenum usage) {
280 return usage == GL_STREAM_DRAW && use_client_side_arrays_for_stream_buffers_;
283 bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() {
284 return feature_info_.get() &&
285 feature_info_->workarounds()
286 .use_non_zero_size_for_client_side_stream_buffers;
289 void BufferManager::SetInfo(Buffer* buffer, GLenum target, GLsizeiptr size,
290 GLenum usage, const GLvoid* data) {
291 DCHECK(buffer);
292 memory_type_tracker_->TrackMemFree(buffer->size());
293 const bool is_client_side_array = IsUsageClientSideArray(usage);
294 const bool support_fixed_attribs =
295 gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
296 // TODO(zmo): Don't shadow buffer data on ES3. crbug.com/491002.
297 const bool shadow = target == GL_ELEMENT_ARRAY_BUFFER ||
298 allow_buffers_on_multiple_targets_ ||
299 (allow_fixed_attribs_ && !support_fixed_attribs) ||
300 is_client_side_array;
301 buffer->SetInfo(size, usage, shadow, data, is_client_side_array);
302 memory_type_tracker_->TrackMemAlloc(buffer->size());
305 void BufferManager::ValidateAndDoBufferData(
306 ContextState* context_state, GLenum target, GLsizeiptr size,
307 const GLvoid* data, GLenum usage) {
308 ErrorState* error_state = context_state->GetErrorState();
309 if (!feature_info_->validators()->buffer_target.IsValid(target)) {
310 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
311 error_state, "glBufferData", target, "target");
312 return;
314 if (!feature_info_->validators()->buffer_usage.IsValid(usage)) {
315 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
316 error_state, "glBufferData", usage, "usage");
317 return;
319 if (size < 0) {
320 ERRORSTATE_SET_GL_ERROR(
321 error_state, GL_INVALID_VALUE, "glBufferData", "size < 0");
322 return;
325 Buffer* buffer = GetBufferInfoForTarget(context_state, target);
326 if (!buffer) {
327 ERRORSTATE_SET_GL_ERROR(
328 error_state, GL_INVALID_VALUE, "glBufferData", "unknown buffer");
329 return;
332 if (!memory_type_tracker_->EnsureGPUMemoryAvailable(size)) {
333 ERRORSTATE_SET_GL_ERROR(
334 error_state, GL_OUT_OF_MEMORY, "glBufferData", "out of memory");
335 return;
338 DoBufferData(error_state, buffer, target, size, usage, data);
342 void BufferManager::DoBufferData(
343 ErrorState* error_state,
344 Buffer* buffer,
345 GLenum target,
346 GLsizeiptr size,
347 GLenum usage,
348 const GLvoid* data) {
349 // Clear the buffer to 0 if no initial data was passed in.
350 scoped_ptr<int8[]> zero;
351 if (!data) {
352 zero.reset(new int8[size]);
353 memset(zero.get(), 0, size);
354 data = zero.get();
357 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData");
358 if (IsUsageClientSideArray(usage)) {
359 GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0;
360 glBufferData(target, empty_size, NULL, usage);
361 } else {
362 glBufferData(target, size, data, usage);
364 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData");
365 if (error == GL_NO_ERROR) {
366 SetInfo(buffer, target, size, usage, data);
367 } else {
368 SetInfo(buffer, target, 0, usage, NULL);
372 void BufferManager::ValidateAndDoBufferSubData(
373 ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size,
374 const GLvoid * data) {
375 ErrorState* error_state = context_state->GetErrorState();
376 Buffer* buffer = GetBufferInfoForTarget(context_state, target);
377 if (!buffer) {
378 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, "glBufferSubData",
379 "unknown buffer");
380 return;
383 DoBufferSubData(error_state, buffer, target, offset, size, data);
386 void BufferManager::DoBufferSubData(
387 ErrorState* error_state,
388 Buffer* buffer,
389 GLenum target,
390 GLintptr offset,
391 GLsizeiptr size,
392 const GLvoid* data) {
393 if (!buffer->SetRange(offset, size, data)) {
394 ERRORSTATE_SET_GL_ERROR(
395 error_state, GL_INVALID_VALUE, "glBufferSubData", "out of range");
396 return;
399 if (!buffer->IsClientSideArray()) {
400 glBufferSubData(target, offset, size, data);
404 void BufferManager::ValidateAndDoGetBufferParameteri64v(
405 ContextState* context_state, GLenum target, GLenum pname, GLint64* params) {
406 Buffer* buffer = GetBufferInfoForTarget(context_state, target);
407 if (!buffer) {
408 ERRORSTATE_SET_GL_ERROR(
409 context_state->GetErrorState(), GL_INVALID_OPERATION,
410 "glGetBufferParameteri64v", "no buffer bound for target");
411 return;
413 switch (pname) {
414 case GL_BUFFER_SIZE:
415 *params = buffer->size();
416 break;
417 case GL_BUFFER_MAP_LENGTH:
419 const Buffer::MappedRange* mapped_range = buffer->GetMappedRange();
420 *params = mapped_range ? mapped_range->size : 0;
421 break;
423 case GL_BUFFER_MAP_OFFSET:
425 const Buffer::MappedRange* mapped_range = buffer->GetMappedRange();
426 *params = mapped_range ? mapped_range->offset : 0;
427 break;
429 default:
430 NOTREACHED();
434 void BufferManager::ValidateAndDoGetBufferParameteriv(
435 ContextState* context_state, GLenum target, GLenum pname, GLint* params) {
436 Buffer* buffer = GetBufferInfoForTarget(context_state, target);
437 if (!buffer) {
438 ERRORSTATE_SET_GL_ERROR(
439 context_state->GetErrorState(), GL_INVALID_OPERATION,
440 "glGetBufferParameteriv", "no buffer bound for target");
441 return;
443 switch (pname) {
444 case GL_BUFFER_SIZE:
445 *params = buffer->size();
446 break;
447 case GL_BUFFER_USAGE:
448 *params = buffer->usage();
449 break;
450 case GL_BUFFER_ACCESS_FLAGS:
452 const Buffer::MappedRange* mapped_range = buffer->GetMappedRange();
453 *params = mapped_range ? mapped_range->access : 0;
454 break;
456 case GL_BUFFER_MAPPED:
457 *params = buffer->GetMappedRange() == nullptr ? false : true;
458 break;
459 default:
460 NOTREACHED();
464 bool BufferManager::SetTarget(Buffer* buffer, GLenum target) {
465 if (!allow_buffers_on_multiple_targets_) {
466 // After being bound to ELEMENT_ARRAY_BUFFER target, a buffer cannot be
467 // bound to any other targets except for COPY_READ/WRITE_BUFFER target;
468 // After being bound to non ELEMENT_ARRAY_BUFFER target, a buffer cannot
469 // be bound to ELEMENT_ARRAY_BUFFER target.
471 // Note that we don't force the WebGL 2 rule that a buffer bound to
472 // TRANSFORM_FEEDBACK_BUFFER target should not be bound to any other
473 // targets, because that is not a security threat, so we only enforce it
474 // in the WebGL2RenderingContextBase.
475 switch (buffer->initial_target()) {
476 case GL_ELEMENT_ARRAY_BUFFER:
477 switch (target) {
478 case GL_ARRAY_BUFFER:
479 case GL_PIXEL_PACK_BUFFER:
480 case GL_PIXEL_UNPACK_BUFFER:
481 case GL_TRANSFORM_FEEDBACK_BUFFER:
482 case GL_UNIFORM_BUFFER:
483 return false;
484 default:
485 break;
487 break;
488 case GL_ARRAY_BUFFER:
489 case GL_COPY_READ_BUFFER:
490 case GL_COPY_WRITE_BUFFER:
491 case GL_PIXEL_PACK_BUFFER:
492 case GL_PIXEL_UNPACK_BUFFER:
493 case GL_TRANSFORM_FEEDBACK_BUFFER:
494 case GL_UNIFORM_BUFFER:
495 if (target == GL_ELEMENT_ARRAY_BUFFER) {
496 return false;
498 break;
499 default:
500 break;
503 if (buffer->initial_target() == 0)
504 buffer->set_initial_target(target);
505 return true;
508 // Since one BufferManager can be shared by multiple decoders, ContextState is
509 // passed in each time and not just passed in during initialization.
510 Buffer* BufferManager::GetBufferInfoForTarget(
511 ContextState* state, GLenum target) const {
512 switch (target) {
513 case GL_ARRAY_BUFFER:
514 return state->bound_array_buffer.get();
515 case GL_ELEMENT_ARRAY_BUFFER:
516 return state->vertex_attrib_manager->element_array_buffer();
517 case GL_COPY_READ_BUFFER:
518 return state->bound_copy_read_buffer.get();
519 case GL_COPY_WRITE_BUFFER:
520 return state->bound_copy_write_buffer.get();
521 case GL_PIXEL_PACK_BUFFER:
522 return state->bound_pixel_pack_buffer.get();
523 case GL_PIXEL_UNPACK_BUFFER:
524 return state->bound_pixel_unpack_buffer.get();
525 case GL_TRANSFORM_FEEDBACK_BUFFER:
526 return state->bound_transform_feedback_buffer.get();
527 case GL_UNIFORM_BUFFER:
528 return state->bound_uniform_buffer.get();
529 default:
530 NOTREACHED();
531 return nullptr;
535 bool BufferManager::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
536 base::trace_event::ProcessMemoryDump* pmd) {
537 const int client_id = memory_tracker_->ClientId();
538 for (const auto& buffer_entry : buffers_) {
539 const auto& client_buffer_id = buffer_entry.first;
540 const auto& buffer = buffer_entry.second;
542 std::string dump_name = base::StringPrintf("gl/client_%d/buffers/buffer_%d",
543 client_id, client_buffer_id);
544 base::trace_event::MemoryAllocatorDump* dump =
545 pmd->CreateAllocatorDump(dump_name);
546 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
547 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
548 static_cast<uint64_t>(buffer->size()));
550 auto guid = gfx::GetGLBufferGUIDForTracing(
551 memory_tracker_->ClientTracingId(), client_buffer_id);
552 pmd->CreateSharedGlobalAllocatorDump(guid);
553 pmd->AddOwnershipEdge(dump->guid(), guid);
555 return true;
558 } // namespace gles2
559 } // namespace gpu