OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "gpu/command_buffer/service/buffer_manager.h" | 5 #include "gpu/command_buffer/service/buffer_manager.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <limits> | 9 #include <limits> |
10 | 10 |
(...skipping 29 matching lines...) Expand all Loading... |
40 max_buffer_size_(kDefaultMaxBufferSize), | 40 max_buffer_size_(kDefaultMaxBufferSize), |
41 allow_buffers_on_multiple_targets_(false), | 41 allow_buffers_on_multiple_targets_(false), |
42 allow_fixed_attribs_(false), | 42 allow_fixed_attribs_(false), |
43 buffer_count_(0), | 43 buffer_count_(0), |
44 primitive_restart_fixed_index_(0), | 44 primitive_restart_fixed_index_(0), |
45 lost_context_(false), | 45 lost_context_(false), |
46 use_client_side_arrays_for_stream_buffers_( | 46 use_client_side_arrays_for_stream_buffers_( |
47 feature_info | 47 feature_info |
48 ? feature_info->workarounds() | 48 ? feature_info->workarounds() |
49 .use_client_side_arrays_for_stream_buffers | 49 .use_client_side_arrays_for_stream_buffers |
50 : 0) { | 50 : 0), |
| 51 mapped_buffer_count_(0) { |
51 // When created from InProcessCommandBuffer, we won't have a |memory_tracker_| | 52 // When created from InProcessCommandBuffer, we won't have a |memory_tracker_| |
52 // so don't register a dump provider. | 53 // so don't register a dump provider. |
53 if (memory_tracker_) { | 54 if (memory_tracker_) { |
54 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | 55 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
55 this, "gpu::BufferManager", base::ThreadTaskRunnerHandle::Get()); | 56 this, "gpu::BufferManager", base::ThreadTaskRunnerHandle::Get()); |
56 } | 57 } |
57 } | 58 } |
58 | 59 |
59 BufferManager::~BufferManager() { | 60 BufferManager::~BufferManager() { |
60 DCHECK(buffers_.empty()); | 61 DCHECK(buffers_.empty()); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 usage_(GL_STATIC_DRAW) { | 136 usage_(GL_STATIC_DRAW) { |
136 manager_->StartTracking(this); | 137 manager_->StartTracking(this); |
137 } | 138 } |
138 | 139 |
139 Buffer::~Buffer() { | 140 Buffer::~Buffer() { |
140 if (manager_) { | 141 if (manager_) { |
141 if (!manager_->lost_context_) { | 142 if (!manager_->lost_context_) { |
142 GLuint id = service_id(); | 143 GLuint id = service_id(); |
143 glDeleteBuffersARB(1, &id); | 144 glDeleteBuffersARB(1, &id); |
144 } | 145 } |
| 146 RemoveMappedRange(); |
145 manager_->StopTracking(this); | 147 manager_->StopTracking(this); |
146 manager_ = NULL; | 148 manager_ = nullptr; |
147 } | 149 } |
148 } | 150 } |
149 | 151 |
150 const GLvoid* Buffer::StageShadow(bool use_shadow, | 152 const GLvoid* Buffer::StageShadow(bool use_shadow, |
151 GLsizeiptr size, | 153 GLsizeiptr size, |
152 const GLvoid* data) { | 154 const GLvoid* data) { |
153 shadow_.clear(); | 155 shadow_.clear(); |
154 if (use_shadow) { | 156 if (use_shadow) { |
155 if (data) { | 157 if (data) { |
156 shadow_.insert(shadow_.begin(), | 158 shadow_.insert(shadow_.begin(), |
157 static_cast<const uint8_t*>(data), | 159 static_cast<const uint8_t*>(data), |
158 static_cast<const uint8_t*>(data) + size); | 160 static_cast<const uint8_t*>(data) + size); |
159 } else { | 161 } else { |
160 shadow_.resize(size); | 162 shadow_.resize(size); |
| 163 memset(shadow_.data(), 0, static_cast<size_t>(size)); |
161 } | 164 } |
162 return shadow_.data(); | 165 return shadow_.data(); |
163 } else { | 166 } else { |
164 return data; | 167 return data; |
165 } | 168 } |
166 } | 169 } |
167 | 170 |
168 void Buffer::SetInfo(GLsizeiptr size, | 171 void Buffer::SetInfo(GLsizeiptr size, |
169 GLenum usage, | 172 GLenum usage, |
170 bool use_shadow, | 173 bool use_shadow, |
(...skipping 12 matching lines...) Expand all Loading... |
183 bool Buffer::CheckRange(GLintptr offset, GLsizeiptr size) const { | 186 bool Buffer::CheckRange(GLintptr offset, GLsizeiptr size) const { |
184 if (offset < 0 || offset > std::numeric_limits<int32_t>::max() || | 187 if (offset < 0 || offset > std::numeric_limits<int32_t>::max() || |
185 size < 0 || size > std::numeric_limits<int32_t>::max()) { | 188 size < 0 || size > std::numeric_limits<int32_t>::max()) { |
186 return false; | 189 return false; |
187 } | 190 } |
188 base::CheckedNumeric<int32_t> max = offset; | 191 base::CheckedNumeric<int32_t> max = offset; |
189 max += size; | 192 max += size; |
190 return max.IsValid() && max.ValueOrDefault(0) <= size_; | 193 return max.IsValid() && max.ValueOrDefault(0) <= size_; |
191 } | 194 } |
192 | 195 |
193 bool Buffer::SetRange(GLintptr offset, GLsizeiptr size, const GLvoid * data) { | 196 void Buffer::SetRange(GLintptr offset, GLsizeiptr size, const GLvoid * data) { |
194 if (!CheckRange(offset, size)) { | 197 DCHECK(CheckRange(offset, size)); |
195 return false; | |
196 } | |
197 if (!shadow_.empty()) { | 198 if (!shadow_.empty()) { |
198 DCHECK_LE(static_cast<size_t>(offset + size), shadow_.size()); | 199 DCHECK_LE(static_cast<size_t>(offset + size), shadow_.size()); |
199 memcpy(shadow_.data() + offset, data, size); | 200 memcpy(shadow_.data() + offset, data, size); |
200 ClearCache(); | 201 ClearCache(); |
201 } | 202 } |
202 return true; | |
203 } | 203 } |
204 | 204 |
205 const void* Buffer::GetRange(GLintptr offset, GLsizeiptr size) const { | 205 const void* Buffer::GetRange(GLintptr offset, GLsizeiptr size) const { |
206 if (shadow_.empty()) { | 206 if (shadow_.empty()) { |
207 return NULL; | 207 return NULL; |
208 } | 208 } |
209 if (!CheckRange(offset, size)) { | 209 if (!CheckRange(offset, size)) { |
210 return NULL; | 210 return NULL; |
211 } | 211 } |
212 DCHECK_LE(static_cast<size_t>(offset + size), shadow_.size()); | 212 DCHECK_LE(static_cast<size_t>(offset + size), shadow_.size()); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 break; | 327 break; |
328 default: | 328 default: |
329 NOTREACHED(); // should never get here by validation. | 329 NOTREACHED(); // should never get here by validation. |
330 break; | 330 break; |
331 } | 331 } |
332 range_set_.insert(std::make_pair(range, max_v)); | 332 range_set_.insert(std::make_pair(range, max_v)); |
333 *max_value = max_v; | 333 *max_value = max_v; |
334 return true; | 334 return true; |
335 } | 335 } |
336 | 336 |
| 337 void Buffer::SetMappedRange(GLintptr offset, GLsizeiptr size, GLenum access, |
| 338 void* pointer, scoped_refptr<gpu::Buffer> shm, |
| 339 unsigned int shm_offset) { |
| 340 mapped_range_.reset( |
| 341 new MappedRange(offset, size, access, pointer, shm, shm_offset)); |
| 342 manager_->IncreaseMappedBufferCount(); |
| 343 } |
| 344 |
| 345 void Buffer::RemoveMappedRange() { |
| 346 if (mapped_range_.get()) |
| 347 manager_->DecreaseMappedBufferCount(); |
| 348 mapped_range_.reset(nullptr); |
| 349 } |
| 350 |
337 bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const { | 351 bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const { |
338 // This doesn't need to be fast. It's only used during slow queries. | 352 // This doesn't need to be fast. It's only used during slow queries. |
339 for (BufferMap::const_iterator it = buffers_.begin(); | 353 for (BufferMap::const_iterator it = buffers_.begin(); |
340 it != buffers_.end(); ++it) { | 354 it != buffers_.end(); ++it) { |
341 if (it->second->service_id() == service_id) { | 355 if (it->second->service_id() == service_id) { |
342 *client_id = it->first; | 356 *client_id = it->first; |
343 return true; | 357 return true; |
344 } | 358 } |
345 } | 359 } |
346 return false; | 360 return false; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 GLenum usage, | 450 GLenum usage, |
437 const GLvoid* data) { | 451 const GLvoid* data) { |
438 // Stage the shadow buffer first if we are using a shadow buffer so that we | 452 // Stage the shadow buffer first if we are using a shadow buffer so that we |
439 // validate what we store internally. | 453 // validate what we store internally. |
440 const bool use_shadow = UseShadowBuffer(buffer->initial_target(), usage); | 454 const bool use_shadow = UseShadowBuffer(buffer->initial_target(), usage); |
441 data = buffer->StageShadow(use_shadow, size, data); | 455 data = buffer->StageShadow(use_shadow, size, data); |
442 | 456 |
443 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData"); | 457 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData"); |
444 if (IsUsageClientSideArray(usage)) { | 458 if (IsUsageClientSideArray(usage)) { |
445 GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0; | 459 GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0; |
446 glBufferData(target, empty_size, NULL, usage); | 460 glBufferData(target, empty_size, nullptr, usage); |
447 } else { | 461 } else { |
448 glBufferData(target, size, data, usage); | 462 if (data || !size) { |
| 463 glBufferData(target, size, data, usage); |
| 464 } else { |
| 465 std::unique_ptr<char[]> zero(new char[size]); |
| 466 memset(zero.get(), 0, size); |
| 467 glBufferData(target, size, zero.get(), usage); |
| 468 } |
449 } | 469 } |
450 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData"); | 470 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData"); |
451 if (error != GL_NO_ERROR) { | 471 if (error != GL_NO_ERROR) { |
| 472 DCHECK_EQ(static_cast<GLenum>(GL_OUT_OF_MEMORY), error); |
452 size = 0; | 473 size = 0; |
| 474 // TODO(zmo): This doesn't seem correct. There might be shadow data from |
| 475 // a previous successful BufferData() call. |
453 buffer->StageShadow(false, 0, nullptr); // Also clear the shadow. | 476 buffer->StageShadow(false, 0, nullptr); // Also clear the shadow. |
| 477 return; |
454 } | 478 } |
455 | 479 |
456 SetInfo(buffer, target, size, usage, use_shadow); | 480 SetInfo(buffer, target, size, usage, use_shadow); |
457 } | 481 } |
458 | 482 |
459 void BufferManager::ValidateAndDoBufferSubData( | 483 void BufferManager::ValidateAndDoBufferSubData( |
460 ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size, | 484 ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size, |
461 const GLvoid * data) { | 485 const GLvoid * data) { |
462 const char* func_name = "glBufferSubData"; | 486 Buffer* buffer = RequestBufferAccess( |
463 | 487 context_state, target, offset, size, "glBufferSubData"); |
464 ErrorState* error_state = context_state->GetErrorState(); | |
465 Buffer* buffer = GetBufferInfoForTarget(context_state, target); | |
466 if (!buffer) { | 488 if (!buffer) { |
467 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, | |
468 "unknown buffer"); | |
469 return; | 489 return; |
470 } | 490 } |
471 | 491 DoBufferSubData(buffer, target, offset, size, data); |
472 if (buffer->GetMappedRange()) { | |
473 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, | |
474 "buffer is mapped"); | |
475 return; | |
476 } | |
477 | |
478 DoBufferSubData(error_state, buffer, target, offset, size, data); | |
479 } | 492 } |
480 | 493 |
481 void BufferManager::DoBufferSubData( | 494 void BufferManager::DoBufferSubData( |
482 ErrorState* error_state, | 495 Buffer* buffer, GLenum target, GLintptr offset, GLsizeiptr size, |
483 Buffer* buffer, | |
484 GLenum target, | |
485 GLintptr offset, | |
486 GLsizeiptr size, | |
487 const GLvoid* data) { | 496 const GLvoid* data) { |
488 if (!buffer->SetRange(offset, size, data)) { | 497 buffer->SetRange(offset, size, data); |
489 ERRORSTATE_SET_GL_ERROR( | |
490 error_state, GL_INVALID_VALUE, "glBufferSubData", "out of range"); | |
491 return; | |
492 } | |
493 | 498 |
494 if (!buffer->IsClientSideArray()) { | 499 if (!buffer->IsClientSideArray()) { |
495 glBufferSubData(target, offset, size, data); | 500 glBufferSubData(target, offset, size, data); |
496 } | 501 } |
497 } | 502 } |
498 | 503 |
499 void BufferManager::ValidateAndDoCopyBufferSubData( | 504 void BufferManager::ValidateAndDoCopyBufferSubData( |
500 ContextState* context_state, GLenum readtarget, GLenum writetarget, | 505 ContextState* context_state, GLenum readtarget, GLenum writetarget, |
501 GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) { | 506 GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) { |
502 const char* func_name = "glCopyBufferSubData"; | 507 const char* func_name = "glCopyBufferSubData"; |
| 508 Buffer* readbuffer = RequestBufferAccess( |
| 509 context_state, readtarget, readoffset, size, func_name); |
| 510 if (!readbuffer) |
| 511 return; |
| 512 Buffer* writebuffer = RequestBufferAccess( |
| 513 context_state, writetarget, writeoffset, size, func_name); |
| 514 if (!writebuffer) |
| 515 return; |
| 516 |
503 ErrorState* error_state = context_state->GetErrorState(); | 517 ErrorState* error_state = context_state->GetErrorState(); |
504 | |
505 Buffer* readbuffer = GetBufferInfoForTarget(context_state, readtarget); | |
506 if (!readbuffer) { | |
507 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, | |
508 "no buffer is bound to readtarget"); | |
509 return; | |
510 } | |
511 if (readbuffer->GetMappedRange()) { | |
512 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, | |
513 "buffer bound to readtarget is mapped"); | |
514 return; | |
515 } | |
516 if (!readbuffer->CheckRange(readoffset, size)) { | |
517 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, | |
518 "readoffset/size out of range"); | |
519 return; | |
520 } | |
521 | |
522 Buffer* writebuffer = GetBufferInfoForTarget(context_state, writetarget); | |
523 if (!writebuffer) { | |
524 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, | |
525 "no buffer is bound to writetarget"); | |
526 return; | |
527 } | |
528 if (writebuffer->GetMappedRange()) { | |
529 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, | |
530 "buffer bound to writetarget is mapped"); | |
531 return; | |
532 } | |
533 if (!writebuffer->CheckRange(writeoffset, size)) { | |
534 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, | |
535 "writeoffset/size out of range"); | |
536 return; | |
537 } | |
538 | |
539 if (readbuffer == writebuffer && | 518 if (readbuffer == writebuffer && |
540 ((writeoffset >= readoffset && writeoffset < readoffset + size) || | 519 ((writeoffset >= readoffset && writeoffset < readoffset + size) || |
541 (readoffset >= writeoffset && readoffset < writeoffset + size))) { | 520 (readoffset >= writeoffset && readoffset < writeoffset + size))) { |
542 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, | 521 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, |
543 "read/write ranges overlap"); | 522 "read/write ranges overlap"); |
544 return; | 523 return; |
545 } | 524 } |
546 | 525 |
547 if (!allow_buffers_on_multiple_targets_) { | 526 if (!allow_buffers_on_multiple_targets_) { |
548 if ((readbuffer->initial_target() == GL_ELEMENT_ARRAY_BUFFER && | 527 if ((readbuffer->initial_target() == GL_ELEMENT_ARRAY_BUFFER && |
(...skipping 16 matching lines...) Expand all Loading... |
565 GLintptr readoffset, | 544 GLintptr readoffset, |
566 Buffer* writebuffer, | 545 Buffer* writebuffer, |
567 GLenum writetarget, | 546 GLenum writetarget, |
568 GLintptr writeoffset, | 547 GLintptr writeoffset, |
569 GLsizeiptr size) { | 548 GLsizeiptr size) { |
570 DCHECK(readbuffer); | 549 DCHECK(readbuffer); |
571 DCHECK(writebuffer); | 550 DCHECK(writebuffer); |
572 if (writebuffer->shadowed()) { | 551 if (writebuffer->shadowed()) { |
573 const void* data = readbuffer->GetRange(readoffset, size); | 552 const void* data = readbuffer->GetRange(readoffset, size); |
574 DCHECK(data); | 553 DCHECK(data); |
575 bool success = writebuffer->SetRange(writeoffset, size, data); | 554 writebuffer->SetRange(writeoffset, size, data); |
576 DCHECK(success); | |
577 } | 555 } |
578 | 556 |
579 glCopyBufferSubData(readtarget, writetarget, readoffset, writeoffset, size); | 557 glCopyBufferSubData(readtarget, writetarget, readoffset, writeoffset, size); |
580 } | 558 } |
581 | 559 |
582 void BufferManager::ValidateAndDoGetBufferParameteri64v( | 560 void BufferManager::ValidateAndDoGetBufferParameteri64v( |
583 ContextState* context_state, GLenum target, GLenum pname, GLint64* params) { | 561 ContextState* context_state, GLenum target, GLenum pname, GLint64* params) { |
584 Buffer* buffer = GetBufferInfoForTarget(context_state, target); | 562 Buffer* buffer = GetBufferInfoForTarget(context_state, target); |
585 if (!buffer) { | 563 if (!buffer) { |
586 ERRORSTATE_SET_GL_ERROR( | 564 ERRORSTATE_SET_GL_ERROR( |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 static_cast<uint64_t>(buffer->size())); | 728 static_cast<uint64_t>(buffer->size())); |
751 | 729 |
752 auto guid = gl::GetGLBufferGUIDForTracing(share_group_tracing_guid, | 730 auto guid = gl::GetGLBufferGUIDForTracing(share_group_tracing_guid, |
753 client_buffer_id); | 731 client_buffer_id); |
754 pmd->CreateSharedGlobalAllocatorDump(guid); | 732 pmd->CreateSharedGlobalAllocatorDump(guid); |
755 pmd->AddOwnershipEdge(dump->guid(), guid); | 733 pmd->AddOwnershipEdge(dump->guid(), guid); |
756 } | 734 } |
757 return true; | 735 return true; |
758 } | 736 } |
759 | 737 |
| 738 Buffer* BufferManager::RequestBufferAccess(ContextState* context_state, |
| 739 GLenum target, |
| 740 GLintptr offset, |
| 741 GLsizeiptr size, |
| 742 const char* func_name) { |
| 743 DCHECK(context_state); |
| 744 ErrorState* error_state = context_state->GetErrorState(); |
| 745 |
| 746 std::string msg_tag = base::StringPrintf("bound to target 0x%04x", target); |
| 747 Buffer* buffer = GetBufferInfoForTarget(context_state, target); |
| 748 if (!RequestBufferAccess(error_state, buffer, func_name, msg_tag.c_str())) { |
| 749 return nullptr; |
| 750 } |
| 751 if (!buffer->CheckRange(offset, size)) { |
| 752 std::string msg = base::StringPrintf( |
| 753 "%s : offset/size out of range", msg_tag.c_str()); |
| 754 ERRORSTATE_SET_GL_ERROR( |
| 755 error_state, GL_INVALID_VALUE, func_name, msg.c_str()); |
| 756 return nullptr; |
| 757 } |
| 758 return buffer; |
| 759 } |
| 760 |
| 761 Buffer* BufferManager::RequestBufferAccess(ContextState* context_state, |
| 762 GLenum target, |
| 763 const char* func_name) { |
| 764 DCHECK(context_state); |
| 765 ErrorState* error_state = context_state->GetErrorState(); |
| 766 |
| 767 std::string msg_tag = base::StringPrintf("bound to target 0x%04x", target); |
| 768 Buffer* buffer = GetBufferInfoForTarget(context_state, target); |
| 769 return RequestBufferAccess( |
| 770 error_state, buffer, func_name, msg_tag.c_str()) ? buffer : nullptr; |
| 771 } |
| 772 |
| 773 bool BufferManager::RequestBufferAccess(ErrorState* error_state, |
| 774 Buffer* buffer, |
| 775 const char* func_name, |
| 776 const char* message_tag) { |
| 777 DCHECK(error_state); |
| 778 |
| 779 if (!buffer || buffer->IsDeleted()) { |
| 780 std::string msg = base::StringPrintf("%s : no buffer", message_tag); |
| 781 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
| 782 msg.c_str()); |
| 783 return false; |
| 784 } |
| 785 if (buffer->GetMappedRange()) { |
| 786 std::string msg = base::StringPrintf("%s : buffer is mapped", message_tag); |
| 787 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
| 788 msg.c_str()); |
| 789 return false; |
| 790 } |
| 791 return true; |
| 792 } |
| 793 |
| 794 void BufferManager::IncreaseMappedBufferCount() { |
| 795 DCHECK_GT(std::numeric_limits<uint32_t>::max(), mapped_buffer_count_); |
| 796 mapped_buffer_count_++; |
| 797 } |
| 798 |
| 799 void BufferManager::DecreaseMappedBufferCount() { |
| 800 DCHECK_LT(0u, mapped_buffer_count_); |
| 801 mapped_buffer_count_--; |
| 802 } |
| 803 |
760 } // namespace gles2 | 804 } // namespace gles2 |
761 } // namespace gpu | 805 } // namespace gpu |
OLD | NEW |