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) { | |
52 // When created from InProcessCommandBuffer, we won't have a |memory_tracker_| | 51 // When created from InProcessCommandBuffer, we won't have a |memory_tracker_| |
53 // so don't register a dump provider. | 52 // so don't register a dump provider. |
54 if (memory_tracker_) { | 53 if (memory_tracker_) { |
55 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | 54 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
56 this, "gpu::BufferManager", base::ThreadTaskRunnerHandle::Get()); | 55 this, "gpu::BufferManager", base::ThreadTaskRunnerHandle::Get()); |
57 } | 56 } |
58 } | 57 } |
59 | 58 |
60 BufferManager::~BufferManager() { | 59 BufferManager::~BufferManager() { |
61 DCHECK(buffers_.empty()); | 60 DCHECK(buffers_.empty()); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 usage_(GL_STATIC_DRAW) { | 135 usage_(GL_STATIC_DRAW) { |
137 manager_->StartTracking(this); | 136 manager_->StartTracking(this); |
138 } | 137 } |
139 | 138 |
140 Buffer::~Buffer() { | 139 Buffer::~Buffer() { |
141 if (manager_) { | 140 if (manager_) { |
142 if (!manager_->lost_context_) { | 141 if (!manager_->lost_context_) { |
143 GLuint id = service_id(); | 142 GLuint id = service_id(); |
144 glDeleteBuffersARB(1, &id); | 143 glDeleteBuffersARB(1, &id); |
145 } | 144 } |
146 RemoveMappedRange(); | |
147 manager_->StopTracking(this); | 145 manager_->StopTracking(this); |
148 manager_ = nullptr; | 146 manager_ = NULL; |
149 } | 147 } |
150 } | 148 } |
151 | 149 |
152 const GLvoid* Buffer::StageShadow(bool use_shadow, | 150 const GLvoid* Buffer::StageShadow(bool use_shadow, |
153 GLsizeiptr size, | 151 GLsizeiptr size, |
154 const GLvoid* data) { | 152 const GLvoid* data) { |
155 shadow_.clear(); | 153 shadow_.clear(); |
156 if (use_shadow) { | 154 if (use_shadow) { |
157 if (data) { | 155 if (data) { |
158 shadow_.insert(shadow_.begin(), | 156 shadow_.insert(shadow_.begin(), |
159 static_cast<const uint8_t*>(data), | 157 static_cast<const uint8_t*>(data), |
160 static_cast<const uint8_t*>(data) + size); | 158 static_cast<const uint8_t*>(data) + size); |
161 } else { | 159 } else { |
162 shadow_.resize(size); | 160 shadow_.resize(size); |
163 memset(shadow_.data(), 0, static_cast<size_t>(size)); | |
164 } | 161 } |
165 return shadow_.data(); | 162 return shadow_.data(); |
166 } else { | 163 } else { |
167 return data; | 164 return data; |
168 } | 165 } |
169 } | 166 } |
170 | 167 |
171 void Buffer::SetInfo(GLsizeiptr size, | 168 void Buffer::SetInfo(GLsizeiptr size, |
172 GLenum usage, | 169 GLenum usage, |
173 bool use_shadow, | 170 bool use_shadow, |
(...skipping 12 matching lines...) Expand all Loading... |
186 bool Buffer::CheckRange(GLintptr offset, GLsizeiptr size) const { | 183 bool Buffer::CheckRange(GLintptr offset, GLsizeiptr size) const { |
187 if (offset < 0 || offset > std::numeric_limits<int32_t>::max() || | 184 if (offset < 0 || offset > std::numeric_limits<int32_t>::max() || |
188 size < 0 || size > std::numeric_limits<int32_t>::max()) { | 185 size < 0 || size > std::numeric_limits<int32_t>::max()) { |
189 return false; | 186 return false; |
190 } | 187 } |
191 base::CheckedNumeric<int32_t> max = offset; | 188 base::CheckedNumeric<int32_t> max = offset; |
192 max += size; | 189 max += size; |
193 return max.IsValid() && max.ValueOrDefault(0) <= size_; | 190 return max.IsValid() && max.ValueOrDefault(0) <= size_; |
194 } | 191 } |
195 | 192 |
196 void Buffer::SetRange(GLintptr offset, GLsizeiptr size, const GLvoid * data) { | 193 bool Buffer::SetRange(GLintptr offset, GLsizeiptr size, const GLvoid * data) { |
197 DCHECK(CheckRange(offset, size)); | 194 if (!CheckRange(offset, size)) { |
| 195 return false; |
| 196 } |
198 if (!shadow_.empty()) { | 197 if (!shadow_.empty()) { |
199 DCHECK_LE(static_cast<size_t>(offset + size), shadow_.size()); | 198 DCHECK_LE(static_cast<size_t>(offset + size), shadow_.size()); |
200 memcpy(shadow_.data() + offset, data, size); | 199 memcpy(shadow_.data() + offset, data, size); |
201 ClearCache(); | 200 ClearCache(); |
202 } | 201 } |
| 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 | |
351 bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const { | 337 bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const { |
352 // This doesn't need to be fast. It's only used during slow queries. | 338 // This doesn't need to be fast. It's only used during slow queries. |
353 for (BufferMap::const_iterator it = buffers_.begin(); | 339 for (BufferMap::const_iterator it = buffers_.begin(); |
354 it != buffers_.end(); ++it) { | 340 it != buffers_.end(); ++it) { |
355 if (it->second->service_id() == service_id) { | 341 if (it->second->service_id() == service_id) { |
356 *client_id = it->first; | 342 *client_id = it->first; |
357 return true; | 343 return true; |
358 } | 344 } |
359 } | 345 } |
360 return false; | 346 return false; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 GLenum usage, | 436 GLenum usage, |
451 const GLvoid* data) { | 437 const GLvoid* data) { |
452 // Stage the shadow buffer first if we are using a shadow buffer so that we | 438 // Stage the shadow buffer first if we are using a shadow buffer so that we |
453 // validate what we store internally. | 439 // validate what we store internally. |
454 const bool use_shadow = UseShadowBuffer(buffer->initial_target(), usage); | 440 const bool use_shadow = UseShadowBuffer(buffer->initial_target(), usage); |
455 data = buffer->StageShadow(use_shadow, size, data); | 441 data = buffer->StageShadow(use_shadow, size, data); |
456 | 442 |
457 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData"); | 443 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData"); |
458 if (IsUsageClientSideArray(usage)) { | 444 if (IsUsageClientSideArray(usage)) { |
459 GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0; | 445 GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0; |
460 glBufferData(target, empty_size, nullptr, usage); | 446 glBufferData(target, empty_size, NULL, usage); |
461 } else { | 447 } else { |
462 if (data || !size) { | 448 glBufferData(target, size, data, usage); |
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 } | |
469 } | 449 } |
470 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData"); | 450 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData"); |
471 if (error != GL_NO_ERROR) { | 451 if (error != GL_NO_ERROR) { |
472 DCHECK_EQ(static_cast<GLenum>(GL_OUT_OF_MEMORY), error); | |
473 size = 0; | 452 size = 0; |
474 // TODO(zmo): This doesn't seem correct. There might be shadow data from | |
475 // a previous successful BufferData() call. | |
476 buffer->StageShadow(false, 0, nullptr); // Also clear the shadow. | 453 buffer->StageShadow(false, 0, nullptr); // Also clear the shadow. |
477 return; | |
478 } | 454 } |
479 | 455 |
480 SetInfo(buffer, target, size, usage, use_shadow); | 456 SetInfo(buffer, target, size, usage, use_shadow); |
481 } | 457 } |
482 | 458 |
483 void BufferManager::ValidateAndDoBufferSubData( | 459 void BufferManager::ValidateAndDoBufferSubData( |
484 ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size, | 460 ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size, |
485 const GLvoid * data) { | 461 const GLvoid * data) { |
486 Buffer* buffer = RequestBufferAccess( | 462 const char* func_name = "glBufferSubData"; |
487 context_state, target, offset, size, "glBufferSubData"); | 463 |
| 464 ErrorState* error_state = context_state->GetErrorState(); |
| 465 Buffer* buffer = GetBufferInfoForTarget(context_state, target); |
488 if (!buffer) { | 466 if (!buffer) { |
| 467 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, |
| 468 "unknown buffer"); |
489 return; | 469 return; |
490 } | 470 } |
491 DoBufferSubData(buffer, target, offset, size, data); | 471 |
| 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); |
492 } | 479 } |
493 | 480 |
494 void BufferManager::DoBufferSubData( | 481 void BufferManager::DoBufferSubData( |
495 Buffer* buffer, GLenum target, GLintptr offset, GLsizeiptr size, | 482 ErrorState* error_state, |
| 483 Buffer* buffer, |
| 484 GLenum target, |
| 485 GLintptr offset, |
| 486 GLsizeiptr size, |
496 const GLvoid* data) { | 487 const GLvoid* data) { |
497 buffer->SetRange(offset, size, data); | 488 if (!buffer->SetRange(offset, size, data)) { |
| 489 ERRORSTATE_SET_GL_ERROR( |
| 490 error_state, GL_INVALID_VALUE, "glBufferSubData", "out of range"); |
| 491 return; |
| 492 } |
498 | 493 |
499 if (!buffer->IsClientSideArray()) { | 494 if (!buffer->IsClientSideArray()) { |
500 glBufferSubData(target, offset, size, data); | 495 glBufferSubData(target, offset, size, data); |
501 } | 496 } |
502 } | 497 } |
503 | 498 |
504 void BufferManager::ValidateAndDoCopyBufferSubData( | 499 void BufferManager::ValidateAndDoCopyBufferSubData( |
505 ContextState* context_state, GLenum readtarget, GLenum writetarget, | 500 ContextState* context_state, GLenum readtarget, GLenum writetarget, |
506 GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) { | 501 GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) { |
507 const char* func_name = "glCopyBufferSubData"; | 502 const char* func_name = "glCopyBufferSubData"; |
508 Buffer* readbuffer = RequestBufferAccess( | 503 ErrorState* error_state = context_state->GetErrorState(); |
509 context_state, readtarget, readoffset, size, func_name); | 504 |
510 if (!readbuffer) | 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"); |
511 return; | 509 return; |
512 Buffer* writebuffer = RequestBufferAccess( | 510 } |
513 context_state, writetarget, writeoffset, size, func_name); | 511 if (readbuffer->GetMappedRange()) { |
514 if (!writebuffer) | 512 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
| 513 "buffer bound to readtarget is mapped"); |
515 return; | 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 } |
516 | 521 |
517 ErrorState* error_state = context_state->GetErrorState(); | 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 |
518 if (readbuffer == writebuffer && | 539 if (readbuffer == writebuffer && |
519 ((writeoffset >= readoffset && writeoffset < readoffset + size) || | 540 ((writeoffset >= readoffset && writeoffset < readoffset + size) || |
520 (readoffset >= writeoffset && readoffset < writeoffset + size))) { | 541 (readoffset >= writeoffset && readoffset < writeoffset + size))) { |
521 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, | 542 ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, |
522 "read/write ranges overlap"); | 543 "read/write ranges overlap"); |
523 return; | 544 return; |
524 } | 545 } |
525 | 546 |
526 if (!allow_buffers_on_multiple_targets_) { | 547 if (!allow_buffers_on_multiple_targets_) { |
527 if ((readbuffer->initial_target() == GL_ELEMENT_ARRAY_BUFFER && | 548 if ((readbuffer->initial_target() == GL_ELEMENT_ARRAY_BUFFER && |
(...skipping 16 matching lines...) Expand all Loading... |
544 GLintptr readoffset, | 565 GLintptr readoffset, |
545 Buffer* writebuffer, | 566 Buffer* writebuffer, |
546 GLenum writetarget, | 567 GLenum writetarget, |
547 GLintptr writeoffset, | 568 GLintptr writeoffset, |
548 GLsizeiptr size) { | 569 GLsizeiptr size) { |
549 DCHECK(readbuffer); | 570 DCHECK(readbuffer); |
550 DCHECK(writebuffer); | 571 DCHECK(writebuffer); |
551 if (writebuffer->shadowed()) { | 572 if (writebuffer->shadowed()) { |
552 const void* data = readbuffer->GetRange(readoffset, size); | 573 const void* data = readbuffer->GetRange(readoffset, size); |
553 DCHECK(data); | 574 DCHECK(data); |
554 writebuffer->SetRange(writeoffset, size, data); | 575 bool success = writebuffer->SetRange(writeoffset, size, data); |
| 576 DCHECK(success); |
555 } | 577 } |
556 | 578 |
557 glCopyBufferSubData(readtarget, writetarget, readoffset, writeoffset, size); | 579 glCopyBufferSubData(readtarget, writetarget, readoffset, writeoffset, size); |
558 } | 580 } |
559 | 581 |
560 void BufferManager::ValidateAndDoGetBufferParameteri64v( | 582 void BufferManager::ValidateAndDoGetBufferParameteri64v( |
561 ContextState* context_state, GLenum target, GLenum pname, GLint64* params) { | 583 ContextState* context_state, GLenum target, GLenum pname, GLint64* params) { |
562 Buffer* buffer = GetBufferInfoForTarget(context_state, target); | 584 Buffer* buffer = GetBufferInfoForTarget(context_state, target); |
563 if (!buffer) { | 585 if (!buffer) { |
564 ERRORSTATE_SET_GL_ERROR( | 586 ERRORSTATE_SET_GL_ERROR( |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 static_cast<uint64_t>(buffer->size())); | 750 static_cast<uint64_t>(buffer->size())); |
729 | 751 |
730 auto guid = gl::GetGLBufferGUIDForTracing(share_group_tracing_guid, | 752 auto guid = gl::GetGLBufferGUIDForTracing(share_group_tracing_guid, |
731 client_buffer_id); | 753 client_buffer_id); |
732 pmd->CreateSharedGlobalAllocatorDump(guid); | 754 pmd->CreateSharedGlobalAllocatorDump(guid); |
733 pmd->AddOwnershipEdge(dump->guid(), guid); | 755 pmd->AddOwnershipEdge(dump->guid(), guid); |
734 } | 756 } |
735 return true; | 757 return true; |
736 } | 758 } |
737 | 759 |
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 | |
804 } // namespace gles2 | 760 } // namespace gles2 |
805 } // namespace gpu | 761 } // namespace gpu |
OLD | NEW |