| 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 85b7df82f8ca9908ac73845b9a4515c343df7495..7360e89ca013a2ecb485bc063fc556667a3e1bdc 100644
|
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| @@ -166,6 +166,25 @@ struct TexSubCoord3D {
|
| int depth;
|
| };
|
|
|
| +// Check if all |ref| bits are set in |bits|.
|
| +bool AllBitsSet(GLbitfield bits, GLbitfield ref) {
|
| + DCHECK_NE(0u, ref);
|
| + return ((bits & ref) == ref);
|
| +}
|
| +
|
| +// Check if any of |ref| bits are set in |bits|.
|
| +bool AnyBitsSet(GLbitfield bits, GLbitfield ref) {
|
| + DCHECK_NE(0u, ref);
|
| + return ((bits & ref) != 0);
|
| +}
|
| +
|
| +// Check if any bits are set in |bits| other than the bits in |ref|.
|
| +bool AnyOtherBitsSet(GLbitfield bits, GLbitfield ref) {
|
| + DCHECK_NE(0u, ref);
|
| + GLbitfield mask = ~ref;
|
| + return ((bits & mask) != 0);
|
| +}
|
| +
|
| } // namespace
|
|
|
| class GLES2DecoderImpl;
|
| @@ -1034,6 +1053,9 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
|
| void DoScheduleCALayerInUseQueryCHROMIUM(GLsizei count,
|
| const volatile GLuint* textures);
|
|
|
| + void DoFlushMappedBufferRange(
|
| + GLenum target, GLintptr offset, GLsizeiptr size);
|
| +
|
| // Creates a Program for the given program.
|
| Program* CreateProgram(GLuint client_id, GLuint service_id) {
|
| return program_manager()->CreateProgram(client_id, service_id);
|
| @@ -16831,37 +16853,10 @@ error::Error GLES2DecoderImpl::HandleMapBufferRange(
|
| *result = 0;
|
| return error::kInvalidArguments;
|
| }
|
| - int8_t* mem =
|
| - GetSharedMemoryAs<int8_t*>(data_shm_id, data_shm_offset, size);
|
| - if (!mem) {
|
| - return error::kOutOfBounds;
|
| - }
|
| -
|
| if (!validators_->buffer_target.IsValid(target)) {
|
| LOCAL_SET_GL_ERROR_INVALID_ENUM(func_name, target, "target");
|
| return error::kNoError;
|
| }
|
| -
|
| - 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, func_name, "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);
|
| - }
|
| Buffer* buffer = buffer_manager()->GetBufferInfoForTarget(&state_, target);
|
| if (!buffer) {
|
| LOCAL_SET_GL_ERROR(
|
| @@ -16871,11 +16866,62 @@ error::Error GLES2DecoderImpl::HandleMapBufferRange(
|
| if (buffer->GetMappedRange()) {
|
| LOCAL_SET_GL_ERROR(
|
| GL_INVALID_OPERATION, func_name, "buffer is already mapped");
|
| + return error::kNoError;
|
| + }
|
| + if (size == 0) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, "size is zero");
|
| + return error::kNoError;
|
| }
|
| if (!buffer->CheckRange(offset, size)) {
|
| LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "invalid range");
|
| return error::kNoError;
|
| }
|
| + int8_t* mem =
|
| + GetSharedMemoryAs<int8_t*>(data_shm_id, data_shm_offset, size);
|
| + if (!mem) {
|
| + return error::kOutOfBounds;
|
| + }
|
| + if (AnyOtherBitsSet(access, (GL_MAP_READ_BIT |
|
| + GL_MAP_WRITE_BIT |
|
| + GL_MAP_INVALIDATE_RANGE_BIT |
|
| + GL_MAP_INVALIDATE_BUFFER_BIT |
|
| + GL_MAP_FLUSH_EXPLICIT_BIT |
|
| + GL_MAP_UNSYNCHRONIZED_BIT))) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, "invalid access bits");
|
| + return error::kNoError;
|
| + }
|
| + if (!AnyBitsSet(access, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
|
| + "neither MAP_READ_BIT nore MAP_WRITE_BIT is set");
|
| + return error::kNoError;
|
| + }
|
| + if (AllBitsSet(access, GL_MAP_READ_BIT) &&
|
| + AnyBitsSet(access, (GL_MAP_INVALIDATE_RANGE_BIT |
|
| + GL_MAP_INVALIDATE_BUFFER_BIT |
|
| + GL_MAP_UNSYNCHRONIZED_BIT))) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
|
| + "Incompatible access bits with MAP_READ_BIT");
|
| + return error::kNoError;
|
| + }
|
| + if (AllBitsSet(access, GL_MAP_FLUSH_EXPLICIT_BIT) &&
|
| + !AllBitsSet(access, GL_MAP_WRITE_BIT)) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
|
| + "MAP_FLUSH_EXPLICIT_BIT set without MAP_WRITE_BIT");
|
| + return error::kNoError;
|
| + }
|
| + if (AllBitsSet(access, GL_MAP_INVALIDATE_BUFFER_BIT)) {
|
| + // 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);
|
| + }
|
| + // Always filter out GL_MAP_UNSYNCHRONIZED_BIT to get rid of undefined
|
| + // behaviors.
|
| + access = (access & ~GL_MAP_UNSYNCHRONIZED_BIT);
|
| + if (AllBitsSet(access, GL_MAP_WRITE_BIT) &&
|
| + !AllBitsSet(access, GL_MAP_INVALIDATE_RANGE_BIT)) {
|
| + access = (access | GL_MAP_READ_BIT);
|
| + }
|
| void* ptr = glMapBufferRange(target, offset, size, access);
|
| if (ptr == nullptr) {
|
| return error::kNoError;
|
| @@ -16891,41 +16937,38 @@ error::Error GLES2DecoderImpl::HandleMapBufferRange(
|
| }
|
|
|
| error::Error GLES2DecoderImpl::HandleUnmapBuffer(
|
| - uint32_t immediate_data_size,
|
| - const volatile void* cmd_data) {
|
| + uint32_t immediate_data_size, const volatile void* cmd_data) {
|
| if (!unsafe_es3_apis_enabled()) {
|
| return error::kUnknownCommand;
|
| }
|
| + const char* func_name = "glUnmapBuffer";
|
| +
|
| const volatile gles2::cmds::UnmapBuffer& c =
|
| *static_cast<const volatile gles2::cmds::UnmapBuffer*>(cmd_data);
|
| GLenum target = static_cast<GLenum>(c.target);
|
|
|
| if (!validators_->buffer_target.IsValid(target)) {
|
| - LOCAL_SET_GL_ERROR_INVALID_ENUM("glMapBufferRange", target, "target");
|
| + LOCAL_SET_GL_ERROR_INVALID_ENUM(func_name, target, "target");
|
| return error::kNoError;
|
| }
|
|
|
| Buffer* buffer = buffer_manager()->GetBufferInfoForTarget(&state_, target);
|
| if (!buffer) {
|
| - LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "UnmapBuffer", "no buffer bound");
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, "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");
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, "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 (!AllBitsSet(mapped_range->access, GL_MAP_WRITE_BIT) ||
|
| + AllBitsSet(mapped_range->access, 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(mem);
|
| DCHECK(mapped_range->pointer);
|
| memcpy(mapped_range->pointer, mem, mapped_range->size);
|
| if (buffer->shadowed()) {
|
| @@ -16942,7 +16985,7 @@ error::Error GLES2DecoderImpl::HandleUnmapBuffer(
|
| // 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";
|
| + LOG(ERROR) << func_name << " unexpectedly returned GL_FALSE";
|
| // Need to lose current context before broadcasting!
|
| MarkContextLost(error::kGuilty);
|
| group_->LoseContexts(error::kInnocent);
|
| @@ -16951,6 +16994,50 @@ error::Error GLES2DecoderImpl::HandleUnmapBuffer(
|
| return error::kNoError;
|
| }
|
|
|
| +void GLES2DecoderImpl::DoFlushMappedBufferRange(
|
| + GLenum target, GLintptr offset, GLsizeiptr size) {
|
| + const char* func_name = "glFlushMappedBufferRange";
|
| + // |size| is validated in HandleFlushMappedBufferRange().
|
| + if (offset < 0) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "offset < 0");
|
| + return;
|
| + }
|
| + Buffer* buffer = buffer_manager()->GetBufferInfoForTarget(&state_, target);
|
| + if (!buffer) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, "no buffer bound");
|
| + return;
|
| + }
|
| + const Buffer::MappedRange* mapped_range = buffer->GetMappedRange();
|
| + if (!mapped_range) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, "buffer is unmapped");
|
| + return;
|
| + }
|
| + if (!AllBitsSet(mapped_range->access, GL_MAP_FLUSH_EXPLICIT_BIT)) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
|
| + "buffer is mapped without MAP_FLUSH_EXPLICIT_BIT flag");
|
| + return;
|
| + }
|
| + base::CheckedNumeric<int32_t> range_size = size;
|
| + range_size += offset;
|
| + if (!range_size.IsValid() ||
|
| + range_size.ValueOrDefault(0) > mapped_range->size) {
|
| + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name,
|
| + "offset + size out of bounds");
|
| + return;
|
| + }
|
| + char* client_data = reinterpret_cast<char*>(mapped_range->GetShmPointer());
|
| + DCHECK(client_data);
|
| + char* gpu_data = reinterpret_cast<char*>(mapped_range->pointer);
|
| + DCHECK(gpu_data);
|
| + memcpy(gpu_data + offset, client_data + offset, size);
|
| + if (buffer->shadowed()) {
|
| + bool success = buffer->SetRange(
|
| + mapped_range->offset + offset, size, client_data + offset);
|
| + DCHECK(success);
|
| + }
|
| + glFlushMappedBufferRange(target, offset, size);
|
| +}
|
| +
|
| // Note that GL_LOST_CONTEXT is specific to GLES.
|
| // For desktop GL we have to query the reset status proactively.
|
| void GLES2DecoderImpl::OnContextLostError() {
|
|
|