Index: gpu/command_buffer/service/buffer_manager.cc |
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc |
index e1a2171e1bd122f16e261b7a66fe072f1464f9b1..8c470fc1063300010b73a8e2ebc4d92534ed3443 100644 |
--- a/gpu/command_buffer/service/buffer_manager.cc |
+++ b/gpu/command_buffer/service/buffer_manager.cc |
@@ -47,7 +47,8 @@ BufferManager::BufferManager(MemoryTracker* memory_tracker, |
feature_info |
? feature_info->workarounds() |
.use_client_side_arrays_for_stream_buffers |
- : 0) { |
+ : 0), |
+ mapped_buffer_count_(0) { |
// When created from InProcessCommandBuffer, we won't have a |memory_tracker_| |
// so don't register a dump provider. |
if (memory_tracker_) { |
@@ -142,8 +143,9 @@ Buffer::~Buffer() { |
GLuint id = service_id(); |
glDeleteBuffersARB(1, &id); |
} |
+ RemoveMappedRange(); |
manager_->StopTracking(this); |
- manager_ = NULL; |
+ manager_ = nullptr; |
} |
} |
@@ -158,6 +160,7 @@ const GLvoid* Buffer::StageShadow(bool use_shadow, |
static_cast<const uint8_t*>(data) + size); |
} else { |
shadow_.resize(size); |
+ memset(shadow_.data(), 0, static_cast<size_t>(size)); |
} |
return shadow_.data(); |
} else { |
@@ -190,16 +193,13 @@ bool Buffer::CheckRange(GLintptr offset, GLsizeiptr size) const { |
return max.IsValid() && max.ValueOrDefault(0) <= size_; |
} |
-bool Buffer::SetRange(GLintptr offset, GLsizeiptr size, const GLvoid * data) { |
- if (!CheckRange(offset, size)) { |
- return false; |
- } |
+void Buffer::SetRange(GLintptr offset, GLsizeiptr size, const GLvoid * data) { |
+ DCHECK(CheckRange(offset, size)); |
if (!shadow_.empty()) { |
DCHECK_LE(static_cast<size_t>(offset + size), shadow_.size()); |
memcpy(shadow_.data() + offset, data, size); |
ClearCache(); |
} |
- return true; |
} |
const void* Buffer::GetRange(GLintptr offset, GLsizeiptr size) const { |
@@ -334,6 +334,20 @@ bool Buffer::GetMaxValueForRange( |
return true; |
} |
+void Buffer::SetMappedRange(GLintptr offset, GLsizeiptr size, GLenum access, |
+ void* pointer, scoped_refptr<gpu::Buffer> shm, |
+ unsigned int shm_offset) { |
+ mapped_range_.reset( |
+ new MappedRange(offset, size, access, pointer, shm, shm_offset)); |
+ manager_->IncreaseMappedBufferCount(); |
+} |
+ |
+void Buffer::RemoveMappedRange() { |
+ if (mapped_range_.get()) |
+ manager_->DecreaseMappedBufferCount(); |
+ mapped_range_.reset(nullptr); |
+} |
+ |
bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const { |
// This doesn't need to be fast. It's only used during slow queries. |
for (BufferMap::const_iterator it = buffers_.begin(); |
@@ -443,14 +457,24 @@ void BufferManager::DoBufferData( |
ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData"); |
if (IsUsageClientSideArray(usage)) { |
GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0; |
- glBufferData(target, empty_size, NULL, usage); |
+ glBufferData(target, empty_size, nullptr, usage); |
} else { |
- glBufferData(target, size, data, usage); |
+ if (data || !size) { |
+ glBufferData(target, size, data, usage); |
+ } else { |
+ std::unique_ptr<char[]> zero(new char[size]); |
+ memset(zero.get(), 0, size); |
+ glBufferData(target, size, zero.get(), usage); |
+ } |
} |
GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData"); |
if (error != GL_NO_ERROR) { |
+ DCHECK_EQ(static_cast<GLenum>(GL_OUT_OF_MEMORY), error); |
size = 0; |
+ // TODO(zmo): This doesn't seem correct. There might be shadow data from |
+ // a previous successful BufferData() call. |
buffer->StageShadow(false, 0, nullptr); // Also clear the shadow. |
+ return; |
} |
SetInfo(buffer, target, size, usage, use_shadow); |
@@ -459,37 +483,18 @@ void BufferManager::DoBufferData( |
void BufferManager::ValidateAndDoBufferSubData( |
ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size, |
const GLvoid * data) { |
- const char* func_name = "glBufferSubData"; |
- |
- ErrorState* error_state = context_state->GetErrorState(); |
- Buffer* buffer = GetBufferInfoForTarget(context_state, target); |
+ Buffer* buffer = RequestBufferAccess( |
+ context_state, target, offset, size, "glBufferSubData"); |
if (!buffer) { |
- ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, |
- "unknown buffer"); |
return; |
} |
- |
- if (buffer->GetMappedRange()) { |
- ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
- "buffer is mapped"); |
- return; |
- } |
- |
- DoBufferSubData(error_state, buffer, target, offset, size, data); |
+ DoBufferSubData(buffer, target, offset, size, data); |
} |
void BufferManager::DoBufferSubData( |
- ErrorState* error_state, |
- Buffer* buffer, |
- GLenum target, |
- GLintptr offset, |
- GLsizeiptr size, |
+ Buffer* buffer, GLenum target, GLintptr offset, GLsizeiptr size, |
const GLvoid* data) { |
- if (!buffer->SetRange(offset, size, data)) { |
- ERRORSTATE_SET_GL_ERROR( |
- error_state, GL_INVALID_VALUE, "glBufferSubData", "out of range"); |
- return; |
- } |
+ buffer->SetRange(offset, size, data); |
if (!buffer->IsClientSideArray()) { |
glBufferSubData(target, offset, size, data); |
@@ -500,42 +505,16 @@ void BufferManager::ValidateAndDoCopyBufferSubData( |
ContextState* context_state, GLenum readtarget, GLenum writetarget, |
GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) { |
const char* func_name = "glCopyBufferSubData"; |
- ErrorState* error_state = context_state->GetErrorState(); |
- |
- Buffer* readbuffer = GetBufferInfoForTarget(context_state, readtarget); |
- if (!readbuffer) { |
- ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
- "no buffer is bound to readtarget"); |
+ Buffer* readbuffer = RequestBufferAccess( |
+ context_state, readtarget, readoffset, size, func_name); |
+ if (!readbuffer) |
return; |
- } |
- if (readbuffer->GetMappedRange()) { |
- ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
- "buffer bound to readtarget is mapped"); |
+ Buffer* writebuffer = RequestBufferAccess( |
+ context_state, writetarget, writeoffset, size, func_name); |
+ if (!writebuffer) |
return; |
- } |
- if (!readbuffer->CheckRange(readoffset, size)) { |
- ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, |
- "readoffset/size out of range"); |
- return; |
- } |
- |
- Buffer* writebuffer = GetBufferInfoForTarget(context_state, writetarget); |
- if (!writebuffer) { |
- ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
- "no buffer is bound to writetarget"); |
- return; |
- } |
- if (writebuffer->GetMappedRange()) { |
- ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
- "buffer bound to writetarget is mapped"); |
- return; |
- } |
- if (!writebuffer->CheckRange(writeoffset, size)) { |
- ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, func_name, |
- "writeoffset/size out of range"); |
- return; |
- } |
+ ErrorState* error_state = context_state->GetErrorState(); |
if (readbuffer == writebuffer && |
((writeoffset >= readoffset && writeoffset < readoffset + size) || |
(readoffset >= writeoffset && readoffset < writeoffset + size))) { |
@@ -572,8 +551,7 @@ void BufferManager::DoCopyBufferSubData( |
if (writebuffer->shadowed()) { |
const void* data = readbuffer->GetRange(readoffset, size); |
DCHECK(data); |
- bool success = writebuffer->SetRange(writeoffset, size, data); |
- DCHECK(success); |
+ writebuffer->SetRange(writeoffset, size, data); |
} |
glCopyBufferSubData(readtarget, writetarget, readoffset, writeoffset, size); |
@@ -757,5 +735,71 @@ bool BufferManager::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, |
return true; |
} |
+Buffer* BufferManager::RequestBufferAccess(ContextState* context_state, |
+ GLenum target, |
+ GLintptr offset, |
+ GLsizeiptr size, |
+ const char* func_name) { |
+ DCHECK(context_state); |
+ ErrorState* error_state = context_state->GetErrorState(); |
+ |
+ std::string msg_tag = base::StringPrintf("bound to target 0x%04x", target); |
+ Buffer* buffer = GetBufferInfoForTarget(context_state, target); |
+ if (!RequestBufferAccess(error_state, buffer, func_name, msg_tag.c_str())) { |
+ return nullptr; |
+ } |
+ if (!buffer->CheckRange(offset, size)) { |
+ std::string msg = base::StringPrintf( |
+ "%s : offset/size out of range", msg_tag.c_str()); |
+ ERRORSTATE_SET_GL_ERROR( |
+ error_state, GL_INVALID_VALUE, func_name, msg.c_str()); |
+ return nullptr; |
+ } |
+ return buffer; |
+} |
+ |
+Buffer* BufferManager::RequestBufferAccess(ContextState* context_state, |
+ GLenum target, |
+ const char* func_name) { |
+ DCHECK(context_state); |
+ ErrorState* error_state = context_state->GetErrorState(); |
+ |
+ std::string msg_tag = base::StringPrintf("bound to target 0x%04x", target); |
+ Buffer* buffer = GetBufferInfoForTarget(context_state, target); |
+ return RequestBufferAccess( |
+ error_state, buffer, func_name, msg_tag.c_str()) ? buffer : nullptr; |
+} |
+ |
+bool BufferManager::RequestBufferAccess(ErrorState* error_state, |
+ Buffer* buffer, |
+ const char* func_name, |
+ const char* message_tag) { |
+ DCHECK(error_state); |
+ |
+ if (!buffer || buffer->IsDeleted()) { |
+ std::string msg = base::StringPrintf("%s : no buffer", message_tag); |
+ ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
+ msg.c_str()); |
+ return false; |
+ } |
+ if (buffer->GetMappedRange()) { |
+ std::string msg = base::StringPrintf("%s : buffer is mapped", message_tag); |
+ ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, func_name, |
+ msg.c_str()); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+void BufferManager::IncreaseMappedBufferCount() { |
+ DCHECK_GT(std::numeric_limits<uint32_t>::max(), mapped_buffer_count_); |
+ mapped_buffer_count_++; |
+} |
+ |
+void BufferManager::DecreaseMappedBufferCount() { |
+ DCHECK_LT(0u, mapped_buffer_count_); |
+ mapped_buffer_count_--; |
+} |
+ |
} // namespace gles2 |
} // namespace gpu |