| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
| |
| #include <limits.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| |
| #include "base/command_line.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "gpu/command_buffer/common/gles2_cmd_format.h" |
| #include "gpu/command_buffer/common/gles2_cmd_utils.h" |
| #include "gpu/command_buffer/service/context_group.h" |
| #include "gpu/command_buffer/service/context_state.h" |
| #include "gpu/command_buffer/service/gl_surface_mock.h" |
| #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h" |
| #include "gpu/command_buffer/service/gpu_switches.h" |
| #include "gpu/command_buffer/service/image_manager.h" |
| #include "gpu/command_buffer/service/mailbox_manager.h" |
| #include "gpu/command_buffer/service/mocks.h" |
| #include "gpu/command_buffer/service/program_manager.h" |
| #include "gpu/command_buffer/service/test_helper.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gl/gl_implementation.h" |
| #include "ui/gl/gl_mock.h" |
| #include "ui/gl/gl_surface_stub.h" |
| |
| #if !defined(GL_DEPTH24_STENCIL8) |
| #define GL_DEPTH24_STENCIL8 0x88F0 |
| #endif |
| |
| using ::gl::MockGLInterface; |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::DoAll; |
| using ::testing::InSequence; |
| using ::testing::Invoke; |
| using ::testing::MatcherCast; |
| using ::testing::Mock; |
| using ::testing::Pointee; |
| using ::testing::Return; |
| using ::testing::SaveArg; |
| using ::testing::SetArrayArgument; |
| using ::testing::SetArgPointee; |
| using ::testing::StrEq; |
| using ::testing::StrictMock; |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| using namespace cmds; |
| |
| class GLES2DecoderTestWithExtensionsOnGLES2 : public GLES2DecoderTest { |
| public: |
| GLES2DecoderTestWithExtensionsOnGLES2() = default; |
| |
| void SetUp() override {} |
| void Init(const char* extensions) { |
| InitState init; |
| init.extensions = extensions; |
| init.gl_version = "OpenGL ES 2.0"; |
| init.has_alpha = true; |
| init.has_depth = true; |
| init.request_alpha = true; |
| init.request_depth = true; |
| InitDecoder(init); |
| } |
| }; |
| |
| TEST_P(GLES2DecoderTest, CheckFramebufferStatusWithNoBoundTarget) { |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_)).Times(0); |
| CheckFramebufferStatus::Result* result = |
| static_cast<CheckFramebufferStatus::Result*>(shared_memory_address_); |
| *result = 0; |
| CheckFramebufferStatus cmd; |
| cmd.Init(GL_FRAMEBUFFER, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), *result); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, BindAndDeleteFramebuffer) { |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoDeleteFramebuffer(client_framebuffer_id_, |
| kServiceFramebufferId, |
| true, |
| GL_FRAMEBUFFER, |
| 0, |
| true, |
| GL_FRAMEBUFFER, |
| 0); |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferRenderbufferWithNoBoundTarget) { |
| EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _)).Times(0); |
| FramebufferRenderbuffer cmd; |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DWithNoBoundTarget) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTexture2DWithNoBoundTarget) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DValidArgs) { |
| EXPECT_CALL(*gl_, |
| FramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, kServiceTextureId, 0)); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| client_texture_id_, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTexture2DValidArgs) { |
| EXPECT_CALL(*gl_, |
| FramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, kServiceTextureId, 1)); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| client_texture_id_, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTexture2DDepthStencil) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| FramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
| GL_TEXTURE_2D, kServiceTextureId, 4)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| FramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, |
| GL_TEXTURE_2D, kServiceTextureId, 4)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| client_texture_id_, 4); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| Framebuffer* framebuffer = GetFramebuffer(client_framebuffer_id_); |
| ASSERT_TRUE(framebuffer); |
| ASSERT_FALSE(framebuffer->GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); |
| ASSERT_TRUE(framebuffer->GetAttachment(GL_DEPTH_ATTACHMENT)); |
| ASSERT_TRUE(framebuffer->GetAttachment(GL_STENCIL_ATTACHMENT)); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DInvalidArgs0_0) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_RENDERBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| client_texture_id_, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTexture2DInvalidArgs0_0) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_RENDERBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| client_texture_id_, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DInvalidArgs1_0) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR, GL_TEXTURE_2D, client_texture_id_, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTexture2DInvalidArgs1_0) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR, GL_TEXTURE_2D, client_texture_id_, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DInvalidArgs2_0) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_PROXY_TEXTURE_CUBE_MAP, |
| client_texture_id_, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTexture2DInvalidArgs2_0) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_PROXY_TEXTURE_CUBE_MAP, |
| client_texture_id_, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DInvalidArgs4_0) { |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| client_texture_id_, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTexture2DValidArgs4_0) { |
| EXPECT_CALL(*gl_, |
| FramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, kServiceTextureId, 0)); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| client_texture_id_, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DMismatchedTexture1) { |
| EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _)) |
| .Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, |
| client_texture_id_, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DMismatchedTexture2) { |
| EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _)) |
| .Times(0); |
| DoBindTexture(GL_TEXTURE_CUBE_MAP, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferTexture2D cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| client_texture_id_, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithNoBoundTarget) { |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _)) |
| .Times(0); |
| GetFramebufferAttachmentParameteriv cmd; |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, |
| shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithRenderbuffer) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillRepeatedly(Return(GL_NO_ERROR)); |
| EXPECT_CALL(*gl_, |
| FramebufferRenderbufferEXT(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| GetFramebufferAttachmentParameteriv::Result* result = |
| static_cast<GetFramebufferAttachmentParameteriv::Result*>( |
| shared_memory_address_); |
| result->size = 0; |
| const GLint* result_value = result->GetData(); |
| FramebufferRenderbuffer fbrb_cmd; |
| GetFramebufferAttachmentParameteriv cmd; |
| fbrb_cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, |
| shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(client_renderbuffer_id_, static_cast<GLuint>(*result_value)); |
| } |
| |
| TEST_P(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithTexture) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillRepeatedly(Return(GL_NO_ERROR)); |
| EXPECT_CALL(*gl_, |
| FramebufferTexture2DEXT(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kServiceTextureId, |
| 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| GetFramebufferAttachmentParameteriv::Result* result = |
| static_cast<GetFramebufferAttachmentParameteriv::Result*>( |
| shared_memory_address_); |
| result->SetNumResults(0); |
| const GLint* result_value = result->GetData(); |
| FramebufferTexture2D fbtex_cmd; |
| GetFramebufferAttachmentParameteriv cmd; |
| fbtex_cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| 0); |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, |
| shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(fbtex_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(client_texture_id_, static_cast<GLuint>(*result_value)); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, |
| GetRenderbufferParameterivRebindRenderbuffer) { |
| SetupTexture(); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 1, 1, GL_NO_ERROR); |
| |
| GetRenderbufferParameteriv cmd; |
| cmd.Init(GL_RENDERBUFFER, |
| GL_RENDERBUFFER_RED_SIZE, |
| shared_memory_id_, |
| shared_memory_offset_); |
| |
| RestoreRenderbufferBindings(); |
| EnsureRenderbufferBound(true); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| GetRenderbufferParameterivEXT( |
| GL_RENDERBUFFER, GL_RENDERBUFFER_RED_SIZE, _)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, GetRenderbufferParameterivWithNoBoundTarget) { |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetRenderbufferParameterivEXT(_, _, _)).Times(0); |
| GetRenderbufferParameteriv cmd; |
| cmd.Init(GL_RENDERBUFFER, |
| GL_RENDERBUFFER_WIDTH, |
| shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, RenderbufferStorageRebindRenderbuffer) { |
| SetupTexture(); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| RestoreRenderbufferBindings(); |
| EnsureRenderbufferBound(true); |
| DoRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 1, 1, GL_NO_ERROR); |
| } |
| |
| TEST_P(GLES2DecoderTest, RenderbufferStorageWithNoBoundTarget) { |
| EXPECT_CALL(*gl_, RenderbufferStorageEXT(_, _, _, _)).Times(0); |
| RenderbufferStorage cmd; |
| cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 3, 4); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| namespace { |
| |
| // A class to emulate glReadPixels |
| class ReadPixelsEmulator { |
| public: |
| // pack_alignment is the alignment you want ReadPixels to use |
| // when copying. The actual data passed in pixels should be contiguous. |
| ReadPixelsEmulator(GLsizei width, |
| GLsizei height, |
| GLint bytes_per_pixel, |
| const void* src_pixels, |
| const void* expected_pixels, |
| GLint pack_alignment) |
| : width_(width), |
| height_(height), |
| pack_alignment_(pack_alignment), |
| bytes_per_pixel_(bytes_per_pixel), |
| src_pixels_(reinterpret_cast<const int8_t*>(src_pixels)), |
| expected_pixels_(reinterpret_cast<const int8_t*>(expected_pixels)) {} |
| |
| void ReadPixels(GLint x, |
| GLint y, |
| GLsizei width, |
| GLsizei height, |
| GLenum format, |
| GLenum type, |
| void* pixels) const { |
| DCHECK_GE(x, 0); |
| DCHECK_GE(y, 0); |
| DCHECK_LE(x + width, width_); |
| DCHECK_LE(y + height, height_); |
| for (GLint yy = 0; yy < height; ++yy) { |
| const int8_t* src = GetPixelAddress(src_pixels_, x, y + yy); |
| const void* dst = ComputePackAlignmentAddress(0, yy, width, pixels); |
| memcpy(const_cast<void*>(dst), src, width * bytes_per_pixel_); |
| } |
| } |
| |
| bool CompareRowSegment(GLint x, |
| GLint y, |
| GLsizei width, |
| const void* data) const { |
| DCHECK(x + width <= width_ || width == 0); |
| return memcmp(data, |
| GetPixelAddress(expected_pixels_, x, y), |
| width * bytes_per_pixel_) == 0; |
| } |
| |
| // Helper to compute address of pixel in pack aligned data. |
| const void* ComputePackAlignmentAddress(GLint x, |
| GLint y, |
| GLsizei width, |
| const void* address) const { |
| GLint unpadded_row_size = ComputeImageDataSize(width, 1); |
| GLint two_rows_size = ComputeImageDataSize(width, 2); |
| GLsizei padded_row_size = two_rows_size - unpadded_row_size; |
| GLint offset = y * padded_row_size + x * bytes_per_pixel_; |
| return static_cast<const int8_t*>(address) + offset; |
| } |
| |
| GLint ComputeImageDataSize(GLint width, GLint height) const { |
| GLint row_size = width * bytes_per_pixel_; |
| if (height > 1) { |
| GLint temp = row_size + pack_alignment_ - 1; |
| GLint padded_row_size = (temp / pack_alignment_) * pack_alignment_; |
| GLint size_of_all_but_last_row = (height - 1) * padded_row_size; |
| return size_of_all_but_last_row + row_size; |
| } else { |
| return height * row_size; |
| } |
| } |
| |
| private: |
| const int8_t* GetPixelAddress(const int8_t* base, GLint x, GLint y) const { |
| return base + (width_ * y + x) * bytes_per_pixel_; |
| } |
| |
| GLsizei width_; |
| GLsizei height_; |
| GLint pack_alignment_; |
| GLint bytes_per_pixel_; |
| const int8_t* src_pixels_; |
| const int8_t* expected_pixels_; |
| }; |
| |
| } // anonymous namespace |
| |
| void GLES2DecoderTest::CheckReadPixelsOutOfRange(GLint in_read_x, |
| GLint in_read_y, |
| GLsizei in_read_width, |
| GLsizei in_read_height, |
| bool init) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| const GLint kPackAlignment = 4; |
| const GLenum kFormat = GL_RGBA; |
| static const uint8_t kSrcPixels[kWidth * kHeight * kBytesPerPixel] = { |
| 12, 13, 14, 255, 18, 19, 18, 255, 19, 12, 13, 255, 14, 18, 19, 255, |
| 18, 19, 13, 255, 29, 28, 23, 255, 22, 21, 22, 255, 21, 29, 28, 255, |
| 23, 22, 21, 255, 22, 21, 28, 255, 31, 34, 39, 255, 37, 32, 37, 255, |
| 32, 31, 34, 255, 39, 37, 32, 255, 37, 32, 34, 255}; |
| |
| ClearSharedMemory(); |
| |
| // We need to setup an FBO so we can know the max size that ReadPixels will |
| // access |
| if (init) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0, kFormat, |
| GL_UNSIGNED_BYTE, shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| kServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| } |
| |
| ReadPixelsEmulator emu( |
| kWidth, kHeight, kBytesPerPixel, kSrcPixels, kSrcPixels, kPackAlignment); |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(*result); |
| void* dest = &result[1]; |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| // ReadPixels will be called for valid size only even though the command |
| // is requesting a larger size. |
| GLint read_x = std::max(0, in_read_x); |
| GLint read_y = std::max(0, in_read_y); |
| GLint read_end_x = std::max(0, std::min(kWidth, in_read_x + in_read_width)); |
| GLint read_end_y = std::max(0, std::min(kHeight, in_read_y + in_read_height)); |
| GLint read_width = read_end_x - read_x; |
| GLint read_height = read_end_y - read_y; |
| if (read_width > 0 && read_height > 0) { |
| for (GLint yy = read_y; yy < read_end_y; ++yy) { |
| EXPECT_CALL( |
| *gl_, |
| ReadPixels(read_x, yy, read_width, 1, kFormat, GL_UNSIGNED_BYTE, _)) |
| .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels)) |
| .RetiresOnSaturation(); |
| } |
| } |
| ReadPixels cmd; |
| cmd.Init(in_read_x, |
| in_read_y, |
| in_read_width, |
| in_read_height, |
| kFormat, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| |
| GLint unpadded_row_size = emu.ComputeImageDataSize(in_read_width, 1); |
| std::unique_ptr<int8_t[]> zero(new int8_t[unpadded_row_size]); |
| std::unique_ptr<int8_t[]> pack(new int8_t[kPackAlignment]); |
| memset(zero.get(), kInitialMemoryValue, unpadded_row_size); |
| memset(pack.get(), kInitialMemoryValue, kPackAlignment); |
| for (GLint yy = 0; yy < in_read_height; ++yy) { |
| const int8_t* row = static_cast<const int8_t*>( |
| emu.ComputePackAlignmentAddress(0, yy, in_read_width, dest)); |
| GLint y = in_read_y + yy; |
| if (y < 0 || y >= kHeight) { |
| EXPECT_EQ(0, memcmp(zero.get(), row, unpadded_row_size)); |
| } else { |
| // check off left. |
| GLint num_left_pixels = std::max(-in_read_x, 0); |
| GLint num_left_bytes = num_left_pixels * kBytesPerPixel; |
| EXPECT_EQ(0, memcmp(zero.get(), row, num_left_bytes)); |
| |
| // check off right. |
| GLint num_right_pixels = std::max(in_read_x + in_read_width - kWidth, 0); |
| GLint num_right_bytes = num_right_pixels * kBytesPerPixel; |
| EXPECT_EQ(0, |
| memcmp(zero.get(), |
| row + unpadded_row_size - num_right_bytes, |
| num_right_bytes)); |
| |
| // check middle. |
| GLint x = std::max(in_read_x, 0); |
| GLint num_middle_pixels = |
| std::max(in_read_width - num_left_pixels - num_right_pixels, 0); |
| EXPECT_TRUE( |
| emu.CompareRowSegment(x, y, num_middle_pixels, row + num_left_bytes)); |
| } |
| |
| // check padding |
| if (yy != in_read_height - 1) { |
| GLint temp = unpadded_row_size + kPackAlignment - 1; |
| GLint padded_row_size = (temp / kPackAlignment ) * kPackAlignment; |
| GLint num_padding_bytes = padded_row_size - unpadded_row_size; |
| if (num_padding_bytes) { |
| EXPECT_EQ(0, memcmp(pack.get(), |
| row + unpadded_row_size, num_padding_bytes)); |
| } |
| } |
| } |
| } |
| |
| TEST_P(GLES2DecoderTest, ReadPixels) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| const GLint kPackAlignment = 4; |
| static const uint8_t kSrcPixels[kWidth * kHeight * kBytesPerPixel] = { |
| 12, 13, 14, 255, 18, 19, 18, 255, 19, 12, 13, 255, 14, 18, 19, 255, |
| 18, 19, 13, 255, 29, 28, 23, 255, 22, 21, 22, 255, 21, 29, 28, 255, |
| 23, 22, 21, 255, 22, 21, 28, 255, 31, 34, 39, 255, 37, 32, 37, 255, |
| 32, 31, 34, 255, 39, 37, 32, 255, 37, 32, 34, 255}; |
| |
| surface_->SetSize(gfx::Size(INT_MAX, INT_MAX)); |
| |
| ReadPixelsEmulator emu( |
| kWidth, kHeight, kBytesPerPixel, kSrcPixels, kSrcPixels, kPackAlignment); |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(*result); |
| void* dest = &result[1]; |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| ReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, _)) |
| .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels)); |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| kWidth, |
| kHeight, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 1; |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd)); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| for (GLint yy = 0; yy < kHeight; ++yy) { |
| EXPECT_TRUE(emu.CompareRowSegment( |
| 0, yy, kWidth, emu.ComputePackAlignmentAddress(0, yy, kWidth, dest))); |
| } |
| } |
| |
| TEST_P(GLES3DecoderTest, ReadPixels2PixelPackBufferNoBufferBound) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| EXPECT_CALL(*gl_, ReadPixels(_, _, _, _, _, _, _)).Times(0); |
| |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| kWidth, |
| kHeight, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| 0, |
| 0, |
| 0, |
| 0, |
| false); |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, ReadPixelsBufferBound) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| GLint size = kWidth * kHeight * kBytesPerPixel; |
| EXPECT_CALL(*gl_, ReadPixels(_, _, _, _, _, _, _)).Times(0); |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| |
| DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId); |
| DoBufferData(GL_PIXEL_PACK_BUFFER, size); |
| |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| kWidth, |
| kHeight, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, ReadPixels2PixelPackBuffer) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| GLint size = kWidth * kHeight * kBytesPerPixel; |
| |
| DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId); |
| DoBufferData(GL_PIXEL_PACK_BUFFER, size); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| ReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, _)); |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| kWidth, |
| kHeight, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| 0, |
| 0, |
| 0, |
| 0, |
| false); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, ReadPixelsPixelPackBufferMapped) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| GLint size = kWidth * kHeight * kBytesPerPixel; |
| |
| DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId); |
| DoBufferData(GL_PIXEL_PACK_BUFFER, size); |
| |
| std::vector<int8_t> mapped_data(size); |
| |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t data_shm_id = shared_memory_id_; |
| // uint32_t is Result for both MapBufferRange and UnmapBuffer commands. |
| uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(uint32_t); |
| EXPECT_CALL(*gl_, |
| MapBufferRange(GL_PIXEL_PACK_BUFFER, 0, size, GL_MAP_READ_BIT)) |
| .WillOnce(Return(mapped_data.data())) |
| .RetiresOnSaturation(); |
| MapBufferRange map_buffer_range; |
| map_buffer_range.Init(GL_PIXEL_PACK_BUFFER, 0, size, GL_MAP_READ_BIT, |
| data_shm_id, data_shm_offset, |
| result_shm_id, result_shm_offset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(map_buffer_range)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| EXPECT_CALL(*gl_, ReadPixels(_, _, _, _, _, _, _)).Times(0); |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| kWidth, |
| kHeight, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| 0, |
| 0, |
| 0, |
| 0, |
| false); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, ReadPixelsPixelPackBufferIsNotLargeEnough) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| GLint size = kWidth * kHeight * kBytesPerPixel; |
| |
| DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId); |
| |
| DoBufferData(GL_PIXEL_PACK_BUFFER, size - 4); |
| EXPECT_CALL(*gl_, ReadPixels(_, _, _, _, _, _, _)).Times(0); |
| |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| kWidth, |
| kHeight, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| 0, |
| 0, |
| 0, |
| 0, |
| false); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ReadPixels2RowLengthWorkaround) { |
| gpu::GpuDriverBugWorkarounds workarounds; |
| workarounds.pack_parameters_workaround_with_pack_buffer = true; |
| InitState init; |
| init.gl_version = "OpenGL ES 3.0"; |
| init.bind_generates_resource = true; |
| init.context_type = CONTEXT_TYPE_OPENGLES3; |
| InitDecoderWithWorkarounds(init, workarounds); |
| |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| const GLenum kFormat = GL_RGBA; |
| const GLenum kType = GL_UNSIGNED_BYTE; |
| const GLint kRowLength = 4; |
| GLint size = (kRowLength * (kHeight - 1) + kWidth) * kBytesPerPixel; |
| |
| DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId); |
| DoBufferData(GL_PIXEL_PACK_BUFFER, size); |
| |
| DoPixelStorei(GL_PACK_ROW_LENGTH, kRowLength); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| for (GLint ii = 0; ii < kHeight; ++ii) { |
| if (ii + 1 == kHeight) { |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, kWidth)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| void* offset = reinterpret_cast<void*>(ii * kRowLength * kBytesPerPixel); |
| EXPECT_CALL(*gl_, ReadPixels(0, ii, kWidth, 1, kFormat, kType, offset)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| if (ii + 1 == kHeight) { |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, kRowLength)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| } |
| |
| ReadPixels cmd; |
| cmd.Init(0, 0, kWidth, kHeight, |
| kFormat, kType, |
| 0, 0, 0, 0, |
| false); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ReadPixels2AlignmentWorkaround) { |
| gpu::GpuDriverBugWorkarounds workarounds; |
| workarounds.pack_parameters_workaround_with_pack_buffer = true; |
| InitState init; |
| init.gl_version = "OpenGL ES 3.0"; |
| init.bind_generates_resource = true; |
| init.context_type = CONTEXT_TYPE_OPENGLES3; |
| InitDecoderWithWorkarounds(init, workarounds); |
| |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| const GLenum kFormat = GL_RGBA; |
| const GLenum kType = GL_UNSIGNED_BYTE; |
| const GLint kAlignment = 8; |
| const GLint kPadding = 4; |
| GLint size = kWidth * kBytesPerPixel * kHeight + kPadding * (kHeight - 1); |
| |
| DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId); |
| DoBufferData(GL_PIXEL_PACK_BUFFER, size); |
| |
| DoPixelStorei(GL_PACK_ALIGNMENT, kAlignment); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| uint8_t* offset = reinterpret_cast<uint8_t*>(0); |
| EXPECT_CALL(*gl_, |
| ReadPixels(0, 0, kWidth, kHeight - 1, kFormat, kType, offset)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| offset += (kWidth * kBytesPerPixel + kPadding) * (kHeight - 1); |
| EXPECT_CALL(*gl_, |
| ReadPixels(0, kHeight - 1, kWidth, 1, kFormat, kType, offset)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, kAlignment)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| ReadPixels cmd; |
| cmd.Init(0, 0, kWidth, kHeight, |
| kFormat, kType, |
| 0, 0, 0, 0, |
| false); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, |
| ReadPixels2RowLengthAndAlignmentWorkarounds) { |
| gpu::GpuDriverBugWorkarounds workarounds; |
| workarounds.pack_parameters_workaround_with_pack_buffer = true; |
| InitState init; |
| init.gl_version = "OpenGL ES 3.0"; |
| init.bind_generates_resource = true; |
| init.context_type = CONTEXT_TYPE_OPENGLES3; |
| InitDecoderWithWorkarounds(init, workarounds); |
| |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| const GLenum kFormat = GL_RGBA; |
| const GLenum kType = GL_UNSIGNED_BYTE; |
| const GLint kAlignment = 8; |
| const GLint kRowLength = 3; |
| const GLint kPadding = 4; |
| GLint padded_row_size = kRowLength * kBytesPerPixel + kPadding; |
| GLint unpadded_row_size = kWidth * kBytesPerPixel; |
| GLint size = padded_row_size * (kHeight - 1) + unpadded_row_size; |
| |
| DoBindBuffer(GL_PIXEL_PACK_BUFFER, client_buffer_id_, kServiceBufferId); |
| DoBufferData(GL_PIXEL_PACK_BUFFER, size); |
| |
| DoPixelStorei(GL_PACK_ALIGNMENT, kAlignment); |
| DoPixelStorei(GL_PACK_ROW_LENGTH, kRowLength); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| for (GLint ii = 0; ii < kHeight - 1; ++ii) { |
| void* offset = reinterpret_cast<void*>(ii * padded_row_size); |
| EXPECT_CALL(*gl_, ReadPixels(0, ii, kWidth, 1, kFormat, kType, offset)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, kWidth)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| void* offset = reinterpret_cast<void*>((kHeight - 1) * padded_row_size); |
| EXPECT_CALL(*gl_, |
| ReadPixels(0, kHeight - 1, kWidth, 1, kFormat, kType, offset)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, kAlignment)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, kRowLength)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| ReadPixels cmd; |
| cmd.Init(0, 0, kWidth, kHeight, |
| kFormat, kType, |
| 0, 0, 0, 0, |
| false); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderRGBBackbufferTest, ReadPixelsNoAlphaBackbuffer) { |
| const GLsizei kWidth = 3; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| const GLint kPackAlignment = 4; |
| static const uint8_t kSrcPixels[kWidth * kHeight * kBytesPerPixel] = { |
| 12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19, 29, 28, 23, 22, 21, 22, |
| 21, 29, 28, 23, 22, 21, 31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32, |
| }; |
| |
| surface_->SetSize(gfx::Size(INT_MAX, INT_MAX)); |
| |
| ReadPixelsEmulator emu(kWidth, kHeight, kBytesPerPixel, kSrcPixels, |
| kSrcPixels, kPackAlignment); |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(*result); |
| void* dest = &result[1]; |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| ReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, _)) |
| .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels)); |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| kWidth, |
| kHeight, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| for (GLint yy = 0; yy < kHeight; ++yy) { |
| EXPECT_TRUE(emu.CompareRowSegment( |
| 0, yy, kWidth, emu.ComputePackAlignmentAddress(0, yy, kWidth, dest))); |
| } |
| } |
| |
| TEST_P(GLES2DecoderTest, ReadPixelsOutOfRange) { |
| static GLint tests[][4] = { |
| { |
| -2, -1, 9, 5, |
| }, // out of range on all sides |
| { |
| 2, 1, 9, 5, |
| }, // out of range on right, bottom |
| { |
| -7, -4, 9, 5, |
| }, // out of range on left, top |
| { |
| 0, -5, 9, 5, |
| }, // completely off top |
| { |
| 0, 3, 9, 5, |
| }, // completely off bottom |
| { |
| -9, 0, 9, 5, |
| }, // completely off left |
| { |
| 5, 0, 9, 5, |
| }, // completely off right |
| }; |
| |
| for (size_t tt = 0; tt < base::size(tests); ++tt) { |
| CheckReadPixelsOutOfRange( |
| tests[tt][0], tests[tt][1], tests[tt][2], tests[tt][3], tt == 0); |
| } |
| } |
| |
| TEST_P(GLES2DecoderTest, ReadPixelsInvalidArgs) { |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| EXPECT_CALL(*gl_, ReadPixels(_, _, _, _, _, _, _)).Times(0); |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| -1, |
| 1, |
| GL_RGB, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(0, |
| 0, |
| 1, |
| -1, |
| GL_RGB, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(0, |
| 0, |
| 1, |
| 1, |
| GL_RGB, |
| GL_INT, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(0, |
| 0, |
| 1, |
| 1, |
| GL_RGB, |
| GL_UNSIGNED_BYTE, |
| kInvalidSharedMemoryId, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(0, |
| 0, |
| 1, |
| 1, |
| GL_RGB, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| kInvalidSharedMemoryOffset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(0, |
| 0, |
| 1, |
| 1, |
| GL_RGB, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| kInvalidSharedMemoryId, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(0, |
| 0, |
| 1, |
| 1, |
| GL_RGB, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| kInvalidSharedMemoryOffset, |
| false); |
| result->success = 0; |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ReadPixelsAsyncError) { |
| InitState init; |
| init.extensions = "GL_ARB_sync"; |
| init.gl_version = "OpenGL ES 3.0"; |
| init.has_alpha = true; |
| init.request_alpha = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| const GLsizei kWidth = 4; |
| const GLsizei kHeight = 4; |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| // first error check must pass to get to the test |
| .WillOnce(Return(GL_NO_ERROR)) |
| // second check is after BufferData, simulate fail here |
| .WillOnce(Return(GL_INVALID_OPERATION)) |
| // third error check is fall-through call to sync ReadPixels |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| |
| EXPECT_CALL(*gl_, |
| ReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, _)) |
| .Times(1); |
| EXPECT_CALL(*gl_, GenBuffersARB(1, _)).Times(1); |
| EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)).Times(1); |
| EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, _)).Times(2); |
| EXPECT_CALL(*gl_, |
| BufferData(GL_PIXEL_PACK_BUFFER_ARB, _, nullptr, GL_STREAM_READ)) |
| .Times(1); |
| |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| kWidth, |
| kHeight, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| true); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| class GLES2ReadPixelsAsyncTest : public GLES2DecoderManualInitTest { |
| public: |
| void SetUp() override { |
| InitState init; |
| init.extensions = "GL_ARB_sync"; |
| init.gl_version = "OpenGL ES 3.0"; |
| init.has_alpha = true; |
| init.request_alpha = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| } |
| |
| void SetupReadPixelsAsyncExpectation(GLsizei width, GLsizei height) { |
| const size_t kBufferSize = width * height * 4; |
| EXPECT_CALL(*gl_, GetError()) |
| .WillRepeatedly(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| |
| EXPECT_CALL(*gl_, |
| ReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, _)) |
| .Times(1); |
| EXPECT_CALL(*gl_, GenBuffersARB(1, _)) |
| .WillOnce(SetArgPointee<1>(kServiceBufferId)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, kServiceBufferId)) |
| .Times(1); |
| EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0)).Times(1); |
| EXPECT_CALL(*gl_, BufferData(GL_PIXEL_PACK_BUFFER_ARB, kBufferSize, nullptr, |
| GL_STREAM_READ)) |
| .Times(1); |
| GLsync sync = reinterpret_cast<GLsync>(kServiceSyncId); |
| EXPECT_CALL(*gl_, FenceSync(0x9117, 0)).WillOnce(Return(sync)); |
| EXPECT_CALL(*gl_, IsSync(sync)).WillRepeatedly(Return(GL_TRUE)); |
| EXPECT_CALL(*gl_, Flush()).Times(1); |
| } |
| |
| void FinishReadPixelsAndCheckResult(GLsizei width, |
| GLsizei height, |
| char* pixels) { |
| EXPECT_TRUE(decoder_->HasMoreIdleWork()); |
| |
| const size_t kBufferSize = width * height * 4; |
| auto buffer = std::make_unique<char[]>(kBufferSize); |
| for (size_t i = 0; i < kBufferSize; ++i) |
| buffer[i] = i; |
| |
| GLsync sync = reinterpret_cast<GLsync>(kServiceSyncId); |
| EXPECT_CALL(*gl_, ClientWaitSync(sync, 0, 0)) |
| .WillOnce(Return(GL_CONDITION_SATISFIED)); |
| EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, kServiceBufferId)) |
| .Times(1); |
| EXPECT_CALL(*gl_, MapBufferRange(GL_PIXEL_PACK_BUFFER_ARB, 0, kBufferSize, |
| GL_MAP_READ_BIT)) |
| .WillOnce(Return(buffer.get())) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB)).Times(1); |
| EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0)).Times(1); |
| EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)).Times(1); |
| EXPECT_CALL(*gl_, DeleteSync(sync)).Times(1); |
| decoder_->PerformIdleWork(); |
| EXPECT_FALSE(decoder_->HasMoreIdleWork()); |
| EXPECT_EQ(0, memcmp(pixels, buffer.get(), kBufferSize)); |
| } |
| }; |
| |
| TEST_P(GLES2ReadPixelsAsyncTest, ReadPixelsAsync) { |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| const GLsizei kWidth = 4; |
| const GLsizei kHeight = 4; |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| char* pixels = reinterpret_cast<char*>(result + 1); |
| |
| SetupReadPixelsAsyncExpectation(kWidth, kHeight); |
| |
| ReadPixels cmd; |
| cmd.Init(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels_shm_id, |
| pixels_shm_offset, result_shm_id, result_shm_offset, true); |
| result->success = 0; |
| |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_TRUE(decoder_->HasMoreIdleWork()); |
| |
| GLsync sync = reinterpret_cast<GLsync>(kServiceSyncId); |
| EXPECT_CALL(*gl_, ClientWaitSync(sync, 0, 0)) |
| .WillOnce(Return(GL_TIMEOUT_EXPIRED)); |
| decoder_->PerformIdleWork(); |
| |
| FinishReadPixelsAndCheckResult(kWidth, kHeight, pixels); |
| } |
| |
| TEST_P(GLES2ReadPixelsAsyncTest, ReadPixelsAsyncModifyCommand) { |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| const GLsizei kWidth = 4; |
| const GLsizei kHeight = 4; |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| char* pixels = reinterpret_cast<char*>(result + 1); |
| |
| SetupReadPixelsAsyncExpectation(kWidth, kHeight); |
| |
| ReadPixels cmd; |
| cmd.Init(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels_shm_id, |
| pixels_shm_offset, result_shm_id, result_shm_offset, true); |
| result->success = 0; |
| |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_TRUE(decoder_->HasMoreIdleWork()); |
| |
| // Change command after ReadPixels issued, but before we finish the read, |
| // should have no impact. |
| cmd.Init(1, 2, 6, 7, GL_RGB, GL_UNSIGNED_SHORT, pixels_shm_id, |
| pixels_shm_offset, result_shm_id, result_shm_offset, false); |
| |
| FinishReadPixelsAndCheckResult(kWidth, kHeight, pixels); |
| } |
| |
| TEST_P(GLES2ReadPixelsAsyncTest, ReadPixelsAsyncChangePackAlignment) { |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| const GLsizei kWidth = 1; |
| const GLsizei kHeight = 4; |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| char* pixels = reinterpret_cast<char*>(result + 1); |
| |
| SetupReadPixelsAsyncExpectation(kWidth, kHeight); |
| |
| { |
| ReadPixels cmd; |
| cmd.Init(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels_shm_id, |
| pixels_shm_offset, result_shm_id, result_shm_offset, true); |
| result->success = 0; |
| |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| EXPECT_TRUE(decoder_->HasMoreIdleWork()); |
| |
| // Changing the pack alignment after the ReadPixels is issued but before we |
| // finish the read should have no impact. |
| { |
| PixelStorei cmd; |
| cmd.Init(GL_PACK_ALIGNMENT, 8); |
| |
| EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, 8)).Times(1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| FinishReadPixelsAndCheckResult(kWidth, kHeight, pixels); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(Service, GLES2ReadPixelsAsyncTest, ::testing::Bool()); |
| |
| // Check that if a renderbuffer is attached and GL returns |
| // GL_FRAMEBUFFER_COMPLETE that the buffer is cleared and state is restored. |
| TEST_P(GLES2DecoderTest, FramebufferRenderbufferClearColor) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| ClearColor color_cmd; |
| ColorMask color_mask_cmd; |
| Enable enable_cmd; |
| FramebufferRenderbuffer cmd; |
| color_cmd.Init(0.1f, 0.2f, 0.3f, 0.4f); |
| color_mask_cmd.Init(0, 1, 0, 1); |
| enable_cmd.Init(GL_SCISSOR_TEST); |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| InSequence sequence; |
| EXPECT_CALL(*gl_, ClearColor(0.1f, 0.2f, 0.3f, 0.4f)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| SetupExpectationsForEnableDisable(GL_SCISSOR_TEST, true); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| FramebufferRenderbufferEXT(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(color_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(color_mask_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(enable_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferRenderbufferClearDepth) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| ClearDepthf depth_cmd; |
| DepthMask depth_mask_cmd; |
| FramebufferRenderbuffer cmd; |
| depth_cmd.Init(0.5f); |
| depth_mask_cmd.Init(false); |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_DEPTH_ATTACHMENT, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| InSequence sequence; |
| EXPECT_CALL(*gl_, ClearDepth(0.5f)).Times(1).RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| FramebufferRenderbufferEXT(GL_FRAMEBUFFER, |
| GL_DEPTH_ATTACHMENT, |
| GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(depth_mask_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferRenderbufferClearStencil) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| ClearStencil stencil_cmd; |
| StencilMaskSeparate stencil_mask_separate_cmd; |
| FramebufferRenderbuffer cmd; |
| stencil_cmd.Init(123); |
| stencil_mask_separate_cmd.Init(GL_BACK, 0x1234u); |
| cmd.Init(GL_FRAMEBUFFER, |
| GL_STENCIL_ATTACHMENT, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| InSequence sequence; |
| EXPECT_CALL(*gl_, ClearStencil(123)).Times(1).RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| FramebufferRenderbufferEXT(GL_FRAMEBUFFER, |
| GL_STENCIL_ATTACHMENT, |
| GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_mask_separate_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferRenderbufferClearDepthStencil) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| ClearDepthf depth_cmd; |
| ClearStencil stencil_cmd; |
| FramebufferRenderbuffer cmd; |
| depth_cmd.Init(0.5f); |
| stencil_cmd.Init(123); |
| cmd.Init( |
| GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| InSequence sequence; |
| EXPECT_CALL(*gl_, ClearDepth(0.5f)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ClearStencil(123)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( |
| GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( |
| GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| Framebuffer* framebuffer = GetFramebuffer(client_framebuffer_id_); |
| ASSERT_TRUE(framebuffer); |
| ASSERT_FALSE(framebuffer->GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); |
| ASSERT_TRUE(framebuffer->GetAttachment(GL_DEPTH_ATTACHMENT)); |
| ASSERT_TRUE(framebuffer->GetAttachment(GL_STENCIL_ATTACHMENT)); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ActualAlphaMatchesRequestedAlpha) { |
| InitState init; |
| init.has_alpha = true; |
| init.request_alpha = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_ALPHA_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_ALPHA_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(8, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ActualAlphaDoesNotMatchRequestedAlpha) { |
| InitState init; |
| init.has_alpha = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_ALPHA_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_ALPHA_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(0, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ActualDepthMatchesRequestedDepth) { |
| InitState init; |
| init.has_depth = true; |
| init.request_depth = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) |
| .WillOnce(SetArgPointee<1>(24)) |
| .RetiresOnSaturation(); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(24, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ActualDepthDoesNotMatchRequestedDepth) { |
| InitState init; |
| init.has_depth = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) |
| .WillOnce(SetArgPointee<1>(24)) |
| .RetiresOnSaturation(); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(0, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ActualStencilMatchesRequestedStencil) { |
| InitState init; |
| init.has_stencil = true; |
| init.request_stencil = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) |
| .WillOnce(SetArgPointee<1>(8)) |
| .RetiresOnSaturation(); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(8, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ActualStencilDoesNotMatchRequestedStencil) { |
| InitState init; |
| init.has_stencil = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) |
| .WillOnce(SetArgPointee<1>(8)) |
| .RetiresOnSaturation(); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(0, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, PackedDepthStencilReportsCorrectValues) { |
| InitState init; |
| init.extensions = "GL_OES_packed_depth_stencil"; |
| init.gl_version = "OpenGL ES 2.0"; |
| init.has_depth = true; |
| init.has_stencil = true; |
| init.request_depth = true; |
| init.request_stencil = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) |
| .WillOnce(SetArgPointee<1>(8)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(8, result->GetData()[0]); |
| result->size = 0; |
| cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) |
| .WillOnce(SetArgPointee<1>(24)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(24, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, PackedDepthStencilNoRequestedStencil) { |
| InitState init; |
| init.extensions = "GL_OES_packed_depth_stencil"; |
| init.gl_version = "OpenGL ES 2.0"; |
| init.has_depth = true; |
| init.has_stencil = true; |
| init.request_depth = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) |
| .WillOnce(SetArgPointee<1>(8)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(0, result->GetData()[0]); |
| result->size = 0; |
| cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) |
| .WillOnce(SetArgPointee<1>(24)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(24, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, PackedDepthStencilRenderbufferDepth) { |
| InitState init; |
| init.extensions = "GL_OES_packed_depth_stencil"; |
| init.gl_version = "OpenGL ES 2.0"; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| |
| EnsureRenderbufferBound(false); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) // for RenderbufferStoage |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) // for FramebufferRenderbuffer |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) // for GetIntegerv |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) // for GetIntegerv |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| |
| EXPECT_CALL( |
| *gl_, |
| RenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 100, 50)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| RenderbufferStorage cmd; |
| cmd.Init(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 100, 50); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_CALL(*gl_, |
| FramebufferRenderbufferEXT(GL_FRAMEBUFFER, |
| GL_DEPTH_ATTACHMENT, |
| GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| FramebufferRenderbuffer fbrb_cmd; |
| fbrb_cmd.Init(GL_FRAMEBUFFER, |
| GL_DEPTH_ATTACHMENT, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd)); |
| |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) |
| .WillOnce(SetArgPointee<1>(8)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(0, result->GetData()[0]); |
| result->size = 0; |
| cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) |
| .WillOnce(SetArgPointee<1>(24)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(24, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, PackedDepthStencilRenderbufferStencil) { |
| InitState init; |
| init.extensions = "GL_OES_packed_depth_stencil"; |
| init.gl_version = "OpenGL ES 2.0"; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| |
| EnsureRenderbufferBound(false); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) // for RenderbufferStoage |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) // for FramebufferRenderbuffer |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) // for GetIntegerv |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) // for GetIntegerv |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| |
| EXPECT_CALL( |
| *gl_, |
| RenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 100, 50)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| RenderbufferStorage cmd; |
| cmd.Init(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 100, 50); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_CALL(*gl_, |
| FramebufferRenderbufferEXT(GL_FRAMEBUFFER, |
| GL_STENCIL_ATTACHMENT, |
| GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| FramebufferRenderbuffer fbrb_cmd; |
| fbrb_cmd.Init(GL_FRAMEBUFFER, |
| GL_STENCIL_ATTACHMENT, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd)); |
| |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) |
| .WillOnce(SetArgPointee<1>(8)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(8, result->GetData()[0]); |
| result->size = 0; |
| cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_); |
| EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) |
| .WillOnce(SetArgPointee<1>(24)) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(0, result->GetData()[0]); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferRenderbufferGLError) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| FramebufferRenderbuffer cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| FramebufferRenderbufferEXT(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, FramebufferTexture2DGLError) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLenum kFormat = GL_RGB; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, |
| 0, |
| kFormat, |
| kWidth, |
| kHeight, |
| 0, |
| kFormat, |
| GL_UNSIGNED_BYTE, |
| 0, |
| 0); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| FramebufferTexture2DEXT(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kServiceTextureId, |
| 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| FramebufferTexture2D fbtex_cmd; |
| fbtex_cmd.Init(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(fbtex_cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, RenderbufferStorageGLError) { |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| EnsureRenderbufferBound(false); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, RenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA, 100, 50)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| RenderbufferStorage cmd; |
| cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 100, 50); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, RenderbufferStorageBadArgs) { |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| EXPECT_CALL(*gl_, RenderbufferStorageEXT(_, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| RenderbufferStorage cmd; |
| cmd.Init(GL_RENDERBUFFER, GL_RGBA4, TestHelper::kMaxRenderbufferSize + 1, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 1, TestHelper::kMaxRenderbufferSize + 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, ClearBufferivImmediateValidArgs) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoRenderbufferStorage( |
| GL_RENDERBUFFER, GL_RGBA8I, GL_RGBA8I, 1, 1, GL_NO_ERROR); |
| DoFramebufferRenderbuffer( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR); |
| |
| // TODO(zmo): Set up expectations for the path where the attachment isn't |
| // marked as cleared. |
| Framebuffer* framebuffer = GetFramebuffer(client_framebuffer_id_); |
| framebuffer->MarkAttachmentAsCleared( |
| group().renderbuffer_manager(), nullptr, GL_COLOR_ATTACHMENT0, true); |
| |
| ClearBufferivImmediate& cmd = |
| *GetImmediateAs<ClearBufferivImmediate>(); |
| GLint temp[4] = { 0 }; |
| cmd.Init(GL_COLOR, 0, &temp[0]); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| SetupExpectationsForApplyingDirtyState( |
| false, false, false, 0x1111, false, false, 0, 0, false); |
| EXPECT_CALL(*gl_, ClearBufferiv(GL_COLOR, 0, PointsToArray(temp, 4))); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, ClearBufferuivImmediateValidArgs) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoRenderbufferStorage( |
| GL_RENDERBUFFER, GL_RGBA8UI, GL_RGBA8UI, 1, 1, GL_NO_ERROR); |
| DoFramebufferRenderbuffer( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR); |
| |
| // TODO(zmo): Set up expectations for the path where the attachment isn't |
| // marked as cleared. |
| Framebuffer* framebuffer = GetFramebuffer(client_framebuffer_id_); |
| framebuffer->MarkAttachmentAsCleared( |
| group().renderbuffer_manager(), nullptr, GL_COLOR_ATTACHMENT0, true); |
| |
| ClearBufferuivImmediate& cmd = |
| *GetImmediateAs<ClearBufferuivImmediate>(); |
| GLuint temp[4] = { 0u }; |
| cmd.Init(GL_COLOR, 0, &temp[0]); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| SetupExpectationsForApplyingDirtyState( |
| false, false, false, 0x1111, false, false, 0, 0, false); |
| EXPECT_CALL(*gl_, ClearBufferuiv(GL_COLOR, 0, PointsToArray(temp, 4))); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, ClearBufferfvImmediateValidArgs) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoRenderbufferStorage( |
| GL_RENDERBUFFER, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT32F, |
| 1, 1, GL_NO_ERROR); |
| DoFramebufferRenderbuffer( |
| GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, |
| client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR); |
| |
| // TODO(zmo): Set up expectations for the path where the attachment isn't |
| // marked as cleared. |
| Framebuffer* framebuffer = GetFramebuffer(client_framebuffer_id_); |
| framebuffer->MarkAttachmentAsCleared( |
| group().renderbuffer_manager(), nullptr, GL_DEPTH_ATTACHMENT, true); |
| |
| Enable cmd_enable; |
| cmd_enable.Init(GL_DEPTH_TEST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd_enable)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| ClearBufferfvImmediate& cmd = |
| *GetImmediateAs<ClearBufferfvImmediate>(); |
| GLfloat temp[4] = { 1.0f }; |
| cmd.Init(GL_DEPTH, 0, &temp[0]); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| SetupExpectationsForApplyingDirtyState( |
| true, true, false, 0x1110, true, true, 0, 0, false); |
| EXPECT_CALL(*gl_, ClearBufferfv(GL_DEPTH, 0, PointsToArray(temp, 4))); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, ClearBufferfiValidArgs) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoRenderbufferStorage( |
| GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, |
| 1, 1, GL_NO_ERROR); |
| DoFramebufferRenderbuffer( |
| GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR); |
| |
| // TODO(zmo): Set up expectations for the path where the attachment isn't |
| // marked as cleared. |
| Framebuffer* framebuffer = GetFramebuffer(client_framebuffer_id_); |
| framebuffer->MarkAttachmentAsCleared(group().renderbuffer_manager(), nullptr, |
| GL_DEPTH_ATTACHMENT, true); |
| framebuffer->MarkAttachmentAsCleared(group().renderbuffer_manager(), nullptr, |
| GL_STENCIL_ATTACHMENT, true); |
| |
| Enable cmd_enable; |
| cmd_enable.Init(GL_STENCIL_TEST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd_enable)); |
| cmd_enable.Init(GL_DEPTH_TEST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd_enable)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| ClearBufferfi cmd; |
| cmd.Init(GL_DEPTH_STENCIL, 0, 1.0f, 0); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| SetupExpectationsForApplyingDirtyState( |
| true, true, true, 0x1110, true, true, |
| GLES2Decoder::kDefaultStencilMask, GLES2Decoder::kDefaultStencilMask, |
| true); |
| EXPECT_CALL(*gl_, ClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, |
| RenderbufferStorageMultisampleCHROMIUMGLError) { |
| InitState init; |
| init.extensions = "GL_ARB_framebuffer_object"; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| EnsureRenderbufferBound(false); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, RenderbufferStorageMultisample(GL_RENDERBUFFER, 1, GL_RGBA, |
| 100, 50)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| RenderbufferStorageMultisampleCHROMIUM cmd; |
| cmd.Init(GL_RENDERBUFFER, 1, GL_RGBA4, 100, 50); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, |
| RenderbufferStorageMultisampleCHROMIUMBadArgs) { |
| InitState init; |
| init.extensions = "GL_ARB_framebuffer_object"; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| EXPECT_CALL(*gl_, RenderbufferStorageMultisample(_, _, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| RenderbufferStorageMultisampleCHROMIUM cmd; |
| cmd.Init(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples + 1, |
| GL_RGBA4, |
| TestHelper::kMaxRenderbufferSize, |
| 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples, |
| GL_RGBA4, |
| TestHelper::kMaxRenderbufferSize + 1, |
| 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples, |
| GL_RGBA4, |
| 1, |
| TestHelper::kMaxRenderbufferSize + 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, RenderbufferStorageMultisampleCHROMIUM) { |
| InitState init; |
| init.extensions = "GL_ARB_framebuffer_object"; |
| InitDecoder(init); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| InSequence sequence; |
| DoRenderbufferStorageMultisampleCHROMIUM( |
| GL_RENDERBUFFER, TestHelper::kMaxSamples, GL_RGBA4, GL_RGBA, |
| TestHelper::kMaxRenderbufferSize, 1, false); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, |
| RenderbufferStorageMultisampleCHROMIUMRebindRenderbuffer) { |
| InitState init; |
| init.extensions = "GL_ARB_framebuffer_object"; |
| InitDecoder(init); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| RestoreRenderbufferBindings(); |
| InSequence sequence; |
| DoRenderbufferStorageMultisampleCHROMIUM( |
| GL_RENDERBUFFER, TestHelper::kMaxSamples, GL_RGBA4, GL_RGBA, |
| TestHelper::kMaxRenderbufferSize, 1, true); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, |
| RenderbufferStorageMultisampleEXTNotSupported) { |
| InitState init; |
| init.extensions = "GL_ARB_framebuffer_object"; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| InSequence sequence; |
| // GL_CHROMIUM_framebuffer_multisample uses |
| // RenderbufferStorageMultisampleCHROMIUM. |
| RenderbufferStorageMultisampleEXT cmd; |
| cmd.Init(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples, |
| GL_RGBA4, |
| TestHelper::kMaxRenderbufferSize, |
| 1); |
| EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); |
| } |
| |
| class GLES2DecoderMultisampledRenderToTextureTest |
| : public GLES2DecoderTestWithExtensionsOnGLES2 { |
| public: |
| void TestNotCompatibleWithRenderbufferStorageMultisampleCHROMIUM() { |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| RenderbufferStorageMultisampleCHROMIUM cmd; |
| cmd.Init(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples, |
| GL_RGBA4, |
| TestHelper::kMaxRenderbufferSize, |
| 1); |
| EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); |
| } |
| |
| void TestRenderbufferStorageMultisampleEXT(const char* extension, |
| bool rb_rebind) { |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| InSequence sequence; |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| if (rb_rebind) { |
| RestoreRenderbufferBindings(); |
| EnsureRenderbufferBound(true); |
| } else { |
| EnsureRenderbufferBound(false); |
| } |
| EXPECT_CALL(*gl_, RenderbufferStorageMultisampleEXT( |
| GL_RENDERBUFFER, TestHelper::kMaxSamples, GL_RGBA4, |
| TestHelper::kMaxRenderbufferSize, 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| RenderbufferStorageMultisampleEXT cmd; |
| cmd.Init(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples, |
| GL_RGBA4, |
| TestHelper::kMaxRenderbufferSize, |
| 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(Service, |
| GLES2DecoderMultisampledRenderToTextureTest, |
| ::testing::Bool()); |
| |
| TEST_P(GLES2DecoderMultisampledRenderToTextureTest, |
| NotCompatibleWithRenderbufferStorageMultisampleCHROMIUM_EXT) { |
| Init("GL_EXT_multisampled_render_to_texture"); |
| TestNotCompatibleWithRenderbufferStorageMultisampleCHROMIUM(); |
| } |
| |
| TEST_P(GLES2DecoderMultisampledRenderToTextureTest, |
| NotCompatibleWithRenderbufferStorageMultisampleCHROMIUM_IMG) { |
| Init("GL_IMG_multisampled_render_to_texture"); |
| TestNotCompatibleWithRenderbufferStorageMultisampleCHROMIUM(); |
| } |
| |
| TEST_P(GLES2DecoderMultisampledRenderToTextureTest, |
| RenderbufferStorageMultisampleEXT_EXT) { |
| Init("GL_EXT_multisampled_render_to_texture"); |
| TestRenderbufferStorageMultisampleEXT("GL_EXT_multisampled_render_to_texture", |
| false); |
| } |
| |
| TEST_P(GLES2DecoderMultisampledRenderToTextureTest, |
| RenderbufferStorageMultisampleEXT_IMG) { |
| Init("GL_IMG_multisampled_render_to_texture"); |
| TestRenderbufferStorageMultisampleEXT("GL_IMG_multisampled_render_to_texture", |
| false); |
| } |
| |
| TEST_P(GLES2DecoderMultisampledRenderToTextureTest, |
| RenderbufferStorageMultisampleEXT_EXT_RebindRenderbuffer) { |
| Init("GL_EXT_multisampled_render_to_texture"); |
| TestRenderbufferStorageMultisampleEXT("GL_EXT_multisampled_render_to_texture", |
| true); |
| } |
| |
| TEST_P(GLES2DecoderMultisampledRenderToTextureTest, |
| RenderbufferStorageMultisampleEXT_IMG_RebindRenderbuffer) { |
| Init("GL_IMG_multisampled_render_to_texture"); |
| TestRenderbufferStorageMultisampleEXT("GL_IMG_multisampled_render_to_texture", |
| true); |
| } |
| |
| TEST_P(GLES2DecoderTest, ReadPixelsGLError) { |
| GLenum kFormat = GL_RGBA; |
| GLint x = 0; |
| GLint y = 0; |
| GLsizei width = 2; |
| GLsizei height = 4; |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| ReadPixels(x, y, width, height, kFormat, GL_UNSIGNED_BYTE, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| ReadPixels cmd; |
| cmd.Init(x, |
| y, |
| width, |
| height, |
| kFormat, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnClear) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| // Setup "render to" texture. |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| // Set scissor rect and enable GL_SCISSOR_TEST to make sure we re-enable it |
| // and restore the rect again after the clear. |
| DoEnableDisable(GL_SCISSOR_TEST, true); |
| DoScissor(0, 0, 64, 64); |
| |
| // Setup "render from" texture. |
| SetupTexture(); |
| |
| SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT, // clear bits |
| 0, 0, 0, |
| 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| true, // scissor test |
| 0, 0, 64, 64); |
| SetupExpectationsForApplyingDirtyState(false, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1111, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false); // stencil enabled |
| |
| EXPECT_CALL(*gl_, Clear(GL_COLOR_BUFFER_BIT)).Times(1).RetiresOnSaturation(); |
| |
| Clear cmd; |
| cmd.Init(GL_COLOR_BUFFER_BIT); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnReadPixels) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| // Setup "render to" texture. |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| DoEnableDisable(GL_SCISSOR_TEST, false); |
| DoScissor(0, 0, 1, 1); |
| |
| // Setup "render from" texture. |
| SetupTexture(); |
| |
| SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT, // clear bits |
| 0, 0, 0, |
| 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| false, // scissor test |
| 0, 0, 1, 1); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| 1, |
| 1, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, CopyTexImage2DValidInternalFormat) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RG32I; |
| GLenum format = GL_RG_INTEGER; |
| GLenum type = GL_INT; |
| GLsizei width = 16; |
| GLsizei height = 8; |
| GLint border = 0; |
| |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, level, internal_format, width, height, 0, format, |
| type, shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| |
| EXPECT_CALL(*gl_, |
| CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderManualInitTest, CopyTexImage2DValidInternalFormat_FloatEXT) { |
| InitState init; |
| init.extensions = "GL_EXT_color_buffer_float"; |
| init.gl_version = "OpenGL ES 3.0"; |
| init.bind_generates_resource = true; |
| init.context_type = CONTEXT_TYPE_OPENGLES3; |
| InitDecoder(init); |
| |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RG16F; |
| GLenum format = GL_RGBA; |
| GLenum type = GL_HALF_FLOAT; |
| GLsizei width = 16; |
| GLsizei height = 8; |
| GLint border = 0; |
| |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, level, GL_RGBA16F, width, height, 0, format, type, |
| shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| EXPECT_CALL(*gl_, |
| CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderManualInitTest, |
| CopyTexImage2DInvalidInternalFormat_FloatEXT) { |
| InitState init; |
| init.extensions = "GL_EXT_color_buffer_float"; |
| init.gl_version = "OpenGL ES 3.0"; |
| init.bind_generates_resource = true; |
| init.context_type = CONTEXT_TYPE_OPENGLES3; |
| InitDecoder(init); |
| |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RG16F; |
| GLenum format = GL_RGBA; |
| GLenum type = GL_UNSIGNED_BYTE; |
| GLsizei width = 16; |
| GLsizei height = 8; |
| GLint border = 0; |
| |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, width, height, 0, format, type, |
| shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| EXPECT_CALL(*gl_, |
| CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(0); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, CopyTexImage2DInvalidInternalFormat) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RG_INTEGER; |
| GLenum format = GL_RG; |
| GLenum type = GL_UNSIGNED_BYTE; |
| GLsizei width = 16; |
| GLsizei height = 8; |
| GLint border = 0; |
| |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, level, GL_RG8, width, height, 0, format, type, |
| shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| EXPECT_CALL(*gl_, |
| CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, CopyTexImage2DInvalidInternalFormat_Float) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RG16F; |
| GLenum format = GL_RGBA; |
| GLenum type = GL_UNSIGNED_BYTE; |
| GLsizei width = 16; |
| GLsizei height = 8; |
| GLint border = 0; |
| |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, width, height, 0, format, type, |
| shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| EXPECT_CALL(*gl_, |
| CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(0); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, CopyTexImage2DInvalidInternalFormat_Integer) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RG8I; |
| GLenum format = GL_RG_INTEGER; |
| GLenum type = GL_UNSIGNED_BYTE; |
| GLsizei width = 16; |
| GLsizei height = 8; |
| GLint border = 0; |
| |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, level, GL_RG8UI, width, height, 0, format, type, |
| shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| EXPECT_CALL(*gl_, |
| CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(0); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, CopyTexImage2DInvalidInternalFormat_sRGB) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_SRGB8; |
| GLenum format = GL_RGB; |
| GLenum type = GL_UNSIGNED_BYTE; |
| GLsizei width = 16; |
| GLsizei height = 8; |
| GLint border = 0; |
| |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, level, GL_RGB, width, height, 0, format, type, |
| shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| EXPECT_CALL(*gl_, |
| CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(0); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, |
| UnClearedAttachmentsGetClearedOnReadPixelsAndDrawBufferGetsRestored) { |
| InitState init; |
| init.extensions = "GL_ARB_framebuffer_object"; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| // Setup "render from" texture. |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| |
| // Set scissor rect and disable GL_SCISSOR_TEST to make sure we enable it in |
| // the clear, then disable it and restore the rect again. |
| DoScissor(0, 0, 32, 32); |
| DoEnableDisable(GL_SCISSOR_TEST, false); |
| |
| SetupExpectationsForFramebufferClearingMulti( |
| kServiceFramebufferId, // read framebuffer service id |
| 0, // backbuffer service id |
| GL_READ_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT, // clear bits |
| 0, 0, 0, |
| 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| false, // scissor test |
| 0, 0, 32, 32); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32_t result_shm_id = shared_memory_id_; |
| uint32_t result_shm_offset = kSharedMemoryOffset; |
| uint32_t pixels_shm_id = shared_memory_id_; |
| uint32_t pixels_shm_offset = kSharedMemoryOffset + sizeof(Result); |
| ReadPixels cmd; |
| cmd.Init(0, |
| 0, |
| 1, |
| 1, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| pixels_shm_id, |
| pixels_shm_offset, |
| result_shm_id, |
| result_shm_offset, |
| false); |
| result->success = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, CopyTexImageWithInCompleteFBOFails) { |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RGBA; |
| GLsizei width = 2; |
| GLsizei height = 4; |
| SetupTexture(); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 0, 0, GL_NO_ERROR); |
| DoFramebufferRenderbuffer(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_, |
| kServiceRenderbufferId, |
| GL_NO_ERROR); |
| |
| EXPECT_CALL(*gl_, CopyTexImage2D(_, _, _, _, _, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError()); |
| } |
| |
| void GLES2DecoderWithShaderTest::CheckRenderbufferChangesMarkFBOAsNotComplete( |
| bool bound_fbo) { |
| FramebufferManager* framebuffer_manager = GetFramebufferManager(); |
| SetupTexture(); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 1, 1, GL_NO_ERROR); |
| DoFramebufferRenderbuffer(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_, |
| kServiceRenderbufferId, |
| GL_NO_ERROR); |
| |
| if (!bound_fbo) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); |
| } |
| |
| Framebuffer* framebuffer = |
| framebuffer_manager->GetFramebuffer(client_framebuffer_id_); |
| ASSERT_TRUE(framebuffer != nullptr); |
| framebuffer_manager->MarkAsComplete(framebuffer); |
| EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer)); |
| |
| // Test that renderbufferStorage marks fbo as not complete. |
| DoRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 1, 1, GL_NO_ERROR); |
| EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer)); |
| framebuffer_manager->MarkAsComplete(framebuffer); |
| EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer)); |
| |
| // Test deleting renderbuffer marks fbo as not complete. |
| DoDeleteRenderbuffer(client_renderbuffer_id_, kServiceRenderbufferId); |
| if (bound_fbo) { |
| EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer)); |
| } else { |
| EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer)); |
| } |
| // Cleanup |
| DoDeleteFramebuffer(client_framebuffer_id_, |
| kServiceFramebufferId, |
| bound_fbo, |
| GL_FRAMEBUFFER, |
| 0, |
| bound_fbo, |
| GL_FRAMEBUFFER, |
| 0); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, |
| RenderbufferChangesMarkFBOAsNotCompleteBoundFBO) { |
| CheckRenderbufferChangesMarkFBOAsNotComplete(true); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, |
| RenderbufferChangesMarkFBOAsNotCompleteUnboundFBO) { |
| CheckRenderbufferChangesMarkFBOAsNotComplete(false); |
| } |
| |
| void GLES2DecoderWithShaderTest::CheckTextureChangesMarkFBOAsNotComplete( |
| bool bound_fbo) { |
| FramebufferManager* framebuffer_manager = GetFramebufferManager(); |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| SetupTexture(); |
| |
| // Setup "render to" texture. |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoRenderbufferStorage(GL_RENDERBUFFER, |
| GL_DEPTH_COMPONENT16, |
| GL_DEPTH_COMPONENT, |
| 1, |
| 1, |
| GL_NO_ERROR); |
| DoFramebufferRenderbuffer(GL_FRAMEBUFFER, |
| GL_DEPTH_ATTACHMENT, |
| GL_RENDERBUFFER, |
| client_renderbuffer_id_, |
| kServiceRenderbufferId, |
| GL_NO_ERROR); |
| |
| if (!bound_fbo) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); |
| } |
| |
| Framebuffer* framebuffer = |
| framebuffer_manager->GetFramebuffer(client_framebuffer_id_); |
| ASSERT_TRUE(framebuffer != nullptr); |
| framebuffer_manager->MarkAsComplete(framebuffer); |
| EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer)); |
| |
| // Test TexImage2D marks fbo as not complete. |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, 0, 0); |
| EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer)); |
| framebuffer_manager->MarkAsComplete(framebuffer); |
| EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer)); |
| |
| // Test CopyImage2D marks fbo as not complete. |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 1, 1, 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| CopyTexImage2D cmd; |
| cmd.Init(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 1, 1); |
| // Unbind fbo and bind again after CopyTexImage2D tp avoid feedback loops. |
| if (bound_fbo) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); |
| } |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| if (bound_fbo) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| } |
| EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer)); |
| |
| // Test deleting texture marks fbo as not complete. |
| framebuffer_manager->MarkAsComplete(framebuffer); |
| EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer)); |
| DoDeleteTexture(kFBOClientTextureId, kFBOServiceTextureId); |
| |
| if (bound_fbo) { |
| EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer)); |
| } else { |
| EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer)); |
| } |
| // Cleanup |
| DoDeleteFramebuffer(client_framebuffer_id_, |
| kServiceFramebufferId, |
| bound_fbo, |
| GL_FRAMEBUFFER, |
| 0, |
| bound_fbo, |
| GL_FRAMEBUFFER, |
| 0); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, TextureChangesMarkFBOAsNotCompleteBoundFBO) { |
| CheckTextureChangesMarkFBOAsNotComplete(true); |
| } |
| |
| TEST_P(GLES2DecoderWithShaderTest, |
| TextureChangesMarkFBOAsNotCompleteUnboundFBO) { |
| CheckTextureChangesMarkFBOAsNotComplete(false); |
| } |
| |
| TEST_P(GLES2DecoderTest, CanChangeSurface) { |
| scoped_refptr<GLSurfaceMock> other_surface(new GLSurfaceMock); |
| EXPECT_CALL(*other_surface.get(), GetBackingFramebufferObject()) |
| .WillOnce(Return(7)); |
| EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 7)); |
| |
| decoder_->SetSurface(other_surface); |
| } |
| |
| TEST_P(GLES2DecoderTest, DrawBuffersEXTImmediateSuccceeds) { |
| const GLsizei count = 1; |
| const GLenum bufs[] = {GL_COLOR_ATTACHMENT0}; |
| DrawBuffersEXTImmediate& cmd = *GetImmediateAs<DrawBuffersEXTImmediate>(); |
| cmd.Init(count, bufs); |
| |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| EXPECT_CALL(*gl_, DrawBuffersARB(count, _)).Times(1).RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(bufs))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, DrawBuffersEXTImmediateFails) { |
| const GLsizei count = 1; |
| const GLenum bufs[] = {GL_COLOR_ATTACHMENT1_EXT}; |
| DrawBuffersEXTImmediate& cmd = *GetImmediateAs<DrawBuffersEXTImmediate>(); |
| cmd.Init(count, bufs); |
| |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(bufs))); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, DrawBuffersEXTImmediateBackbuffer) { |
| const GLsizei count = 1; |
| const GLenum bufs[] = {GL_BACK}; |
| DrawBuffersEXTImmediate& cmd = *GetImmediateAs<DrawBuffersEXTImmediate>(); |
| cmd.Init(count, bufs); |
| |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(bufs))); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); // unbind |
| |
| EXPECT_CALL(*gl_, DrawBuffersARB(count, _)).Times(1).RetiresOnSaturation(); |
| |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(bufs))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderTest, DrawBuffersEXTMainFramebuffer) { |
| DrawBuffersEXTImmediate& cmd = *GetImmediateAs<DrawBuffersEXTImmediate>(); |
| { |
| const GLenum bufs[] = {GL_BACK}; |
| const GLsizei count = base::size(bufs); |
| cmd.Init(count, bufs); |
| |
| EXPECT_CALL(*gl_, DrawBuffersARB(count, Pointee(GL_BACK))) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(bufs))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| { |
| const GLsizei count = 0; |
| cmd.Init(count, nullptr); |
| |
| EXPECT_CALL(*gl_, DrawBuffersARB(_, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, 0)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| { |
| const GLenum bufs[] = {GL_BACK, GL_NONE}; |
| const GLsizei count = base::size(bufs); |
| cmd.Init(count, bufs); |
| |
| EXPECT_CALL(*gl_, DrawBuffersARB(_, _)).Times(0).RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(bufs))); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, InvalidateFramebufferBinding) { |
| InitState init; |
| init.gl_version = "OpenGL ES 3.0"; |
| InitDecoder(init); |
| |
| // EXPECT_EQ can't be used to compare function pointers |
| EXPECT_TRUE( |
| gl::MockGLInterface::GetGLProcAddress("glInvalidateFramebuffer") != |
| reinterpret_cast<gl::GLFunctionPointerType>( |
| gl::g_current_gl_driver->fn.glDiscardFramebufferEXTFn)); |
| EXPECT_TRUE( |
| gl::MockGLInterface::GetGLProcAddress("glInvalidateFramebuffer") != |
| gl::MockGLInterface::GetGLProcAddress("glDiscardFramebufferEXT")); |
| } |
| |
| TEST_P(GLES2DecoderTest, ClearBackbufferBitsOnFlipSwap) { |
| surface_->set_buffers_flipped(true); |
| |
| EXPECT_EQ(0u, GetAndClearBackbufferClearBitsForTest()); |
| |
| SwapBuffers& cmd = *GetImmediateAs<SwapBuffers>(); |
| cmd.Init(1, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(static_cast<uint32_t>(GL_COLOR_BUFFER_BIT), |
| GetAndClearBackbufferClearBitsForTest()); |
| |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(0u, GetAndClearBackbufferClearBitsForTest()); |
| |
| EXPECT_CALL(*gl_, Finish()).Times(AnyNumber()); |
| ResizeCHROMIUM& resize_cmd = *GetImmediateAs<ResizeCHROMIUM>(); |
| resize_cmd.Init(1, 1, 1.0f, GL_COLOR_SPACE_UNSPECIFIED_CHROMIUM, GL_TRUE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(resize_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(static_cast<uint32_t>(GL_COLOR_BUFFER_BIT), |
| GetAndClearBackbufferClearBitsForTest()); |
| |
| cmd.Init(1, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(static_cast<uint32_t>(GL_COLOR_BUFFER_BIT), |
| GetAndClearBackbufferClearBitsForTest()); |
| |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(0u, GetAndClearBackbufferClearBitsForTest()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, DiscardFramebufferEXT) { |
| InitState init; |
| init.extensions = "GL_EXT_discard_framebuffer"; |
| init.gl_version = "OpenGL ES 2.0"; |
| InitDecoder(init); |
| |
| // EXPECT_EQ can't be used to compare function pointers |
| EXPECT_TRUE( |
| gl::MockGLInterface::GetGLProcAddress("glDiscardFramebufferEXT") == |
| reinterpret_cast<gl::GLFunctionPointerType>( |
| gl::g_current_gl_driver->fn.glDiscardFramebufferEXTFn)); |
| |
| const GLenum target = GL_FRAMEBUFFER; |
| const GLsizei count = 1; |
| const GLenum attachments[] = {GL_COLOR_ATTACHMENT0}; |
| |
| SetupTexture(); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| kServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| FramebufferManager* framebuffer_manager = GetFramebufferManager(); |
| Framebuffer* framebuffer = |
| framebuffer_manager->GetFramebuffer(client_framebuffer_id_); |
| EXPECT_TRUE(framebuffer->IsCleared()); |
| |
| EXPECT_CALL(*gl_, DiscardFramebufferEXT(target, count, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DiscardFramebufferEXTImmediate& cmd = |
| *GetImmediateAs<DiscardFramebufferEXTImmediate>(); |
| cmd.Init(target, count, attachments); |
| |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_FALSE(framebuffer->IsCleared()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, ClearBackbufferBitsOnDiscardFramebufferEXT) { |
| InitState init; |
| init.extensions = "GL_EXT_discard_framebuffer"; |
| init.gl_version = "OpenGL ES 2.0"; |
| InitDecoder(init); |
| |
| // EXPECT_EQ can't be used to compare function pointers. |
| EXPECT_TRUE( |
| gl::MockGLInterface::GetGLProcAddress("glDiscardFramebufferEXT") == |
| reinterpret_cast<gl::GLFunctionPointerType>( |
| gl::g_current_gl_driver->fn.glDiscardFramebufferEXTFn)); |
| |
| const GLenum target = GL_FRAMEBUFFER; |
| const GLsizei count = 1; |
| GLenum attachments[] = {GL_COLOR_EXT}; |
| |
| EXPECT_CALL(*gl_, DiscardFramebufferEXT(target, count, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DiscardFramebufferEXTImmediate& cmd = |
| *GetImmediateAs<DiscardFramebufferEXTImmediate>(); |
| cmd.Init(target, count, attachments); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(static_cast<uint32_t>(GL_COLOR_BUFFER_BIT), |
| GetAndClearBackbufferClearBitsForTest()); |
| |
| attachments[0] = GL_DEPTH_EXT; |
| EXPECT_CALL(*gl_, DiscardFramebufferEXT(target, count, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| cmd.Init(target, count, attachments); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(static_cast<uint32_t>(GL_DEPTH_BUFFER_BIT), |
| GetAndClearBackbufferClearBitsForTest()); |
| |
| attachments[0] = GL_STENCIL_EXT; |
| EXPECT_CALL(*gl_, DiscardFramebufferEXT(target, count, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| cmd.Init(target, count, attachments); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(static_cast<uint32_t>(GL_STENCIL_BUFFER_BIT), |
| GetAndClearBackbufferClearBitsForTest()); |
| |
| const GLsizei count0 = 3; |
| const GLenum attachments0[] = {GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT}; |
| EXPECT_CALL(*gl_, DiscardFramebufferEXT(target, count0, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| cmd.Init(target, count0, attachments0); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments0))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(static_cast<uint32_t>(GL_COLOR_BUFFER_BIT | |
| GL_DEPTH_BUFFER_BIT | |
| GL_STENCIL_BUFFER_BIT), |
| GetAndClearBackbufferClearBitsForTest()); |
| } |
| |
| TEST_P(GLES2DecoderTest, DiscardFramebufferEXTUnsupported) { |
| const GLenum target = GL_FRAMEBUFFER; |
| const GLsizei count = 1; |
| const GLenum attachments[] = {GL_COLOR_EXT}; |
| DiscardFramebufferEXTImmediate& cmd = |
| *GetImmediateAs<DiscardFramebufferEXTImmediate>(); |
| cmd.Init(target, count, attachments); |
| |
| // Should not result into a call into GL. |
| EXPECT_EQ(error::kUnknownCommand, |
| ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| } |
| |
| TEST_P(GLES3DecoderTest, DiscardFramebufferEXTInvalidTarget) { |
| const GLenum target = GL_RED; // Invalid |
| const GLsizei count = 1; |
| const GLenum attachments[] = {GL_COLOR_ATTACHMENT0}; |
| |
| SetupTexture(); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| kServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| FramebufferManager* framebuffer_manager = GetFramebufferManager(); |
| Framebuffer* framebuffer = |
| framebuffer_manager->GetFramebuffer(client_framebuffer_id_); |
| EXPECT_TRUE(framebuffer->IsCleared()); |
| |
| EXPECT_CALL(*gl_, InvalidateFramebuffer(target, count, _)).Times(0); |
| DiscardFramebufferEXTImmediate& cmd = |
| *GetImmediateAs<DiscardFramebufferEXTImmediate>(); |
| cmd.Init(target, count, attachments); |
| |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| EXPECT_TRUE(framebuffer->IsCleared()); |
| } |
| |
| TEST_P(GLES3DecoderTest, DiscardFramebufferEXTUseCorrectTarget) { |
| const GLenum target = GL_READ_FRAMEBUFFER; |
| const GLsizei count = 1; |
| const GLenum attachments[] = {GL_COLOR_ATTACHMENT0}; |
| |
| SetupTexture(); |
| DoBindFramebuffer( |
| GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_READ_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| kServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| |
| EXPECT_CALL(*gl_, GenFramebuffersEXT(_, _)) |
| .WillOnce(SetArgPointee<1>(kServiceFramebufferId + 1)) |
| .RetiresOnSaturation(); |
| DoBindFramebuffer(GL_DRAW_FRAMEBUFFER, client_framebuffer_id_ + 1, |
| kServiceFramebufferId + 1); |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kServiceTextureId + 1)) |
| .RetiresOnSaturation(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_ + 1, kServiceTextureId + 1); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_id_, kSharedMemoryOffset); |
| DoFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_ + 1, |
| kServiceTextureId + 1, |
| 0, |
| GL_NO_ERROR); |
| |
| FramebufferManager* framebuffer_manager = GetFramebufferManager(); |
| Framebuffer* framebuffer = |
| framebuffer_manager->GetFramebuffer(client_framebuffer_id_); |
| EXPECT_TRUE(framebuffer->IsCleared()); |
| Framebuffer* other_framebuffer = |
| framebuffer_manager->GetFramebuffer(client_framebuffer_id_ + 1); |
| EXPECT_TRUE(other_framebuffer->IsCleared()); |
| |
| EXPECT_CALL(*gl_, InvalidateFramebuffer(target, count, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DiscardFramebufferEXTImmediate& cmd = |
| *GetImmediateAs<DiscardFramebufferEXTImmediate>(); |
| cmd.Init(target, count, attachments); |
| |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_FALSE(framebuffer->IsCleared()); |
| EXPECT_TRUE(other_framebuffer->IsCleared()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, |
| DiscardedAttachmentsEXTMarksFramebufferIncomplete) { |
| InitState init; |
| init.extensions = "GL_EXT_discard_framebuffer"; |
| init.gl_version = "OpenGL ES 2.0"; |
| init.has_alpha = true; |
| init.bind_generates_resource = true; |
| InitDecoder(init); |
| |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| // Setup "render to" texture. |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| kFBOClientTextureId, |
| kFBOServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| DoEnableDisable(GL_SCISSOR_TEST, false); |
| DoScissor(0, 0, 1, 1); |
| |
| // Setup "render from" texture. |
| SetupTexture(); |
| |
| SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT, // clear bits |
| 0, 0, 0, |
| 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| false, // scissor test |
| 0, 0, 1, 1); |
| SetupExpectationsForApplyingDirtyState(false, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1111, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false); // stencil enabled |
| |
| EXPECT_CALL(*gl_, Clear(GL_COLOR_BUFFER_BIT)).Times(1).RetiresOnSaturation(); |
| |
| Clear clear_cmd; |
| clear_cmd.Init(GL_COLOR_BUFFER_BIT); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(clear_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Check that framebuffer is cleared and complete. |
| FramebufferManager* framebuffer_manager = GetFramebufferManager(); |
| Framebuffer* framebuffer = |
| framebuffer_manager->GetFramebuffer(client_framebuffer_id_); |
| EXPECT_TRUE(framebuffer->IsCleared()); |
| EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer)); |
| |
| // Check that Discard GL_COLOR_ATTACHMENT0, sets the attachment as uncleared |
| // and the framebuffer as incomplete. |
| EXPECT_TRUE( |
| gl::MockGLInterface::GetGLProcAddress("glDiscardFramebufferEXT") == |
| reinterpret_cast<gl::GLFunctionPointerType>( |
| gl::g_current_gl_driver->fn.glDiscardFramebufferEXTFn)); |
| |
| const GLenum target = GL_FRAMEBUFFER; |
| const GLsizei count = 1; |
| const GLenum attachments[] = {GL_COLOR_ATTACHMENT0}; |
| |
| DiscardFramebufferEXTImmediate& discard_cmd = |
| *GetImmediateAs<DiscardFramebufferEXTImmediate>(); |
| discard_cmd.Init(target, count, attachments); |
| |
| EXPECT_CALL(*gl_, DiscardFramebufferEXT(target, count, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(discard_cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_FALSE(framebuffer->IsCleared()); |
| EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer)); |
| } |
| |
| TEST_P(GLES2DecoderTest, ImplementationReadColorFormatAndType) { |
| ClearSharedMemory(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_id_, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, |
| client_texture_id_, |
| kServiceTextureId, |
| 0, |
| GL_NO_ERROR); |
| |
| typedef GetIntegerv::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| GetIntegerv cmd; |
| |
| result->size = 0; |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| cmd.Init(GL_IMPLEMENTATION_COLOR_READ_FORMAT, |
| shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(1, result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| result->size = 0; |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| cmd.Init(GL_IMPLEMENTATION_COLOR_READ_TYPE, |
| shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(1, result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTextureLayerNoBoundFramebuffer) { |
| DoBindTexture(GL_TEXTURE_3D, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*gl_, FramebufferTextureLayer(_, _, _, _, _)).Times(0); |
| FramebufferTextureLayer cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, client_texture_id_, 4, 5); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTextureLayerInvalidTextureTarget) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*gl_, FramebufferTextureLayer(_, _, _, _, _)).Times(0); |
| FramebufferTextureLayer cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, client_texture_id_, 4, 5); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTextureLayerValidArgs) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindTexture(GL_TEXTURE_3D, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*gl_, FramebufferTextureLayer(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| kServiceTextureId, 4, 5)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| FramebufferTextureLayer cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, client_texture_id_, 4, 5); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, FramebufferTextureLayerDepthStencil) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindTexture(GL_TEXTURE_2D_ARRAY, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*gl_, FramebufferTextureLayer(GL_FRAMEBUFFER, |
| GL_DEPTH_STENCIL_ATTACHMENT, |
| kServiceTextureId, 4, 5)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| FramebufferTextureLayer cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, client_texture_id_, 4, |
| 5); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| Framebuffer* framebuffer = GetFramebuffer(client_framebuffer_id_); |
| ASSERT_TRUE(framebuffer); |
| ASSERT_FALSE(framebuffer->GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); |
| ASSERT_TRUE(framebuffer->GetAttachment(GL_DEPTH_ATTACHMENT)); |
| ASSERT_TRUE(framebuffer->GetAttachment(GL_STENCIL_ATTACHMENT)); |
| } |
| |
| TEST_P(GLES3DecoderTest, InvalidateFramebufferDepthStencilAttachment) { |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoBindRenderbuffer( |
| GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId); |
| DoRenderbufferStorage( |
| GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, |
| 1, 1, GL_NO_ERROR); |
| DoFramebufferRenderbuffer( |
| GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR); |
| |
| Framebuffer* framebuffer = GetFramebuffer(client_framebuffer_id_); |
| ASSERT_TRUE(framebuffer); |
| ASSERT_FALSE(framebuffer->GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); |
| ASSERT_TRUE(framebuffer->GetAttachment(GL_DEPTH_ATTACHMENT)); |
| ASSERT_TRUE(framebuffer->GetAttachment(GL_STENCIL_ATTACHMENT)); |
| framebuffer->MarkAttachmentAsCleared(group().renderbuffer_manager(), nullptr, |
| GL_DEPTH_ATTACHMENT, true); |
| framebuffer->MarkAttachmentAsCleared(group().renderbuffer_manager(), nullptr, |
| GL_STENCIL_ATTACHMENT, true); |
| EXPECT_TRUE(framebuffer->IsCleared()); |
| |
| const GLenum target = GL_FRAMEBUFFER; |
| const GLsizei count = 1; |
| GLenum attachments[] = {GL_DEPTH_ATTACHMENT}; |
| EXPECT_CALL(*gl_, InvalidateFramebuffer(target, 0, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| InvalidateFramebufferImmediate& cmd = |
| *GetImmediateAs<InvalidateFramebufferImmediate>(); |
| cmd.Init(target, count, attachments); |
| |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Invalidating part of DEPTH_STENCIL attachment doesn't change framebuffer |
| // clearance status. |
| EXPECT_TRUE(framebuffer->IsCleared()); |
| EXPECT_FALSE(framebuffer->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); |
| EXPECT_FALSE(framebuffer->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); |
| |
| attachments[0] = GL_DEPTH_STENCIL_ATTACHMENT; |
| EXPECT_CALL(*gl_, InvalidateFramebuffer(target, 2, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| cmd.Init(target, count, attachments); |
| |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Invalidating DEPTH_STENCIL attachment should make framebuffer uncleared. |
| EXPECT_FALSE(framebuffer->IsCleared()); |
| EXPECT_TRUE(framebuffer->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); |
| EXPECT_TRUE(framebuffer->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); |
| } |
| |
| TEST_P(GLES3DecoderTest, BlitFramebufferFeedbackLoopDefaultFramebuffer) { |
| // Run BlitFramebufferCHROMIUM targetting the default framebuffer for both |
| // read and draw, should result in a feedback loop. |
| BlitFramebufferCHROMIUM cmd; |
| cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_DEPTH_BUFFER_BIT, GL_LINEAR); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_STENCIL_BUFFER_BIT, GL_LINEAR); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES3DecoderTest, BlitFramebufferDisabledReadBuffer) { |
| // Run BlitFramebufferCHROMIUM from a disabled read buffer. Even though the |
| // read and draw framebuffer use the same attachment, since the read buffer is |
| // disabled, no feedback loop happens. |
| DoBindFramebuffer(GL_DRAW_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| DoRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, GL_RGBA8, 1, 1, GL_NO_ERROR); |
| DoFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId, GL_NO_ERROR); |
| |
| EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _)) |
| .WillOnce(SetArgPointee<1>(kNewServiceId)) |
| .RetiresOnSaturation(); |
| GLuint read_fbo = client_framebuffer_id_ + 1; |
| DoBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo, kNewServiceId); |
| DoFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId, GL_NO_ERROR); |
| { |
| EXPECT_CALL(*gl_, ReadBuffer(GL_NONE)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| ReadBuffer cmd; |
| cmd.Init(GL_NONE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| { |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| SetupExpectationsForFramebufferClearing(GL_DRAW_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT, // clear bits |
| 0, 0, 0, 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| false, // scissor test |
| 0, 0, 128, 64); |
| BlitFramebufferCHROMIUM cmd; |
| cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| // Generate INVALID_OPERATION because of missing read buffer image. |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| } |
| |
| TEST_P(GLES3DecoderTest, BlitFramebufferMissingDepthOrStencil) { |
| // Run BlitFramebufferCHROMIUM with depth or stencil bits, from/to a read/draw |
| // framebuffer that doesn't have depth/stencil. It should generate |
| // INVALID_OPERATION. |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| DoRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, |
| GL_DEPTH24_STENCIL8, 1, 1, GL_NO_ERROR); |
| GLuint color_renderbuffer = client_renderbuffer_id_ + 1; |
| GLuint color_renderbuffer_service = kServiceRenderbufferId + 1; |
| EXPECT_CALL(*gl_, GenRenderbuffersEXT(1, _)) |
| .WillOnce(SetArgPointee<1>(color_renderbuffer_service)) |
| .RetiresOnSaturation(); |
| DoBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer, |
| color_renderbuffer_service); |
| DoRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, GL_RGBA8, 1, 1, GL_NO_ERROR); |
| DoBindFramebuffer(GL_DRAW_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| DoFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
| GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId, GL_NO_ERROR); |
| DoFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, |
| GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId, GL_NO_ERROR); |
| DoFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, color_renderbuffer, |
| color_renderbuffer_service, GL_NO_ERROR); |
| |
| EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _)) |
| .WillOnce(SetArgPointee<1>(kNewServiceId)) |
| .RetiresOnSaturation(); |
| GLuint color_fbo = client_framebuffer_id_ + 1; |
| DoBindFramebuffer(GL_READ_FRAMEBUFFER, color_fbo, kNewServiceId); |
| DoFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_RENDERBUFFER, color_renderbuffer, |
| color_renderbuffer_service, GL_NO_ERROR); |
| |
| { |
| SetupExpectationsForFramebufferClearing( |
| GL_DRAW_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | |
| GL_STENCIL_BUFFER_BIT, // clear bits |
| 0, |
| 0, 0, 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| false, // scissor test |
| 0, 0, 128, 64); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| BlitFramebufferCHROMIUM cmd; |
| cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| // Switch FBOs and try the same. |
| DoBindFramebuffer(GL_READ_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| DoBindFramebuffer(GL_DRAW_FRAMEBUFFER, color_fbo, kNewServiceId); |
| { |
| EXPECT_CALL(*gl_, BlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, _, _)).Times(0); |
| BlitFramebufferCHROMIUM cmd; |
| cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_DEPTH_BUFFER_BIT, GL_NEAREST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| cmd.Init(0, 0, 1, 1, 0, 0, 1, 1, GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| } |
| |
| class GLES2DecoderTestWithDrawRectangle : public GLES2DecoderTest { |
| void SetUp() override { |
| surface_supports_draw_rectangle_ = true; |
| GLES2DecoderTest::SetUp(); |
| } |
| }; |
| |
| // Test that the draw offset is correctly honored when SetDrawRectangle is |
| // supported. |
| TEST_P(GLES2DecoderTestWithDrawRectangle, FramebufferDrawRectangleClear) { |
| EXPECT_CALL(*gl_, Scissor(101, 202, 3, 4)).Times(1).RetiresOnSaturation(); |
| cmds::Scissor scissor_cmd; |
| scissor_cmd.Init(1, 2, 3, 4); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(scissor_cmd)); |
| |
| // Scissor and Viewport should be restored to (0,0) offset on when clearing |
| // a framebuffer. |
| { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| // Setup "render to" texture. |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| DoFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| kFBOClientTextureId, kFBOServiceTextureId, 0, |
| GL_NO_ERROR); |
| // Set scissor rect and enable GL_SCISSOR_TEST to make sure we re-enable it |
| // and restore the rect again after the clear. |
| DoEnableDisable(GL_SCISSOR_TEST, true); |
| EXPECT_CALL(*gl_, Viewport(0, 0, 128, 64)).Times(1).RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, Scissor(1, 2, 3, 4)).Times(1).RetiresOnSaturation(); |
| |
| // Setup "render from" texture. |
| SetupTexture(); |
| |
| SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT, // clear bits |
| 0, 0, 0, |
| 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| true, // scissor test |
| 1, 2, 3, 4); |
| SetupExpectationsForApplyingDirtyState(false, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1111, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false); // stencil enabled |
| |
| EXPECT_CALL(*gl_, Clear(GL_COLOR_BUFFER_BIT)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| Clear cmd; |
| cmd.Init(GL_COLOR_BUFFER_BIT); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| // Check that the draw offset is used when switching to the default |
| // framebuffer and clearing it. |
| { |
| DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); |
| EXPECT_CALL(*gl_, Clear(GL_COLOR_BUFFER_BIT)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| SetupExpectationsForColorMask(true, true, true, true); |
| SetupExpectationsForDepthMask(true); |
| SetupExpectationsForStencilMask(0, 0); |
| SetupExpectationsForEnableDisable(GL_DEPTH_TEST, false); |
| SetupExpectationsForEnableDisable(GL_STENCIL_TEST, false); |
| EXPECT_CALL(*gl_, Viewport(100, 200, 128, 64)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, Scissor(101, 202, 3, 4)).Times(1).RetiresOnSaturation(); |
| Clear cmd; |
| cmd.Init(GL_COLOR_BUFFER_BIT); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(Service, |
| GLES2DecoderTestWithDrawRectangle, |
| ::testing::Bool()); |
| |
| TEST_P(GLES2DecoderManualInitTest, MESAFramebufferFlipYExtensionEnabled) { |
| InitState init; |
| init.gl_version = "OpenGL ES 3.1"; |
| init.context_type = CONTEXT_TYPE_WEBGL1; |
| init.extensions = "GL_MESA_framebuffer_flip_y"; |
| InitDecoder(init); |
| |
| EXPECT_TRUE(feature_info()->validators()->framebuffer_parameter.IsValid( |
| GL_FRAMEBUFFER_FLIP_Y_MESA)); |
| |
| EXPECT_CALL(*gl_, FramebufferParameteri(_, _, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| cmds::FramebufferParameteri cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderManualInitTest, MESAFramebufferFlipYExtensionDisabled) { |
| InitState init; |
| init.gl_version = "OpenGL ES 3.1"; |
| init.context_type = CONTEXT_TYPE_WEBGL1; |
| InitDecoder(init); |
| |
| EXPECT_FALSE(feature_info()->validators()->framebuffer_parameter.IsValid( |
| GL_FRAMEBUFFER_FLIP_Y_MESA)); |
| |
| EXPECT_CALL(*gl_, FramebufferParameteri(_, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| cmds::FramebufferParameteri cmd; |
| cmd.Init(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1); |
| EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| // TODO(gman): PixelStorei |
| |
| // TODO(gman): SwapBuffers |
| |
| } // namespace gles2 |
| } // namespace gpu |