| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdint.h> |
| |
| #include "base/compiler_specific.h" |
| #include "base/containers/heap_array.h" |
| #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
| #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h" |
| |
| using ::gl::MockGLInterface; |
| using ::testing::_; |
| using ::testing::Return; |
| using ::testing::SetArgPointee; |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| namespace { |
| |
| } // namespace anonymous |
| |
| TEST_P(GLES3DecoderTest, BindBufferBaseValidArgs) { |
| EXPECT_CALL( |
| *gl_, BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kServiceBufferId)); |
| SpecializedSetup<cmds::BindBufferBase, 0>(true); |
| cmds::BindBufferBase cmd; |
| cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, client_buffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, BindBufferRangeValidArgs) { |
| const GLenum kTarget = GL_TRANSFORM_FEEDBACK_BUFFER; |
| const GLintptr kRangeOffset = 4; |
| const GLsizeiptr kRangeSize = 8; |
| const GLsizeiptr kBufferSize = kRangeOffset + kRangeSize; |
| DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); |
| DoBufferData(kTarget, kBufferSize); |
| EXPECT_CALL(*gl_, BindBufferRange(kTarget, 2, kServiceBufferId, |
| kRangeOffset, kRangeSize)); |
| SpecializedSetup<cmds::BindBufferRange, 0>(true); |
| cmds::BindBufferRange cmd; |
| cmd.Init(kTarget, 2, client_buffer_id_, kRangeOffset, kRangeSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, BindBufferRangeValidArgsWithNoData) { |
| const GLenum kTarget = GL_TRANSFORM_FEEDBACK_BUFFER; |
| const GLintptr kRangeOffset = 4; |
| const GLsizeiptr kRangeSize = 8; |
| DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); |
| EXPECT_CALL(*gl_, BindBufferBase(kTarget, 2, kServiceBufferId)); |
| SpecializedSetup<cmds::BindBufferRange, 0>(true); |
| cmds::BindBufferRange cmd; |
| cmd.Init(kTarget, 2, client_buffer_id_, kRangeOffset, kRangeSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, BindBufferRangeValidArgsWithLessData) { |
| const GLenum kTarget = GL_TRANSFORM_FEEDBACK_BUFFER; |
| const GLintptr kRangeOffset = 4; |
| const GLsizeiptr kRangeSize = 8; |
| const GLsizeiptr kBufferSize = kRangeOffset + kRangeSize - 4; |
| DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); |
| DoBufferData(kTarget, kBufferSize); |
| EXPECT_CALL(*gl_, BindBufferRange(kTarget, 2, kServiceBufferId, |
| kRangeOffset, kRangeSize - 4)); |
| SpecializedSetup<cmds::BindBufferRange, 0>(true); |
| cmds::BindBufferRange cmd; |
| cmd.Init(kTarget, 2, client_buffer_id_, kRangeOffset, kRangeSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, CopyBufferSubDataValidArgs) { |
| const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; |
| const GLsizeiptr kSize = 64; |
| const GLsizeiptr kHalfSize = kSize / 2; |
| const GLintptr kReadOffset = 0; |
| const GLintptr kWriteOffset = kHalfSize; |
| const GLsizeiptr kCopySize = 5; |
| const char kValue0 = 3; |
| const char kValue1 = 21; |
| |
| // Set up the buffer so first half is kValue0 and second half is kValue1. |
| DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); |
| DoBufferData(kTarget, kSize); |
| auto data = base::HeapArray<char>::Uninit(kHalfSize); |
| UNSAFE_TODO(memset(data.data(), kValue0, kHalfSize)); |
| DoBufferSubData(kTarget, 0, kHalfSize, data.data()); |
| UNSAFE_TODO(memset(data.data(), kValue1, kHalfSize)); |
| DoBufferSubData(kTarget, kHalfSize, kHalfSize, data.data()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| Buffer* buffer = GetBuffer(client_buffer_id_); |
| EXPECT_TRUE(buffer); |
| const char* shadow_data = reinterpret_cast<const char*>( |
| buffer->GetRange(0, kSize)); |
| EXPECT_TRUE(shadow_data); |
| // Verify the shadow data is initialized. |
| for (GLsizeiptr ii = 0; ii < kHalfSize; ++ii) { |
| UNSAFE_TODO(EXPECT_EQ(kValue0, shadow_data[ii])); |
| } |
| for (GLsizeiptr ii = kHalfSize; ii < kSize; ++ii) { |
| UNSAFE_TODO(EXPECT_EQ(kValue1, shadow_data[ii])); |
| } |
| |
| EXPECT_CALL(*gl_, CopyBufferSubData(kTarget, kTarget, |
| kReadOffset, kWriteOffset, kCopySize)); |
| cmds::CopyBufferSubData cmd; |
| cmd.Init(kTarget, kTarget, kReadOffset, kWriteOffset, kCopySize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Verify the shadow data is updated. |
| for (GLsizeiptr ii = 0; ii < kHalfSize; ++ii) { |
| UNSAFE_TODO(EXPECT_EQ(kValue0, shadow_data[ii])); |
| } |
| for (GLsizeiptr ii = kHalfSize; ii < kSize; ++ii) { |
| if (ii >= kWriteOffset && ii < kWriteOffset + kCopySize) { |
| UNSAFE_TODO(EXPECT_EQ(kValue0, shadow_data[ii])); |
| } else { |
| UNSAFE_TODO(EXPECT_EQ(kValue1, shadow_data[ii])); |
| } |
| } |
| } |
| |
| TEST_P(GLES3DecoderTest, BufferDataWhileTransformFeedbackPausedFails) { |
| const GLenum kTarget = GL_TRANSFORM_FEEDBACK_BUFFER; |
| const GLsizeiptr kBufferSize = 64; |
| |
| EXPECT_CALL(*gl_, BindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DoBindTransformFeedback(GL_TRANSFORM_FEEDBACK, client_transformfeedback_id_, |
| kServiceTransformFeedbackId); |
| |
| DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId); |
| EXPECT_CALL(*gl_, BindBufferBase(kTarget, 0, kServiceBufferId)); |
| SpecializedSetup<cmds::BindBufferBase, 0>(true); |
| cmds::BindBufferBase bind_base_cmd; |
| bind_base_cmd.Init(kTarget, 0, client_buffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(bind_base_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| DoBufferData(kTarget, kBufferSize); |
| |
| TransformFeedback* tf = GetTransformFeedback(client_transformfeedback_id_); |
| ASSERT_TRUE(tf); |
| |
| EXPECT_CALL(*gl_, BeginTransformFeedback(GL_POINTS)).Times(1); |
| EXPECT_CALL(*gl_, PauseTransformFeedback()).Times(1); |
| tf->DoBeginTransformFeedback(GL_POINTS); |
| tf->DoPauseTransformFeedback(); |
| EXPECT_TRUE(tf->active()); |
| EXPECT_TRUE(tf->paused()); |
| |
| // BufferData (respecification) must fail with GL_INVALID_OPERATION even while |
| // paused. |
| cmds::BufferData buffer_data_cmd; |
| buffer_data_cmd.Init(kTarget, kBufferSize * 2, 0, 0, GL_STREAM_DRAW); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(buffer_data_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // BufferSubData while paused is permitted by ES 3.0. |
| EXPECT_CALL(*gl_, BufferSubData(kTarget, 0, 4, _)).Times(1); |
| cmds::BufferSubData buffer_sub_data_cmd; |
| buffer_sub_data_cmd.Init(kTarget, 0, 4, shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(buffer_sub_data_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // End transform feedback and ensure BufferData succeeds again. |
| EXPECT_CALL(*gl_, EndTransformFeedback()).Times(1); |
| tf->DoEndTransformFeedback(); |
| EXPECT_FALSE(tf->active()); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)); |
| EXPECT_CALL(*gl_, BufferData(kTarget, kBufferSize * 2, _, GL_STREAM_DRAW)) |
| .Times(1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(buffer_data_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |