Index: gpu/command_buffer/service/gles2_cmd_decoder.cc |
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
index f76c085eb35b97d269bc5549fb29b0996e1b7a48..3e568e3c5ed7e3ce11285591512433a31326867b 100644 |
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
@@ -2474,14 +2474,6 @@ bool GLES2DecoderImpl::Initialize( |
set_log_commands(true); |
} |
- if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kEnableUnsafeES3APIs) && |
- attrib_parser.es3_context_required) { |
- // TODO(zmo): We need to implement capabilities check to ensure we can |
- // actually create ES3 contexts. |
- set_unsafe_es3_apis_enabled(true); |
- } |
- |
compile_shader_always_succeeds_ = |
base::CommandLine::ForCurrentProcess()->HasSwitch( |
switches::kCompileShaderAlwaysSucceeds); |
@@ -2516,6 +2508,14 @@ bool GLES2DecoderImpl::Initialize( |
} |
CHECK_GL_ERROR(); |
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kEnableUnsafeES3APIs) && |
+ attrib_parser.es3_context_required && |
+ feature_info_->IsES3Capable()) { |
+ feature_info_->EnableES3Validators(); |
+ set_unsafe_es3_apis_enabled(true); |
+ } |
+ |
disallowed_features_ = disallowed_features; |
state_.attrib_values.resize(group_->max_vertex_attribs()); |
@@ -3113,6 +3113,7 @@ void GLES2DecoderImpl::DeleteBuffersHelper( |
for (GLsizei ii = 0; ii < n; ++ii) { |
Buffer* buffer = GetBuffer(client_ids[ii]); |
if (buffer && !buffer->IsDeleted()) { |
+ buffer->RemoveMappedRange(); |
state_.vertex_attrib_manager->Unbind(buffer); |
if (state_.bound_array_buffer.get() == buffer) { |
state_.bound_array_buffer = NULL; |
@@ -12288,6 +12289,118 @@ error::Error GLES2DecoderImpl::HandleWaitSync( |
return error::kNoError; |
} |
+error::Error GLES2DecoderImpl::HandleMapBufferRange( |
+ uint32_t immediate_data_size, const void* cmd_data) { |
+ if (!unsafe_es3_apis_enabled()) { |
+ return error::kUnknownCommand; |
+ } |
+ const gles2::cmds::MapBufferRange& c = |
+ *static_cast<const gles2::cmds::MapBufferRange*>(cmd_data); |
+ GLenum target = static_cast<GLenum>(c.target); |
+ GLbitfield access = static_cast<GLbitfield>(c.access); |
+ GLintptr offset = static_cast<GLintptr>(c.offset); |
+ GLsizeiptr size = static_cast<GLsizeiptr>(c.size); |
+ |
+ typedef cmds::MapBufferRange::Result Result; |
+ Result* result = GetSharedMemoryAs<Result*>( |
+ c.result_shm_id, c.result_shm_offset, sizeof(*result)); |
+ if (!result) { |
+ return error::kOutOfBounds; |
+ } |
+ if (*result != 0) { |
+ *result = 0; |
+ return error::kInvalidArguments; |
+ } |
+ int8_t* mem = |
+ GetSharedMemoryAs<int8_t*>(c.data_shm_id, c.data_shm_offset, size); |
+ if (!mem) { |
+ return error::kOutOfBounds; |
+ } |
+ |
+ GLbitfield mask = GL_MAP_INVALIDATE_BUFFER_BIT; |
+ if ((access & mask) == mask) { |
+ // TODO(zmo): To be on the safe side, always map |
+ // GL_MAP_INVALIDATE_BUFFER_BIT to GL_MAP_INVALIDATE_RANGE_BIT. |
+ access = (access & ~GL_MAP_INVALIDATE_BUFFER_BIT); |
+ access = (access | GL_MAP_INVALIDATE_RANGE_BIT); |
+ } |
+ // TODO(zmo): Always filter out GL_MAP_UNSYNCHRONIZED_BIT to get rid of |
+ // undefined behaviors. |
+ mask = GL_MAP_READ_BIT | GL_MAP_UNSYNCHRONIZED_BIT; |
+ if ((access & mask) == mask) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "MapBufferRange", |
+ "incompatible access bits"); |
+ return error::kNoError; |
+ } |
+ access = (access & ~GL_MAP_UNSYNCHRONIZED_BIT); |
+ if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT && |
+ (access & GL_MAP_INVALIDATE_RANGE_BIT) == 0) { |
+ access = (access | GL_MAP_READ_BIT); |
+ } |
+ void* ptr = glMapBufferRange(target, offset, size, access); |
+ if (ptr == nullptr) { |
+ return error::kNoError; |
+ } |
+ Buffer* buffer = buffer_manager()->GetBufferInfoForTarget(&state_, target); |
+ DCHECK(buffer); |
+ buffer->SetMappedRange(offset, size, access, ptr, |
+ GetSharedMemoryBuffer(c.data_shm_id)); |
+ if ((access & GL_MAP_INVALIDATE_RANGE_BIT) == 0) { |
+ memcpy(mem, ptr, size); |
+ } |
+ *result = 1; |
+ return error::kNoError; |
+} |
+ |
+error::Error GLES2DecoderImpl::HandleUnmapBuffer( |
+ uint32_t immediate_data_size, const void* cmd_data) { |
+ if (!unsafe_es3_apis_enabled()) { |
+ return error::kUnknownCommand; |
+ } |
+ const gles2::cmds::UnmapBuffer& c = |
+ *static_cast<const gles2::cmds::UnmapBuffer*>(cmd_data); |
+ GLenum target = static_cast<GLenum>(c.target); |
+ |
+ Buffer* buffer = buffer_manager()->GetBufferInfoForTarget(&state_, target); |
+ if (!buffer) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "UnmapBuffer", "no buffer bound"); |
+ return error::kNoError; |
+ } |
+ const Buffer::MappedRange* mapped_range = buffer->GetMappedRange(); |
+ if (!mapped_range) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "UnmapBuffer", |
+ "buffer is unmapped"); |
+ return error::kNoError; |
+ } |
+ if ((mapped_range->access & GL_MAP_WRITE_BIT) == 0 || |
+ (mapped_range->access & GL_MAP_FLUSH_EXPLICIT_BIT) == |
+ GL_MAP_FLUSH_EXPLICIT_BIT) { |
+ // If we don't need to write back, or explict flush is required, no copying |
+ // back is needed. |
+ } else { |
+ void* mem = mapped_range->GetShmPointer(); |
+ if (!mem) { |
+ return error::kOutOfBounds; |
+ } |
+ DCHECK(mapped_range->pointer); |
+ memcpy(mapped_range->pointer, mem, mapped_range->size); |
+ } |
+ buffer->RemoveMappedRange(); |
+ GLboolean rt = glUnmapBuffer(target); |
+ if (rt == GL_FALSE) { |
+ // At this point, we have already done the necessary validation, so |
+ // GL_FALSE indicates data corruption. |
+ // TODO(zmo): We could redo the map / copy data / unmap to recover, but |
+ // the second unmap could still return GL_FALSE. For now, we simply lose |
+ // the contexts in the share group. |
+ LOG(ERROR) << "glUnmapBuffer unexpectedly returned GL_FALSE"; |
+ group_->LoseContexts(GL_INNOCENT_CONTEXT_RESET_ARB); |
+ reset_status_ = GL_GUILTY_CONTEXT_RESET_ARB; |
+ return error::kLostContext; |
+ } |
+ return error::kNoError; |
+} |
+ |
void GLES2DecoderImpl::OnTextureRefDetachedFromFramebuffer( |
TextureRef* texture_ref) { |
Texture* texture = texture_ref->texture(); |