| // Copyright (c) 2012 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 "base/command_line.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/common/id_allocator.h" |
| #include "gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h" |
| #include "gpu/command_buffer/service/async_pixel_transfer_manager.h" |
| #include "gpu/command_buffer/service/async_pixel_transfer_manager_mock.h" |
| #include "gpu/command_buffer/service/cmd_buffer_engine.h" |
| #include "gpu/command_buffer/service/context_group.h" |
| #include "gpu/command_buffer/service/gl_surface_mock.h" |
| #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.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/stream_texture_manager_mock.h" |
| #include "gpu/command_buffer/service/stream_texture_mock.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 ::gfx::MockGLInterface; |
| using ::testing::_; |
| using ::testing::DoAll; |
| using ::testing::InSequence; |
| using ::testing::Invoke; |
| using ::testing::MatcherCast; |
| using ::testing::Pointee; |
| using ::testing::Return; |
| using ::testing::SaveArg; |
| using ::testing::SetArrayArgument; |
| using ::testing::SetArgumentPointee; |
| using ::testing::SetArgPointee; |
| using ::testing::StrEq; |
| using ::testing::StrictMock; |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| using namespace cmds; |
| |
| class GLES2DecoderTest : public GLES2DecoderTestBase { |
| public: |
| GLES2DecoderTest() { } |
| |
| protected: |
| void CheckReadPixelsOutOfRange( |
| GLint in_read_x, GLint in_read_y, |
| GLsizei in_read_width, GLsizei in_read_height, |
| bool init); |
| }; |
| |
| class GLES2DecoderTestWithExtensions |
| : public GLES2DecoderTest, |
| public ::testing::WithParamInterface<const char*> { |
| public: |
| GLES2DecoderTestWithExtensions() {} |
| |
| virtual void SetUp() { |
| InitDecoder(GetParam(), // extensions |
| true, // has alpha |
| true, // has depth |
| false, // has stencil |
| true, // request alpha |
| true, // request depth |
| false, // request stencil |
| false); // bind generates resource |
| } |
| }; |
| |
| class GLES2DecoderWithShaderTest : public GLES2DecoderWithShaderTestBase { |
| public: |
| GLES2DecoderWithShaderTest() |
| : GLES2DecoderWithShaderTestBase() { |
| } |
| |
| void CheckTextureChangesMarkFBOAsNotComplete(bool bound_fbo); |
| void CheckRenderbufferChangesMarkFBOAsNotComplete(bool bound_fbo); |
| }; |
| |
| class GLES2DecoderGeometryInstancingTest : public GLES2DecoderWithShaderTest { |
| public: |
| GLES2DecoderGeometryInstancingTest() |
| : GLES2DecoderWithShaderTest() { |
| } |
| |
| virtual void SetUp() { |
| InitDecoder( |
| "GL_ANGLE_instanced_arrays", // extensions |
| true, // has alpha |
| true, // has depth |
| false, // has stencil |
| true, // request alpha |
| true, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| SetupDefaultProgram(); |
| } |
| }; |
| |
| class GLES2DecoderRGBBackbufferTest : public GLES2DecoderWithShaderTest { |
| public: |
| GLES2DecoderRGBBackbufferTest() { } |
| |
| virtual void SetUp() { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| SetupDefaultProgram(); |
| } |
| }; |
| |
| class GLES2DecoderManualInitTest : public GLES2DecoderWithShaderTest { |
| public: |
| GLES2DecoderManualInitTest() { } |
| |
| // Override default setup so nothing gets setup. |
| virtual void SetUp() { |
| } |
| }; |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysNoAttributesSucceeds) { |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| 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()); |
| } |
| |
| // Tests when the math overflows (0x40000000 * sizeof GLfloat) |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0OverflowFails) { |
| const GLsizei kLargeCount = 0x40000000; |
| SetupTexture(); |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kLargeCount); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| // Tests when the math overflows (0x7FFFFFFF + 1 = 0x8000000 verts) |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0PosToNegFails) { |
| const GLsizei kLargeCount = 0x7FFFFFFF; |
| SetupTexture(); |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kLargeCount); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| // Tests when the driver returns an error |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0OOMFails) { |
| const GLsizei kFakeLargeCount = 0x1234; |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0WithError( |
| kFakeLargeCount, 0, GL_OUT_OF_MEMORY); |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kFakeLargeCount); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysBadTextureUsesBlack) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| // This is an NPOT texture. As the default filtering requires mips |
| // this should trigger replacing with black textures before rendering. |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| { |
| InSequence sequence; |
| EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindTexture( |
| GL_TEXTURE_2D, TestHelper::kServiceBlackTexture2dId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysMissingAttributesFails) { |
| DoEnableVertexAttribArray(1); |
| |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(0); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, |
| DrawArraysMissingAttributesZeroCountSucceeds) { |
| DoEnableVertexAttribArray(1); |
| |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(0); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysValidAttributesSucceeds) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| DoEnableVertexAttribArray(1); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| 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_F(GLES2DecoderWithShaderTest, DrawArraysDeletedBufferFails) { |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| DeleteVertexBuffer(); |
| |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(0); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedProgramSucceeds) { |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DoDeleteProgram(client_program_id_, kServiceProgramId); |
| |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId)) |
| .Times(1); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysWithInvalidModeFails) { |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(0); |
| DrawArrays cmd; |
| cmd.Init(GL_QUADS, 0, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(GL_POLYGON, 0, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysInvalidCountFails) { |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| // Try start > 0 |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 1, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Try with count > size |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices + 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Try with attrib offset > 0 |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 4); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Try with size > 2 (ie, vec3 instead of vec2) |
| DoVertexAttribPointer(1, 3, GL_FLOAT, 0, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Try with stride > 8 (vec2 + vec2 byte) |
| DoVertexAttribPointer(1, 2, GL_FLOAT, sizeof(GLfloat) * 3, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysInstancedANGLEFails) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| DoEnableVertexAttribArray(1); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLENoAttributesFails) { |
| SetupTexture(); |
| |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLESimulatedAttrib0) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, 3)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, 3); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLEMissingAttributesFails) { |
| DoEnableVertexAttribArray(1); |
| |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLEMissingAttributesZeroCountSucceeds) { |
| DoEnableVertexAttribArray(1); |
| |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, 0, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLEValidAttributesSucceeds) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| DoEnableVertexAttribArray(1); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLEWithInvalidModeFails) { |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_QUADS, 0, 1, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(GL_POLYGON, 0, 1, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLEInvalidPrimcountFails) { |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, 1, -1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| // Per-instance data is twice as large, but number of instances is half |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLELargeInstanceSucceeds) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, |
| kNumVertices / 2)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices / 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| // Per-instance data is twice as large, but divisor is twice |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLELargeDivisorSucceeds) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 2); |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, |
| kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, DrawArraysInstancedANGLELargeFails) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices + 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices + 1, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| // Per-index data is twice as large, but number of indices is half |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLELargeIndexSucceeds) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DoVertexAttribPointer(1, 4, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices / 2, |
| kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices / 2, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawArraysInstancedANGLENoDivisor0Fails) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| DoVertexAttribDivisorANGLE(1, 1); |
| EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawArraysInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsNoAttributesSucceeds) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2))) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsMissingAttributesFails) { |
| SetupIndexBuffer(); |
| DoEnableVertexAttribArray(1); |
| |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)) |
| .Times(0); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, |
| DrawElementsMissingAttributesZeroCountSucceeds) { |
| SetupIndexBuffer(); |
| DoEnableVertexAttribArray(1); |
| |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)) |
| .Times(0); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsExtraAttributesFails) { |
| SetupIndexBuffer(); |
| DoEnableVertexAttribArray(6); |
| |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)) |
| .Times(0); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsValidAttributesSucceeds) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| SetupIndexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2))) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedBufferFails) { |
| SetupVertexBuffer(); |
| SetupIndexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| DeleteIndexBuffer(); |
| |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)) |
| .Times(0); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedProgramSucceeds) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DoDeleteProgram(client_program_id_, kServiceProgramId); |
| |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)) |
| .Times(1); |
| EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId)) |
| .Times(1); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsWithInvalidModeFails) { |
| SetupVertexBuffer(); |
| SetupIndexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)) |
| .Times(0); |
| DrawElements cmd; |
| cmd.Init(GL_QUADS, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(GL_POLYGON, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsInvalidCountFails) { |
| SetupVertexBuffer(); |
| SetupIndexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| // Try start > 0 |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kNumIndices, GL_UNSIGNED_SHORT, 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Try with count > size |
| cmd.Init(GL_TRIANGLES, kNumIndices + 1, GL_UNSIGNED_SHORT, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsOutOfRangeIndicesFails) { |
| SetupVertexBuffer(); |
| SetupIndexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kInvalidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsOddOffsetForUint16Fails) { |
| SetupVertexBuffer(); |
| SetupIndexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsInstancedANGLEFails) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| SetupIndexBuffer(); |
| DoEnableVertexAttribArray(1); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLENoAttributesFails) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLESimulatedAttrib0) { |
| SetupTexture(); |
| SetupVertexBuffer(); |
| SetupIndexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( |
| GL_TRIANGLES, |
| kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2), |
| 3)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, 3); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLEMissingAttributesFails) { |
| SetupIndexBuffer(); |
| DoEnableVertexAttribArray(1); |
| |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLEMissingAttributesZeroCountSucceeds) { |
| SetupIndexBuffer(); |
| DoEnableVertexAttribArray(1); |
| |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLEValidAttributesSucceeds) { |
| SetupIndexBuffer(); |
| SetupTexture(); |
| SetupVertexBuffer(); |
| DoEnableVertexAttribArray(1); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( |
| GL_TRIANGLES, |
| kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2), |
| 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLEWithInvalidModeFails) { |
| SetupIndexBuffer(); |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_QUADS, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(GL_INVALID_ENUM, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| // Per-instance data is twice as large, but number of instances is half |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLELargeInstanceSucceeds) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| SetupVertexBuffer(); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| //Add offset so we're sure we're accessing data near the end of the buffer. |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, |
| (kNumVertices - kMaxValidIndex - 1) * 2 * |
| sizeof(GLfloat)); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( |
| GL_TRIANGLES, |
| kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2), |
| kNumVertices / 2)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kNumVertices / 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| // Per-instance data is twice as large, but divisor is twice |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLELargeDivisorSucceeds) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| SetupVertexBuffer(); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 2); |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( |
| GL_TRIANGLES, |
| kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2), |
| kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLELargeFails) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kNumVertices + 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kInvalidIndexRangeStart * 2, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLEInvalidPrimcountFails) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, -1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| // Per-index data is twice as large, but values of indices are smaller |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLELargeIndexSucceeds) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| SetupVertexBuffer(); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| DoVertexAttribPointer(1, 4, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( |
| GL_TRIANGLES, |
| kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2), |
| kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderGeometryInstancingTest, |
| DrawElementsInstancedANGLENoDivisor0Fails) { |
| SetupTexture(); |
| SetupIndexBuffer(); |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); |
| DoVertexAttribDivisorANGLE(0, 1); |
| DoVertexAttribDivisorANGLE(1, 1); |
| EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawElementsInstancedANGLE cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetVertexAttribPointervSucceeds) { |
| const float dummy = 0; |
| const GLuint kOffsetToTestFor = sizeof(dummy) * 4; |
| const GLuint kIndexToTest = 1; |
| GetVertexAttribPointerv::Result* result = |
| static_cast<GetVertexAttribPointerv::Result*>(shared_memory_address_); |
| result->size = 0; |
| const GLuint* result_value = result->GetData(); |
| // Test that initial value is 0. |
| GetVertexAttribPointerv cmd; |
| cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(sizeof(*result_value), result->size); |
| EXPECT_EQ(0u, *result_value); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Set the value and see that we get it. |
| SetupVertexBuffer(); |
| DoVertexAttribPointer(kIndexToTest, 2, GL_FLOAT, 0, kOffsetToTestFor); |
| result->size = 0; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(sizeof(*result_value), result->size); |
| EXPECT_EQ(kOffsetToTestFor, *result_value); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetVertexAttribPointervBadArgsFails) { |
| const GLuint kIndexToTest = 1; |
| GetVertexAttribPointerv::Result* result = |
| static_cast<GetVertexAttribPointerv::Result*>(shared_memory_address_); |
| result->size = 0; |
| const GLuint* result_value = result->GetData(); |
| // Test pname invalid fails. |
| GetVertexAttribPointerv cmd; |
| cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER + 1, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0u, result->size); |
| EXPECT_EQ(kInitialResult, *result_value); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| |
| // Test index out of range fails. |
| result->size = 0; |
| cmd.Init(kNumVertexAttribs, GL_VERTEX_ATTRIB_ARRAY_POINTER, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0u, result->size); |
| EXPECT_EQ(kInitialResult, *result_value); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| |
| // Test memory id bad fails. |
| cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER, |
| kInvalidSharedMemoryId, shared_memory_offset_); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| |
| // Test memory offset bad fails. |
| cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER, |
| shared_memory_id_, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformivSucceeds) { |
| GetUniformiv::Result* result = |
| static_cast<GetUniformiv::Result*>(shared_memory_address_); |
| result->size = 0; |
| GetUniformiv cmd; |
| cmd.Init(client_program_id_, |
| kUniform2FakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, GetUniformiv(kServiceProgramId, kUniform2RealLocation, _)) |
| .Times(1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type), |
| result->size); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformivArrayElementSucceeds) { |
| GetUniformiv::Result* result = |
| static_cast<GetUniformiv::Result*>(shared_memory_address_); |
| result->size = 0; |
| GetUniformiv cmd; |
| cmd.Init(client_program_id_, |
| kUniform2ElementFakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, |
| GetUniformiv(kServiceProgramId, kUniform2ElementRealLocation, _)) |
| .Times(1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type), |
| result->size); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadProgramFails) { |
| GetUniformiv::Result* result = |
| static_cast<GetUniformiv::Result*>(shared_memory_address_); |
| result->size = 0; |
| GetUniformiv cmd; |
| // non-existant program |
| cmd.Init(kInvalidClientId, |
| kUniform2FakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, GetUniformiv(_, _, _)) |
| .Times(0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| // Valid id that is not a program. The GL spec requires a different error for |
| // this case. |
| #if GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| result->size = kInitialResult; |
| cmd.Init(client_shader_id_, |
| kUniform2FakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| #endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| // Unlinked program |
| EXPECT_CALL(*gl_, CreateProgram()) |
| .Times(1) |
| .WillOnce(Return(kNewServiceId)) |
| .RetiresOnSaturation(); |
| CreateProgram cmd2; |
| cmd2.Init(kNewClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| result->size = kInitialResult; |
| cmd.Init(kNewClientId, |
| kUniform2FakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadLocationFails) { |
| GetUniformiv::Result* result = |
| static_cast<GetUniformiv::Result*>(shared_memory_address_); |
| result->size = 0; |
| GetUniformiv cmd; |
| // invalid location |
| cmd.Init(client_program_id_, kInvalidUniformLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, GetUniformiv(_, _, _)) |
| .Times(0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadSharedMemoryFails) { |
| GetUniformiv cmd; |
| cmd.Init(client_program_id_, |
| kUniform2FakeLocation, |
| kInvalidSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, GetUniformiv(_, _, _)) |
| .Times(0); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, kUniform2FakeLocation, |
| kSharedMemoryId, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| }; |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformfvSucceeds) { |
| GetUniformfv::Result* result = |
| static_cast<GetUniformfv::Result*>(shared_memory_address_); |
| result->size = 0; |
| GetUniformfv cmd; |
| cmd.Init(client_program_id_, |
| kUniform2FakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, GetUniformfv(kServiceProgramId, kUniform2RealLocation, _)) |
| .Times(1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type), |
| result->size); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformfvArrayElementSucceeds) { |
| GetUniformfv::Result* result = |
| static_cast<GetUniformfv::Result*>(shared_memory_address_); |
| result->size = 0; |
| GetUniformfv cmd; |
| cmd.Init(client_program_id_, |
| kUniform2ElementFakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, |
| GetUniformfv(kServiceProgramId, kUniform2ElementRealLocation, _)) |
| .Times(1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type), |
| result->size); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadProgramFails) { |
| GetUniformfv::Result* result = |
| static_cast<GetUniformfv::Result*>(shared_memory_address_); |
| result->size = 0; |
| GetUniformfv cmd; |
| // non-existant program |
| cmd.Init(kInvalidClientId, |
| kUniform2FakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, GetUniformfv(_, _, _)) |
| .Times(0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| // Valid id that is not a program. The GL spec requires a different error for |
| // this case. |
| #if GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| result->size = kInitialResult; |
| cmd.Init(client_shader_id_, |
| kUniform2FakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| #endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| // Unlinked program |
| EXPECT_CALL(*gl_, CreateProgram()) |
| .Times(1) |
| .WillOnce(Return(kNewServiceId)) |
| .RetiresOnSaturation(); |
| CreateProgram cmd2; |
| cmd2.Init(kNewClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| result->size = kInitialResult; |
| cmd.Init(kNewClientId, |
| kUniform2FakeLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadLocationFails) { |
| GetUniformfv::Result* result = |
| static_cast<GetUniformfv::Result*>(shared_memory_address_); |
| result->size = 0; |
| GetUniformfv cmd; |
| // invalid location |
| cmd.Init(client_program_id_, kInvalidUniformLocation, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, GetUniformfv(_, _, _)) |
| .Times(0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadSharedMemoryFails) { |
| GetUniformfv cmd; |
| cmd.Init(client_program_id_, |
| kUniform2FakeLocation, |
| kInvalidSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, GetUniformfv(_, _, _)) |
| .Times(0); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, kUniform2FakeLocation, |
| kSharedMemoryId, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| }; |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersSucceeds) { |
| GetAttachedShaders cmd; |
| typedef GetAttachedShaders::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 0; |
| EXPECT_CALL(*gl_, GetAttachedShaders(kServiceProgramId, 1, _, _)) |
| .WillOnce(DoAll(SetArgumentPointee<2>(1), |
| SetArgumentPointee<3>(kServiceShaderId))); |
| cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_, |
| Result::ComputeSize(1)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(1, result->GetNumResults()); |
| EXPECT_EQ(client_shader_id_, result->GetData()[0]); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersResultNotInitFail) { |
| GetAttachedShaders cmd; |
| typedef GetAttachedShaders::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 1; |
| EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _)) |
| .Times(0); |
| cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_, |
| Result::ComputeSize(1)); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersBadProgramFails) { |
| GetAttachedShaders cmd; |
| typedef GetAttachedShaders::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->size = 0; |
| EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _)) |
| .Times(0); |
| cmd.Init(kInvalidClientId, shared_memory_id_, shared_memory_offset_, |
| Result::ComputeSize(1)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0U, result->size); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersBadSharedMemoryFails) { |
| GetAttachedShaders cmd; |
| typedef GetAttachedShaders::Result Result; |
| cmd.Init(client_program_id_, kInvalidSharedMemoryId, shared_memory_offset_, |
| Result::ComputeSize(1)); |
| EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _)) |
| .Times(0); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, shared_memory_id_, kInvalidSharedMemoryOffset, |
| Result::ComputeSize(1)); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatSucceeds) { |
| ScopedGLImplementationSetter gl_impl(::gfx::kGLImplementationEGLGLES2); |
| GetShaderPrecisionFormat cmd; |
| typedef GetShaderPrecisionFormat::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 0; |
| const GLint range[2] = { 62, 62 }; |
| const GLint precision = 16; |
| EXPECT_CALL(*gl_,GetShaderPrecisionFormat(_, _, _, _)) |
| .WillOnce(DoAll(SetArrayArgument<2>(range,range+2), |
| SetArgumentPointee<3>(precision))) |
| .RetiresOnSaturation(); |
| cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_NE(0, result->success); |
| EXPECT_EQ(range[0], result->min_range); |
| EXPECT_EQ(range[1], result->max_range); |
| EXPECT_EQ(precision, result->precision); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatResultNotInitFails) { |
| GetShaderPrecisionFormat cmd; |
| typedef GetShaderPrecisionFormat::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 1; |
| // NOTE: GL might not be called. There is no Desktop OpenGL equivalent |
| cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatBadArgsFails) { |
| typedef GetShaderPrecisionFormat::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 0; |
| GetShaderPrecisionFormat cmd; |
| cmd.Init(GL_TEXTURE_2D, GL_HIGH_FLOAT, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| result->success = 0; |
| cmd.Init(GL_VERTEX_SHADER, GL_TEXTURE_2D, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, |
| GetShaderPrecisionFormatBadSharedMemoryFails) { |
| GetShaderPrecisionFormat cmd; |
| cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT, |
| kInvalidSharedMemoryId, shared_memory_offset_); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(GL_VERTEX_SHADER, GL_TEXTURE_2D, |
| shared_memory_id_, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformSucceeds) { |
| const GLuint kUniformIndex = 1; |
| const uint32 kBucketId = 123; |
| GetActiveUniform cmd; |
| typedef GetActiveUniform::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 0; |
| cmd.Init(client_program_id_, kUniformIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_NE(0, result->success); |
| EXPECT_EQ(kUniform2Size, result->size); |
| EXPECT_EQ(kUniform2Type, result->type); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId); |
| ASSERT_TRUE(bucket != NULL); |
| EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kUniform2Name, |
| bucket->size())); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformResultNotInitFails) { |
| const GLuint kUniformIndex = 1; |
| const uint32 kBucketId = 123; |
| GetActiveUniform cmd; |
| typedef GetActiveUniform::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 1; |
| cmd.Init(client_program_id_, kUniformIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadProgramFails) { |
| const GLuint kUniformIndex = 1; |
| const uint32 kBucketId = 123; |
| GetActiveUniform cmd; |
| typedef GetActiveUniform::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 0; |
| cmd.Init(kInvalidClientId, kUniformIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0, result->success); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| #if GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| result->success = 0; |
| cmd.Init(client_shader_id_, kUniformIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0, result->success); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| #endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadIndexFails) { |
| const uint32 kBucketId = 123; |
| GetActiveUniform cmd; |
| typedef GetActiveUniform::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 0; |
| cmd.Init(client_program_id_, kBadUniformIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0, result->success); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadSharedMemoryFails) { |
| const GLuint kUniformIndex = 1; |
| const uint32 kBucketId = 123; |
| GetActiveUniform cmd; |
| typedef GetActiveUniform::Result Result; |
| cmd.Init(client_program_id_, kUniformIndex, kBucketId, |
| kInvalidSharedMemoryId, shared_memory_offset_); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, kUniformIndex, kBucketId, |
| shared_memory_id_, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribSucceeds) { |
| const GLuint kAttribIndex = 1; |
| const uint32 kBucketId = 123; |
| GetActiveAttrib cmd; |
| typedef GetActiveAttrib::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 0; |
| cmd.Init(client_program_id_, kAttribIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_NE(0, result->success); |
| EXPECT_EQ(kAttrib2Size, result->size); |
| EXPECT_EQ(kAttrib2Type, result->type); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId); |
| ASSERT_TRUE(bucket != NULL); |
| EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kAttrib2Name, |
| bucket->size())); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribResultNotInitFails) { |
| const GLuint kAttribIndex = 1; |
| const uint32 kBucketId = 123; |
| GetActiveAttrib cmd; |
| typedef GetActiveAttrib::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 1; |
| cmd.Init(client_program_id_, kAttribIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadProgramFails) { |
| const GLuint kAttribIndex = 1; |
| const uint32 kBucketId = 123; |
| GetActiveAttrib cmd; |
| typedef GetActiveAttrib::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 0; |
| cmd.Init(kInvalidClientId, kAttribIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0, result->success); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| #if GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| result->success = 0; |
| cmd.Init(client_shader_id_, kAttribIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0, result->success); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| #endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadIndexFails) { |
| const uint32 kBucketId = 123; |
| GetActiveAttrib cmd; |
| typedef GetActiveAttrib::Result Result; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| result->success = 0; |
| cmd.Init(client_program_id_, kBadAttribIndex, kBucketId, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0, result->success); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadSharedMemoryFails) { |
| const GLuint kAttribIndex = 1; |
| const uint32 kBucketId = 123; |
| GetActiveAttrib cmd; |
| typedef GetActiveAttrib::Result Result; |
| cmd.Init(client_program_id_, kAttribIndex, kBucketId, |
| kInvalidSharedMemoryId, shared_memory_offset_); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, kAttribIndex, kBucketId, |
| shared_memory_id_, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetShaderInfoLogValidArgs) { |
| const char* kInfo = "hello"; |
| const uint32 kBucketId = 123; |
| CompileShader compile_cmd; |
| GetShaderInfoLog cmd; |
| EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _)); |
| EXPECT_CALL(*gl_, CompileShader(kServiceShaderId)); |
| EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _)) |
| .WillOnce(SetArgumentPointee<2>(GL_FALSE)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_INFO_LOG_LENGTH, _)) |
| .WillOnce(SetArgumentPointee<2>(strlen(kInfo) + 1)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL( |
| *gl_, GetShaderInfoLog(kServiceShaderId, strlen(kInfo) + 1, _, _)) |
| .WillOnce(DoAll(SetArgumentPointee<2>(strlen(kInfo)), |
| SetArrayArgument<3>(kInfo, kInfo + strlen(kInfo) + 1))); |
| compile_cmd.Init(client_shader_id_); |
| cmd.Init(client_shader_id_, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(compile_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId); |
| ASSERT_TRUE(bucket != NULL); |
| EXPECT_EQ(strlen(kInfo) + 1, bucket->size()); |
| EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kInfo, |
| bucket->size())); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetShaderInfoLogInvalidArgs) { |
| const uint32 kBucketId = 123; |
| GetShaderInfoLog cmd; |
| cmd.Init(kInvalidClientId, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, GetIntegervCached) { |
| struct TestInfo { |
| GLenum pname; |
| GLint expected; |
| }; |
| TestInfo tests[] = { |
| { GL_MAX_TEXTURE_SIZE, TestHelper::kMaxTextureSize, }, |
| { GL_MAX_CUBE_MAP_TEXTURE_SIZE, TestHelper::kMaxCubeMapTextureSize, }, |
| { GL_MAX_RENDERBUFFER_SIZE, TestHelper::kMaxRenderbufferSize, }, |
| }; |
| typedef GetIntegerv::Result Result; |
| for (size_t ii = 0; ii < sizeof(tests) / sizeof(tests[0]); ++ii) { |
| const TestInfo& test = tests[ii]; |
| Result* result = static_cast<Result*>(shared_memory_address_); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetIntegerv(test.pname, _)) |
| .Times(0); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(test.pname, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ( |
| decoder_->GetGLES2Util()->GLGetNumValuesReturned(test.pname), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(test.expected, result->GetData()[0]); |
| } |
| } |
| |
| TEST_F(GLES2DecoderTest, CompileShaderValidArgs) { |
| EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _)); |
| EXPECT_CALL(*gl_, CompileShader(kServiceShaderId)); |
| EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _)) |
| .WillOnce(SetArgumentPointee<2>(GL_TRUE)) |
| .RetiresOnSaturation(); |
| CompileShader cmd; |
| cmd.Init(client_shader_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, CompileShaderInvalidArgs) { |
| CompileShader cmd; |
| cmd.Init(kInvalidClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| #if GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| cmd.Init(client_program_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| #endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| } |
| |
| TEST_F(GLES2DecoderTest, ShaderSourceAndGetShaderSourceValidArgs) { |
| const uint32 kBucketId = 123; |
| const char kSource[] = "hello"; |
| const uint32 kSourceSize = sizeof(kSource) - 1; |
| memcpy(shared_memory_address_, kSource, kSourceSize); |
| ShaderSource cmd; |
| cmd.Init(client_shader_id_, |
| kSharedMemoryId, kSharedMemoryOffset, kSourceSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| memset(shared_memory_address_, 0, kSourceSize); |
| GetShaderSource get_cmd; |
| get_cmd.Init(client_shader_id_, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(get_cmd)); |
| CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId); |
| ASSERT_TRUE(bucket != NULL); |
| EXPECT_EQ(kSourceSize + 1, bucket->size()); |
| EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kSource, |
| bucket->size())); |
| } |
| |
| TEST_F(GLES2DecoderTest, ShaderSourceInvalidArgs) { |
| const char kSource[] = "hello"; |
| const uint32 kSourceSize = sizeof(kSource) - 1; |
| memcpy(shared_memory_address_, kSource, kSourceSize); |
| ShaderSource cmd; |
| cmd.Init(kInvalidClientId, |
| kSharedMemoryId, kSharedMemoryOffset, kSourceSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| #if GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kSharedMemoryOffset, kSourceSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| #endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS |
| cmd.Init(client_shader_id_, |
| kInvalidSharedMemoryId, kSharedMemoryOffset, kSourceSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_shader_id_, |
| kSharedMemoryId, kInvalidSharedMemoryOffset, kSourceSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_shader_id_, |
| kSharedMemoryId, kSharedMemoryOffset, kSharedBufferSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, ShaderSourceBucketAndGetShaderSourceValidArgs) { |
| const uint32 kInBucketId = 123; |
| const uint32 kOutBucketId = 125; |
| const char kSource[] = "hello"; |
| const uint32 kSourceSize = sizeof(kSource) - 1; |
| SetBucketAsCString(kInBucketId, kSource); |
| ShaderSourceBucket cmd; |
| cmd.Init(client_shader_id_, kInBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| ClearSharedMemory(); |
| GetShaderSource get_cmd; |
| get_cmd.Init(client_shader_id_, kOutBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(get_cmd)); |
| CommonDecoder::Bucket* bucket = decoder_->GetBucket(kOutBucketId); |
| ASSERT_TRUE(bucket != NULL); |
| EXPECT_EQ(kSourceSize + 1, bucket->size()); |
| EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kSource, |
| bucket->size())); |
| } |
| |
| TEST_F(GLES2DecoderTest, ShaderSourceBucketInvalidArgs) { |
| const uint32 kBucketId = 123; |
| const char kSource[] = "hello"; |
| const uint32 kSourceSize = sizeof(kSource) - 1; |
| memcpy(shared_memory_address_, kSource, kSourceSize); |
| ShaderSourceBucket cmd; |
| // Test no bucket. |
| cmd.Init(client_texture_id_, kBucketId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| // Test invalid client. |
| SetBucketAsCString(kBucketId, kSource); |
| cmd.Init(kInvalidClientId, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, ShaderSourceStripComments) { |
| const uint32 kInBucketId = 123; |
| const char kSource[] = "hello/*te\ast*/world//a\ab"; |
| SetBucketAsCString(kInBucketId, kSource); |
| ShaderSourceBucket cmd; |
| cmd.Init(client_shader_id_, kInBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, GenerateMipmapWrongFormatsFails) { |
| EXPECT_CALL(*gl_, GenerateMipmapEXT(_)) |
| .Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 16, 17, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| GenerateMipmap cmd; |
| cmd.Init(GL_TEXTURE_2D); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, GenerateMipmapHandlesOutOfMemory) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| TextureManager* manager = group().texture_manager(); |
| TextureRef* texture_ref = manager->GetTexture(client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| GLint width = 0; |
| GLint height = 0; |
| EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 2, &width, &height)); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, TexParameteri( |
| GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D)) |
| .Times(1); |
| EXPECT_CALL(*gl_, TexParameteri( |
| GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| GenerateMipmap cmd; |
| cmd.Init(GL_TEXTURE_2D); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 2, &width, &height)); |
| } |
| |
| TEST_F(GLES2DecoderTest, GenerateMipmapClearsUnclearedTexture) { |
| EXPECT_CALL(*gl_, GenerateMipmapEXT(_)) |
| .Times(0); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2); |
| EXPECT_CALL(*gl_, TexParameteri( |
| GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D)); |
| EXPECT_CALL(*gl_, TexParameteri( |
| GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| GenerateMipmap cmd; |
| cmd.Init(GL_TEXTURE_2D); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1iValidArgs) { |
| EXPECT_CALL(*gl_, Uniform1i(kUniform1RealLocation, 2)); |
| Uniform1i cmd; |
| cmd.Init(kUniform1FakeLocation, 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1ivValidArgs) { |
| EXPECT_CALL( |
| *gl_, Uniform1iv(kUniform1RealLocation, 1, |
| reinterpret_cast<const GLint*>(shared_memory_address_))); |
| Uniform1iv cmd; |
| cmd.Init(kUniform1FakeLocation, |
| 1, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1ivInvalidArgs2_0) { |
| EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0); |
| Uniform1iv cmd; |
| cmd.Init(kUniform1FakeLocation, |
| 1, kInvalidSharedMemoryId, 0); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1ivInvalidArgs2_1) { |
| EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0); |
| Uniform1iv cmd; |
| cmd.Init(kUniform1FakeLocation, |
| 1, shared_memory_id_, kInvalidSharedMemoryOffset); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1ivImmediateValidArgs) { |
| Uniform1ivImmediate& cmd = *GetImmediateAs<Uniform1ivImmediate>(); |
| EXPECT_CALL( |
| *gl_, |
| Uniform1iv(kUniform1RealLocation, 1, |
| reinterpret_cast<GLint*>(ImmediateDataAddress(&cmd)))); |
| GLint temp[1 * 2] = { 0, }; |
| cmd.Init(kUniform1FakeLocation, 1, |
| &temp[0]); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(cmd, sizeof(temp))); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1ivInvalidValidArgs) { |
| EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0); |
| Uniform1iv cmd; |
| cmd.Init(kUniform1FakeLocation, |
| 2, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1ivZeroCount) { |
| EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0); |
| Uniform1iv cmd; |
| cmd.Init(kUniform1FakeLocation, |
| 0, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1iSamplerIsLmited) { |
| EXPECT_CALL(*gl_, Uniform1i(_, _)).Times(0); |
| Uniform1i cmd; |
| cmd.Init( |
| kUniform1FakeLocation, |
| kNumTextureUnits); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, Uniform1ivSamplerIsLimited) { |
| EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0); |
| Uniform1ivImmediate& cmd = *GetImmediateAs<Uniform1ivImmediate>(); |
| GLint temp[] = { kNumTextureUnits }; |
| cmd.Init(kUniform1FakeLocation, 1, |
| &temp[0]); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(cmd, sizeof(temp))); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, BindBufferToDifferentTargetFails) { |
| // Bind the buffer to GL_ARRAY_BUFFER |
| DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId); |
| // Attempt to rebind to GL_ELEMENT_ARRAY_BUFFER |
| // NOTE: Real GLES2 does not have this restriction but WebGL and we do. |
| // This can be restriction can be removed at runtime. |
| EXPECT_CALL(*gl_, BindBuffer(_, _)) |
| .Times(0); |
| BindBuffer cmd; |
| cmd.Init(GL_ELEMENT_ARRAY_BUFFER, client_buffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, ActiveTextureValidArgs) { |
| EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE1)); |
| SpecializedSetup<ActiveTexture, 0>(true); |
| ActiveTexture cmd; |
| cmd.Init(GL_TEXTURE1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, ActiveTextureInvalidArgs) { |
| EXPECT_CALL(*gl_, ActiveTexture(_)).Times(0); |
| SpecializedSetup<ActiveTexture, 0>(false); |
| ActiveTexture cmd; |
| cmd.Init(GL_TEXTURE0 - 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(kNumTextureUnits); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(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_F(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_F(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_F(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_F(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_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithRenderbuffer) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| 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_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .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(static_cast<GLuint>(*result_value), client_renderbuffer_id_); |
| } |
| |
| TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithTexture) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| kServiceTextureId, 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .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(static_cast<GLuint>(*result_value), client_texture_id_); |
| } |
| |
| TEST_F(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_F(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*>(src_pixels)), |
| expected_pixels_(reinterpret_cast<const int8*>(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* 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*>(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* GetPixelAddress(const int8* 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* src_pixels_; |
| const int8* 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 = 3; |
| const GLint kPackAlignment = 4; |
| const GLenum kFormat = GL_RGB; |
| static const int8 kSrcPixels[kWidth * kHeight * kBytesPerPixel] = { |
| 12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19, 18, 19, 13, |
| 29, 28, 23, 22, 21, 22, 21, 29, 28, 23, 22, 21, 22, 21, 28, |
| 31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32, 37, 32, 34, |
| }; |
| |
| 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, kSharedMemoryId, |
| 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 result_shm_id = kSharedMemoryId; |
| uint32 result_shm_offset = kSharedMemoryOffset; |
| uint32 pixels_shm_id = kSharedMemoryId; |
| uint32 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); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| |
| GLint unpadded_row_size = emu.ComputeImageDataSize(in_read_width, 1); |
| scoped_ptr<int8[]> zero(new int8[unpadded_row_size]); |
| scoped_ptr<int8[]> pack(new int8[kPackAlignment]); |
| memset(zero.get(), 0, unpadded_row_size); |
| memset(pack.get(), kInitialMemoryValue, kPackAlignment); |
| for (GLint yy = 0; yy < in_read_height; ++yy) { |
| const int8* row = static_cast<const int8*>( |
| 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 num_padding_bytes = |
| (kPackAlignment - 1) - (unpadded_row_size % kPackAlignment); |
| EXPECT_EQ(0, |
| memcmp(pack.get(), row + unpadded_row_size, num_padding_bytes)); |
| } |
| } |
| } |
| |
| TEST_F(GLES2DecoderTest, ReadPixels) { |
| const GLsizei kWidth = 5; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 3; |
| const GLint kPackAlignment = 4; |
| static const int8 kSrcPixels[kWidth * kHeight * kBytesPerPixel] = { |
| 12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19, 18, 19, 13, |
| 29, 28, 23, 22, 21, 22, 21, 29, 28, 23, 22, 21, 22, 21, 28, |
| 31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32, 37, 32, 34, |
| }; |
| |
| 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 result_shm_id = kSharedMemoryId; |
| uint32 result_shm_offset = kSharedMemoryOffset; |
| uint32 pixels_shm_id = kSharedMemoryId; |
| uint32 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_RGB, GL_UNSIGNED_BYTE, _)) |
| .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels)); |
| ReadPixels cmd; |
| cmd.Init(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, |
| pixels_shm_id, pixels_shm_offset, |
| result_shm_id, result_shm_offset, |
| false); |
| 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_F(GLES2DecoderRGBBackbufferTest, ReadPixelsNoAlphaBackbuffer) { |
| const GLsizei kWidth = 3; |
| const GLsizei kHeight = 3; |
| const GLint kBytesPerPixel = 4; |
| const GLint kPackAlignment = 4; |
| static const uint8 kExpectedPixels[kWidth * kHeight * kBytesPerPixel] = { |
| 12, 13, 14, 255, 19, 18, 19, 255, 13, 14, 18, 255, |
| 29, 28, 23, 255, 21, 22, 21, 255, 28, 23, 22, 255, |
| 31, 34, 39, 255, 32, 37, 32, 255, 34, 39, 37, 255, |
| }; |
| static const uint8 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, kExpectedPixels, |
| kPackAlignment); |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32 result_shm_id = kSharedMemoryId; |
| uint32 result_shm_offset = kSharedMemoryOffset; |
| uint32 pixels_shm_id = kSharedMemoryId; |
| uint32 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); |
| 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_F(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 < arraysize(tests); ++tt) { |
| CheckReadPixelsOutOfRange( |
| tests[tt][0], tests[tt][1], tests[tt][2], tests[tt][3], tt == 0); |
| } |
| } |
| |
| TEST_F(GLES2DecoderTest, ReadPixelsInvalidArgs) { |
| typedef ReadPixels::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| uint32 result_shm_id = kSharedMemoryId; |
| uint32 result_shm_offset = kSharedMemoryOffset; |
| uint32 pixels_shm_id = kSharedMemoryId; |
| uint32 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); |
| 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); |
| 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); |
| 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); |
| 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); |
| 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); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, BindAttribLocation) { |
| const GLint kLocation = 2; |
| const char* kName = "testing"; |
| const uint32 kNameSize = strlen(kName); |
| EXPECT_CALL( |
| *gl_, BindAttribLocation(kServiceProgramId, kLocation, StrEq(kName))) |
| .Times(1); |
| memcpy(shared_memory_address_, kName, kNameSize); |
| BindAttribLocation cmd; |
| cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, BindAttribLocationInvalidArgs) { |
| const GLint kLocation = 2; |
| const char* kName = "testing"; |
| const char* kBadName = "test\aing"; |
| const uint32 kNameSize = strlen(kName); |
| const uint32 kBadNameSize = strlen(kBadName); |
| EXPECT_CALL(*gl_, BindAttribLocation(_, _, _)).Times(0); |
| memcpy(shared_memory_address_, kName, kNameSize); |
| BindAttribLocation cmd; |
| cmd.Init(kInvalidClientId, kLocation, |
| kSharedMemoryId, kSharedMemoryOffset, kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(client_program_id_, kLocation, |
| kInvalidSharedMemoryId, kSharedMemoryOffset, kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, kLocation, |
| kSharedMemoryId, kInvalidSharedMemoryOffset, kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, kLocation, |
| kSharedMemoryId, kSharedMemoryOffset, kSharedBufferSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| memcpy(shared_memory_address_, kBadName, kBadNameSize); |
| cmd.Init(client_program_id_, kLocation, |
| kSharedMemoryId, kSharedMemoryOffset, kBadNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, BindAttribLocationBucket) { |
| const uint32 kBucketId = 123; |
| const GLint kLocation = 2; |
| const char* kName = "testing"; |
| EXPECT_CALL( |
| *gl_, BindAttribLocation(kServiceProgramId, kLocation, StrEq(kName))) |
| .Times(1); |
| SetBucketAsCString(kBucketId, kName); |
| BindAttribLocationBucket cmd; |
| cmd.Init(client_program_id_, kLocation, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, BindAttribLocationBucketInvalidArgs) { |
| const uint32 kBucketId = 123; |
| const GLint kLocation = 2; |
| const char* kName = "testing"; |
| EXPECT_CALL(*gl_, BindAttribLocation(_, _, _)).Times(0); |
| BindAttribLocationBucket cmd; |
| // check bucket does not exist. |
| cmd.Init(client_program_id_, kLocation, kBucketId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| // check bucket is empty. |
| SetBucketAsCString(kBucketId, NULL); |
| cmd.Init(client_program_id_, kLocation, kBucketId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| // Check bad program id |
| SetBucketAsCString(kBucketId, kName); |
| cmd.Init(kInvalidClientId, kLocation, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetAttribLocation) { |
| const uint32 kNameSize = strlen(kAttrib2Name); |
| const char* kNonExistentName = "foobar"; |
| const uint32 kNonExistentNameSize = strlen(kNonExistentName); |
| typedef GetAttribLocation::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| *result = -1; |
| char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result)); |
| const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result); |
| memcpy(name, kAttrib2Name, kNameSize); |
| GetAttribLocation cmd; |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(kAttrib2Location, *result); |
| *result = -1; |
| memcpy(name, kNonExistentName, kNonExistentNameSize); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNonExistentNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationInvalidArgs) { |
| const uint32 kNameSize = strlen(kAttrib2Name); |
| const char* kBadName = "foo\abar"; |
| const uint32 kBadNameSize = strlen(kBadName); |
| typedef GetAttribLocation::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| *result = -1; |
| char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result)); |
| const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result); |
| memcpy(name, kAttrib2Name, kNameSize); |
| GetAttribLocation cmd; |
| cmd.Init(kInvalidClientId, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| *result = -1; |
| cmd.Init(client_program_id_, |
| kInvalidSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kInvalidSharedMemoryOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kInvalidSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kInvalidSharedMemoryOffset, |
| kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kSharedBufferSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| memcpy(name, kBadName, kBadNameSize); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kBadNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationBucket) { |
| const uint32 kBucketId = 123; |
| const char* kNonExistentName = "foobar"; |
| typedef GetAttribLocationBucket::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| SetBucketAsCString(kBucketId, kAttrib2Name); |
| *result = -1; |
| GetAttribLocationBucket cmd; |
| cmd.Init(client_program_id_, kBucketId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(kAttrib2Location, *result); |
| SetBucketAsCString(kBucketId, kNonExistentName); |
| *result = -1; |
| cmd.Init(client_program_id_, kBucketId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationBucketInvalidArgs) { |
| const uint32 kBucketId = 123; |
| typedef GetAttribLocationBucket::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| *result = -1; |
| GetAttribLocationBucket cmd; |
| // Check no bucket |
| cmd.Init(client_program_id_, kBucketId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| // Check bad program id. |
| SetBucketAsCString(kBucketId, kAttrib2Name); |
| cmd.Init(kInvalidClientId, kBucketId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| *result = -1; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| // Check bad memory |
| cmd.Init(client_program_id_, kBucketId, |
| kInvalidSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, kBucketId, |
| kSharedMemoryId, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformLocation) { |
| const uint32 kNameSize = strlen(kUniform2Name); |
| const char* kNonExistentName = "foobar"; |
| const uint32 kNonExistentNameSize = strlen(kNonExistentName); |
| typedef GetUniformLocation::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| *result = -1; |
| char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result)); |
| const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result); |
| memcpy(name, kUniform2Name, kNameSize); |
| GetUniformLocation cmd; |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(kUniform2FakeLocation, *result); |
| memcpy(name, kNonExistentName, kNonExistentNameSize); |
| *result = -1; |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNonExistentNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationInvalidArgs) { |
| const uint32 kNameSize = strlen(kUniform2Name); |
| const char* kBadName = "foo\abar"; |
| const uint32 kBadNameSize = strlen(kBadName); |
| typedef GetUniformLocation::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| *result = -1; |
| char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result)); |
| const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result); |
| memcpy(name, kUniform2Name, kNameSize); |
| GetUniformLocation cmd; |
| cmd.Init(kInvalidClientId, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| *result = -1; |
| cmd.Init(client_program_id_, |
| kInvalidSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kInvalidSharedMemoryOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kInvalidSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kInvalidSharedMemoryOffset, |
| kNameSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kSharedBufferSize); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| memcpy(name, kBadName, kBadNameSize); |
| cmd.Init(client_program_id_, |
| kSharedMemoryId, kNameOffset, |
| kSharedMemoryId, kSharedMemoryOffset, |
| kBadNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationBucket) { |
| const uint32 kBucketId = 123; |
| const char* kNonExistentName = "foobar"; |
| typedef GetUniformLocationBucket::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| SetBucketAsCString(kBucketId, kUniform2Name); |
| *result = -1; |
| GetUniformLocationBucket cmd; |
| cmd.Init(client_program_id_, kBucketId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(kUniform2FakeLocation, *result); |
| SetBucketAsCString(kBucketId, kNonExistentName); |
| *result = -1; |
| cmd.Init(client_program_id_, kBucketId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationBucketInvalidArgs) { |
| const uint32 kBucketId = 123; |
| typedef GetUniformLocationBucket::Result Result; |
| Result* result = GetSharedMemoryAs<Result*>(); |
| *result = -1; |
| GetUniformLocationBucket cmd; |
| // Check no bucket |
| cmd.Init(client_program_id_, kBucketId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| // Check bad program id. |
| SetBucketAsCString(kBucketId, kUniform2Name); |
| cmd.Init(kInvalidClientId, kBucketId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| *result = -1; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(-1, *result); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| // Check bad memory |
| cmd.Init(client_program_id_, kBucketId, |
| kInvalidSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_program_id_, kBucketId, |
| kSharedMemoryId, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetMaxValueInBufferCHROMIUM) { |
| SetupIndexBuffer(); |
| GetMaxValueInBufferCHROMIUM::Result* result = |
| static_cast<GetMaxValueInBufferCHROMIUM::Result*>(shared_memory_address_); |
| *result = 0; |
| |
| GetMaxValueInBufferCHROMIUM cmd; |
| cmd.Init(client_element_buffer_id_, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(7u, *result); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1, |
| GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(100u, *result); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| cmd.Init(kInvalidClientId, kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(client_element_buffer_id_, kOutOfRangeIndexRangeEnd, |
| GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1, |
| GL_UNSIGNED_SHORT, |
| kOutOfRangeIndexRangeEnd * 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1, |
| GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_buffer_id_, kValidIndexRangeCount + 1, |
| GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1, |
| GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, |
| kInvalidSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1, |
| GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2, |
| kSharedMemoryId, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, SharedIds) { |
| GenSharedIdsCHROMIUM gen_cmd; |
| RegisterSharedIdsCHROMIUM reg_cmd; |
| DeleteSharedIdsCHROMIUM del_cmd; |
| |
| const GLuint kNamespaceId = id_namespaces::kTextures; |
| const GLuint kExpectedId1 = 1; |
| const GLuint kExpectedId2 = 2; |
| const GLuint kExpectedId3 = 4; |
| const GLuint kRegisterId = 3; |
| GLuint* ids = GetSharedMemoryAs<GLuint*>(); |
| gen_cmd.Init(kNamespaceId, 0, 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); |
| IdAllocatorInterface* id_allocator = GetIdAllocator(kNamespaceId); |
| ASSERT_TRUE(id_allocator != NULL); |
| // This check is implementation dependant but it's kind of hard to check |
| // otherwise. |
| EXPECT_EQ(kExpectedId1, ids[0]); |
| EXPECT_EQ(kExpectedId2, ids[1]); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId1)); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId2)); |
| EXPECT_FALSE(id_allocator->InUse(kRegisterId)); |
| EXPECT_FALSE(id_allocator->InUse(kExpectedId3)); |
| |
| ClearSharedMemory(); |
| ids[0] = kRegisterId; |
| reg_cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(reg_cmd)); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId1)); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId2)); |
| EXPECT_TRUE(id_allocator->InUse(kRegisterId)); |
| EXPECT_FALSE(id_allocator->InUse(kExpectedId3)); |
| |
| ClearSharedMemory(); |
| gen_cmd.Init(kNamespaceId, 0, 1, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); |
| EXPECT_EQ(kExpectedId3, ids[0]); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId1)); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId2)); |
| EXPECT_TRUE(id_allocator->InUse(kRegisterId)); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId3)); |
| |
| ClearSharedMemory(); |
| ids[0] = kExpectedId1; |
| ids[1] = kRegisterId; |
| del_cmd.Init(kNamespaceId, 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(del_cmd)); |
| EXPECT_FALSE(id_allocator->InUse(kExpectedId1)); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId2)); |
| EXPECT_FALSE(id_allocator->InUse(kRegisterId)); |
| EXPECT_TRUE(id_allocator->InUse(kExpectedId3)); |
| |
| ClearSharedMemory(); |
| ids[0] = kExpectedId3; |
| ids[1] = kExpectedId2; |
| del_cmd.Init(kNamespaceId, 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(del_cmd)); |
| EXPECT_FALSE(id_allocator->InUse(kExpectedId1)); |
| EXPECT_FALSE(id_allocator->InUse(kExpectedId2)); |
| EXPECT_FALSE(id_allocator->InUse(kRegisterId)); |
| EXPECT_FALSE(id_allocator->InUse(kExpectedId3)); |
| |
| // Check passing in an id_offset. |
| ClearSharedMemory(); |
| const GLuint kOffset = 0xABCDEF; |
| gen_cmd.Init(kNamespaceId, kOffset, 2, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); |
| EXPECT_EQ(kOffset, ids[0]); |
| EXPECT_EQ(kOffset + 1, ids[1]); |
| } |
| |
| TEST_F(GLES2DecoderTest, GenSharedIdsCHROMIUMBadArgs) { |
| const GLuint kNamespaceId = id_namespaces::kTextures; |
| GenSharedIdsCHROMIUM cmd; |
| cmd.Init(kNamespaceId, 0, -1, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(kNamespaceId, 0, 1, kInvalidSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(kNamespaceId, 0, 1, kSharedMemoryId, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, RegisterSharedIdsCHROMIUMBadArgs) { |
| const GLuint kNamespaceId = id_namespaces::kTextures; |
| RegisterSharedIdsCHROMIUM cmd; |
| cmd.Init(kNamespaceId, -1, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(kNamespaceId, 1, kInvalidSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(kNamespaceId, 1, kSharedMemoryId, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, RegisterSharedIdsCHROMIUMDuplicateIds) { |
| const GLuint kNamespaceId = id_namespaces::kTextures; |
| const GLuint kRegisterId = 3; |
| RegisterSharedIdsCHROMIUM cmd; |
| GLuint* ids = GetSharedMemoryAs<GLuint*>(); |
| ids[0] = kRegisterId; |
| cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, DeleteSharedIdsCHROMIUMBadArgs) { |
| const GLuint kNamespaceId = id_namespaces::kTextures; |
| DeleteSharedIdsCHROMIUM cmd; |
| cmd.Init(kNamespaceId, -1, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(kNamespaceId, 1, kInvalidSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(kNamespaceId, 1, kSharedMemoryId, kInvalidSharedMemoryOffset); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, TexSubImage2DValidArgs) { |
| const int kWidth = 16; |
| const int kHeight = 8; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 1, 1, 0, kWidth - 1, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| TexSubImage2D cmd; |
| cmd.Init( |
| GL_TEXTURE_2D, 1, 1, 0, kWidth - 1, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, TexSubImage2DBadArgs) { |
| const int kWidth = 16; |
| const int kHeight = 8; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| TexSubImage2D cmd; |
| cmd.Init(GL_TEXTURE0, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_TRUE, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_INT, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, -1, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 1, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, -1, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 1, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth + 1, kHeight, GL_RGBA, |
| GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight + 1, GL_RGBA, |
| GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, |
| GL_UNSIGNED_SHORT_4_4_4_4, kSharedMemoryId, kSharedMemoryOffset, |
| GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| kInvalidSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kInvalidSharedMemoryOffset, GL_FALSE); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, CopyTexSubImage2DValidArgs) { |
| const int kWidth = 16; |
| const int kHeight = 8; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, CopyTexSubImage2D( |
| GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| CopyTexSubImage2D cmd; |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, CopyTexSubImage2DBadArgs) { |
| const int kWidth = 16; |
| const int kHeight = 8; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| CopyTexSubImage2D cmd; |
| cmd.Init(GL_TEXTURE0, 1, 0, 0, 0, 0, kWidth, kHeight); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, -1, 0, 0, 0, kWidth, kHeight); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 1, 0, 0, 0, kWidth, kHeight); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, -1, 0, 0, kWidth, kHeight); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 1, 0, 0, kWidth, kHeight); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth + 1, kHeight); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight + 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| // Check that if a renderbuffer is attached and GL returns |
| // GL_FRAMEBUFFER_COMPLETE that the buffer is cleared and state is restored. |
| TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearColor) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| 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(); |
| 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_F(GLES2DecoderTest, FramebufferRenderbufferClearDepth) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| 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_F(GLES2DecoderTest, FramebufferRenderbufferClearStencil) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| 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_F(GLES2DecoderTest, IsBuffer) { |
| EXPECT_FALSE(DoIsBuffer(client_buffer_id_)); |
| DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId); |
| EXPECT_TRUE(DoIsBuffer(client_buffer_id_)); |
| DoDeleteBuffer(client_buffer_id_, kServiceBufferId); |
| EXPECT_FALSE(DoIsBuffer(client_buffer_id_)); |
| } |
| |
| TEST_F(GLES2DecoderTest, IsFramebuffer) { |
| EXPECT_FALSE(DoIsFramebuffer(client_framebuffer_id_)); |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| EXPECT_TRUE(DoIsFramebuffer(client_framebuffer_id_)); |
| DoDeleteFramebuffer( |
| client_framebuffer_id_, kServiceFramebufferId, |
| true, GL_FRAMEBUFFER, 0, |
| true, GL_FRAMEBUFFER, 0); |
| EXPECT_FALSE(DoIsFramebuffer(client_framebuffer_id_)); |
| } |
| |
| TEST_F(GLES2DecoderTest, IsProgram) { |
| // IsProgram is true as soon as the program is created. |
| EXPECT_TRUE(DoIsProgram(client_program_id_)); |
| EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DoDeleteProgram(client_program_id_, kServiceProgramId); |
| EXPECT_FALSE(DoIsProgram(client_program_id_)); |
| |
| } |
| |
| TEST_F(GLES2DecoderTest, IsRenderbuffer) { |
| EXPECT_FALSE(DoIsRenderbuffer(client_renderbuffer_id_)); |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| EXPECT_TRUE(DoIsRenderbuffer(client_renderbuffer_id_)); |
| DoDeleteRenderbuffer(client_renderbuffer_id_, kServiceRenderbufferId); |
| EXPECT_FALSE(DoIsRenderbuffer(client_renderbuffer_id_)); |
| } |
| |
| TEST_F(GLES2DecoderTest, IsShader) { |
| // IsShader is true as soon as the program is created. |
| EXPECT_TRUE(DoIsShader(client_shader_id_)); |
| DoDeleteShader(client_shader_id_, kServiceShaderId); |
| EXPECT_FALSE(DoIsShader(client_shader_id_)); |
| } |
| |
| TEST_F(GLES2DecoderTest, IsTexture) { |
| EXPECT_FALSE(DoIsTexture(client_texture_id_)); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| EXPECT_TRUE(DoIsTexture(client_texture_id_)); |
| DoDeleteTexture(client_texture_id_, kServiceTextureId); |
| EXPECT_FALSE(DoIsTexture(client_texture_id_)); |
| } |
| |
| #if 0 // Turn this test on once we allow GL_DEPTH_STENCIL_ATTACHMENT |
| TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepthStencil) { |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| 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_, FramebufferRenderbufferEXT( |
| GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| #endif |
| |
| TEST_F(GLES2DecoderWithShaderTest, VertexAttribPointer) { |
| SetupVertexBuffer(); |
| static const GLenum types[] = { |
| GL_BYTE, |
| GL_UNSIGNED_BYTE, |
| GL_SHORT, |
| GL_UNSIGNED_SHORT, |
| GL_FLOAT, |
| GL_FIXED, |
| GL_INT, |
| GL_UNSIGNED_INT, |
| }; |
| static const GLsizei sizes[] = { |
| 1, |
| 1, |
| 2, |
| 2, |
| 4, |
| 4, |
| 4, |
| 4, |
| }; |
| static const GLuint indices[] = { |
| 0, |
| 1, |
| kNumVertexAttribs - 1, |
| kNumVertexAttribs, |
| }; |
| static const GLsizei offset_mult[] = { |
| 0, |
| 0, |
| 1, |
| 1, |
| 2, |
| 1000, |
| }; |
| static const GLsizei offset_offset[] = { |
| 0, |
| 1, |
| 0, |
| 1, |
| 0, |
| 0, |
| }; |
| static const GLsizei stride_mult[] = { |
| -1, |
| 0, |
| 0, |
| 1, |
| 1, |
| 2, |
| 1000, |
| }; |
| static const GLsizei stride_offset[] = { |
| 0, |
| 0, |
| 1, |
| 0, |
| 1, |
| 0, |
| 0, |
| }; |
| for (size_t tt = 0; tt < arraysize(types); ++tt) { |
| GLenum type = types[tt]; |
| GLsizei num_bytes = sizes[tt]; |
| for (size_t ii = 0; ii < arraysize(indices); ++ii) { |
| GLuint index = indices[ii]; |
| for (GLint size = 0; size < 5; ++size) { |
| for (size_t oo = 0; oo < arraysize(offset_mult); ++oo) { |
| GLuint offset = num_bytes * offset_mult[oo] + offset_offset[oo]; |
| for (size_t ss = 0; ss < arraysize(stride_mult); ++ss) { |
| GLsizei stride = num_bytes * stride_mult[ss] + stride_offset[ss]; |
| for (int normalize = 0; normalize < 2; ++normalize) { |
| bool index_good = index < static_cast<GLuint>(kNumVertexAttribs); |
| bool size_good = (size > 0 && size < 5); |
| bool offset_good = (offset % num_bytes == 0); |
| bool stride_good = (stride % num_bytes == 0) && stride >= 0 && |
| stride <= 255; |
| bool type_good = (type != GL_INT && type != GL_UNSIGNED_INT && |
| type != GL_FIXED); |
| bool good = size_good && offset_good && stride_good && |
| type_good && index_good; |
| bool call = good && (type != GL_FIXED); |
| if (call) { |
| EXPECT_CALL(*gl_, VertexAttribPointer( |
| index, size, type, normalize, stride, |
| BufferOffset(offset))); |
| } |
| VertexAttribPointer cmd; |
| cmd.Init(index, size, type, normalize, stride, offset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| if (good) { |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } else if (size_good && |
| offset_good && |
| stride_good && |
| type_good && |
| !index_good) { |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } else if (size_good && |
| offset_good && |
| stride_good && |
| !type_good && |
| index_good) { |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } else if (size_good && |
| offset_good && |
| !stride_good && |
| type_good && |
| index_good) { |
| if (stride < 0 || stride > 255) { |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } else { |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| } else if (size_good && |
| !offset_good && |
| stride_good && |
| type_good && |
| index_good) { |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } else if (!size_good && |
| offset_good && |
| stride_good && |
| type_good && |
| index_good) { |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } else { |
| EXPECT_NE(GL_NO_ERROR, GetGLError()); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // Test that with an RGB backbuffer if we set the color mask to 1,1,1,1 it is |
| // set to 1,1,1,0 at Draw time but is 1,1,1,1 at query time. |
| TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMask) { |
| ColorMask cmd; |
| cmd.Init(true, true, true, true); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays draw_cmd; |
| draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| 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_COLOR_WRITEMASK, result->GetData())) |
| .Times(0); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_COLOR_WRITEMASK, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ( |
| decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_COLOR_WRITEMASK), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(1, result->GetData()[0]); |
| EXPECT_EQ(1, result->GetData()[1]); |
| EXPECT_EQ(1, result->GetData()[2]); |
| EXPECT_EQ(1, result->GetData()[3]); |
| } |
| |
| // Test that with no depth if we set DepthMask true that it's set to false at |
| // draw time but querying it returns true. |
| TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferDepthMask) { |
| EXPECT_CALL(*gl_, DepthMask(true)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DepthMask cmd; |
| cmd.Init(true); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays draw_cmd; |
| draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| 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_WRITEMASK, result->GetData())) |
| .Times(0); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_DEPTH_WRITEMASK, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ( |
| decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_WRITEMASK), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(1, result->GetData()[0]); |
| } |
| |
| // Test that with no stencil if we set the stencil mask it's still set to 0 at |
| // draw time but gets our value if we query. |
| TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferStencilMask) { |
| const GLint kMask = 123; |
| EXPECT_CALL(*gl_, StencilMask(kMask)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| StencilMask cmd; |
| cmd.Init(kMask); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays draw_cmd; |
| draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| 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_WRITEMASK, result->GetData())) |
| .Times(0); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_WRITEMASK, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ( |
| decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_WRITEMASK), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(kMask, result->GetData()[0]); |
| } |
| |
| // Test that if an FBO is bound we get the correct masks. |
| TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMaskFBO) { |
| ColorMask cmd; |
| cmd.Init(true, true, true, true); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupTexture(); |
| SetupVertexBuffer(); |
| DoEnableVertexAttribArray(0); |
| DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); |
| DoEnableVertexAttribArray(1); |
| DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); |
| DoEnableVertexAttribArray(2); |
| DoVertexAttribPointer(2, 2, GL_FLOAT, 0, 0); |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays draw_cmd; |
| draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Check that no extra calls are made on the next draw. |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Setup Frame buffer. |
| // needs to be 1x1 or else it's not renderable. |
| const GLsizei kWidth = 1; |
| const GLsizei kHeight = 1; |
| const GLenum kFormat = GL_RGB; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| // Pass some data so the texture will be marked as cleared. |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0, |
| kFormat, GL_UNSIGNED_BYTE, kSharedMemoryId, 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(); |
| |
| // This time state needs to be set. |
| SetupExpectationsForApplyingDirtyState( |
| false, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Check that no extra calls are made on the next draw. |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Unbind |
| DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); |
| |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ActualAlphaMatchesRequestedAlpha) { |
| InitDecoder( |
| "", // extensions |
| true, // has alpha |
| false, // has depth |
| false, // has stencil |
| true, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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_ALPHA_BITS, _)) |
| .WillOnce(SetArgumentPointee<1>(8)) |
| .RetiresOnSaturation(); |
| 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_F(GLES2DecoderManualInitTest, ActualAlphaDoesNotMatchRequestedAlpha) { |
| InitDecoder( |
| "", // extensions |
| true, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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_ALPHA_BITS, _)) |
| .WillOnce(SetArgumentPointee<1>(8)) |
| .RetiresOnSaturation(); |
| 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_F(GLES2DecoderManualInitTest, ActualDepthMatchesRequestedDepth) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| true, // has depth |
| false, // has stencil |
| false, // request alpha |
| true, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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(SetArgumentPointee<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_F(GLES2DecoderManualInitTest, ActualDepthDoesNotMatchRequestedDepth) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| true, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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(SetArgumentPointee<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_F(GLES2DecoderManualInitTest, ActualStencilMatchesRequestedStencil) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| true, // has stencil |
| false, // request alpha |
| false, // request depth |
| true, // request stencil |
| true); // bind generates resource |
| |
| 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(SetArgumentPointee<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_F(GLES2DecoderManualInitTest, ActualStencilDoesNotMatchRequestedStencil) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| true, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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(SetArgumentPointee<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_F(GLES2DecoderManualInitTest, DepthEnableWithDepth) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| true, // has depth |
| false, // has stencil |
| false, // request alpha |
| true, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| Enable cmd; |
| cmd.Init(GL_DEPTH_TEST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupDefaultProgram(); |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| true, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| true, // depth mask |
| true, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays draw_cmd; |
| draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| 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_TEST, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_DEPTH_TEST, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ( |
| decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_TEST), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(1, result->GetData()[0]); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, DepthEnableWithoutRequestedDepth) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| true, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| Enable cmd; |
| cmd.Init(GL_DEPTH_TEST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupDefaultProgram(); |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays draw_cmd; |
| draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| 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_TEST, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_DEPTH_TEST, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ( |
| decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_TEST), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(1, result->GetData()[0]); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, StencilEnableWithStencil) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| true, // has stencil |
| false, // request alpha |
| false, // request depth |
| true, // request stencil |
| true); // bind generates resource |
| |
| Enable cmd; |
| cmd.Init(GL_STENCIL_TEST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupDefaultProgram(); |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| true, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| -1, // front stencil mask |
| -1, // back stencil mask |
| true, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays draw_cmd; |
| draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| 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_TEST, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_TEST, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ( |
| decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_TEST), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(1, result->GetData()[0]); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, StencilEnableWithoutRequestedStencil) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| true, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| Enable cmd; |
| cmd.Init(GL_STENCIL_TEST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupDefaultProgram(); |
| SetupTexture(); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDirtyState( |
| true, // Framebuffer is RGB |
| false, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1110, // color bits |
| false, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawArrays draw_cmd; |
| draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| 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_TEST, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| result->size = 0; |
| GetIntegerv cmd2; |
| cmd2.Init(GL_STENCIL_TEST, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ( |
| decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_TEST), |
| result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(1, result->GetData()[0]); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, PackedDepthStencilReportsCorrectValues) { |
| InitDecoder( |
| "GL_OES_packed_depth_stencil", // extensions |
| false, // has alpha |
| true, // has depth |
| true, // has stencil |
| false, // request alpha |
| true, // request depth |
| true, // request stencil |
| true); // bind generates resource |
| |
| 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(SetArgumentPointee<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(SetArgumentPointee<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_F(GLES2DecoderManualInitTest, PackedDepthStencilNoRequestedStencil) { |
| InitDecoder( |
| "GL_OES_packed_depth_stencil", // extensions |
| false, // has alpha |
| true, // has depth |
| true, // has stencil |
| false, // request alpha |
| true, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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(SetArgumentPointee<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(SetArgumentPointee<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_F(GLES2DecoderManualInitTest, PackedDepthStencilRenderbufferDepth) { |
| InitDecoder( |
| "GL_OES_packed_depth_stencil", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| |
| 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(SetArgumentPointee<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(SetArgumentPointee<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_F(GLES2DecoderManualInitTest, PackedDepthStencilRenderbufferStencil) { |
| InitDecoder( |
| "GL_OES_packed_depth_stencil", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| |
| 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(SetArgumentPointee<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(SetArgumentPointee<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_F(GLES2DecoderTest, GetMultipleIntegervCHROMIUMValidArgs) { |
| const GLsizei kCount = 3; |
| GLenum* pnames = GetSharedMemoryAs<GLenum*>(); |
| pnames[0] = GL_DEPTH_WRITEMASK; |
| pnames[1] = GL_COLOR_WRITEMASK; |
| pnames[2] = GL_STENCIL_WRITEMASK; |
| GLint* results = |
| GetSharedMemoryAsWithOffset<GLint*>(sizeof(*pnames) * kCount); |
| |
| GLsizei num_results = 0; |
| for (GLsizei ii = 0; ii < kCount; ++ii) { |
| num_results += decoder_->GetGLES2Util()->GLGetNumValuesReturned(pnames[ii]); |
| } |
| const GLsizei result_size = num_results * sizeof(*results); |
| memset(results, 0, result_size); |
| |
| const GLint kSentinel = 0x12345678; |
| results[num_results] = kSentinel; |
| |
| GetMultipleIntegervCHROMIUM cmd; |
| cmd.Init( |
| kSharedMemoryId, kSharedMemoryOffset, kCount, |
| kSharedMemoryId, kSharedMemoryOffset + sizeof(*pnames) * kCount, |
| result_size); |
| |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(1, results[0]); // Depth writemask |
| EXPECT_EQ(1, results[1]); // color writemask red |
| EXPECT_EQ(1, results[2]); // color writemask green |
| EXPECT_EQ(1, results[3]); // color writemask blue |
| EXPECT_EQ(1, results[4]); // color writemask alpha |
| EXPECT_EQ(-1, results[5]); // stencil writemask alpha |
| EXPECT_EQ(kSentinel, results[num_results]); // End of results |
| } |
| |
| TEST_F(GLES2DecoderTest, GetMultipleIntegervCHROMIUMInvalidArgs) { |
| const GLsizei kCount = 3; |
| // Offset the pnames because GLGetError will use the first uint32. |
| const uint32 kPnameOffset = sizeof(uint32); |
| const uint32 kResultsOffset = kPnameOffset + sizeof(GLint) * kCount; |
| GLenum* pnames = GetSharedMemoryAsWithOffset<GLenum*>(kPnameOffset); |
| pnames[0] = GL_DEPTH_WRITEMASK; |
| pnames[1] = GL_COLOR_WRITEMASK; |
| pnames[2] = GL_STENCIL_WRITEMASK; |
| GLint* results = GetSharedMemoryAsWithOffset<GLint*>(kResultsOffset); |
| |
| GLsizei num_results = 0; |
| for (GLsizei ii = 0; ii < kCount; ++ii) { |
| num_results += decoder_->GetGLES2Util()->GLGetNumValuesReturned(pnames[ii]); |
| } |
| const GLsizei result_size = num_results * sizeof(*results); |
| memset(results, 0, result_size); |
| |
| const GLint kSentinel = 0x12345678; |
| results[num_results] = kSentinel; |
| |
| GetMultipleIntegervCHROMIUM cmd; |
| // Check bad pnames pointer. |
| cmd.Init( |
| kInvalidSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount, |
| kSharedMemoryId, kSharedMemoryOffset + kResultsOffset, |
| result_size); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Check bad pnames pointer. |
| cmd.Init( |
| kSharedMemoryId, kInvalidSharedMemoryOffset, kCount, |
| kSharedMemoryId, kSharedMemoryOffset + kResultsOffset, |
| result_size); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Check bad count. |
| cmd.Init( |
| kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, -1, |
| kSharedMemoryId, kSharedMemoryOffset + kResultsOffset, |
| result_size); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Check bad results pointer. |
| cmd.Init( |
| kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount, |
| kInvalidSharedMemoryId, kSharedMemoryOffset + kResultsOffset, |
| result_size); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Check bad results pointer. |
| cmd.Init( |
| kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount, |
| kSharedMemoryId, kInvalidSharedMemoryOffset, |
| result_size); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Check bad size. |
| cmd.Init( |
| kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount, |
| kSharedMemoryId, kSharedMemoryOffset + kResultsOffset, |
| result_size + 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| // Check bad size. |
| cmd.Init( |
| kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount, |
| kSharedMemoryId, kSharedMemoryOffset + kResultsOffset, |
| result_size - 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| // Check bad enum. |
| cmd.Init( |
| kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount, |
| kSharedMemoryId, kSharedMemoryOffset + kResultsOffset, |
| result_size); |
| GLenum temp = pnames[2]; |
| pnames[2] = GL_TRUE; |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| pnames[2] = temp; |
| // Check results area has not been cleared by client. |
| results[1] = 1; |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd)); |
| // Check buffer is what we expect |
| EXPECT_EQ(0, results[0]); |
| EXPECT_EQ(1, results[1]); |
| EXPECT_EQ(0, results[2]); |
| EXPECT_EQ(0, results[3]); |
| EXPECT_EQ(0, results[4]); |
| EXPECT_EQ(0, results[5]); |
| EXPECT_EQ(kSentinel, results[num_results]); // End of results |
| } |
| |
| TEST_F(GLES2DecoderTest, TexImage2DRedefinitionSucceeds) { |
| const int kWidth = 16; |
| const int kHeight = 8; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillRepeatedly(Return(GL_NO_ERROR)); |
| for (int ii = 0; ii < 2; ++ii) { |
| TexImage2D cmd; |
| if (ii == 0) { |
| EXPECT_CALL(*gl_, TexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| cmd.Init( |
| GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset); |
| } else { |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 0, GL_RGBA, GL_UNSIGNED_BYTE, kWidth, kHeight); |
| cmd.Init( |
| GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, 0, 0); |
| } |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight - 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| // Consider this TexSubImage2D command part of the previous TexImage2D |
| // (last GL_TRUE argument). It will be skipped if there are bugs in the |
| // redefinition case. |
| TexSubImage2D cmd2; |
| cmd2.Init( |
| GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight - 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_TRUE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| } |
| } |
| |
| TEST_F(GLES2DecoderTest, TexImage2DGLError) { |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RGBA; |
| GLsizei width = 2; |
| GLsizei height = 4; |
| GLint border = 0; |
| GLenum format = GL_RGBA; |
| GLenum type = GL_UNSIGNED_BYTE; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| TextureManager* manager = group().texture_manager(); |
| TextureRef* texture_ref = manager->GetTexture(client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height)); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, TexImage2D(target, level, internal_format, |
| width, height, border, format, type, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| TexImage2D cmd; |
| cmd.Init(target, level, internal_format, width, height, border, format, |
| type, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height)); |
| } |
| |
| TEST_F(GLES2DecoderTest, BufferDataGLError) { |
| GLenum target = GL_ARRAY_BUFFER; |
| GLsizeiptr size = 4; |
| DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId); |
| BufferManager* manager = group().buffer_manager(); |
| Buffer* buffer = manager->GetBuffer(client_buffer_id_); |
| ASSERT_TRUE(buffer != NULL); |
| EXPECT_EQ(0, buffer->size()); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BufferData(target, size, _, GL_STREAM_DRAW)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| BufferData cmd; |
| cmd.Init(target, size, 0, 0, GL_STREAM_DRAW); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| EXPECT_EQ(0, buffer->size()); |
| } |
| |
| TEST_F(GLES2DecoderTest, CopyTexImage2DGLError) { |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RGBA; |
| GLsizei width = 2; |
| GLsizei height = 4; |
| GLint border = 0; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| TextureManager* manager = group().texture_manager(); |
| TextureRef* texture_ref = manager->GetTexture(client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height)); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_OUT_OF_MEMORY)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height, border); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height)); |
| } |
| |
| TEST_F(GLES2DecoderTest, FramebufferRenderbufferGLError) { |
| 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_, FramebufferRenderbufferEXT( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| FramebufferRenderbuffer cmd; |
| cmd.Init( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| TEST_F(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_F(GLES2DecoderTest, RenderbufferStorageGLError) { |
| 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_, 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_F(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_F(GLES2DecoderManualInitTest, |
| RenderbufferStorageMultisampleCHROMIUMGLError) { |
| InitDecoder( |
| "GL_EXT_framebuffer_multisample", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| 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_, RenderbufferStorageMultisampleEXT( |
| 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_F(GLES2DecoderManualInitTest, |
| RenderbufferStorageMultisampleCHROMIUMBadArgs) { |
| InitDecoder( |
| "GL_EXT_framebuffer_multisample", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| EXPECT_CALL(*gl_, RenderbufferStorageMultisampleEXT(_, _, _, _, _)) |
| .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_F(GLES2DecoderManualInitTest, RenderbufferStorageMultisampleCHROMIUM) { |
| InitDecoder( |
| "GL_EXT_framebuffer_multisample", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| false); // bind generates resource |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| InSequence sequence; |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL( |
| *gl_, |
| RenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples, |
| GL_RGBA, |
| TestHelper::kMaxRenderbufferSize, |
| 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| RenderbufferStorageMultisampleCHROMIUM cmd; |
| cmd.Init(GL_RENDERBUFFER, TestHelper::kMaxSamples, |
| GL_RGBA4, TestHelper::kMaxRenderbufferSize, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, |
| RenderbufferStorageMultisampleEXTNotSupported) { |
| InitDecoder( |
| "GL_EXT_framebuffer_multisample", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| false); // bind generates resource |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| InSequence sequence; |
| // GL_EXT_framebuffer_multisample uses RenderbufferStorageMultisampleCHROMIUM. |
| RenderbufferStorageMultisampleEXT cmd; |
| cmd.Init(GL_RENDERBUFFER, TestHelper::kMaxSamples, |
| GL_RGBA4, TestHelper::kMaxRenderbufferSize, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| class GLES2DecoderMultisampledRenderToTextureTest |
| : public GLES2DecoderTestWithExtensions {}; |
| |
| TEST_P(GLES2DecoderMultisampledRenderToTextureTest, |
| NotCompatibleWithRenderbufferStorageMultisampleCHROMIUM) { |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| RenderbufferStorageMultisampleCHROMIUM cmd; |
| cmd.Init(GL_RENDERBUFFER, TestHelper::kMaxSamples, |
| GL_RGBA4, TestHelper::kMaxRenderbufferSize, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_P(GLES2DecoderMultisampledRenderToTextureTest, |
| RenderbufferStorageMultisampleEXT) { |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| InSequence sequence; |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| if (strstr(GetParam(), "GL_IMG_multisampled_render_to_texture")) { |
| EXPECT_CALL( |
| *gl_, |
| RenderbufferStorageMultisampleIMG(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples, |
| GL_RGBA, |
| TestHelper::kMaxRenderbufferSize, |
| 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } else { |
| EXPECT_CALL( |
| *gl_, |
| RenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, |
| TestHelper::kMaxSamples, |
| GL_RGBA, |
| 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_CASE_P( |
| GLES2DecoderMultisampledRenderToTextureTests, |
| GLES2DecoderMultisampledRenderToTextureTest, |
| ::testing::Values("GL_EXT_multisampled_render_to_texture", |
| "GL_IMG_multisampled_render_to_texture")); |
| |
| TEST_F(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 result_shm_id = kSharedMemoryId; |
| uint32 result_shm_offset = kSharedMemoryOffset; |
| uint32 pixels_shm_id = kSharedMemoryId; |
| uint32 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); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| static bool ValueInArray(GLint value, GLint* array, GLint count) { |
| for (GLint ii = 0; ii < count; ++ii) { |
| if (array[ii] == value) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, GetCompressedTextureFormats) { |
| InitDecoder( |
| "GL_EXT_texture_compression_s3tc", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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_); |
| GetIntegerv cmd; |
| result->size = 0; |
| EXPECT_CALL(*gl_, GetIntegerv(_, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| cmd.Init( |
| GL_NUM_COMPRESSED_TEXTURE_FORMATS, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(1, result->GetNumResults()); |
| GLint num_formats = result->GetData()[0]; |
| EXPECT_EQ(4, num_formats); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| result->size = 0; |
| cmd.Init( |
| GL_COMPRESSED_TEXTURE_FORMATS, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(num_formats, result->GetNumResults()); |
| |
| EXPECT_TRUE(ValueInArray( |
| GL_COMPRESSED_RGB_S3TC_DXT1_EXT, |
| result->GetData(), result->GetNumResults())); |
| EXPECT_TRUE(ValueInArray( |
| GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, |
| result->GetData(), result->GetNumResults())); |
| EXPECT_TRUE(ValueInArray( |
| GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, |
| result->GetData(), result->GetNumResults())); |
| EXPECT_TRUE(ValueInArray( |
| GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, |
| result->GetData(), result->GetNumResults())); |
| |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, GetNoCompressedTextureFormats) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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_); |
| GetIntegerv cmd; |
| result->size = 0; |
| EXPECT_CALL(*gl_, GetIntegerv(_, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| cmd.Init( |
| GL_NUM_COMPRESSED_TEXTURE_FORMATS, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(1, result->GetNumResults()); |
| GLint num_formats = result->GetData()[0]; |
| EXPECT_EQ(0, num_formats); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| result->size = 0; |
| cmd.Init( |
| GL_COMPRESSED_TEXTURE_FORMATS, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(num_formats, result->GetNumResults()); |
| |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, CompressedTexImage2DBucketBadBucket) { |
| InitDecoder( |
| "GL_EXT_texture_compression_s3tc", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| const uint32 kBadBucketId = 123; |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| CompressedTexImage2DBucket cmd; |
| cmd.Init( |
| GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 4, 4, 0, |
| kBadBucketId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| CompressedTexSubImage2DBucket cmd2; |
| cmd2.Init( |
| GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, |
| kBadBucketId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| namespace { |
| |
| struct S3TCTestData { |
| GLenum format; |
| size_t block_size; |
| }; |
| |
| } // anonymous namespace. |
| |
| TEST_F(GLES2DecoderManualInitTest, CompressedTexImage2DS3TC) { |
| InitDecoder( |
| "GL_EXT_texture_compression_s3tc", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| const uint32 kBucketId = 123; |
| CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId); |
| ASSERT_TRUE(bucket != NULL); |
| |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| |
| static const S3TCTestData test_data[] = { |
| { GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 8, }, |
| { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 8, }, |
| { GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 16, }, |
| { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 16, }, |
| }; |
| |
| for (size_t ii = 0; ii < arraysize(test_data); ++ii) { |
| const S3TCTestData& test = test_data[ii]; |
| CompressedTexImage2DBucket cmd; |
| // test small width. |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 0, test.format, 2, 4, 0, test.block_size, |
| kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // test bad width. |
| cmd.Init( |
| GL_TEXTURE_2D, 0, test.format, 5, 4, 0, |
| kBucketId); |
| bucket->SetSize(test.block_size * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // test small height. |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 0, test.format, 4, 2, 0, test.block_size, |
| kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // test too bad height. |
| cmd.Init( |
| GL_TEXTURE_2D, 0, test.format, 4, 5, 0, |
| kBucketId); |
| bucket->SetSize(test.block_size * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // test small for level 0. |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 0, test.format, 1, 1, 0, test.block_size, |
| kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // test small for level 0. |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 0, test.format, 2, 2, 0, test.block_size, |
| kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // test size too large. |
| cmd.Init( |
| GL_TEXTURE_2D, 0, test.format, 4, 4, 0, |
| kBucketId); |
| bucket->SetSize(test.block_size * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| |
| // test size too small. |
| cmd.Init( |
| GL_TEXTURE_2D, 0, test.format, 4, 4, 0, |
| kBucketId); |
| bucket->SetSize(test.block_size / 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| |
| // test with 3 mips. |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 0, test.format, 4, 4, 0, test.block_size, kBucketId); |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 1, test.format, 2, 2, 0, test.block_size, kBucketId); |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 2, test.format, 1, 1, 0, test.block_size, kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Test a 16x16 |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 0, test.format, 16, 16, 0, test.block_size * 4 * 4, |
| kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| CompressedTexSubImage2DBucket sub_cmd; |
| bucket->SetSize(test.block_size); |
| // Test sub image bad xoffset |
| sub_cmd.Init( |
| GL_TEXTURE_2D, 0, 1, 0, 4, 4, test.format, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Test sub image bad yoffset |
| sub_cmd.Init( |
| GL_TEXTURE_2D, 0, 0, 2, 4, 4, test.format, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Test sub image bad width |
| bucket->SetSize(test.block_size * 2); |
| sub_cmd.Init( |
| GL_TEXTURE_2D, 0, 0, 0, 5, 4, test.format, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Test sub image bad height |
| sub_cmd.Init( |
| GL_TEXTURE_2D, 0, 0, 0, 4, 5, test.format, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Test sub image bad size |
| bucket->SetSize(test.block_size + 1); |
| sub_cmd.Init( |
| GL_TEXTURE_2D, 0, 0, 0, 4, 4, test.format, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| |
| for (GLint yoffset = 0; yoffset <= 8; yoffset += 4) { |
| for (GLint xoffset = 0; xoffset <= 8; xoffset += 4) { |
| for (GLsizei height = 4; height <= 8; height +=4 ) { |
| for (GLsizei width = 4; width <= 8; width += 4) { |
| GLsizei size = test.block_size * (width / 4) * (height / 4); |
| bucket->SetSize(size); |
| EXPECT_CALL(*gl_, CompressedTexSubImage2D( |
| GL_TEXTURE_2D, 0, xoffset, yoffset, width, height, test.format, |
| size, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| sub_cmd.Init( |
| GL_TEXTURE_2D, 0, xoffset, yoffset, width, height, test.format, |
| kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, CompressedTexImage2DETC1) { |
| InitDecoder( |
| "GL_OES_compressed_ETC1_RGB8_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| const uint32 kBucketId = 123; |
| CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId); |
| ASSERT_TRUE(bucket != NULL); |
| |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| |
| const GLenum kFormat = GL_ETC1_RGB8_OES; |
| const size_t kBlockSize = 8; |
| |
| CompressedTexImage2DBucket cmd; |
| // test small width. |
| DoCompressedTexImage2D(GL_TEXTURE_2D, 0, kFormat, 4, 8, 0, 16, kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // test small height. |
| DoCompressedTexImage2D(GL_TEXTURE_2D, 0, kFormat, 8, 4, 0, 16, kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // test size too large. |
| cmd.Init(GL_TEXTURE_2D, 0, kFormat, 4, 4, 0, kBucketId); |
| bucket->SetSize(kBlockSize * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| |
| // test size too small. |
| cmd.Init(GL_TEXTURE_2D, 0, kFormat, 4, 4, 0, kBucketId); |
| bucket->SetSize(kBlockSize / 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| |
| // Test a 16x16 |
| DoCompressedTexImage2D( |
| GL_TEXTURE_2D, 0, kFormat, 16, 16, 0, kBlockSize * 16, kBucketId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Test CompressedTexSubImage not allowed |
| CompressedTexSubImage2DBucket sub_cmd; |
| bucket->SetSize(kBlockSize); |
| sub_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 4, 4, kFormat, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Test TexSubImage not allowed for ETC1 compressed texture |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| GLenum type, internal_format; |
| EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format)); |
| EXPECT_EQ(kFormat, internal_format); |
| TexSubImage2D texsub_cmd; |
| texsub_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(texsub_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Test CopyTexSubImage not allowed for ETC1 compressed texture |
| CopyTexSubImage2D copy_cmd; |
| copy_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 4, 4); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(copy_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, GetCompressedTextureFormatsETC1) { |
| InitDecoder( |
| "GL_OES_compressed_ETC1_RGB8_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| 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_); |
| GetIntegerv cmd; |
| result->size = 0; |
| EXPECT_CALL(*gl_, GetIntegerv(_, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| cmd.Init( |
| GL_NUM_COMPRESSED_TEXTURE_FORMATS, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(1, result->GetNumResults()); |
| GLint num_formats = result->GetData()[0]; |
| EXPECT_EQ(1, num_formats); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| result->size = 0; |
| cmd.Init( |
| GL_COMPRESSED_TEXTURE_FORMATS, |
| shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(num_formats, result->GetNumResults()); |
| |
| EXPECT_TRUE(ValueInArray( |
| GL_ETC1_RGB8_OES, |
| result->GetData(), result->GetNumResults())); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetProgramInfoCHROMIUMValidArgs) { |
| const uint32 kBucketId = 123; |
| GetProgramInfoCHROMIUM cmd; |
| cmd.Init(client_program_id_, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId); |
| EXPECT_GT(bucket->size(), 0u); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, GetProgramInfoCHROMIUMInvalidArgs) { |
| const uint32 kBucketId = 123; |
| CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId); |
| EXPECT_TRUE(bucket == NULL); |
| GetProgramInfoCHROMIUM cmd; |
| cmd.Init(kInvalidClientId, kBucketId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| bucket = decoder_->GetBucket(kBucketId); |
| ASSERT_TRUE(bucket != NULL); |
| EXPECT_EQ(sizeof(ProgramInfoHeader), bucket->size()); |
| ProgramInfoHeader* info = bucket->GetDataAs<ProgramInfoHeader*>( |
| 0, sizeof(ProgramInfoHeader)); |
| ASSERT_TRUE(info != 0); |
| EXPECT_EQ(0u, info->link_status); |
| EXPECT_EQ(0u, info->num_attribs); |
| EXPECT_EQ(0u, info->num_uniforms); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, EGLImageExternalBindTexture) { |
| InitDecoder( |
| "GL_OES_EGL_image_external", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_EXTERNAL_OES, kNewServiceId)); |
| EXPECT_CALL(*gl_, GenTextures(1, _)) |
| .WillOnce(SetArgumentPointee<1>(kNewServiceId)); |
| BindTexture cmd; |
| cmd.Init(GL_TEXTURE_EXTERNAL_OES, kNewClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| TextureRef* texture_ref = GetTexture(kNewClientId); |
| EXPECT_TRUE(texture_ref != NULL); |
| EXPECT_TRUE(texture_ref->texture()->target() == GL_TEXTURE_EXTERNAL_OES); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, EGLImageExternalGetBinding) { |
| InitDecoder( |
| "GL_OES_EGL_image_external", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId); |
| |
| 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_TEXTURE_BINDING_EXTERNAL_OES, |
| result->GetData())) |
| .Times(0); |
| result->size = 0; |
| GetIntegerv cmd; |
| cmd.Init(GL_TEXTURE_BINDING_EXTERNAL_OES, |
| shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned( |
| GL_TEXTURE_BINDING_EXTERNAL_OES), result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(client_texture_id_, (uint32)result->GetData()[0]); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, EGLImageExternalTextureDefaults) { |
| InitDecoder( |
| "GL_OES_EGL_image_external", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId); |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| EXPECT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_TRUE(texture->target() == GL_TEXTURE_EXTERNAL_OES); |
| EXPECT_TRUE(texture->min_filter() == GL_LINEAR); |
| EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE); |
| EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, EGLImageExternalTextureParam) { |
| InitDecoder( |
| "GL_OES_EGL_image_external", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId); |
| |
| EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_MIN_FILTER, |
| GL_NEAREST)); |
| EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_MIN_FILTER, |
| GL_LINEAR)); |
| EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_WRAP_S, |
| GL_CLAMP_TO_EDGE)); |
| EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_WRAP_T, |
| GL_CLAMP_TO_EDGE)); |
| TexParameteri cmd; |
| cmd.Init(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_MIN_FILTER, |
| GL_NEAREST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_MIN_FILTER, |
| GL_LINEAR); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_WRAP_S, |
| GL_CLAMP_TO_EDGE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_WRAP_T, |
| GL_CLAMP_TO_EDGE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| EXPECT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_TRUE(texture->target() == GL_TEXTURE_EXTERNAL_OES); |
| EXPECT_TRUE(texture->min_filter() == GL_LINEAR); |
| EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE); |
| EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, EGLImageExternalTextureParamInvalid) { |
| InitDecoder( |
| "GL_OES_EGL_image_external", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId); |
| |
| TexParameteri cmd; |
| cmd.Init(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_MIN_FILTER, |
| GL_NEAREST_MIPMAP_NEAREST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_WRAP_S, |
| GL_REPEAT); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_EXTERNAL_OES, |
| GL_TEXTURE_WRAP_T, |
| GL_REPEAT); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| EXPECT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_TRUE(texture->target() == GL_TEXTURE_EXTERNAL_OES); |
| EXPECT_TRUE(texture->min_filter() == GL_LINEAR); |
| EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE); |
| EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, EGLImageExternalTexImage2DError) { |
| InitDecoder( |
| "GL_OES_EGL_image_external", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| GLenum target = GL_TEXTURE_EXTERNAL_OES; |
| GLint level = 0; |
| GLenum internal_format = GL_RGBA; |
| GLsizei width = 2; |
| GLsizei height = 4; |
| GLint border = 0; |
| GLenum format = GL_RGBA; |
| GLenum type = GL_UNSIGNED_BYTE; |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId); |
| ASSERT_TRUE(GetTexture(client_texture_id_) != NULL); |
| TexImage2D cmd; |
| cmd.Init(target, level, internal_format, width, height, border, format, |
| type, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| |
| // TexImage2D is not allowed with GL_TEXTURE_EXTERNAL_OES targets. |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, BindGeneratesResourceFalse) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| false); // bind generates resource |
| |
| BindTexture cmd1; |
| cmd1.Init(GL_TEXTURE_2D, kInvalidClientId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd1)); |
| |
| BindBuffer cmd2; |
| cmd2.Init(GL_ARRAY_BUFFER, kInvalidClientId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd2)); |
| |
| BindFramebuffer cmd3; |
| cmd3.Init(GL_FRAMEBUFFER, kInvalidClientId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd3)); |
| |
| BindRenderbuffer cmd4; |
| cmd4.Init(GL_RENDERBUFFER, kInvalidClientId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd4)); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, CreateStreamTextureCHROMIUM) { |
| const GLuint kObjectId = 123; |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| EXPECT_CALL(*stream_texture_manager(), CreateStreamTexture( |
| kServiceTextureId, client_texture_id_)) |
| .WillOnce(Return(kObjectId)) |
| .RetiresOnSaturation(); |
| |
| CreateStreamTextureCHROMIUM cmd; |
| CreateStreamTextureCHROMIUM::Result* result = |
| static_cast<CreateStreamTextureCHROMIUM::Result*>(shared_memory_address_); |
| cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(kObjectId, *result); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| EXPECT_TRUE(texture_ref != NULL); |
| EXPECT_TRUE(texture_ref->texture()->IsStreamTexture()); |
| EXPECT_CALL(*stream_texture_manager(), |
| DestroyStreamTexture(kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, CreateStreamTextureCHROMIUMBadId) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| CreateStreamTextureCHROMIUM cmd; |
| CreateStreamTextureCHROMIUM::Result* result = |
| static_cast<CreateStreamTextureCHROMIUM::Result*>(shared_memory_address_); |
| cmd.Init(kNewClientId, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(static_cast<GLuint>(GL_ZERO), *result); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, CreateStreamTextureCHROMIUMAlreadyBound) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| |
| CreateStreamTextureCHROMIUM cmd; |
| CreateStreamTextureCHROMIUM::Result* result = |
| static_cast<CreateStreamTextureCHROMIUM::Result*>(shared_memory_address_); |
| cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(static_cast<GLuint>(GL_ZERO), *result); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, CreateStreamTextureCHROMIUMAlreadySet) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| group().texture_manager()->SetStreamTexture(texture_ref, true); |
| |
| CreateStreamTextureCHROMIUM cmd; |
| cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| EXPECT_CALL(*stream_texture_manager(), |
| DestroyStreamTexture(kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, DrawStreamTextureCHROMIUM) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture GL_OES_EGL_image_external", // extensions |
| true, // has alpha |
| true, // has depth |
| false, // has stencil |
| true, // request alpha |
| true, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| StrictMock<MockStreamTexture> stream_texture; |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| group().texture_manager()->SetStreamTexture(texture_ref, true); |
| |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| SetupSamplerExternalProgram(); |
| SetupIndexBuffer(); |
| AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| EXPECT_TRUE(group().texture_manager()->CanRender(texture_ref)); |
| |
| InSequence s; |
| EXPECT_CALL(*stream_texture_manager(), LookupStreamTexture(kServiceTextureId)) |
| .WillOnce(Return(&stream_texture)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(stream_texture, Update()) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, DrawElements(_, _, _, _)) |
| .Times(1); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| EXPECT_CALL(*stream_texture_manager(), |
| DestroyStreamTexture(kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, BindStreamTextureCHROMIUMInvalid) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| group().texture_manager()->SetStreamTexture(texture_ref, true); |
| |
| BindTexture cmd; |
| cmd.Init(GL_TEXTURE_2D, client_texture_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| BindTexture cmd2; |
| cmd2.Init(GL_TEXTURE_CUBE_MAP, client_texture_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| EXPECT_CALL(*stream_texture_manager(), |
| DestroyStreamTexture(kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, DestroyStreamTextureCHROMIUM) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| group().texture_manager()->SetStreamTexture(texture_ref, true); |
| |
| EXPECT_CALL(*stream_texture_manager(), |
| DestroyStreamTexture(kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| DestroyStreamTextureCHROMIUM cmd; |
| cmd.Init(client_texture_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_FALSE(texture_ref->texture()->IsStreamTexture()); |
| EXPECT_EQ(0U, texture_ref->texture()->target()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, DestroyStreamTextureCHROMIUMInvalid) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| DestroyStreamTextureCHROMIUM cmd; |
| cmd.Init(client_texture_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, DestroyStreamTextureCHROMIUMBadId) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| DestroyStreamTextureCHROMIUM cmd; |
| cmd.Init(GL_ZERO); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, StreamTextureCHROMIUMNullMgr) { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| CreateStreamTextureCHROMIUM cmd; |
| cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd)); |
| GetGLError(); // ignore internal error |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| group().texture_manager()->SetStreamTexture(texture_ref, true); |
| |
| DestroyStreamTextureCHROMIUM cmd2; |
| cmd2.Init(client_texture_id_); |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd2)); |
| GetGLError(); // ignore internal error |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ReCreateStreamTextureCHROMIUM) { |
| const GLuint kObjectId = 123; |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture GL_OES_EGL_image_external", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| EXPECT_CALL(*stream_texture_manager(), |
| DestroyStreamTexture(kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*stream_texture_manager(), |
| CreateStreamTexture(kServiceTextureId, client_texture_id_)) |
| .WillOnce(Return(kObjectId)) |
| .RetiresOnSaturation(); |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| group().texture_manager()->SetStreamTexture(texture_ref, true); |
| |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| DestroyStreamTextureCHROMIUM cmd; |
| cmd.Init(client_texture_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_FALSE(texture_ref->texture()->IsStreamTexture()); |
| |
| CreateStreamTextureCHROMIUM cmd2; |
| cmd2.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE(texture_ref->texture()->IsStreamTexture()); |
| |
| EXPECT_CALL(*stream_texture_manager(), |
| DestroyStreamTexture(kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ProduceAndConsumeStreamTextureCHROMIUM) { |
| InitDecoder( |
| "GL_CHROMIUM_stream_texture GL_OES_EGL_image_external", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| group().texture_manager()->SetStreamTexture(texture_ref, true); |
| |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId); |
| |
| GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM]; |
| group().mailbox_manager()->GenerateMailboxName( |
| reinterpret_cast<MailboxName*>(mailbox)); |
| |
| memcpy(shared_memory_address_, mailbox, sizeof(mailbox)); |
| |
| EXPECT_EQ(kServiceTextureId, texture_ref->service_id()); |
| |
| ProduceTextureCHROMIUM produce_cmd; |
| produce_cmd.Init( |
| GL_TEXTURE_EXTERNAL_OES, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(produce_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Create new texture for consume. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<1>(kNewServiceId)) |
| .RetiresOnSaturation(); |
| DoBindTexture(GL_TEXTURE_EXTERNAL_OES, kNewClientId, kNewServiceId); |
| |
| // Assigns and binds original service size texture ID. |
| EXPECT_CALL(*gl_, DeleteTextures(1, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_EXTERNAL_OES, kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| // Shared mem got clobbered from GetError() above. |
| memcpy(shared_memory_address_, mailbox, sizeof(mailbox)); |
| ConsumeTextureCHROMIUM consume_cmd; |
| consume_cmd.Init( |
| GL_TEXTURE_EXTERNAL_OES, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(consume_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Service ID is restored. |
| EXPECT_EQ(kServiceTextureId, texture_ref->service_id()); |
| |
| EXPECT_CALL(*stream_texture_manager(), |
| DestroyStreamTexture(kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleBindTexture) { |
| InitDecoder( |
| "GL_ARB_texture_rectangle", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_RECTANGLE_ARB, kNewServiceId)); |
| EXPECT_CALL(*gl_, GenTextures(1, _)) |
| .WillOnce(SetArgumentPointee<1>(kNewServiceId)); |
| BindTexture cmd; |
| cmd.Init(GL_TEXTURE_RECTANGLE_ARB, kNewClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| Texture* texture = GetTexture(kNewClientId)->texture(); |
| EXPECT_TRUE(texture != NULL); |
| EXPECT_TRUE(texture->target() == GL_TEXTURE_RECTANGLE_ARB); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleGetBinding) { |
| InitDecoder( |
| "GL_ARB_texture_rectangle", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindTexture( |
| GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); |
| |
| 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_TEXTURE_BINDING_RECTANGLE_ARB, |
| result->GetData())) |
| .Times(0); |
| result->size = 0; |
| GetIntegerv cmd; |
| cmd.Init(GL_TEXTURE_BINDING_RECTANGLE_ARB, |
| shared_memory_id_, |
| shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned( |
| GL_TEXTURE_BINDING_RECTANGLE_ARB), result->GetNumResults()); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(client_texture_id_, (uint32)result->GetData()[0]); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureDefaults) { |
| InitDecoder( |
| "GL_ARB_texture_rectangle", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindTexture( |
| GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); |
| |
| Texture* texture = GetTexture(client_texture_id_)->texture(); |
| EXPECT_TRUE(texture != NULL); |
| EXPECT_TRUE(texture->target() == GL_TEXTURE_RECTANGLE_ARB); |
| EXPECT_TRUE(texture->min_filter() == GL_LINEAR); |
| EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE); |
| EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureParam) { |
| InitDecoder( |
| "GL_ARB_texture_rectangle", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| DoBindTexture( |
| GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); |
| |
| EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_MIN_FILTER, |
| GL_NEAREST)); |
| EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_MIN_FILTER, |
| GL_LINEAR)); |
| EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_WRAP_S, |
| GL_CLAMP_TO_EDGE)); |
| EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_WRAP_T, |
| GL_CLAMP_TO_EDGE)); |
| TexParameteri cmd; |
| cmd.Init(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_MIN_FILTER, |
| GL_NEAREST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_MIN_FILTER, |
| GL_LINEAR); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_WRAP_S, |
| GL_CLAMP_TO_EDGE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_WRAP_T, |
| GL_CLAMP_TO_EDGE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| Texture* texture = GetTexture(client_texture_id_)->texture(); |
| EXPECT_TRUE(texture != NULL); |
| EXPECT_TRUE(texture->target() == GL_TEXTURE_RECTANGLE_ARB); |
| EXPECT_TRUE(texture->min_filter() == GL_LINEAR); |
| EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE); |
| EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureParamInvalid) { |
| InitDecoder( |
| "GL_ARB_texture_rectangle", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| DoBindTexture( |
| GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); |
| |
| TexParameteri cmd; |
| cmd.Init(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_MIN_FILTER, |
| GL_NEAREST_MIPMAP_NEAREST); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_WRAP_S, |
| GL_REPEAT); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_RECTANGLE_ARB, |
| GL_TEXTURE_WRAP_T, |
| GL_REPEAT); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| |
| Texture* texture = GetTexture(client_texture_id_)->texture(); |
| EXPECT_TRUE(texture != NULL); |
| EXPECT_TRUE(texture->target() == GL_TEXTURE_RECTANGLE_ARB); |
| EXPECT_TRUE(texture->min_filter() == GL_LINEAR); |
| EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE); |
| EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTexImage2DError) { |
| InitDecoder( |
| "GL_ARB_texture_rectangle", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| GLenum target = GL_TEXTURE_RECTANGLE_ARB; |
| GLint level = 0; |
| GLenum internal_format = GL_RGBA; |
| GLsizei width = 2; |
| GLsizei height = 4; |
| GLint border = 0; |
| GLenum format = GL_RGBA; |
| GLenum type = GL_UNSIGNED_BYTE; |
| DoBindTexture( |
| GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId); |
| ASSERT_TRUE(GetTexture(client_texture_id_) != NULL); |
| TexImage2D cmd; |
| cmd.Init(target, level, internal_format, width, height, border, format, |
| type, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| |
| // TexImage2D is not allowed with GL_TEXTURE_RECTANGLE_ARB targets. |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, EnableFeatureCHROMIUMBadBucket) { |
| const uint32 kBadBucketId = 123; |
| EnableFeatureCHROMIUM cmd; |
| cmd.Init(kBadBucketId, shared_memory_id_, shared_memory_offset_); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, RequestExtensionCHROMIUMBadBucket) { |
| const uint32 kBadBucketId = 123; |
| RequestExtensionCHROMIUM cmd; |
| cmd.Init(kBadBucketId); |
| EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, TexSubImage2DClearsAfterTexImage2DNULL) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2); |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| TexSubImage2D cmd; |
| cmd.Init( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| // Test if we call it again it does not clear. |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, TexSubImage2DDoesNotClearAfterTexImage2DNULLThenData) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| TexSubImage2D cmd; |
| cmd.Init( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| // Test if we call it again it does not clear. |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F( |
| GLES2DecoderManualInitTest, |
| TexSubImage2DDoesNotClearAfterTexImage2DNULLThenDataWithTexImage2DIsFaster) { |
| CommandLine command_line(0, NULL); |
| command_line.AppendSwitchASCII( |
| switches::kGpuDriverBugWorkarounds, |
| base::IntToString(gpu::TEXSUBIMAGE2D_FASTER_THAN_TEXIMAGE2D)); |
| InitDecoderWithCommandLine( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true, // bind generates resource |
| &command_line); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| |
| { |
| // Uses texSubimage internally because the above workaround is active and |
| // the update is for the full size of the texture. |
| EXPECT_CALL(*gl_, |
| TexSubImage2D( |
| GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| cmds::TexImage2D cmd; |
| cmd.Init(GL_TEXTURE_2D, |
| 0, |
| GL_RGBA, |
| 2, |
| 2, |
| 0, |
| GL_RGBA, |
| GL_UNSIGNED_BYTE, |
| kSharedMemoryId, |
| kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| TexSubImage2D cmd; |
| cmd.Init( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| // Test if we call it again it does not clear. |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderTest, TexSubImage2DClearsAfterTexImage2DWithDataThenNULL) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| // Put in data (so it should be marked as cleared) |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| // Put in no data. |
| TexImage2D tex_cmd; |
| tex_cmd.Init( |
| GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); |
| // It won't actually call TexImage2D, just mark it as uncleared. |
| EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd)); |
| // Next call to TexSubImage2d should clear. |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2); |
| EXPECT_CALL(*gl_, TexSubImage2D( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| shared_memory_address_)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| TexSubImage2D cmd; |
| cmd.Init( |
| GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawArraysClearsAfterTexImage2DNULL) { |
| SetupAllNeededVertexBuffers(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| // Create an uncleared texture with 2 levels. |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| DoTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| // Expect 2 levels will be cleared. |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2); |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| 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()); |
| |
| // But not again |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawElementsClearsAfterTexImage2DNULL) { |
| SetupAllNeededVertexBuffers(); |
| SetupIndexBuffer(); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| // Create an uncleared texture with 2 levels. |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| DoTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| // Expect 2 levels will be cleared. |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2); |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2))) |
| .Times(1) |
| .RetiresOnSaturation(); |
| DrawElements cmd; |
| cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, |
| kValidIndexRangeStart * 2); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // But not again |
| EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount, |
| GL_UNSIGNED_SHORT, |
| BufferOffset(kValidIndexRangeStart * 2))) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawClearsAfterTexImage2DNULLInFBO) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| SetupAllNeededVertexBuffers(); |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<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); |
| |
| // 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 |
| |
| 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 |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| 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()); |
| |
| // But not again. |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawWitFBOThatCantClearDoesNotDraw) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<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); |
| |
| // Setup "render from" texture. |
| SetupTexture(); |
| |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_UNSUPPORTED)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, DrawArrays(_, _, _)) |
| .Times(0) |
| .RetiresOnSaturation(); |
| DrawArrays cmd; |
| cmd.Init(GL_TRIANGLES, 0, kNumVertices); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, CopyTexImage2DMarksTextureAsCleared) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| |
| TextureManager* manager = group().texture_manager(); |
| TextureRef* texture_ref = manager->GetTexture(client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 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_RGBA, 0, 0, 1, 1, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| |
| EXPECT_TRUE(texture->SafeToRenderFrom()); |
| } |
| |
| TEST_F(GLES2DecoderTest, CopyTexSubImage2DClearsUnclearedTexture) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); |
| |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D, |
| 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2); |
| EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| CopyTexSubImage2D cmd; |
| cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, CompressedImage2DMarksTextureAsCleared) { |
| InitDecoder( |
| "GL_EXT_texture_compression_s3tc", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, CompressedTexImage2D( |
| GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 8, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| CompressedTexImage2D cmd; |
| cmd.Init(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, |
| 8, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| TextureManager* manager = group().texture_manager(); |
| TextureRef* texture_ref = manager->GetTexture(client_texture_id_); |
| EXPECT_TRUE(texture_ref->texture()->SafeToRenderFrom()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnClear) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<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); |
| |
| // 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 |
| 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 |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_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_F(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnReadPixels) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<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); |
| |
| // 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 |
| |
| 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 result_shm_id = kSharedMemoryId; |
| uint32 result_shm_offset = kSharedMemoryOffset; |
| uint32 pixels_shm_id = kSharedMemoryId; |
| uint32 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); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, |
| UnClearedAttachmentsGetClearedOnReadPixelsAndDrawBufferGetsRestored) { |
| InitDecoder( |
| "GL_EXT_framebuffer_multisample", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<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); |
| |
| 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 |
| |
| 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; |
| uint32 result_shm_id = kSharedMemoryId; |
| uint32 result_shm_offset = kSharedMemoryOffset; |
| uint32 pixels_shm_id = kSharedMemoryId; |
| uint32 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); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, DrawClearsAfterRenderbufferStorageInFBO) { |
| SetupTexture(); |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| DoRenderbufferStorage( |
| GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 100, 50, GL_NO_ERROR); |
| DoFramebufferRenderbuffer( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR); |
| |
| SetupExpectationsForFramebufferClearing( |
| GL_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT, // clear bits |
| 0, 0, 0, 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| false); // scissor test |
| |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| 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 |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| 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_F(GLES2DecoderTest, DrawArraysClearsAfterTexImage2DNULLCubemap) { |
| static const GLenum faces[] = { |
| GL_TEXTURE_CUBE_MAP_POSITIVE_X, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_X, |
| GL_TEXTURE_CUBE_MAP_POSITIVE_Y, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, |
| GL_TEXTURE_CUBE_MAP_POSITIVE_Z, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, |
| }; |
| SetupCubemapProgram(); |
| DoBindTexture(GL_TEXTURE_CUBE_MAP, client_texture_id_, kServiceTextureId); |
| // Fill out all the faces for 2 levels, leave 2 uncleared. |
| for (int ii = 0; ii < 6; ++ii) { |
| GLenum face = faces[ii]; |
| int32 shm_id = |
| (face == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ? 0 : kSharedMemoryId; |
| uint32 shm_offset = |
| (face == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ? 0 : kSharedMemoryOffset; |
| DoTexImage2D(face, 0, GL_RGBA, 2, 2, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, shm_id, shm_offset); |
| DoTexImage2D(face, 1, GL_RGBA, 1, 1, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, shm_id, shm_offset); |
| } |
| // Expect 2 levels will be cleared. |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_CUBE_MAP, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2); |
| SetupClearTextureExpections( |
| kServiceTextureId, kServiceTextureId, GL_TEXTURE_CUBE_MAP, |
| GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1); |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| 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)); |
| } |
| |
| TEST_F(GLES2DecoderTest, TextureUsageAngleExtNotEnabledByDefault) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| |
| TexParameteri cmd; |
| cmd.Init(GL_TEXTURE_2D, |
| GL_TEXTURE_USAGE_ANGLE, |
| GL_FRAMEBUFFER_ATTACHMENT_ANGLE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, |
| DrawClearsAfterRenderbuffersWithMultipleAttachments) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<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); |
| |
| 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); |
| |
| SetupTexture(); |
| SetupExpectationsForFramebufferClearing( |
| GL_FRAMEBUFFER, // target |
| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, // clear bits |
| 0, 0, 0, 0, // color |
| 0, // stencil |
| 1.0f, // depth |
| false); // scissor test |
| |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDirtyState( |
| false, // Framebuffer is RGB |
| true, // Framebuffer has depth |
| false, // Framebuffer has stencil |
| 0x1111, // color bits |
| true, // depth mask |
| false, // depth enabled |
| 0, // front stencil mask |
| 0, // back stencil mask |
| false, // stencil enabled |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| 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_F(GLES2DecoderWithShaderTest, CopyTexImageWithInCompleteFBOFails) { |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RGBA; |
| GLsizei width = 2; |
| GLsizei height = 4; |
| GLint border = 0; |
| 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, border); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError()); |
| } |
| |
| void GLES2DecoderWithShaderTest::CheckRenderbufferChangesMarkFBOAsNotComplete( |
| bool bound_fbo) { |
| FramebufferManager* framebuffer_manager = group().framebuffer_manager(); |
| 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 != NULL); |
| 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)); |
| } |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, |
| RenderbufferChangesMarkFBOAsNotCompleteBoundFBO) { |
| CheckRenderbufferChangesMarkFBOAsNotComplete(true); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, |
| RenderbufferChangesMarkFBOAsNotCompleteUnboundFBO) { |
| CheckRenderbufferChangesMarkFBOAsNotComplete(false); |
| } |
| |
| void GLES2DecoderWithShaderTest::CheckTextureChangesMarkFBOAsNotComplete( |
| bool bound_fbo) { |
| FramebufferManager* framebuffer_manager = group().framebuffer_manager(); |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<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 != NULL); |
| 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, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| 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)); |
| } |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, TextureChangesMarkFBOAsNotCompleteBoundFBO) { |
| CheckTextureChangesMarkFBOAsNotComplete(true); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, |
| TextureChangesMarkFBOAsNotCompleteUnboundFBO) { |
| CheckTextureChangesMarkFBOAsNotComplete(false); |
| } |
| |
| TEST_F(GLES2DecoderWithShaderTest, |
| DrawingWithFBOTwiceChecksForFBOCompleteOnce) { |
| const GLuint kFBOClientTextureId = 4100; |
| const GLuint kFBOServiceTextureId = 4101; |
| |
| SetupAllNeededVertexBuffers(); |
| |
| // Register a texture id. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId)) |
| .RetiresOnSaturation(); |
| GenHelper<GenTexturesImmediate>(kFBOClientTextureId); |
| |
| // Setup "render to" texture that is cleared. |
| DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); |
| DoTexImage2D( |
| GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| DoBindFramebuffer( |
| GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); |
| DoFramebufferTexture2D( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR); |
| |
| // Setup "render from" texture. |
| SetupTexture(); |
| |
| // Make sure we check for framebuffer complete. |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| |
| 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 |
| false, // cull_face_enabled |
| false, // scissor_test_enabled |
| false); // blend_enabled |
| |
| 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()); |
| |
| // But not again. |
| EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderTest, BeginQueryEXTDisabled) { |
| // Test something fails if off. |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, BeginEndQueryEXT) { |
| InitDecoder( |
| "GL_EXT_occlusion_query_boolean", // extensions |
| true, // has alpha |
| false, // has depth |
| false, // has stencil |
| true, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| // Test end fails if no begin. |
| EndQueryEXT end_cmd; |
| end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| BeginQueryEXT begin_cmd; |
| |
| // Test id = 0 fails. |
| begin_cmd.Init( |
| GL_ANY_SAMPLES_PASSED_EXT, 0, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| GenHelper<GenQueriesEXTImmediate>(kNewClientId); |
| |
| // Test valid parameters work. |
| EXPECT_CALL(*gl_, GenQueriesARB(1, _)) |
| .WillOnce(SetArgumentPointee<1>(kNewServiceId)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, kNewServiceId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| begin_cmd.Init( |
| GL_ANY_SAMPLES_PASSED_EXT, kNewClientId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| QueryManager* query_manager = decoder_->GetQueryManager(); |
| ASSERT_TRUE(query_manager != NULL); |
| QueryManager::Query* query = query_manager->GetQuery(kNewClientId); |
| ASSERT_TRUE(query != NULL); |
| EXPECT_FALSE(query->pending()); |
| |
| // Test trying begin again fails |
| EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Test end fails with different target |
| end_cmd.Init(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Test end succeeds |
| EXPECT_CALL(*gl_, EndQueryARB(GL_ANY_SAMPLES_PASSED_EXT)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE(query->pending()); |
| |
| EXPECT_CALL(*gl_, DeleteQueriesARB(1, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| |
| static void CheckBeginEndQueryBadMemoryFails( |
| GLES2DecoderTestBase* test, |
| GLuint client_id, |
| GLuint service_id, |
| int32 shm_id, |
| uint32 shm_offset) { |
| ::testing::StrictMock< ::gfx::MockGLInterface>* gl = test->GetGLMock(); |
| |
| BeginQueryEXT begin_cmd; |
| |
| test->GenHelper<GenQueriesEXTImmediate>(client_id); |
| |
| EXPECT_CALL(*gl, GenQueriesARB(1, _)) |
| .WillOnce(SetArgumentPointee<1>(service_id)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, service_id)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| // Test bad shared memory fails |
| begin_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, client_id, shm_id, shm_offset); |
| error::Error error1 = test->ExecuteCmd(begin_cmd); |
| |
| EXPECT_CALL(*gl, EndQueryARB(GL_ANY_SAMPLES_PASSED_EXT)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| EndQueryEXT end_cmd; |
| end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1); |
| error::Error error2 = test->ExecuteCmd(end_cmd); |
| |
| EXPECT_CALL(*gl, |
| GetQueryObjectuivARB(service_id, GL_QUERY_RESULT_AVAILABLE_EXT, _)) |
| .WillOnce(SetArgumentPointee<2>(1)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl, |
| GetQueryObjectuivARB(service_id, GL_QUERY_RESULT_EXT, _)) |
| .WillOnce(SetArgumentPointee<2>(1)) |
| .RetiresOnSaturation(); |
| |
| QueryManager* query_manager = test->GetDecoder()->GetQueryManager(); |
| ASSERT_TRUE(query_manager != NULL); |
| bool process_success = query_manager->ProcessPendingQueries(); |
| |
| EXPECT_TRUE(error1 != error::kNoError || |
| error2 != error::kNoError || |
| !process_success); |
| |
| EXPECT_CALL(*gl, DeleteQueriesARB(1, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, BeginEndQueryEXTBadMemoryIdFails) { |
| InitDecoder( |
| "GL_EXT_occlusion_query_boolean", // extensions |
| true, // has alpha |
| false, // has depth |
| false, // has stencil |
| true, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| CheckBeginEndQueryBadMemoryFails( |
| this, kNewClientId, kNewServiceId, |
| kInvalidSharedMemoryId, kSharedMemoryOffset); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, BeginEndQueryEXTBadMemoryOffsetFails) { |
| InitDecoder( |
| "GL_EXT_occlusion_query_boolean", // extensions |
| true, // has alpha |
| false, // has depth |
| false, // has stencil |
| true, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| CheckBeginEndQueryBadMemoryFails( |
| this, kNewClientId, kNewServiceId, |
| kSharedMemoryId, kInvalidSharedMemoryOffset); |
| } |
| |
| TEST_F(GLES2DecoderTest, BeginEndQueryEXTCommandsIssuedCHROMIUM) { |
| BeginQueryEXT begin_cmd; |
| |
| GenHelper<GenQueriesEXTImmediate>(kNewClientId); |
| |
| // Test valid parameters work. |
| begin_cmd.Init( |
| GL_COMMANDS_ISSUED_CHROMIUM, kNewClientId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| QueryManager* query_manager = decoder_->GetQueryManager(); |
| ASSERT_TRUE(query_manager != NULL); |
| QueryManager::Query* query = query_manager->GetQuery(kNewClientId); |
| ASSERT_TRUE(query != NULL); |
| EXPECT_FALSE(query->pending()); |
| |
| // Test end succeeds |
| EndQueryEXT end_cmd; |
| end_cmd.Init(GL_COMMANDS_ISSUED_CHROMIUM, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_FALSE(query->pending()); |
| } |
| |
| TEST_F(GLES2DecoderTest, BeginEndQueryEXTGetErrorQueryCHROMIUM) { |
| BeginQueryEXT begin_cmd; |
| |
| GenHelper<GenQueriesEXTImmediate>(kNewClientId); |
| |
| // Test valid parameters work. |
| begin_cmd.Init( |
| GL_GET_ERROR_QUERY_CHROMIUM, kNewClientId, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| QueryManager* query_manager = decoder_->GetQueryManager(); |
| ASSERT_TRUE(query_manager != NULL); |
| QueryManager::Query* query = query_manager->GetQuery(kNewClientId); |
| ASSERT_TRUE(query != NULL); |
| EXPECT_FALSE(query->pending()); |
| |
| // Test end succeeds |
| QuerySync* sync = static_cast<QuerySync*>(shared_memory_address_); |
| |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_INVALID_VALUE)) |
| .RetiresOnSaturation(); |
| |
| EndQueryEXT end_cmd; |
| end_cmd.Init(GL_GET_ERROR_QUERY_CHROMIUM, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_FALSE(query->pending()); |
| EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), |
| static_cast<GLenum>(sync->result)); |
| } |
| |
| TEST_F(GLES2DecoderTest, ProduceAndConsumeTextureCHROMIUM) { |
| GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM]; |
| group().mailbox_manager()->GenerateMailboxName( |
| reinterpret_cast<MailboxName*>(mailbox)); |
| |
| memcpy(shared_memory_address_, mailbox, sizeof(mailbox)); |
| |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| DoTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| TextureRef* texture_ref = group().texture_manager()->GetTexture( |
| client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_EQ(kServiceTextureId, texture->service_id()); |
| |
| ProduceTextureCHROMIUM produce_cmd; |
| produce_cmd.Init(GL_TEXTURE_2D, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(produce_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Texture didn't change. |
| GLsizei width; |
| GLsizei height; |
| GLenum type; |
| GLenum internal_format; |
| |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| EXPECT_EQ(3, width); |
| EXPECT_EQ(1, height); |
| EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format)); |
| EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format); |
| EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type); |
| |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 1, &width, &height)); |
| EXPECT_EQ(2, width); |
| EXPECT_EQ(4, height); |
| EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 1, &type, &internal_format)); |
| EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format); |
| EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type); |
| |
| // Service ID has not changed. |
| EXPECT_EQ(kServiceTextureId, texture->service_id()); |
| |
| // Create new texture for consume. |
| EXPECT_CALL(*gl_, GenTextures(_, _)) |
| .WillOnce(SetArgumentPointee<1>(kNewServiceId)) |
| .RetiresOnSaturation(); |
| DoBindTexture(GL_TEXTURE_2D, kNewClientId, kNewServiceId); |
| |
| // Assigns and binds original service size texture ID. |
| EXPECT_CALL(*gl_, DeleteTextures(1, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| memcpy(shared_memory_address_, mailbox, sizeof(mailbox)); |
| ConsumeTextureCHROMIUM consume_cmd; |
| consume_cmd.Init(GL_TEXTURE_2D, kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(consume_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Texture is redefined. |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| EXPECT_EQ(3, width); |
| EXPECT_EQ(1, height); |
| EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format)); |
| EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format); |
| EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type); |
| |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 1, &width, &height)); |
| EXPECT_EQ(2, width); |
| EXPECT_EQ(4, height); |
| EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 1, &type, &internal_format)); |
| EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format); |
| EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type); |
| |
| // Service ID is restored. |
| EXPECT_EQ(kServiceTextureId, texture->service_id()); |
| } |
| |
| |
| TEST_F(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_F(GLES2DecoderTest, IsEnabledReturnsCachedValue) { |
| // NOTE: There are no expectations because no GL functions should be |
| // called for DEPTH_TEST or STENCIL_TEST |
| static const GLenum kStates[] = { |
| GL_DEPTH_TEST, |
| GL_STENCIL_TEST, |
| }; |
| for (size_t ii = 0; ii < arraysize(kStates); ++ii) { |
| Enable enable_cmd; |
| GLenum state = kStates[ii]; |
| enable_cmd.Init(state); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(enable_cmd)); |
| IsEnabled::Result* result = |
| static_cast<IsEnabled::Result*>(shared_memory_address_); |
| IsEnabled is_enabled_cmd; |
| is_enabled_cmd.Init(state, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(is_enabled_cmd)); |
| EXPECT_NE(0u, *result); |
| Disable disable_cmd; |
| disable_cmd.Init(state); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(disable_cmd)); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(is_enabled_cmd)); |
| EXPECT_EQ(0u, *result); |
| } |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, DepthTextureBadArgs) { |
| InitDecoder( |
| "GL_ANGLE_depth_texture", // extensions |
| false, // has alpha |
| true, // has depth |
| true, // has stencil |
| false, // request alpha |
| true, // request depth |
| true, // request stencil |
| true); // bind generates resource |
| |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| // Check trying to upload data fails. |
| TexImage2D tex_cmd; |
| tex_cmd.Init( |
| GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, |
| 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| // Try level > 0. |
| tex_cmd.Init( |
| GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT, |
| 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| // Make a 1 pixel depth texture. |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, |
| 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0, 0); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| // Check that trying to update it fails. |
| TexSubImage2D tex_sub_cmd; |
| tex_sub_cmd.Init( |
| GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, |
| kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(tex_sub_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Check that trying to CopyTexImage2D fails |
| CopyTexImage2D copy_tex_cmd; |
| copy_tex_cmd.Init(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, 1, 1, 0); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(copy_tex_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| |
| // Check that trying to CopyTexSubImage2D fails |
| CopyTexSubImage2D copy_sub_cmd; |
| copy_sub_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(copy_sub_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, GenerateMipmapDepthTexture) { |
| InitDecoder( |
| "GL_ANGLE_depth_texture", // extensions |
| false, // has alpha |
| true, // has depth |
| true, // has stencil |
| false, // request alpha |
| true, // request depth |
| true, // request stencil |
| true); // bind generates resource |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, |
| 2, 2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, |
| 0, 0); |
| GenerateMipmap cmd; |
| cmd.Init(GL_TEXTURE_2D); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, DrawClearsDepthTexture) { |
| InitDecoder( |
| "GL_ANGLE_depth_texture", // extensions |
| true, // has alpha |
| true, // has depth |
| false, // has stencil |
| true, // request alpha |
| true, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| SetupDefaultProgram(); |
| SetupAllNeededVertexBuffers(); |
| const GLenum attachment = GL_DEPTH_ATTACHMENT; |
| const GLenum target = GL_TEXTURE_2D; |
| const GLint level = 0; |
| DoBindTexture(target, client_texture_id_, kServiceTextureId); |
| |
| // Create a depth texture. |
| DoTexImage2D(target, level, GL_DEPTH_COMPONENT, 1, 1, 0, |
| GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0, 0); |
| |
| EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT( |
| GL_DRAW_FRAMEBUFFER_EXT, attachment, target, kServiceTextureId, level)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT)) |
| .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) |
| .RetiresOnSaturation(); |
| |
| EXPECT_CALL(*gl_, ClearStencil(0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, StencilMask(-1)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ClearDepth(1.0f)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, DepthMask(true)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| EXPECT_CALL(*gl_, Clear(GL_DEPTH_BUFFER_BIT)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| SetupExpectationsForRestoreClearState( |
| 0.0f, 0.0f, 0.0f, 0.0f, 0, 1.0f, false); |
| |
| EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, _)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| 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_F(GLES2DecoderWithShaderTest, BindUniformLocationCHROMIUM) { |
| const GLint kLocation = 2; |
| const char* kName = "testing"; |
| const uint32 kNameSize = strlen(kName); |
| const char* kBadName1 = "gl_testing"; |
| const uint32 kBadName1Size = strlen(kBadName1); |
| const char* kBadName2 = "testing[1]"; |
| const uint32 kBadName2Size = strlen(kBadName2); |
| memcpy(shared_memory_address_, kName, kNameSize); |
| BindUniformLocationCHROMIUM cmd; |
| cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // check negative location |
| memcpy(shared_memory_address_, kName, kNameSize); |
| cmd.Init(client_program_id_, -1, kSharedMemoryId, kSharedMemoryOffset, |
| kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| // check highest location |
| memcpy(shared_memory_address_, kName, kNameSize); |
| GLint kMaxLocation = |
| (kMaxFragmentUniformVectors + kMaxVertexUniformVectors) * 4 - 1; |
| cmd.Init(client_program_id_, kMaxLocation, kSharedMemoryId, |
| kSharedMemoryOffset, kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // check too high location |
| memcpy(shared_memory_address_, kName, kNameSize); |
| cmd.Init(client_program_id_, kMaxLocation + 1, kSharedMemoryId, |
| kSharedMemoryOffset, kNameSize); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| // check bad name "gl_..." |
| memcpy(shared_memory_address_, kBadName1, kBadName1Size); |
| cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset, |
| kBadName1Size); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| // check bad name "name[1]" non zero |
| memcpy(shared_memory_address_, kBadName2, kBadName2Size); |
| cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset, |
| kBadName2Size); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); |
| } |
| |
| class GLES2DecoderVertexArraysOESTest : public GLES2DecoderWithShaderTest { |
| public: |
| GLES2DecoderVertexArraysOESTest() { } |
| |
| bool vertex_array_deleted_manually_; |
| |
| virtual void SetUp() { |
| InitDecoder( |
| "GL_OES_vertex_array_object", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| SetupDefaultProgram(); |
| |
| AddExpectationsForGenVertexArraysOES(); |
| GenHelper<GenVertexArraysOESImmediate>(client_vertexarray_id_); |
| |
| vertex_array_deleted_manually_ = false; |
| } |
| |
| virtual void TearDown() { |
| // This should only be set if the test handled deletion of the vertex array |
| // itself. Necessary because vertex_array_objects are not sharable, and thus |
| // not managed in the ContextGroup, meaning they will be destroyed during |
| // test tear down |
| if (!vertex_array_deleted_manually_) { |
| AddExpectationsForDeleteVertexArraysOES(); |
| } |
| |
| GLES2DecoderWithShaderTest::TearDown(); |
| } |
| |
| void GenVertexArraysOESValidArgs() { |
| AddExpectationsForGenVertexArraysOES(); |
| GetSharedMemoryAs<GLuint*>()[0] = kNewClientId; |
| GenVertexArraysOES cmd; |
| cmd.Init(1, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE(GetVertexArrayInfo(kNewClientId) != NULL); |
| AddExpectationsForDeleteVertexArraysOES(); |
| } |
| |
| void GenVertexArraysOESInvalidArgs() { |
| EXPECT_CALL(*gl_, GenVertexArraysOES(_, _)).Times(0); |
| GetSharedMemoryAs<GLuint*>()[0] = client_vertexarray_id_; |
| GenVertexArraysOES cmd; |
| cmd.Init(1, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd)); |
| } |
| |
| void GenVertexArraysOESImmediateValidArgs() { |
| AddExpectationsForGenVertexArraysOES(); |
| GenVertexArraysOESImmediate* cmd = |
| GetImmediateAs<GenVertexArraysOESImmediate>(); |
| GLuint temp = kNewClientId; |
| cmd->Init(1, &temp); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(*cmd, sizeof(temp))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE(GetVertexArrayInfo(kNewClientId) != NULL); |
| AddExpectationsForDeleteVertexArraysOES(); |
| } |
| |
| void GenVertexArraysOESImmediateInvalidArgs() { |
| EXPECT_CALL(*gl_, GenVertexArraysOES(_, _)).Times(0); |
| GenVertexArraysOESImmediate* cmd = |
| GetImmediateAs<GenVertexArraysOESImmediate>(); |
| cmd->Init(1, &client_vertexarray_id_); |
| EXPECT_EQ(error::kInvalidArguments, |
| ExecuteImmediateCmd(*cmd, sizeof(&client_vertexarray_id_))); |
| } |
| |
| void DeleteVertexArraysOESValidArgs() { |
| AddExpectationsForDeleteVertexArraysOES(); |
| GetSharedMemoryAs<GLuint*>()[0] = client_vertexarray_id_; |
| DeleteVertexArraysOES cmd; |
| cmd.Init(1, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE( |
| GetVertexArrayInfo(client_vertexarray_id_) == NULL); |
| vertex_array_deleted_manually_ = true; |
| } |
| |
| void DeleteVertexArraysOESInvalidArgs() { |
| GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId; |
| DeleteVertexArraysOES cmd; |
| cmd.Init(1, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| |
| void DeleteVertexArraysOESImmediateValidArgs() { |
| AddExpectationsForDeleteVertexArraysOES(); |
| DeleteVertexArraysOESImmediate& cmd = |
| *GetImmediateAs<DeleteVertexArraysOESImmediate>(); |
| cmd.Init(1, &client_vertexarray_id_); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(cmd, sizeof(client_vertexarray_id_))); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_TRUE( |
| GetVertexArrayInfo(client_vertexarray_id_) == NULL); |
| vertex_array_deleted_manually_ = true; |
| } |
| |
| void DeleteVertexArraysOESImmediateInvalidArgs() { |
| DeleteVertexArraysOESImmediate& cmd = |
| *GetImmediateAs<DeleteVertexArraysOESImmediate>(); |
| GLuint temp = kInvalidClientId; |
| cmd.Init(1, &temp); |
| EXPECT_EQ(error::kNoError, |
| ExecuteImmediateCmd(cmd, sizeof(temp))); |
| } |
| |
| void IsVertexArrayOESValidArgs() { |
| IsVertexArrayOES cmd; |
| cmd.Init(client_vertexarray_id_, shared_memory_id_, shared_memory_offset_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| void IsVertexArrayOESInvalidArgsBadSharedMemoryId() { |
| IsVertexArrayOES cmd; |
| cmd.Init( |
| client_vertexarray_id_, kInvalidSharedMemoryId, shared_memory_offset_); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| cmd.Init( |
| client_vertexarray_id_, shared_memory_id_, kInvalidSharedMemoryOffset); |
| EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); |
| } |
| |
| void BindVertexArrayOESValidArgs() { |
| AddExpectationsForBindVertexArrayOES(); |
| BindVertexArrayOES cmd; |
| cmd.Init(client_vertexarray_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| void BindVertexArrayOESValidArgsNewId() { |
| BindVertexArrayOES cmd; |
| cmd.Init(kNewClientId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| }; |
| |
| class GLES2DecoderEmulatedVertexArraysOESTest |
| : public GLES2DecoderVertexArraysOESTest { |
| public: |
| GLES2DecoderEmulatedVertexArraysOESTest() { } |
| |
| virtual void SetUp() { |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| SetupDefaultProgram(); |
| |
| AddExpectationsForGenVertexArraysOES(); |
| GenHelper<GenVertexArraysOESImmediate>(client_vertexarray_id_); |
| |
| vertex_array_deleted_manually_ = false; |
| } |
| }; |
| |
| // Test vertex array objects with native support |
| TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESValidArgs) { |
| GenVertexArraysOESValidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, GenVertexArraysOESValidArgs) { |
| GenVertexArraysOESValidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESInvalidArgs) { |
| GenVertexArraysOESInvalidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, ) { |
| GenVertexArraysOESInvalidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESImmediateValidArgs) { |
| GenVertexArraysOESImmediateValidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, |
| GenVertexArraysOESImmediateValidArgs) { |
| GenVertexArraysOESImmediateValidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, |
| GenVertexArraysOESImmediateInvalidArgs) { |
| GenVertexArraysOESImmediateInvalidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, |
| GenVertexArraysOESImmediateInvalidArgs) { |
| GenVertexArraysOESImmediateInvalidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, DeleteVertexArraysOESValidArgs) { |
| DeleteVertexArraysOESValidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, |
| DeleteVertexArraysOESValidArgs) { |
| DeleteVertexArraysOESValidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, DeleteVertexArraysOESInvalidArgs) { |
| DeleteVertexArraysOESInvalidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, |
| DeleteVertexArraysOESInvalidArgs) { |
| DeleteVertexArraysOESInvalidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, |
| DeleteVertexArraysOESImmediateValidArgs) { |
| DeleteVertexArraysOESImmediateValidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, |
| DeleteVertexArraysOESImmediateValidArgs) { |
| DeleteVertexArraysOESImmediateValidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, |
| DeleteVertexArraysOESImmediateInvalidArgs) { |
| DeleteVertexArraysOESImmediateInvalidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, |
| DeleteVertexArraysOESImmediateInvalidArgs) { |
| DeleteVertexArraysOESImmediateInvalidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, IsVertexArrayOESValidArgs) { |
| IsVertexArrayOESValidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, IsVertexArrayOESValidArgs) { |
| IsVertexArrayOESValidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, |
| IsVertexArrayOESInvalidArgsBadSharedMemoryId) { |
| IsVertexArrayOESInvalidArgsBadSharedMemoryId(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, |
| IsVertexArrayOESInvalidArgsBadSharedMemoryId) { |
| IsVertexArrayOESInvalidArgsBadSharedMemoryId(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, BindVertexArrayOESValidArgs) { |
| BindVertexArrayOESValidArgs(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, BindVertexArrayOESValidArgs) { |
| BindVertexArrayOESValidArgs(); |
| } |
| |
| TEST_F(GLES2DecoderVertexArraysOESTest, BindVertexArrayOESValidArgsNewId) { |
| BindVertexArrayOESValidArgsNewId(); |
| } |
| TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, |
| BindVertexArrayOESValidArgsNewId) { |
| BindVertexArrayOESValidArgsNewId(); |
| } |
| |
| TEST_F(GLES2DecoderTest, BindTexImage2DCHROMIUM) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| TextureRef* texture_ref = group().texture_manager()->GetTexture( |
| client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_EQ(kServiceTextureId, texture->service_id()); |
| |
| group().image_manager()->AddImage(gfx::GLImage::CreateGLImage(0).get(), 1); |
| EXPECT_FALSE(group().image_manager()->LookupImage(1) == NULL); |
| |
| GLsizei width; |
| GLsizei height; |
| GLenum type; |
| GLenum internal_format; |
| |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| EXPECT_EQ(3, width); |
| EXPECT_EQ(1, height); |
| EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format)); |
| EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format); |
| EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type); |
| EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); |
| |
| // Bind image to texture. |
| // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| BindTexImage2DCHROMIUM bind_tex_image_2d_cmd; |
| bind_tex_image_2d_cmd.Init(GL_TEXTURE_2D, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(bind_tex_image_2d_cmd)); |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| // Image should now be set. |
| EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); |
| |
| // Define new texture image. |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| // Image should no longer be set. |
| EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); |
| } |
| |
| TEST_F(GLES2DecoderTest, ReleaseTexImage2DCHROMIUM) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 0, 0); |
| TextureRef* texture_ref = group().texture_manager()->GetTexture( |
| client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_EQ(kServiceTextureId, texture->service_id()); |
| |
| group().image_manager()->AddImage(gfx::GLImage::CreateGLImage(0).get(), 1); |
| EXPECT_FALSE(group().image_manager()->LookupImage(1) == NULL); |
| |
| GLsizei width; |
| GLsizei height; |
| GLenum type; |
| GLenum internal_format; |
| |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| EXPECT_EQ(3, width); |
| EXPECT_EQ(1, height); |
| EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format)); |
| EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format); |
| EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type); |
| EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); |
| |
| // Bind image to texture. |
| // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| BindTexImage2DCHROMIUM bind_tex_image_2d_cmd; |
| bind_tex_image_2d_cmd.Init(GL_TEXTURE_2D, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(bind_tex_image_2d_cmd)); |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| // Image should now be set. |
| EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); |
| |
| // Release image from texture. |
| // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| ReleaseTexImage2DCHROMIUM release_tex_image_2d_cmd; |
| release_tex_image_2d_cmd.Init(GL_TEXTURE_2D, 1); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(release_tex_image_2d_cmd)); |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| // Image should no longer be set. |
| EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); |
| } |
| |
| class MockGLImage : public gfx::GLImage { |
| public: |
| MockGLImage() {} |
| |
| // Overridden from gfx::GLImage: |
| MOCK_METHOD0(Destroy, void()); |
| MOCK_METHOD0(GetSize, gfx::Size()); |
| MOCK_METHOD1(BindTexImage, bool(unsigned)); |
| MOCK_METHOD1(ReleaseTexImage, void(unsigned)); |
| MOCK_METHOD0(WillUseTexImage, void()); |
| MOCK_METHOD0(DidUseTexImage, void()); |
| |
| protected: |
| virtual ~MockGLImage() {} |
| }; |
| |
| TEST_F(GLES2DecoderWithShaderTest, UseTexImage) { |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| |
| TextureRef* texture_ref = group().texture_manager()->GetTexture( |
| client_texture_id_); |
| ASSERT_TRUE(texture_ref != NULL); |
| Texture* texture = texture_ref->texture(); |
| EXPECT_EQ(kServiceTextureId, texture->service_id()); |
| |
| const int32 kImageId = 1; |
| scoped_refptr<MockGLImage> image(new MockGLImage); |
| group().image_manager()->AddImage(image.get(), kImageId); |
| |
| // Bind image to texture. |
| EXPECT_CALL(*image, BindTexImage(GL_TEXTURE_2D)) |
| .Times(1) |
| .WillOnce(Return(true)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*image, GetSize()) |
| .Times(1) |
| .WillOnce(Return(gfx::Size(1, 1))) |
| .RetiresOnSaturation(); |
| // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| BindTexImage2DCHROMIUM bind_tex_image_2d_cmd; |
| bind_tex_image_2d_cmd.Init(GL_TEXTURE_2D, kImageId); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(bind_tex_image_2d_cmd)); |
| |
| AddExpectationsForSimulatedAttrib0(kNumVertices, 0); |
| SetupExpectationsForApplyingDefaultDirtyState(); |
| |
| // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. |
| 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(); |
| EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) |
| .Times(3) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*image, WillUseTexImage()) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*image, DidUseTexImage()) |
| .Times(1) |
| .RetiresOnSaturation(); |
| 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()); |
| |
| DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, |
| kServiceFramebufferId); |
| // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) |
| .Times(2) |
| .RetiresOnSaturation(); |
| // Image will be 'in use' as long as bound to a framebuffer. |
| EXPECT_CALL(*image, WillUseTexImage()) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, FramebufferTexture2DEXT( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| kServiceTextureId, 0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .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_NO_ERROR, GetGLError()); |
| |
| // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| kServiceRenderbufferId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) |
| .Times(2) |
| .RetiresOnSaturation(); |
| // Image should no longer be 'in use' after being unbound from framebuffer. |
| EXPECT_CALL(*image, DidUseTexImage()) |
| .Times(1) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| FramebufferRenderbuffer fbrb_cmd; |
| fbrb_cmd.Init( |
| GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| client_renderbuffer_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd)); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, GpuMemoryManagerCHROMIUM) { |
| InitDecoder( |
| "GL_ARB_texture_rectangle", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| |
| Texture* texture = GetTexture(client_texture_id_)->texture(); |
| EXPECT_TRUE(texture != NULL); |
| EXPECT_TRUE(texture->pool() == GL_TEXTURE_POOL_UNMANAGED_CHROMIUM); |
| |
| DoBindTexture( |
| GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| |
| TexParameteri cmd; |
| cmd.Init(GL_TEXTURE_2D, |
| GL_TEXTURE_POOL_CHROMIUM, |
| GL_TEXTURE_POOL_UNMANAGED_CHROMIUM); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| cmd.Init(GL_TEXTURE_2D, |
| GL_TEXTURE_POOL_CHROMIUM, |
| GL_TEXTURE_POOL_MANAGED_CHROMIUM); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| |
| EXPECT_TRUE(texture->pool() == GL_TEXTURE_POOL_MANAGED_CHROMIUM); |
| |
| cmd.Init(GL_TEXTURE_2D, |
| GL_TEXTURE_POOL_CHROMIUM, |
| GL_NONE); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) { |
| InitDecoder( |
| "GL_CHROMIUM_async_pixel_transfers", // extensions |
| false, false, false, // has alpha/depth/stencil |
| false, false, false, // request alpha/depth/stencil |
| true); // bind generates resource |
| |
| // Set up the texture. |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| Texture* texture = texture_ref->texture(); |
| |
| // Set a mock Async delegate |
| StrictMock<gpu::MockAsyncPixelTransferManager>* manager = |
| new StrictMock<gpu::MockAsyncPixelTransferManager>; |
| manager->Initialize(group().texture_manager()); |
| decoder_->SetAsyncPixelTransferManagerForTest(manager); |
| StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate = NULL; |
| |
| // Tex(Sub)Image2D upload commands. |
| AsyncTexImage2DCHROMIUM teximage_cmd; |
| teximage_cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset); |
| AsyncTexSubImage2DCHROMIUM texsubimage_cmd; |
| texsubimage_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGBA, |
| GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset); |
| WaitAsyncTexImage2DCHROMIUM wait_cmd; |
| wait_cmd.Init(GL_TEXTURE_2D); |
| |
| // No transfer state exists initially. |
| EXPECT_FALSE( |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| |
| base::Closure bind_callback; |
| |
| // AsyncTexImage2D |
| { |
| // Create transfer state since it doesn't exist. |
| EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
| .WillOnce(Return( |
| delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _)) |
| .WillOnce(SaveArg<2>(&bind_callback)) |
| .RetiresOnSaturation(); |
| // Command succeeds. |
| EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ( |
| delegate, |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| EXPECT_TRUE(texture->IsImmutable()); |
| // The texture is safe but the level has not been defined yet. |
| EXPECT_TRUE(texture->SafeToRenderFrom()); |
| GLsizei width, height; |
| EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| } |
| { |
| // Async redefinitions are not allowed! |
| // Command fails. |
| EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ( |
| delegate, |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| EXPECT_TRUE(texture->IsImmutable()); |
| EXPECT_TRUE(texture->SafeToRenderFrom()); |
| } |
| |
| // Binding/defining of the async transfer |
| { |
| // TODO(epenner): We should check that the manager gets the |
| // BindCompletedAsyncTransfers() call, which is required to |
| // guarantee the delegate calls the bind callback. |
| |
| // Simulate the bind callback from the delegate. |
| bind_callback.Run(); |
| |
| // After the bind callback is run, the texture is safe, |
| // and has the right size etc. |
| EXPECT_TRUE(texture->SafeToRenderFrom()); |
| GLsizei width, height; |
| EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height)); |
| EXPECT_EQ(width, 8); |
| EXPECT_EQ(height, 8); |
| } |
| |
| // AsyncTexSubImage2D |
| decoder_->GetAsyncPixelTransferManager() |
| ->ClearPixelTransferDelegateForTest(texture_ref); |
| texture->SetImmutable(false); |
| { |
| // Create transfer state since it doesn't exist. |
| EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
| .WillOnce(Return( |
| delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*delegate, AsyncTexSubImage2D(_, _)) |
| .RetiresOnSaturation(); |
| // Command succeeds. |
| EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ( |
| delegate, |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| EXPECT_TRUE(texture->IsImmutable()); |
| EXPECT_TRUE(texture->SafeToRenderFrom()); |
| } |
| { |
| // No transfer is in progress. |
| EXPECT_CALL(*delegate, TransferIsInProgress()) |
| .WillOnce(Return(false)) // texSubImage validation |
| .WillOnce(Return(false)) // async validation |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*delegate, AsyncTexSubImage2D(_, _)) |
| .RetiresOnSaturation(); |
| // Command succeeds. |
| EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ( |
| delegate, |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| EXPECT_TRUE(texture->IsImmutable()); |
| EXPECT_TRUE(texture->SafeToRenderFrom()); |
| } |
| { |
| // A transfer is still in progress! |
| EXPECT_CALL(*delegate, TransferIsInProgress()) |
| .WillOnce(Return(true)) |
| .RetiresOnSaturation(); |
| // No async call, command fails. |
| EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd)); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| EXPECT_EQ( |
| delegate, |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| EXPECT_TRUE(texture->IsImmutable()); |
| EXPECT_TRUE(texture->SafeToRenderFrom()); |
| } |
| |
| // Delete delegate on DeleteTexture. |
| { |
| EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation(); |
| DoDeleteTexture(client_texture_id_, kServiceTextureId); |
| EXPECT_FALSE( |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| delegate = NULL; |
| } |
| |
| // WaitAsyncTexImage2D |
| { |
| // Get a fresh texture since the existing texture cannot be respecified |
| // asynchronously and AsyncTexSubImage2D does not involved binding. |
| EXPECT_CALL(*gl_, GenTextures(1, _)) |
| .WillOnce(SetArgumentPointee<1>(kServiceTextureId)); |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| texture_ref = GetTexture(client_texture_id_); |
| texture = texture_ref->texture(); |
| texture->SetImmutable(false); |
| // Create transfer state since it doesn't exist. |
| EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
| .WillOnce(Return( |
| delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _)) |
| .RetiresOnSaturation(); |
| // Start async transfer. |
| EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ( |
| delegate, |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| |
| EXPECT_TRUE(texture->IsImmutable()); |
| // Wait for completion. |
| EXPECT_CALL(*delegate, WaitForTransferCompletion()); |
| EXPECT_CALL(*manager, BindCompletedAsyncTransfers()); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(wait_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransferManager) { |
| InitDecoder( |
| "GL_CHROMIUM_async_pixel_transfers", // extensions |
| false, false, false, // has alpha/depth/stencil |
| false, false, false, // request alpha/depth/stencil |
| true); // bind generates resource |
| |
| // Set up the texture. |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| TextureRef* texture_ref = GetTexture(client_texture_id_); |
| |
| // Set a mock Async delegate. |
| StrictMock<gpu::MockAsyncPixelTransferManager>* manager = |
| new StrictMock<gpu::MockAsyncPixelTransferManager>; |
| manager->Initialize(group().texture_manager()); |
| decoder_->SetAsyncPixelTransferManagerForTest(manager); |
| StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate = NULL; |
| |
| AsyncTexImage2DCHROMIUM teximage_cmd; |
| teximage_cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset); |
| |
| // No transfer delegate exists initially. |
| EXPECT_FALSE( |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| |
| // Create delegate on AsyncTexImage2D. |
| { |
| EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _)) |
| .WillOnce(Return( |
| delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _)).RetiresOnSaturation(); |
| |
| // Command succeeds. |
| EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| } |
| |
| // Delegate is cached. |
| EXPECT_EQ(delegate, |
| decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate( |
| texture_ref)); |
| |
| // Delete delegate on manager teardown. |
| { |
| EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation(); |
| decoder_->ResetAsyncPixelTransferManagerForTest(); |
| |
| // Texture ref still valid. |
| EXPECT_EQ(texture_ref, GetTexture(client_texture_id_)); |
| } |
| } |
| |
| namespace { |
| |
| class SizeOnlyMemoryTracker : public MemoryTracker { |
| public: |
| SizeOnlyMemoryTracker() { |
| // These are the default textures. 1 for TEXTURE_2D and 6 faces for |
| // TEXTURE_CUBE_MAP. |
| const size_t kInitialUnmanagedPoolSize = 7 * 4; |
| const size_t kInitialManagedPoolSize = 0; |
| pool_infos_[MemoryTracker::kUnmanaged].initial_size = |
| kInitialUnmanagedPoolSize; |
| pool_infos_[MemoryTracker::kManaged].initial_size = |
| kInitialManagedPoolSize; |
| } |
| |
| // Ensure a certain amount of GPU memory is free. Returns true on success. |
| MOCK_METHOD1(EnsureGPUMemoryAvailable, bool(size_t size_needed)); |
| |
| virtual void TrackMemoryAllocatedChange( |
| size_t old_size, size_t new_size, Pool pool) { |
| PoolInfo& info = pool_infos_[pool]; |
| info.size += new_size - old_size; |
| } |
| |
| size_t GetPoolSize(Pool pool) { |
| const PoolInfo& info = pool_infos_[pool]; |
| return info.size - info.initial_size; |
| } |
| |
| private: |
| virtual ~SizeOnlyMemoryTracker() { |
| } |
| struct PoolInfo { |
| PoolInfo() |
| : initial_size(0), |
| size(0) { |
| } |
| size_t initial_size; |
| size_t size; |
| }; |
| std::map<Pool, PoolInfo> pool_infos_; |
| }; |
| |
| } // anonymous namespace. |
| |
| TEST_F(GLES2DecoderManualInitTest, MemoryTrackerInitialSize) { |
| scoped_refptr<SizeOnlyMemoryTracker> memory_tracker = |
| new SizeOnlyMemoryTracker(); |
| set_memory_tracker(memory_tracker.get()); |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| // Expect that initial size - size is 0. |
| EXPECT_EQ(0u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| EXPECT_EQ(0u, memory_tracker->GetPoolSize(MemoryTracker::kManaged)); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, MemoryTrackerTexImage2D) { |
| scoped_refptr<SizeOnlyMemoryTracker> memory_tracker = |
| new SizeOnlyMemoryTracker(); |
| set_memory_tracker(memory_tracker.get()); |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128)) |
| .WillOnce(Return(true)).RetiresOnSaturation(); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(64)) |
| .WillOnce(Return(true)).RetiresOnSaturation(); |
| DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(64u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Check we get out of memory and no call to glTexImage2D if Ensure fails. |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(64)) |
| .WillOnce(Return(false)).RetiresOnSaturation(); |
| TexImage2D cmd; |
| cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| kSharedMemoryId, kSharedMemoryOffset); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| EXPECT_EQ(64u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, MemoryTrackerTexStorage2DEXT) { |
| scoped_refptr<SizeOnlyMemoryTracker> memory_tracker = |
| new SizeOnlyMemoryTracker(); |
| set_memory_tracker(memory_tracker.get()); |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| // Check we get out of memory and no call to glTexStorage2DEXT |
| // if Ensure fails. |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128)) |
| .WillOnce(Return(false)).RetiresOnSaturation(); |
| TexStorage2DEXT cmd; |
| cmd.Init(GL_TEXTURE_2D, 1, GL_RGBA8, 8, 4); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(0u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, MemoryTrackerCopyTexImage2D) { |
| GLenum target = GL_TEXTURE_2D; |
| GLint level = 0; |
| GLenum internal_format = GL_RGBA; |
| GLsizei width = 4; |
| GLsizei height = 8; |
| GLint border = 0; |
| scoped_refptr<SizeOnlyMemoryTracker> memory_tracker = |
| new SizeOnlyMemoryTracker(); |
| set_memory_tracker(memory_tracker.get()); |
| InitDecoder( |
| "", // extensions |
| true, // has alpha |
| false, // has depth |
| false, // has stencil |
| true, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128)) |
| .WillOnce(Return(true)).RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, CopyTexImage2D( |
| target, level, internal_format, 0, 0, width, height, border)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| CopyTexImage2D cmd; |
| cmd.Init(target, level, internal_format, 0, 0, width, height, border); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| // Check we get out of memory and no call to glCopyTexImage2D if Ensure fails. |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128)) |
| .WillOnce(Return(false)).RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, MemoryTrackerRenderbufferStorage) { |
| scoped_refptr<SizeOnlyMemoryTracker> memory_tracker = |
| new SizeOnlyMemoryTracker(); |
| set_memory_tracker(memory_tracker.get()); |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_, |
| kServiceRenderbufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128)) |
| .WillOnce(Return(true)).RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, RenderbufferStorageEXT( |
| GL_RENDERBUFFER, GL_RGBA, 8, 4)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| RenderbufferStorage cmd; |
| cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 8, 4); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| // Check we get out of memory and no call to glRenderbufferStorage if Ensure |
| // fails. |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128)) |
| .WillOnce(Return(false)).RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged)); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, MemoryTrackerBufferData) { |
| scoped_refptr<SizeOnlyMemoryTracker> memory_tracker = |
| new SizeOnlyMemoryTracker(); |
| set_memory_tracker(memory_tracker.get()); |
| InitDecoder( |
| "", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| true); // bind generates resource |
| DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, |
| kServiceBufferId); |
| EXPECT_CALL(*gl_, GetError()) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .WillOnce(Return(GL_NO_ERROR)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128)) |
| .WillOnce(Return(true)).RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, BufferData(GL_ARRAY_BUFFER, 128, _, GL_STREAM_DRAW)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| BufferData cmd; |
| cmd.Init(GL_ARRAY_BUFFER, 128, 0, 0, GL_STREAM_DRAW); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_NO_ERROR, GetGLError()); |
| EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kManaged)); |
| // Check we get out of memory and no call to glBufferData if Ensure |
| // fails. |
| EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128)) |
| .WillOnce(Return(false)).RetiresOnSaturation(); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kManaged)); |
| } |
| |
| TEST_F(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_F(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_F(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_F(GLES2DecoderManualInitTest, DiscardFramebufferEXT) { |
| InitDecoder("GL_EXT_discard_framebuffer", // extensions |
| false, // has alpha |
| false, // has depth |
| false, // has stencil |
| false, // request alpha |
| false, // request depth |
| false, // request stencil |
| false); // bind generates resource |
| |
| 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 = group().framebuffer_manager(); |
| 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_F(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::kNoError, |
| ExecuteImmediateCmd(cmd, sizeof(attachments))); |
| EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); |
| } |
| |
| TEST_F(GLES2DecoderManualInitTest, ClearUniformsBeforeFirstProgramUse) { |
| CommandLine command_line(0, NULL); |
| command_line.AppendSwitchASCII( |
| switches::kGpuDriverBugWorkarounds, |
| base::IntToString(gpu::CLEAR_UNIFORMS_BEFORE_FIRST_PROGRAM_USE)); |
| InitDecoderWithCommandLine( |
| "", // extensions |
| true, // has alpha |
| false, // has depth |
| false, // has stencil |
| true, // request alpha |
| false, // request depth |
| false, // request stencil |
| true, // bind generates resource |
| &command_line); |
| { |
| static AttribInfo attribs[] = { |
| { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, |
| { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, }, |
| { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, }, |
| }; |
| static UniformInfo uniforms[] = { |
| { kUniform1Name, kUniform1Size, kUniform1Type, |
| kUniform1FakeLocation, kUniform1RealLocation, |
| kUniform1DesiredLocation }, |
| { kUniform2Name, kUniform2Size, kUniform2Type, |
| kUniform2FakeLocation, kUniform2RealLocation, |
| kUniform2DesiredLocation }, |
| { kUniform3Name, kUniform3Size, kUniform3Type, |
| kUniform3FakeLocation, kUniform3RealLocation, |
| kUniform3DesiredLocation }, |
| }; |
| SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms), |
| client_program_id_, kServiceProgramId, |
| client_vertex_shader_id_, kServiceVertexShaderId, |
| client_fragment_shader_id_, kServiceFragmentShaderId); |
| TestHelper::SetupExpectationsForClearingUniforms( |
| gl_.get(), uniforms, arraysize(uniforms)); |
| } |
| |
| { |
| EXPECT_CALL(*gl_, UseProgram(kServiceProgramId)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| cmds::UseProgram cmd; |
| cmd.Init(client_program_id_); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); |
| } |
| } |
| |
| // TODO(gman): Complete this test. |
| // TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) { |
| // } |
| |
| // TODO(gman): BufferData |
| |
| // TODO(gman): BufferDataImmediate |
| |
| // TODO(gman): BufferSubData |
| |
| // TODO(gman): BufferSubDataImmediate |
| |
| // TODO(gman): CompressedTexImage2D |
| |
| // TODO(gman): CompressedTexImage2DImmediate |
| |
| // TODO(gman): CompressedTexSubImage2DImmediate |
| |
| // TODO(gman): DeleteProgram |
| |
| // TODO(gman): DeleteShader |
| |
| // TODO(gman): PixelStorei |
| |
| // TODO(gman): TexImage2D |
| |
| // TODO(gman): TexImage2DImmediate |
| |
| // TODO(gman): TexSubImage2DImmediate |
| |
| // TODO(gman): UseProgram |
| |
| // TODO(gman): SwapBuffers |
| |
| } // namespace gles2 |
| } // namespace gpu |