diff options
author | zmo <zmo@chromium.org> | 2015-03-11 17:48:25 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-12 00:49:13 +0000 |
commit | 2a09dc05582a7cb4664e9f18cb2c4ba1e39e0c98 (patch) | |
tree | 826bac9a2b8e9dd92b59e427742142de57e33ddb /gpu | |
parent | 33886ae4a9d84cee3effc75f86feb22b27bde49d (diff) | |
download | chromium_src-2a09dc05582a7cb4664e9f18cb2c4ba1e39e0c98.zip chromium_src-2a09dc05582a7cb4664e9f18cb2c4ba1e39e0c98.tar.gz chromium_src-2a09dc05582a7cb4664e9f18cb2c4ba1e39e0c98.tar.bz2 |
Add ES3 command glUnmapBuffer to GPU command buffer.
BUG=429053
TEST=gpu_unittests
R=piman@chromium.org
Review URL: https://codereview.chromium.org/996913002
Cr-Commit-Position: refs/heads/master@{#320194}
Diffstat (limited to 'gpu')
22 files changed, 536 insertions, 110 deletions
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h index 0f3ebf3..d04bf11 100644 --- a/gpu/GLES2/gl2chromium_autogen.h +++ b/gpu/GLES2/gl2chromium_autogen.h @@ -257,6 +257,7 @@ #define glMapBufferSubDataCHROMIUM GLES2_GET_FUN(MapBufferSubDataCHROMIUM) #define glUnmapBufferSubDataCHROMIUM GLES2_GET_FUN(UnmapBufferSubDataCHROMIUM) #define glMapBufferRange GLES2_GET_FUN(MapBufferRange) +#define glUnmapBuffer GLES2_GET_FUN(UnmapBuffer) #define glMapTexSubImage2DCHROMIUM GLES2_GET_FUN(MapTexSubImage2DCHROMIUM) #define glUnmapTexSubImage2DCHROMIUM GLES2_GET_FUN(UnmapTexSubImage2DCHROMIUM) #define glResizeCHROMIUM GLES2_GET_FUN(ResizeCHROMIUM) diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 4207305..3e86540 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -2912,6 +2912,10 @@ _FUNCTION_INFO = { 'client_test': False, 'pepper_interface': 'ChromiumMapSub', }, + 'UnmapBuffer': { + 'type': 'Custom', + 'unsafe': True, + }, 'UnmapTexSubImage2DCHROMIUM': { 'gen_cmd': False, 'extension': True, diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 84a5708..ff604c6 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h @@ -1071,6 +1071,9 @@ void* GLES2MapBufferRange(GLenum target, GLbitfield access) { return gles2::GetGLContext()->MapBufferRange(target, offset, size, access); } +GLboolean GLES2UnmapBuffer(GLenum target) { + return gles2::GetGLContext()->UnmapBuffer(target); +} void* GLES2MapTexSubImage2DCHROMIUM(GLenum target, GLint level, GLint xoffset, @@ -2303,6 +2306,10 @@ extern const NameToFunc g_gles2_function_table[] = { reinterpret_cast<GLES2FunctionPointer>(glMapBufferRange), }, { + "glUnmapBuffer", + reinterpret_cast<GLES2FunctionPointer>(glUnmapBuffer), + }, + { "glMapTexSubImage2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(glMapTexSubImage2DCHROMIUM), }, diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index e9abfc7..bd40e41 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h @@ -2241,6 +2241,13 @@ void MapBufferRange(GLenum target, } } +void UnmapBuffer(GLenum target) { + gles2::cmds::UnmapBuffer* c = GetCmdSpace<gles2::cmds::UnmapBuffer>(); + if (c) { + c->Init(target); + } +} + void ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) { gles2::cmds::ResizeCHROMIUM* c = GetCmdSpace<gles2::cmds::ResizeCHROMIUM>(); if (c) { diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 74e79ef..c31ee5e 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -3748,6 +3748,45 @@ void* GLES2Implementation::MapBufferRange( return mem; } +GLboolean GLES2Implementation::UnmapBuffer(GLenum target) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer(" + << GLES2Util::GetStringEnum(target) << ")"); + switch (target) { + case GL_ARRAY_BUFFER: + case GL_ELEMENT_ARRAY_BUFFER: + case GL_COPY_READ_BUFFER: + case GL_COPY_WRITE_BUFFER: + case GL_PIXEL_PACK_BUFFER: + case GL_PIXEL_UNPACK_BUFFER: + case GL_TRANSFORM_FEEDBACK_BUFFER: + case GL_UNIFORM_BUFFER: + break; + default: + SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target"); + return GL_FALSE; + } + GLuint buffer = GetBoundBufferHelper(target); + if (buffer == 0) { + SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound"); + return GL_FALSE; + } + auto iter = mapped_buffer_range_map_.find(buffer); + if (iter == mapped_buffer_range_map_.end()) { + SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped"); + return GL_FALSE; + } + + helper_->UnmapBuffer(target); + RemoveMappedBufferRangeById(buffer); + // TODO(zmo): There is a rare situation that data might be corrupted and + // GL_FALSE should be returned. We lose context on that sitatuon, so we + // don't have to WaitForCmd(). + GPU_CLIENT_LOG(" returned " << GL_TRUE); + CheckGLError(); + return GL_TRUE; +} + void* GLES2Implementation::MapTexSubImage2DCHROMIUM( GLenum target, GLint level, diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 5111a6a..a452193 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -805,6 +805,8 @@ void* MapBufferRange(GLenum target, GLsizeiptr size, GLbitfield access) override; +GLboolean UnmapBuffer(GLenum target) override; + void* MapTexSubImage2DCHROMIUM(GLenum target, GLint level, GLint xoffset, diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 16908ca..4fecbbc 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc @@ -3600,7 +3600,7 @@ TEST_F(GLES2ImplementationTest, WaitSync) { EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } -TEST_F(GLES2ImplementationTest, MapBufferRangeWrite) { +TEST_F(GLES2ImplementationTest, MapBufferRangeUnmapBufferWrite) { ExpectedMemoryInfo result = GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result)); @@ -3613,6 +3613,8 @@ TEST_F(GLES2ImplementationTest, MapBufferRangeWrite) { void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT); EXPECT_TRUE(mem != nullptr); + + EXPECT_TRUE(gl_->UnmapBuffer(GL_ARRAY_BUFFER)); } TEST_F(GLES2ImplementationTest, MapBufferRangeWriteWithInvalidateBit) { @@ -3652,7 +3654,7 @@ TEST_F(GLES2ImplementationTest, MapBufferRangeWriteWithGLError) { EXPECT_TRUE(mem == nullptr); } -TEST_F(GLES2ImplementationTest, MapBufferRangeRead) { +TEST_F(GLES2ImplementationTest, MapBufferRangeUnmapBufferRead) { ExpectedMemoryInfo result = GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result)); @@ -3665,6 +3667,8 @@ TEST_F(GLES2ImplementationTest, MapBufferRangeRead) { void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_READ_BIT); EXPECT_TRUE(mem != nullptr); + + EXPECT_TRUE(gl_->UnmapBuffer(GL_ARRAY_BUFFER)); } TEST_F(GLES2ImplementationTest, MapBufferRangeReadWithGLError) { @@ -3683,6 +3687,63 @@ TEST_F(GLES2ImplementationTest, MapBufferRangeReadWithGLError) { EXPECT_TRUE(mem == nullptr); } +TEST_F(GLES2ImplementationTest, UnmapBufferFails) { + // No bound buffer. + EXPECT_FALSE(gl_->UnmapBuffer(GL_ARRAY_BUFFER)); + EXPECT_EQ(GL_INVALID_OPERATION, CheckError()); + + const GLuint kBufferId = 123; + gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId); + + // Buffer is unmapped. + EXPECT_FALSE(gl_->UnmapBuffer(GL_ARRAY_BUFFER)); + EXPECT_EQ(GL_INVALID_OPERATION, CheckError()); +} + +TEST_F(GLES2ImplementationTest, BufferDataUnmapsDataStore) { + ExpectedMemoryInfo result = + GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result)); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result.ptr, uint32_t(1))) + .RetiresOnSaturation(); + + const GLuint kBufferId = 123; + gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId); + + void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT); + EXPECT_TRUE(mem != nullptr); + + std::vector<uint8_t> data(16); + // BufferData unmaps the data store. + gl_->BufferData(GL_ARRAY_BUFFER, 16, &data[0], GL_STREAM_DRAW); + + EXPECT_FALSE(gl_->UnmapBuffer(GL_ARRAY_BUFFER)); + EXPECT_EQ(GL_INVALID_OPERATION, CheckError()); +} + +TEST_F(GLES2ImplementationTest, DeleteBuffersUnmapsDataStore) { + ExpectedMemoryInfo result = + GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result)); + + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillOnce(SetMemory(result.ptr, uint32_t(1))) + .RetiresOnSaturation(); + + const GLuint kBufferId = 123; + gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId); + + void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT); + EXPECT_TRUE(mem != nullptr); + + std::vector<uint8_t> data(16); + // DeleteBuffers unmaps the data store. + gl_->DeleteBuffers(1, &kBufferId); + + EXPECT_FALSE(gl_->UnmapBuffer(GL_ARRAY_BUFFER)); + EXPECT_EQ(GL_INVALID_OPERATION, CheckError()); +} + TEST_F(GLES2ImplementationManualInitTest, LoseContextOnOOM) { ContextInitOptions init_options; init_options.lose_context_when_out_of_memory = true; diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index 4785ff0..ad794d2 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h @@ -2719,6 +2719,7 @@ TEST_F(GLES2ImplementationTest, IsVertexArrayOES) { } // TODO(zmo): Implement unit test for EnableFeatureCHROMIUM // TODO(zmo): Implement unit test for MapBufferRange +// TODO(zmo): Implement unit test for UnmapBuffer TEST_F(GLES2ImplementationTest, ResizeCHROMIUM) { struct Cmds { diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h index a181c43..0a3c12bf 100644 --- a/gpu/command_buffer/client/gles2_interface_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_autogen.h @@ -587,6 +587,7 @@ virtual void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) = 0; +virtual GLboolean UnmapBuffer(GLenum target) = 0; virtual void* MapTexSubImage2DCHROMIUM(GLenum target, GLint level, GLint xoffset, diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h index 48697d5..fd933f2 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h @@ -572,6 +572,7 @@ void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) override; +GLboolean UnmapBuffer(GLenum target) override; void* MapTexSubImage2DCHROMIUM(GLenum target, GLint level, GLint xoffset, diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h index dfbb319..e350029 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h @@ -993,6 +993,9 @@ void* GLES2InterfaceStub::MapBufferRange(GLenum /* target */, GLbitfield /* access */) { return 0; } +GLboolean GLES2InterfaceStub::UnmapBuffer(GLenum /* target */) { + return 0; +} void* GLES2InterfaceStub::MapTexSubImage2DCHROMIUM(GLenum /* target */, GLint /* level */, GLint /* xoffset */, diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h index 32ccdab..9d148ce 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h @@ -572,6 +572,7 @@ void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) override; +GLboolean UnmapBuffer(GLenum target) override; void* MapTexSubImage2DCHROMIUM(GLenum target, GLint level, GLint xoffset, diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h index 327becc..699f99b 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h @@ -1691,6 +1691,11 @@ void* GLES2TraceImplementation::MapBufferRange(GLenum target, return gl_->MapBufferRange(target, offset, size, access); } +GLboolean GLES2TraceImplementation::UnmapBuffer(GLenum target) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UnmapBuffer"); + return gl_->UnmapBuffer(target); +} + void* GLES2TraceImplementation::MapTexSubImage2DCHROMIUM(GLenum target, GLint level, GLint xoffset, diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index 153aca4..8d32d99 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt @@ -247,6 +247,7 @@ GL_APICALL GLboolean GL_APIENTRY glUnmapBufferCHROMIUM (GLuint target); GL_APICALL void* GL_APIENTRY glMapBufferSubDataCHROMIUM (GLuint target, GLintptrNotNegative offset, GLsizeiptr size, GLenum access); GL_APICALL void GL_APIENTRY glUnmapBufferSubDataCHROMIUM (const void* mem); GL_APICALL void* GL_APIENTRY glMapBufferRange (GLenumBufferTarget target, GLintptrNotNegative offset, GLsizeiptr size, GLbitfieldMapBufferAccess access); +GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer (GLenumBufferTarget target); GL_APICALL void* GL_APIENTRY glMapTexSubImage2DCHROMIUM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLenum access); GL_APICALL void GL_APIENTRY glUnmapTexSubImage2DCHROMIUM (const void* mem); GL_APICALL void GL_APIENTRY glResizeCHROMIUM (GLuint width, GLuint height, GLfloat scale_factor); diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index 251bfff..a829dcb 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h @@ -11019,6 +11019,38 @@ static_assert(offsetof(MapBufferRange, result_shm_id) == 28, static_assert(offsetof(MapBufferRange, result_shm_offset) == 32, "offset of MapBufferRange result_shm_offset should be 32"); +struct UnmapBuffer { + typedef UnmapBuffer ValueType; + static const CommandId kCmdId = kUnmapBuffer; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLenum _target) { + SetHeader(); + target = _target; + } + + void* Set(void* cmd, GLenum _target) { + static_cast<ValueType*>(cmd)->Init(_target); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t target; +}; + +static_assert(sizeof(UnmapBuffer) == 8, "size of UnmapBuffer should be 8"); +static_assert(offsetof(UnmapBuffer, header) == 0, + "offset of UnmapBuffer header should be 0"); +static_assert(offsetof(UnmapBuffer, target) == 4, + "offset of UnmapBuffer target should be 4"); + struct ResizeCHROMIUM { typedef ResizeCHROMIUM ValueType; static const CommandId kCmdId = kResizeCHROMIUM; diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index 55485bf..d14f48df 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h @@ -3799,6 +3799,16 @@ TEST_F(GLES2FormatTest, MapBufferRange) { CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, UnmapBuffer) { + cmds::UnmapBuffer& cmd = *GetBufferAs<cmds::UnmapBuffer>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11)); + EXPECT_EQ(static_cast<uint32_t>(cmds::UnmapBuffer::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.target); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + TEST_F(GLES2FormatTest, ResizeCHROMIUM) { cmds::ResizeCHROMIUM& cmd = *GetBufferAs<cmds::ResizeCHROMIUM>(); void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index 997268c2..ea62be1 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h @@ -244,53 +244,54 @@ OP(GetMaxValueInBufferCHROMIUM) /* 485 */ \ OP(EnableFeatureCHROMIUM) /* 486 */ \ OP(MapBufferRange) /* 487 */ \ - OP(ResizeCHROMIUM) /* 488 */ \ - OP(GetRequestableExtensionsCHROMIUM) /* 489 */ \ - OP(RequestExtensionCHROMIUM) /* 490 */ \ - OP(GetProgramInfoCHROMIUM) /* 491 */ \ - OP(GetUniformBlocksCHROMIUM) /* 492 */ \ - OP(GetTransformFeedbackVaryingsCHROMIUM) /* 493 */ \ - OP(GetUniformsES3CHROMIUM) /* 494 */ \ - OP(GetTranslatedShaderSourceANGLE) /* 495 */ \ - OP(PostSubBufferCHROMIUM) /* 496 */ \ - OP(TexImageIOSurface2DCHROMIUM) /* 497 */ \ - OP(CopyTextureCHROMIUM) /* 498 */ \ - OP(CopySubTextureCHROMIUM) /* 499 */ \ - OP(DrawArraysInstancedANGLE) /* 500 */ \ - OP(DrawElementsInstancedANGLE) /* 501 */ \ - OP(VertexAttribDivisorANGLE) /* 502 */ \ - OP(GenMailboxCHROMIUM) /* 503 */ \ - OP(ProduceTextureCHROMIUMImmediate) /* 504 */ \ - OP(ProduceTextureDirectCHROMIUMImmediate) /* 505 */ \ - OP(ConsumeTextureCHROMIUMImmediate) /* 506 */ \ - OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 507 */ \ - OP(BindUniformLocationCHROMIUMBucket) /* 508 */ \ - OP(GenValuebuffersCHROMIUMImmediate) /* 509 */ \ - OP(DeleteValuebuffersCHROMIUMImmediate) /* 510 */ \ - OP(IsValuebufferCHROMIUM) /* 511 */ \ - OP(BindValuebufferCHROMIUM) /* 512 */ \ - OP(SubscribeValueCHROMIUM) /* 513 */ \ - OP(PopulateSubscribedValuesCHROMIUM) /* 514 */ \ - OP(UniformValuebufferCHROMIUM) /* 515 */ \ - OP(BindTexImage2DCHROMIUM) /* 516 */ \ - OP(ReleaseTexImage2DCHROMIUM) /* 517 */ \ - OP(TraceBeginCHROMIUM) /* 518 */ \ - OP(TraceEndCHROMIUM) /* 519 */ \ - OP(AsyncTexSubImage2DCHROMIUM) /* 520 */ \ - OP(AsyncTexImage2DCHROMIUM) /* 521 */ \ - OP(WaitAsyncTexImage2DCHROMIUM) /* 522 */ \ - OP(WaitAllAsyncTexImage2DCHROMIUM) /* 523 */ \ - OP(DiscardFramebufferEXTImmediate) /* 524 */ \ - OP(LoseContextCHROMIUM) /* 525 */ \ - OP(InsertSyncPointCHROMIUM) /* 526 */ \ - OP(WaitSyncPointCHROMIUM) /* 527 */ \ - OP(DrawBuffersEXTImmediate) /* 528 */ \ - OP(DiscardBackbufferCHROMIUM) /* 529 */ \ - OP(ScheduleOverlayPlaneCHROMIUM) /* 530 */ \ - OP(SwapInterval) /* 531 */ \ - OP(MatrixLoadfCHROMIUMImmediate) /* 532 */ \ - OP(MatrixLoadIdentityCHROMIUM) /* 533 */ \ - OP(BlendBarrierKHR) /* 534 */ + OP(UnmapBuffer) /* 488 */ \ + OP(ResizeCHROMIUM) /* 489 */ \ + OP(GetRequestableExtensionsCHROMIUM) /* 490 */ \ + OP(RequestExtensionCHROMIUM) /* 491 */ \ + OP(GetProgramInfoCHROMIUM) /* 492 */ \ + OP(GetUniformBlocksCHROMIUM) /* 493 */ \ + OP(GetTransformFeedbackVaryingsCHROMIUM) /* 494 */ \ + OP(GetUniformsES3CHROMIUM) /* 495 */ \ + OP(GetTranslatedShaderSourceANGLE) /* 496 */ \ + OP(PostSubBufferCHROMIUM) /* 497 */ \ + OP(TexImageIOSurface2DCHROMIUM) /* 498 */ \ + OP(CopyTextureCHROMIUM) /* 499 */ \ + OP(CopySubTextureCHROMIUM) /* 500 */ \ + OP(DrawArraysInstancedANGLE) /* 501 */ \ + OP(DrawElementsInstancedANGLE) /* 502 */ \ + OP(VertexAttribDivisorANGLE) /* 503 */ \ + OP(GenMailboxCHROMIUM) /* 504 */ \ + OP(ProduceTextureCHROMIUMImmediate) /* 505 */ \ + OP(ProduceTextureDirectCHROMIUMImmediate) /* 506 */ \ + OP(ConsumeTextureCHROMIUMImmediate) /* 507 */ \ + OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 508 */ \ + OP(BindUniformLocationCHROMIUMBucket) /* 509 */ \ + OP(GenValuebuffersCHROMIUMImmediate) /* 510 */ \ + OP(DeleteValuebuffersCHROMIUMImmediate) /* 511 */ \ + OP(IsValuebufferCHROMIUM) /* 512 */ \ + OP(BindValuebufferCHROMIUM) /* 513 */ \ + OP(SubscribeValueCHROMIUM) /* 514 */ \ + OP(PopulateSubscribedValuesCHROMIUM) /* 515 */ \ + OP(UniformValuebufferCHROMIUM) /* 516 */ \ + OP(BindTexImage2DCHROMIUM) /* 517 */ \ + OP(ReleaseTexImage2DCHROMIUM) /* 518 */ \ + OP(TraceBeginCHROMIUM) /* 519 */ \ + OP(TraceEndCHROMIUM) /* 520 */ \ + OP(AsyncTexSubImage2DCHROMIUM) /* 521 */ \ + OP(AsyncTexImage2DCHROMIUM) /* 522 */ \ + OP(WaitAsyncTexImage2DCHROMIUM) /* 523 */ \ + OP(WaitAllAsyncTexImage2DCHROMIUM) /* 524 */ \ + OP(DiscardFramebufferEXTImmediate) /* 525 */ \ + OP(LoseContextCHROMIUM) /* 526 */ \ + OP(InsertSyncPointCHROMIUM) /* 527 */ \ + OP(WaitSyncPointCHROMIUM) /* 528 */ \ + OP(DrawBuffersEXTImmediate) /* 529 */ \ + OP(DiscardBackbufferCHROMIUM) /* 530 */ \ + OP(ScheduleOverlayPlaneCHROMIUM) /* 531 */ \ + OP(SwapInterval) /* 532 */ \ + OP(MatrixLoadfCHROMIUMImmediate) /* 533 */ \ + OP(MatrixLoadIdentityCHROMIUM) /* 534 */ \ + OP(BlendBarrierKHR) /* 535 */ enum CommandId { kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this. diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc index d151a65..c2a0ba5 100644 --- a/gpu/command_buffer/service/buffer_manager.cc +++ b/gpu/command_buffer/service/buffer_manager.cc @@ -74,6 +74,27 @@ void BufferManager::StopTracking(Buffer* buffer) { --buffer_count_; } +Buffer::MappedRange::MappedRange( + GLintptr offset, GLsizeiptr size, GLenum access, void* pointer, + scoped_refptr<gpu::Buffer> shm) + : offset(offset), + size(size), + access(access), + pointer(pointer), + shm(shm) { + DCHECK(pointer); + DCHECK(shm.get() && GetShmPointer()); +} + +Buffer::MappedRange::~MappedRange() { +} + +void* Buffer::MappedRange::GetShmPointer() const { + DCHECK(shm.get()); + return shm->GetDataAddress(static_cast<unsigned int>(offset), + static_cast<unsigned int>(size)); +} + Buffer::Buffer(BufferManager* manager, GLuint service_id) : manager_(manager), size_(0), @@ -82,8 +103,7 @@ Buffer::Buffer(BufferManager* manager, GLuint service_id) is_client_side_array_(false), service_id_(service_id), target_(0), - usage_(GL_STATIC_DRAW), - buffer_range_pointer_(nullptr) { + usage_(GL_STATIC_DRAW) { manager_->StartTracking(this); } @@ -120,7 +140,7 @@ void Buffer::SetInfo( memset(shadow_.get(), 0, size); } } - buffer_range_pointer_ = nullptr; + mapped_range_.reset(nullptr); } bool Buffer::CheckRange( diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h index fb6261d..29bfaf4 100644 --- a/gpu/command_buffer/service/buffer_manager.h +++ b/gpu/command_buffer/service/buffer_manager.h @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "gpu/command_buffer/common/buffer.h" #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/gpu_export.h" @@ -27,6 +28,19 @@ class TestHelper; // Info about Buffers currently in the system. class GPU_EXPORT Buffer : public base::RefCounted<Buffer> { public: + struct MappedRange { + GLintptr offset; + GLsizeiptr size; + GLenum access; + void* pointer; // Pointer returned by driver. + scoped_refptr<gpu::Buffer> shm; // Client side mem. + + MappedRange(GLintptr offset, GLsizeiptr size, GLenum access, + void* pointer, scoped_refptr<gpu::Buffer> shm); + ~MappedRange(); + void* GetShmPointer() const; + }; + Buffer(BufferManager* manager, GLuint service_id); GLuint service_id() const { @@ -67,12 +81,17 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> { return is_client_side_array_; } - void set_buffer_range_pointer(void* mem) { - buffer_range_pointer_ = mem; + void SetMappedRange(GLintptr offset, GLsizeiptr size, GLenum access, + void* pointer, scoped_refptr<gpu::Buffer> shm) { + mapped_range_.reset(new MappedRange(offset, size, access, pointer, shm)); + } + + void RemoveMappedRange() { + mapped_range_.reset(nullptr); } - void* buffer_range_pointer() const { - return buffer_range_pointer_; + const MappedRange* GetMappedRange() const { + return mapped_range_.get(); } private: @@ -171,8 +190,8 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> { // Usage of buffer. GLenum usage_; - // Returned value from last glMapBufferRange call. - void* buffer_range_pointer_; + // Data cached from last glMapBufferRange call. + scoped_ptr<MappedRange> mapped_range_; // A map of ranges to the highest value in that range of a certain type. typedef std::map<Range, GLuint, Range::Less> RangeToMaxValueMap; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 3cf4dda..3e568e3 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -3113,7 +3113,7 @@ void GLES2DecoderImpl::DeleteBuffersHelper( for (GLsizei ii = 0; ii < n; ++ii) { Buffer* buffer = GetBuffer(client_ids[ii]); if (buffer && !buffer->IsDeleted()) { - buffer->set_buffer_range_pointer(nullptr); + buffer->RemoveMappedRange(); state_.vertex_attrib_manager->Unbind(buffer); if (state_.bound_array_buffer.get() == buffer) { state_.bound_array_buffer = NULL; @@ -12343,9 +12343,8 @@ error::Error GLES2DecoderImpl::HandleMapBufferRange( } Buffer* buffer = buffer_manager()->GetBufferInfoForTarget(&state_, target); DCHECK(buffer); - if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) { - buffer->set_buffer_range_pointer(ptr); - } + buffer->SetMappedRange(offset, size, access, ptr, + GetSharedMemoryBuffer(c.data_shm_id)); if ((access & GL_MAP_INVALIDATE_RANGE_BIT) == 0) { memcpy(mem, ptr, size); } @@ -12353,6 +12352,55 @@ error::Error GLES2DecoderImpl::HandleMapBufferRange( 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(); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h index fe5975e..2e153b4 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h @@ -220,6 +220,8 @@ TEST_P(GLES2DecoderTest3, PopGroupMarkerEXTValidArgs) { // TODO(gman): MapBufferRange +// TODO(gman): UnmapBuffer + // TODO(gman): ResizeCHROMIUM // TODO(gman): GetRequestableExtensionsCHROMIUM diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc index 1c934dd..389c78f 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc @@ -19,83 +19,123 @@ namespace { } // namespace anonymous -TEST_P(GLES2DecoderTest, MapBufferRangeReadSucceeds) { +TEST_P(GLES2DecoderTest, MapBufferRangeUnmapBufferReadSucceeds) { const GLenum kTarget = GL_ARRAY_BUFFER; const GLintptr kOffset = 10; const GLsizeiptr kSize = 64; const GLbitfield kAccess = GL_MAP_READ_BIT; + uint32_t result_shm_id = kSharedMemoryId; + uint32_t result_shm_offset = kSharedMemoryOffset; + uint32_t data_shm_id = kSharedMemoryId; + // uint32_t is Result for both MapBufferRange and UnmapBuffer commands. + uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(uint32_t); + DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); std::vector<int8_t> data(kSize); for (GLsizeiptr ii = 0; ii < kSize; ++ii) { data[ii] = static_cast<int8_t>(ii % 255); } - EXPECT_CALL(*gl_, - MapBufferRange(kTarget, kOffset, kSize, kAccess)) - .WillOnce(Return(&data[0])) - .RetiresOnSaturation(); - typedef MapBufferRange::Result Result; - Result* result = GetSharedMemoryAs<Result*>(); - *result = 0; - uint32_t result_shm_id = kSharedMemoryId; - uint32_t result_shm_offset = kSharedMemoryOffset; - uint32_t data_shm_id = kSharedMemoryId; - uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result); + { // MapBufferRange + EXPECT_CALL(*gl_, + MapBufferRange(kTarget, kOffset, kSize, kAccess)) + .WillOnce(Return(&data[0])) + .RetiresOnSaturation(); + + typedef MapBufferRange::Result Result; + Result* result = GetSharedMemoryAs<Result*>(); + + MapBufferRange cmd; + cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset, + result_shm_id, result_shm_offset); + decoder_->set_unsafe_es3_apis_enabled(false); + *result = 0; + EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); + EXPECT_EQ(0u, *result); + decoder_->set_unsafe_es3_apis_enabled(true); + *result = 0; + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + int8_t* mem = reinterpret_cast<int8_t*>(&result[1]); + EXPECT_EQ(0, memcmp(&data[0], mem, kSize)); + EXPECT_EQ(1u, *result); + } - MapBufferRange cmd; - cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset, - result_shm_id, result_shm_offset); - decoder_->set_unsafe_es3_apis_enabled(true); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - int8_t* mem = reinterpret_cast<int8_t*>(&result[1]); - EXPECT_EQ(0, memcmp(&data[0], mem, kSize)); - EXPECT_EQ(1u, *result); - decoder_->set_unsafe_es3_apis_enabled(false); - *result = 0; - EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); - EXPECT_EQ(0u, *result); + { // UnmapBuffer + EXPECT_CALL(*gl_, UnmapBuffer(kTarget)) + .WillOnce(Return(GL_TRUE)) + .RetiresOnSaturation(); + + UnmapBuffer cmd; + cmd.Init(kTarget); + decoder_->set_unsafe_es3_apis_enabled(false); + EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); + decoder_->set_unsafe_es3_apis_enabled(true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + } + + EXPECT_EQ(GL_NO_ERROR, GetGLError()); } -TEST_P(GLES2DecoderTest, MapBufferRangeWriteSucceeds) { +TEST_P(GLES2DecoderTest, MapBufferRangeUnmapBufferWriteSucceeds) { const GLenum kTarget = GL_ARRAY_BUFFER; const GLintptr kOffset = 10; const GLsizeiptr kSize = 64; const GLbitfield kAccess = GL_MAP_WRITE_BIT; const GLbitfield kMappedAccess = GL_MAP_WRITE_BIT | GL_MAP_READ_BIT; + uint32_t result_shm_id = kSharedMemoryId; + uint32_t result_shm_offset = kSharedMemoryOffset; + uint32_t data_shm_id = kSharedMemoryId; + // uint32_t is Result for both MapBufferRange and UnmapBuffer commands. + uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(uint32_t); + DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); std::vector<int8_t> data(kSize); for (GLsizeiptr ii = 0; ii < kSize; ++ii) { data[ii] = static_cast<int8_t>(ii % 255); } - EXPECT_CALL(*gl_, - MapBufferRange(kTarget, kOffset, kSize, kMappedAccess)) - .WillOnce(Return(&data[0])) - .RetiresOnSaturation(); - typedef MapBufferRange::Result Result; - Result* result = GetSharedMemoryAs<Result*>(); - *result = 0; - uint32_t result_shm_id = kSharedMemoryId; - uint32_t result_shm_offset = kSharedMemoryOffset; - uint32_t data_shm_id = kSharedMemoryId; - uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result); + { // MapBufferRange succeeds + EXPECT_CALL(*gl_, + MapBufferRange(kTarget, kOffset, kSize, kMappedAccess)) + .WillOnce(Return(&data[0])) + .RetiresOnSaturation(); + + typedef MapBufferRange::Result Result; + Result* result = GetSharedMemoryAs<Result*>(); + + MapBufferRange cmd; + cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset, + result_shm_id, result_shm_offset); + decoder_->set_unsafe_es3_apis_enabled(false); + *result = 0; + EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); + EXPECT_EQ(0u, *result); + decoder_->set_unsafe_es3_apis_enabled(true); + *result = 0; + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + int8_t* mem = reinterpret_cast<int8_t*>(&result[1]); + EXPECT_EQ(0, memcmp(&data[0], mem, kSize)); + EXPECT_EQ(1u, *result); + } - MapBufferRange cmd; - cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset, - result_shm_id, result_shm_offset); - decoder_->set_unsafe_es3_apis_enabled(true); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - int8_t* mem = reinterpret_cast<int8_t*>(&result[1]); - EXPECT_EQ(0, memcmp(&data[0], mem, kSize)); - EXPECT_EQ(1u, *result); - decoder_->set_unsafe_es3_apis_enabled(false); - *result = 0; - EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); - EXPECT_EQ(0u, *result); + { // UnmapBuffer succeeds + EXPECT_CALL(*gl_, UnmapBuffer(kTarget)) + .WillOnce(Return(GL_TRUE)) + .RetiresOnSaturation(); + + UnmapBuffer cmd; + cmd.Init(kTarget); + decoder_->set_unsafe_es3_apis_enabled(false); + EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); + decoder_->set_unsafe_es3_apis_enabled(true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + } + + EXPECT_EQ(GL_NO_ERROR, GetGLError()); } TEST_P(GLES2DecoderTest, MapBufferRangeNotInitFails) { @@ -307,5 +347,125 @@ TEST_P(GLES2DecoderTest, MapBufferRangeBadSharedMemoryFails) { EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); } +TEST_P(GLES2DecoderTest, UnmapBufferWriteNotMappedFails) { + const GLenum kTarget = GL_ARRAY_BUFFER; + + DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); + + UnmapBuffer cmd; + cmd.Init(kTarget); + decoder_->set_unsafe_es3_apis_enabled(true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_P(GLES2DecoderTest, UnmapBufferWriteNoBoundBufferFails) { + const GLenum kTarget = GL_ARRAY_BUFFER; + + UnmapBuffer cmd; + cmd.Init(kTarget); + decoder_->set_unsafe_es3_apis_enabled(true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_P(GLES2DecoderTest, BufferDataDestroysDataStore) { + const GLenum kTarget = GL_ARRAY_BUFFER; + const GLintptr kOffset = 10; + const GLsizeiptr kSize = 64; + const GLbitfield kAccess = GL_MAP_WRITE_BIT; + const GLbitfield kFilteredAccess = GL_MAP_WRITE_BIT | GL_MAP_READ_BIT; + + uint32_t result_shm_id = kSharedMemoryId; + uint32_t result_shm_offset = kSharedMemoryOffset; + uint32_t data_shm_id = kSharedMemoryId; + // uint32_t is Result for both MapBufferRange and UnmapBuffer commands. + uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(uint32_t); + + DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); + + std::vector<int8_t> data(kSize); + + decoder_->set_unsafe_es3_apis_enabled(true); + + { // MapBufferRange succeeds + EXPECT_CALL(*gl_, + MapBufferRange(kTarget, kOffset, kSize, kFilteredAccess)) + .WillOnce(Return(&data[0])) + .RetiresOnSaturation(); + + typedef MapBufferRange::Result Result; + Result* result = GetSharedMemoryAs<Result*>(); + + MapBufferRange cmd; + cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset, + result_shm_id, result_shm_offset); + *result = 0; + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(1u, *result); + } + + { // BufferData unmaps the data store. + DoBufferData(kTarget, kSize * 2); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + } + + { // UnmapBuffer fails. + UnmapBuffer cmd; + cmd.Init(kTarget); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } +} + +TEST_P(GLES2DecoderTest, DeleteBuffersDestroysDataStore) { + const GLenum kTarget = GL_ARRAY_BUFFER; + const GLintptr kOffset = 10; + const GLsizeiptr kSize = 64; + const GLbitfield kAccess = GL_MAP_WRITE_BIT; + const GLbitfield kFilteredAccess = GL_MAP_WRITE_BIT | GL_MAP_READ_BIT; + + uint32_t result_shm_id = kSharedMemoryId; + uint32_t result_shm_offset = kSharedMemoryOffset; + uint32_t data_shm_id = kSharedMemoryId; + // uint32_t is Result for both MapBufferRange and UnmapBuffer commands. + uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(uint32_t); + + DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); + + std::vector<int8_t> data(kSize); + + decoder_->set_unsafe_es3_apis_enabled(true); + + { // MapBufferRange succeeds + EXPECT_CALL(*gl_, + MapBufferRange(kTarget, kOffset, kSize, kFilteredAccess)) + .WillOnce(Return(&data[0])) + .RetiresOnSaturation(); + + typedef MapBufferRange::Result Result; + Result* result = GetSharedMemoryAs<Result*>(); + + MapBufferRange cmd; + cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset, + result_shm_id, result_shm_offset); + *result = 0; + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(1u, *result); + } + + { // DeleteBuffers unmaps the data store. + DoDeleteBuffer(client_buffer_id_, kServiceBufferId); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + } + + { // UnmapBuffer fails. + UnmapBuffer cmd; + cmd.Init(kTarget); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + } +} + } // namespace gles2 } // namespace gpu |