|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.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/cmd_buffer_engine.h" | 
|  | #include "gpu/command_buffer/service/context_group.h" | 
|  | #include "gpu/command_buffer/service/context_state.h" | 
|  | #include "gpu/command_buffer/service/gl_surface_mock.h" | 
|  | #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h" | 
|  | #include "gpu/command_buffer/service/image_manager.h" | 
|  | #include "gpu/command_buffer/service/mailbox_manager.h" | 
|  | #include "gpu/command_buffer/service/mocks.h" | 
|  | #include "gpu/command_buffer/service/program_manager.h" | 
|  | #include "gpu/command_buffer/service/test_helper.h" | 
|  | #include "gpu/config/gpu_switches.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "ui/gl/gl_image_stub.h" | 
|  | #include "ui/gl/gl_implementation.h" | 
|  | #include "ui/gl/gl_mock.h" | 
|  | #include "ui/gl/gl_surface_stub.h" | 
|  |  | 
|  | #if !defined(GL_DEPTH24_STENCIL8) | 
|  | #define GL_DEPTH24_STENCIL8 0x88F0 | 
|  | #endif | 
|  |  | 
|  | using ::gl::MockGLInterface; | 
|  | using ::testing::_; | 
|  | using ::testing::DoAll; | 
|  | using ::testing::InSequence; | 
|  | using ::testing::Invoke; | 
|  | using ::testing::MatcherCast; | 
|  | using ::testing::Mock; | 
|  | using ::testing::Pointee; | 
|  | using ::testing::Return; | 
|  | using ::testing::SaveArg; | 
|  | using ::testing::SetArrayArgument; | 
|  | using ::testing::SetArgumentPointee; | 
|  | using ::testing::SetArgPointee; | 
|  | using ::testing::StrEq; | 
|  | using ::testing::StrictMock; | 
|  |  | 
|  | namespace { | 
|  | class EmulatingRGBImageStub : public gl::GLImageStub { | 
|  | protected: | 
|  | ~EmulatingRGBImageStub() override {} | 
|  | bool EmulatingRGB() const override { | 
|  | return true; | 
|  | } | 
|  | }; | 
|  | }  // namespace | 
|  |  | 
|  | namespace gpu { | 
|  | namespace gles2 { | 
|  |  | 
|  | using namespace cmds; | 
|  |  | 
|  | TEST_P(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_P(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, nullptr)); | 
|  | DoTexImage2D(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | 16, | 
|  | 16, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | GL_UNSIGNED_BYTE, | 
|  | kSharedMemoryId, | 
|  | kSharedMemoryOffset); | 
|  | EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D)).Times(1); | 
|  | 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, nullptr)); | 
|  | } | 
|  |  | 
|  | TEST_P(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); | 
|  | SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId, | 
|  | GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA, | 
|  | GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2); | 
|  | EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D)); | 
|  | 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_P(GLES3DecoderTest, GenerateMipmapBaseLevel) { | 
|  | EXPECT_CALL(*gl_, GenerateMipmapEXT(_)).Times(0); | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D( | 
|  | GL_TEXTURE_2D, 2, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); | 
|  |  | 
|  | { | 
|  | EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2)); | 
|  | TexParameteri cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId, | 
|  | GL_TEXTURE_2D, GL_TEXTURE_2D, 2, GL_RGBA, | 
|  | GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2); | 
|  | EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D)); | 
|  | 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()); | 
|  | } | 
|  |  | 
|  | // Same as GenerateMipmapClearsUnclearedTexture, but with workaround | 
|  | // |set_texture_filters_before_generating_mipmap|. | 
|  | TEST_P(GLES2DecoderManualInitTest, SetTextureFiltersBeforeGenerateMipmap) { | 
|  | base::CommandLine command_line(0, NULL); | 
|  | command_line.AppendSwitchASCII( | 
|  | switches::kGpuDriverBugWorkarounds, | 
|  | base::IntToString(gpu::SET_TEXTURE_FILTER_BEFORE_GENERATING_MIPMAP)); | 
|  | InitState init; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoderWithCommandLine(init, &command_line); | 
|  |  | 
|  | 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); | 
|  | SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId, | 
|  | GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA, | 
|  | GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 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_P(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_P(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_P(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_P(GLES2DecoderTest, TexSubImage2DBadArgs) { | 
|  | const int kWidth = 8; | 
|  | const int kHeight = 4; | 
|  | 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_P(GLES3DecoderTest, TexSubImage2DTypesDoNotMatchUnsizedFormat) { | 
|  | 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_SHORT_4_4_4_4, | 
|  | 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_P(GLES3DecoderTest, TexSubImage2DTypesDoNotMatchSizedFormat) { | 
|  | const int kWidth = 16; | 
|  | const int kHeight = 8; | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D(GL_TEXTURE_2D, | 
|  | 1, | 
|  | GL_RGBA4, | 
|  | 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_SHORT_4_4_4_4, | 
|  | shared_memory_address_)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | TexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, | 
|  | 1, | 
|  | 1, | 
|  | 0, | 
|  | kWidth - 1, | 
|  | kHeight, | 
|  | GL_RGBA, | 
|  | GL_UNSIGNED_SHORT_4_4_4_4, | 
|  | kSharedMemoryId, | 
|  | kSharedMemoryOffset, | 
|  | GL_FALSE); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(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_P(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()); | 
|  | } | 
|  |  | 
|  | TEST_P(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, | 
|  | GL_RGBA, | 
|  | GL_UNSIGNED_BYTE, | 
|  | kSharedMemoryId, | 
|  | kSharedMemoryOffset); | 
|  | } else { | 
|  | cmd.Init(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | kWidth, | 
|  | kHeight, | 
|  | 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_P(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, nullptr)); | 
|  | 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, | 
|  | 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, nullptr)); | 
|  | } | 
|  |  | 
|  | TEST_P(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, nullptr)); | 
|  | 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); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); | 
|  | EXPECT_FALSE( | 
|  | texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height, nullptr)); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, CopyTexImage2DUnsizedInternalFormat) { | 
|  | base::CommandLine command_line(0, NULL); | 
|  | command_line.AppendSwitch(switches::kEnableUnsafeES3APIs); | 
|  | InitState init; | 
|  | init.gl_version = "OpenGL ES 3.0"; | 
|  | init.extensions = "GL_APPLE_texture_format_BGRA8888 GL_EXT_sRGB"; | 
|  | init.has_alpha = true; | 
|  | init.request_alpha = true; | 
|  | init.bind_generates_resource = true; | 
|  | init.context_type = CONTEXT_TYPE_OPENGLES2; | 
|  | InitDecoderWithCommandLine(init, &command_line); | 
|  |  | 
|  | GLenum kUnsizedInternalFormats[] = { | 
|  | GL_RED, | 
|  | GL_RG, | 
|  | GL_RGB, | 
|  | GL_RGBA, | 
|  | GL_BGRA_EXT, | 
|  | GL_LUMINANCE, | 
|  | GL_LUMINANCE_ALPHA, | 
|  | GL_SRGB, | 
|  | GL_SRGB_ALPHA, | 
|  | }; | 
|  | GLenum target = GL_TEXTURE_2D; | 
|  | GLint level = 0; | 
|  | GLsizei width = 2; | 
|  | GLsizei height = 4; | 
|  | GLint border = 0; | 
|  | EXPECT_CALL(*gl_, GenTextures(_, _)) | 
|  | .WillOnce(SetArgumentPointee<1>(kNewServiceId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<GenTexturesImmediate>(kNewClientId); | 
|  |  | 
|  | TextureManager* manager = group().texture_manager(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GetError()).WillRepeatedly(Return(GL_NO_ERROR)); | 
|  | EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_)) | 
|  | .WillRepeatedly(Return(GL_FRAMEBUFFER_COMPLETE)); | 
|  | for (size_t i = 0; i < arraysize(kUnsizedInternalFormats); ++i) { | 
|  | // Copy from main framebuffer to texture, using the unsized internal format. | 
|  | DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); | 
|  | GLenum internal_format = kUnsizedInternalFormats[i]; | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | 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); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | TextureRef* ref = manager->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(ref != nullptr); | 
|  | Texture* texture = ref->texture(); | 
|  | GLenum chosen_type = 0; | 
|  | GLenum chosen_internal_format = 0; | 
|  | texture->GetLevelType(target, level, &chosen_type, &chosen_internal_format); | 
|  | EXPECT_NE(0u, chosen_type); | 
|  | EXPECT_NE(0u, chosen_internal_format); | 
|  |  | 
|  | // Attach texture to FBO, and copy into second texture. | 
|  | DoBindFramebuffer( | 
|  | GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); | 
|  | DoFramebufferTexture2D(GL_FRAMEBUFFER, | 
|  | GL_COLOR_ATTACHMENT0, | 
|  | GL_TEXTURE_2D, | 
|  | client_texture_id_, | 
|  | kServiceTextureId, | 
|  | 0, | 
|  | GL_NO_ERROR); | 
|  | DoBindTexture(GL_TEXTURE_2D, kNewClientId, kNewServiceId); | 
|  |  | 
|  | bool complete = | 
|  | (DoCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); | 
|  | if (complete) { | 
|  | EXPECT_CALL(*gl_, CopyTexImage2D(target, level, internal_format, 0, 0, | 
|  | width, height, border)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | cmd.Init(target, level, internal_format, 0, 0, width, height); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | if (complete) { | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } else { | 
|  | EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, CopyTexImage2DUnsizedInternalFormatES3) { | 
|  | base::CommandLine command_line(0, NULL); | 
|  | command_line.AppendSwitch(switches::kEnableUnsafeES3APIs); | 
|  | InitState init; | 
|  | init.gl_version = "OpenGL ES 3.0"; | 
|  | init.extensions = "GL_APPLE_texture_format_BGRA8888"; | 
|  | init.has_alpha = true; | 
|  | init.request_alpha = true; | 
|  | init.bind_generates_resource = true; | 
|  | init.context_type = CONTEXT_TYPE_OPENGLES3; | 
|  | InitDecoderWithCommandLine(init, &command_line); | 
|  |  | 
|  | struct UnsizedSizedInternalFormat { | 
|  | GLenum unsized; | 
|  | GLenum sized; | 
|  | }; | 
|  | UnsizedSizedInternalFormat kUnsizedInternalFormats[] = { | 
|  | {GL_RED, GL_R8}, | 
|  | {GL_RG, GL_RG8}, | 
|  | {GL_RGB, GL_RGB8}, | 
|  | {GL_RGBA, GL_RGBA8}, | 
|  | {GL_BGRA_EXT, GL_RGBA8}, | 
|  | {GL_LUMINANCE, GL_RGB8}, | 
|  | {GL_LUMINANCE_ALPHA, GL_RGBA8}, | 
|  | }; | 
|  | GLenum target = GL_TEXTURE_2D; | 
|  | GLint level = 0; | 
|  | GLsizei width = 2; | 
|  | GLsizei height = 4; | 
|  | GLint border = 0; | 
|  | EXPECT_CALL(*gl_, GenTextures(_, _)) | 
|  | .WillOnce(SetArgumentPointee<1>(kNewServiceId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<GenTexturesImmediate>(kNewClientId); | 
|  |  | 
|  | TextureManager* manager = group().texture_manager(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GetError()).WillRepeatedly(Return(GL_NO_ERROR)); | 
|  | EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_)) | 
|  | .WillRepeatedly(Return(GL_FRAMEBUFFER_COMPLETE)); | 
|  | for (size_t i = 0; i < arraysize(kUnsizedInternalFormats); ++i) { | 
|  | // Copy from main framebuffer to texture, using the unsized internal format. | 
|  | DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); | 
|  | GLenum internal_format = kUnsizedInternalFormats[i].unsized; | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | 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); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | TextureRef* ref = manager->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(ref != nullptr); | 
|  | Texture* texture = ref->texture(); | 
|  | GLenum chosen_type = 0; | 
|  | GLenum chosen_internal_format = 0; | 
|  | texture->GetLevelType(target, level, &chosen_type, &chosen_internal_format); | 
|  | EXPECT_NE(0u, chosen_type); | 
|  | EXPECT_NE(0u, chosen_internal_format); | 
|  |  | 
|  | // Attach texture to FBO, and copy into second texture using the sized | 
|  | // internal format. | 
|  | DoBindFramebuffer( | 
|  | GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); | 
|  | DoFramebufferTexture2D(GL_FRAMEBUFFER, | 
|  | GL_COLOR_ATTACHMENT0, | 
|  | GL_TEXTURE_2D, | 
|  | client_texture_id_, | 
|  | kServiceTextureId, | 
|  | 0, | 
|  | GL_NO_ERROR); | 
|  | if (DoCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) | 
|  | continue; | 
|  |  | 
|  | internal_format = kUnsizedInternalFormats[i].sized; | 
|  | DoBindTexture(GL_TEXTURE_2D, kNewClientId, kNewServiceId); | 
|  |  | 
|  | bool complete = | 
|  | (DoCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); | 
|  | if (complete) { | 
|  | EXPECT_CALL(*gl_, CopyTexImage2D(target, level, internal_format, 0, 0, | 
|  | width, height, border)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | cmd.Init(target, level, internal_format, 0, 0, width, height); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | if (complete) { | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } else { | 
|  | EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CompressedTexImage3DBucket) { | 
|  | const uint32_t kBucketId = 123; | 
|  | const uint32_t kBadBucketId = 99; | 
|  | const GLenum kTarget = GL_TEXTURE_2D_ARRAY; | 
|  | const GLint kLevel = 0; | 
|  | const GLenum kInternalFormat = GL_COMPRESSED_R11_EAC; | 
|  | const GLsizei kWidth = 4; | 
|  | const GLsizei kHeight = 4; | 
|  | const GLsizei kDepth = 4; | 
|  | const GLint kBorder = 0; | 
|  | CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId); | 
|  | ASSERT_TRUE(bucket != NULL); | 
|  | const GLsizei kImageSize = 32; | 
|  | bucket->SetSize(kImageSize); | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | CompressedTexImage3DBucket cmd; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | kWidth, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kBadBucketId); | 
|  | EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); | 
|  |  | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | kWidth, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kBucketId); | 
|  | EXPECT_CALL(*gl_, | 
|  | CompressedTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, | 
|  | kHeight, kDepth, kBorder, kImageSize, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CompressedTexImage3DBucketBucketSizeIsZero) { | 
|  | const uint32_t kBucketId = 123; | 
|  | const uint32_t kBadBucketId = 99; | 
|  | const GLenum kTarget = GL_TEXTURE_2D_ARRAY; | 
|  | const GLint kLevel = 0; | 
|  | const GLenum kInternalFormat = GL_COMPRESSED_R11_EAC; | 
|  | const GLsizei kWidth = 4; | 
|  | const GLsizei kHeight = 4; | 
|  | const GLsizei kDepth = 4; | 
|  | const GLint kBorder = 0; | 
|  | CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId); | 
|  | ASSERT_TRUE(bucket != NULL); | 
|  | const GLsizei kImageSize = 0; | 
|  | bucket->SetSize(kImageSize); | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | // Bad bucket | 
|  | CompressedTexImage3DBucket cmd; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | 0, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kBadBucketId); | 
|  | EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); | 
|  |  | 
|  | // Bucket size is zero. Height or width or depth is zero too. | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | 0, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kBucketId); | 
|  | EXPECT_CALL(*gl_, | 
|  | CompressedTexImage3D(kTarget, kLevel, kInternalFormat, 0, | 
|  | kHeight, kDepth, kBorder, kImageSize, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | // Bucket size is zero. But height, width and depth are not zero. | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | kWidth, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kBucketId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, CompressedTexImage3DFailsOnES2) { | 
|  | const uint32_t kBucketId = 123; | 
|  | const GLenum kTarget = GL_TEXTURE_2D_ARRAY; | 
|  | const GLint kLevel = 0; | 
|  | const GLenum kInternalFormat = GL_COMPRESSED_R11_EAC; | 
|  | const GLsizei kWidth = 4; | 
|  | const GLsizei kHeight = 4; | 
|  | const GLsizei kDepth = 4; | 
|  | CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId); | 
|  | ASSERT_TRUE(bucket != NULL); | 
|  | const GLsizei kImageSize = 32; | 
|  | bucket->SetSize(kImageSize); | 
|  |  | 
|  | { | 
|  | CompressedTexImage3DBucket cmd; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | kWidth, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kBucketId); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | { | 
|  | CompressedTexSubImage3DBucket cmd; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | 0, 0, 0, | 
|  | kWidth, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kInternalFormat, | 
|  | kBucketId); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, CopyTexSubImage3DFailsOnES2) { | 
|  | const GLenum kTarget = GL_TEXTURE_2D_ARRAY; | 
|  | const GLint kLevel = 0; | 
|  | const GLsizei kWidth = 4; | 
|  | const GLsizei kHeight = 4; | 
|  |  | 
|  | CopyTexSubImage3D cmd; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | 0, 0, 0, | 
|  | 0, 0, | 
|  | kWidth, | 
|  | kHeight); | 
|  | EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CopyTexSubImage3DFaiures) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kLevel = 1; | 
|  | const GLint kXoffset = 0; | 
|  | const GLint kYoffset = 0; | 
|  | const GLint kZoffset = 0; | 
|  | const GLint kX = 0; | 
|  | const GLint kY = 0; | 
|  | const GLsizei kWidth = 2; | 
|  | const GLsizei kHeight = 2; | 
|  | const GLsizei kDepth = 2; | 
|  |  | 
|  | CopyTexSubImage3D cmd; | 
|  |  | 
|  | // No texture bound | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  |  | 
|  | // Incompatible format / type | 
|  | // The default format/type of default read buffer is RGB/UNSIGNED_BYTE | 
|  | const GLint kInternalFormat = GL_RGBA8; | 
|  | const GLenum kFormat = GL_RGBA; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0, | 
|  | kFormat, kType, kSharedMemoryId, kSharedMemoryOffset); | 
|  |  | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CopyTexSubImage3DCheckArgs) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kLevel = 1; | 
|  | const GLint kInternalFormat = GL_RGB8; | 
|  | const GLint kXoffset = 0; | 
|  | const GLint kYoffset = 0; | 
|  | const GLint kZoffset = 0; | 
|  | const GLint kX = 0; | 
|  | const GLint kY = 0; | 
|  | const GLsizei kWidth = 2; | 
|  | const GLsizei kHeight = 2; | 
|  | const GLsizei kDepth = 2; | 
|  | const GLsizei kBorder = 0; | 
|  | const GLenum kFormat = GL_RGB; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, | 
|  | kBorder, kFormat, kType, kSharedMemoryId, kSharedMemoryOffset); | 
|  |  | 
|  | // Valid args | 
|  | EXPECT_CALL(*gl_, | 
|  | CopyTexSubImage3D(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | CopyTexSubImage3D cmd; | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | // Bad target | 
|  | cmd.Init(GL_TEXTURE_2D, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); | 
|  |  | 
|  | // Bad Level | 
|  | cmd.Init(kTarget, -1, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | cmd.Init(kTarget, 0, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  |  | 
|  | // Bad xoffest / yoffset of 3D texture | 
|  | cmd.Init(kTarget, kLevel, -1, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | cmd.Init(kTarget, kLevel, 1, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | cmd.Init(kTarget, kLevel, kXoffset, -1, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | cmd.Init(kTarget, kLevel, kXoffset, 1, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  |  | 
|  | // Bad zoffset: zoffset specifies the layer of the 3D texture to be replaced | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, -1, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kDepth, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  |  | 
|  | // Bad width / height | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth + 1, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight + 1); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CopyTexSubImage3DFeedbackLoopSucceeds0) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kInternalFormat = GL_RGB8; | 
|  | const GLint kXoffset = 0; | 
|  | const GLint kYoffset = 0; | 
|  | const GLint kZoffset = 0; | 
|  | const GLint kX = 0; | 
|  | const GLint kY = 0; | 
|  | const GLsizei kWidth = 2; | 
|  | const GLsizei kHeight = 2; | 
|  | const GLsizei kDepth = 2; | 
|  | const GLsizei kBorder = 0; | 
|  | const GLenum kFormat = GL_RGB; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoBindFramebuffer( | 
|  | GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); | 
|  |  | 
|  | FramebufferTextureLayer tex_layer; | 
|  | CopyTexSubImage3D cmd; | 
|  |  | 
|  | // The source and the target for CopyTexSubImage3D are the same 3d texture. | 
|  | // But level of 3D texture != level of read attachment in fbo. | 
|  | GLint kLevel = 0; | 
|  | GLint kLayer = 0; // kZoffset is 0 | 
|  | EXPECT_CALL(*gl_, FramebufferTextureLayer(GL_FRAMEBUFFER, | 
|  | GL_COLOR_ATTACHMENT0, | 
|  | kServiceTextureId, kLevel, kLayer)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, | 
|  | kBorder, kFormat, kType, kSharedMemoryId, kSharedMemoryOffset); | 
|  | tex_layer.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, client_texture_id_, | 
|  | kLevel, kLayer); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(tex_layer)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | kLevel = 1; | 
|  | EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_)) | 
|  | .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, | 
|  | CopyTexSubImage3D(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, | 
|  | kBorder, kFormat, kType, kSharedMemoryId, kSharedMemoryOffset); | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CopyTexSubImage3DFeedbackLoopSucceeds1) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kInternalFormat = GL_RGB8; | 
|  | const GLint kXoffset = 0; | 
|  | const GLint kYoffset = 0; | 
|  | const GLint kZoffset = 0; | 
|  | const GLint kX = 0; | 
|  | const GLint kY = 0; | 
|  | const GLsizei kWidth = 2; | 
|  | const GLsizei kHeight = 2; | 
|  | const GLsizei kDepth = 2; | 
|  | const GLsizei kBorder = 0; | 
|  | const GLenum kFormat = GL_RGB; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoBindFramebuffer( | 
|  | GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); | 
|  |  | 
|  | FramebufferTextureLayer tex_layer; | 
|  | CopyTexSubImage3D cmd; | 
|  |  | 
|  | // The source and the target for CopyTexSubImage3D are the same 3d texture. | 
|  | // But zoffset of 3D texture != layer of read attachment in fbo. | 
|  | GLint kLevel = 0; | 
|  | GLint kLayer = 1; // kZoffset is 0 | 
|  | EXPECT_CALL(*gl_, FramebufferTextureLayer(GL_FRAMEBUFFER, | 
|  | GL_COLOR_ATTACHMENT0, | 
|  | kServiceTextureId, kLevel, kLayer)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, | 
|  | kBorder, kFormat, kType, kSharedMemoryId, kSharedMemoryOffset); | 
|  | tex_layer.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, client_texture_id_, | 
|  | kLevel, kLayer); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(tex_layer)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_)) | 
|  | .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, | 
|  | CopyTexSubImage3D(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CopyTexSubImage3DFeedbackLoopFails) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kInternalFormat = GL_RGB8; | 
|  | const GLint kXoffset = 0; | 
|  | const GLint kYoffset = 0; | 
|  | const GLint kZoffset = 0; | 
|  | const GLint kX = 0; | 
|  | const GLint kY = 0; | 
|  | const GLsizei kWidth = 2; | 
|  | const GLsizei kHeight = 2; | 
|  | const GLsizei kDepth = 2; | 
|  | const GLsizei kBorder = 0; | 
|  | const GLenum kFormat = GL_RGB; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoBindFramebuffer( | 
|  | GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); | 
|  |  | 
|  | FramebufferTextureLayer tex_layer; | 
|  | CopyTexSubImage3D cmd; | 
|  |  | 
|  | // The source and the target for CopyTexSubImage3D are the same 3d texture. | 
|  | // And level / zoffset of 3D texture equal to level / layer of read attachment | 
|  | // in fbo. | 
|  | GLint kLevel = 1; | 
|  | GLint kLayer = 0; // kZoffset is 0 | 
|  | EXPECT_CALL(*gl_, FramebufferTextureLayer(GL_FRAMEBUFFER, | 
|  | GL_COLOR_ATTACHMENT0, | 
|  | kServiceTextureId, kLevel, kLayer)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, | 
|  | kBorder, kFormat, kType, kSharedMemoryId, kSharedMemoryOffset); | 
|  | tex_layer.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, client_texture_id_, | 
|  | kLevel, kLayer); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(tex_layer)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_)) | 
|  | .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) | 
|  | .RetiresOnSaturation(); | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CopyTexSubImage3DClearTheUncleared3DTexture) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kLevel = 0; | 
|  | const GLint kXoffset = 0; | 
|  | const GLint kYoffset = 0; | 
|  | const GLint kZoffset = 0; | 
|  | const GLint kX = 0; | 
|  | const GLint kY = 0; | 
|  | const GLint kInternalFormat = GL_RGB8; | 
|  | const GLsizei kWidth = 2; | 
|  | const GLsizei kHeight = 2; | 
|  | const GLsizei kDepth = 2; | 
|  | const GLenum kFormat = GL_RGB; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  | const uint32_t kBufferSize = kWidth * kHeight * kDepth * 4; | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0, | 
|  | kFormat, kType, 0, 0); | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  |  | 
|  | EXPECT_FALSE(texture->SafeToRenderFrom()); | 
|  | EXPECT_FALSE(texture->IsLevelCleared(kTarget, kLevel)); | 
|  |  | 
|  | // CopyTexSubImage3D will clear the uncleared texture | 
|  | EXPECT_CALL(*gl_, GenBuffersARB(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BufferData(GL_PIXEL_UNPACK_BUFFER, | 
|  | kBufferSize, _, GL_STATIC_DRAW)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(kTarget, kServiceTextureId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, | 
|  | kXoffset, kYoffset, kZoffset, | 
|  | kWidth, kHeight, kDepth, | 
|  | kFormat, kType)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(kTarget, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, | 
|  | CopyTexSubImage3D(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | CopyTexSubImage3D cmd; | 
|  | cmd.Init(kTarget, kLevel, kXoffset, kYoffset, kZoffset, | 
|  | kX, kY, kWidth, kHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | EXPECT_TRUE(texture->SafeToRenderFrom()); | 
|  | EXPECT_TRUE(texture->IsLevelCleared(kTarget, kLevel)); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CompressedTexImage3DFailsWithBadImageSize) { | 
|  | const uint32_t kBucketId = 123; | 
|  | const GLenum kTarget = GL_TEXTURE_2D_ARRAY; | 
|  | const GLint kLevel = 0; | 
|  | const GLenum kInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; | 
|  | const GLsizei kWidth = 4; | 
|  | const GLsizei kHeight = 8; | 
|  | const GLsizei kDepth = 4; | 
|  | CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId); | 
|  | ASSERT_TRUE(bucket != NULL); | 
|  | const GLsizei kBadImageSize = 64; | 
|  | bucket->SetSize(kBadImageSize); | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | CompressedTexImage3DBucket cmd; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | kWidth, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kBucketId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CompressedTexSubImage3DFails) { | 
|  | const uint32_t kBucketId = 123; | 
|  | const GLenum kTarget = GL_TEXTURE_2D_ARRAY; | 
|  | const GLint kLevel = 0; | 
|  | const GLenum kInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; | 
|  | const GLsizei kWidth = 4; | 
|  | const GLsizei kHeight = 8; | 
|  | const GLsizei kDepth = 4; | 
|  | const GLint kBorder = 0; | 
|  | CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId); | 
|  | ASSERT_TRUE(bucket != NULL); | 
|  | const GLsizei kImageSize = 128; | 
|  | bucket->SetSize(kImageSize); | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | CompressedTexImage3DBucket tex_cmd; | 
|  | tex_cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | kWidth, | 
|  | kHeight, | 
|  | kDepth, | 
|  | kBucketId); | 
|  | EXPECT_CALL(*gl_, | 
|  | CompressedTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, | 
|  | kHeight, kDepth, kBorder, kImageSize, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | const GLint kXOffset = 0; | 
|  | const GLint kYOffset = 0; | 
|  | const GLint kZOffset = 0; | 
|  | const GLint kSubWidth = 4; | 
|  | const GLint kSubHeight = 4; | 
|  | const GLint kSubDepth = 4; | 
|  | const GLenum kFormat = kInternalFormat; | 
|  | CompressedTexSubImage3DBucket cmd; | 
|  |  | 
|  | // Incorrect image size. | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | kYOffset, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight, | 
|  | kSubDepth, | 
|  | kFormat, | 
|  | kBucketId); | 
|  | const GLsizei kBadSubImageSize = 32; | 
|  | const GLsizei kSubImageSize = 64; | 
|  | bucket->SetSize(kBadSubImageSize); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  |  | 
|  | // Incorrect format. | 
|  | const GLenum kBadFormat = GL_COMPRESSED_R11_EAC; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | kYOffset, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight, | 
|  | kSubDepth, | 
|  | kBadFormat, | 
|  | kBucketId); | 
|  | bucket->SetSize(kSubImageSize); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  |  | 
|  | // Negative offset. | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | -4, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight, | 
|  | kSubDepth, | 
|  | kFormat, | 
|  | kBucketId); | 
|  | bucket->SetSize(kSubImageSize); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  |  | 
|  | // offset + size > texture size | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | kYOffset + 8, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight, | 
|  | kSubDepth, | 
|  | kFormat, | 
|  | kBucketId); | 
|  | bucket->SetSize(kSubImageSize); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  |  | 
|  | // offset not a multiple of 4. | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | kYOffset + 1, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight, | 
|  | kSubDepth, | 
|  | kFormat, | 
|  | kBucketId); | 
|  | bucket->SetSize(kSubImageSize); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  |  | 
|  | // offset + width not a multlple of 4 . | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | kYOffset, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight + 3, | 
|  | kSubDepth, | 
|  | kFormat, | 
|  | kBucketId); | 
|  | const GLsizei kSubImageSize2 = 128; | 
|  | bucket->SetSize(kSubImageSize2); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  |  | 
|  | // Bad bucket id. | 
|  | const uint32_t kBadBucketId = 444; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | kYOffset, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight, | 
|  | kSubDepth, | 
|  | kFormat, | 
|  | kBadBucketId); | 
|  | bucket->SetSize(kSubImageSize); | 
|  | EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); | 
|  |  | 
|  | // Bad target | 
|  | cmd.Init(GL_RGBA, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | kYOffset, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight, | 
|  | kSubDepth, | 
|  | kFormat, | 
|  | kBucketId); | 
|  | bucket->SetSize(kSubImageSize); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); | 
|  |  | 
|  | // Bad format | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kXOffset, | 
|  | kYOffset, | 
|  | kZOffset, | 
|  | kSubWidth, | 
|  | kSubHeight, | 
|  | kSubDepth, | 
|  | GL_ONE, | 
|  | kBucketId); | 
|  | bucket->SetSize(kSubImageSize); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, CompressedTexImage2DBucketBucketSizeIsZero) { | 
|  | const uint32_t kBucketId = 123; | 
|  | const uint32_t kBadBucketId = 99; | 
|  | const GLenum kTarget = GL_TEXTURE_2D; | 
|  | const GLint kLevel = 0; | 
|  | const GLenum kInternalFormat = GL_COMPRESSED_R11_EAC; | 
|  | const GLsizei kWidth = 4; | 
|  | const GLsizei kHeight = 4; | 
|  | const GLint kBorder = 0; | 
|  | CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId); | 
|  | ASSERT_TRUE(bucket != NULL); | 
|  | const GLsizei kImageSize = 0; | 
|  | bucket->SetSize(kImageSize); | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | // Bad bucket | 
|  | CompressedTexImage2DBucket cmd; | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | 0, | 
|  | kHeight, | 
|  | kBadBucketId); | 
|  | EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); | 
|  |  | 
|  | // Bucket size is zero. Height or width is zero too. | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | 0, | 
|  | kHeight, | 
|  | kBucketId); | 
|  | EXPECT_CALL(*gl_, | 
|  | CompressedTexImage2D(kTarget, kLevel, kInternalFormat, 0, | 
|  | kHeight, kBorder, kImageSize, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | // Bucket size is zero. But height and width are not zero. | 
|  | cmd.Init(kTarget, | 
|  | kLevel, | 
|  | kInternalFormat, | 
|  | kWidth, | 
|  | kHeight, | 
|  | kBucketId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, CompressedTexImage2DBucketBadBucket) { | 
|  | InitState init; | 
|  | init.extensions = "GL_EXT_texture_compression_s3tc"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | const uint32_t 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, | 
|  | 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_P(GLES2DecoderManualInitTest, CompressedTexImage2DS3TC) { | 
|  | InitState init; | 
|  | init.extensions = "GL_EXT_texture_compression_s3tc"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | const uint32_t 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, 1, 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, 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, 1, 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, 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, 1, test.format, 1, 1, 0, test.block_size, kBucketId); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | // test small for level 0. | 
|  | DoCompressedTexImage2D( | 
|  | GL_TEXTURE_2D, 1, 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, 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, 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_P(GLES2DecoderManualInitTest, CompressedTexImage2DETC1) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_compressed_ETC1_RGB8_texture"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | const uint32_t 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, 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, 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_P(GLES2DecoderManualInitTest, EGLImageExternalBindTexture) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_EGL_image_external"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_P(GLES2DecoderManualInitTest, EGLImageExternalGetBinding) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_EGL_image_external"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_t)result->GetData()[0]); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, EGLImageExternalTextureDefaults) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_EGL_image_external"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_P(GLES2DecoderManualInitTest, EGLImageExternalTextureParam) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_EGL_image_external"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_P(GLES2DecoderManualInitTest, EGLImageExternalTextureParamInvalid) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_EGL_image_external"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_P(GLES2DecoderManualInitTest, EGLImageExternalTexImage2DError) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_EGL_image_external"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | GLenum target = GL_TEXTURE_EXTERNAL_OES; | 
|  | GLint level = 0; | 
|  | GLenum internal_format = GL_RGBA; | 
|  | GLsizei width = 2; | 
|  | GLsizei height = 4; | 
|  | 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, | 
|  | 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_P(GLES2DecoderManualInitTest, DefaultTextureZero) { | 
|  | InitState init; | 
|  | InitDecoder(init); | 
|  |  | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_2D, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | BindTexture cmd2; | 
|  | cmd2.Init(GL_TEXTURE_CUBE_MAP, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_CUBE_MAP, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, DefaultTextureBGR) { | 
|  | InitState init; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_2D, 0); | 
|  | EXPECT_CALL( | 
|  | *gl_, BindTexture(GL_TEXTURE_2D, TestHelper::kServiceDefaultTexture2dId)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | BindTexture cmd2; | 
|  | cmd2.Init(GL_TEXTURE_CUBE_MAP, 0); | 
|  | EXPECT_CALL(*gl_, | 
|  | BindTexture(GL_TEXTURE_CUBE_MAP, | 
|  | TestHelper::kServiceDefaultTextureCubemapId)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | // Test that default texture 0 is immutable. | 
|  | TEST_P(GLES2DecoderManualInitTest, NoDefaultTexParameterf) { | 
|  | InitState init; | 
|  | InitDecoder(init); | 
|  |  | 
|  | { | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_2D, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | TexParameterf cmd2; | 
|  | cmd2.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | { | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_CUBE_MAP, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_CUBE_MAP, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | TexParameterf cmd2; | 
|  | cmd2.Init(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, NoDefaultTexParameteri) { | 
|  | InitState init; | 
|  | InitDecoder(init); | 
|  |  | 
|  | { | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_2D, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | TexParameteri cmd2; | 
|  | cmd2.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | { | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_CUBE_MAP, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_CUBE_MAP, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | TexParameteri cmd2; | 
|  | cmd2.Init(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, NoDefaultTexParameterfv) { | 
|  | InitState init; | 
|  | InitDecoder(init); | 
|  |  | 
|  | { | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_2D, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | GLfloat data = GL_NEAREST; | 
|  | TexParameterfvImmediate& cmd2 = | 
|  | *GetImmediateAs<TexParameterfvImmediate>(); | 
|  | cmd2.Init(GL_TEXTURE_2D, | 
|  | GL_TEXTURE_MAG_FILTER, | 
|  | &data); | 
|  | EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd2, sizeof(data))); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | { | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_CUBE_MAP, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_CUBE_MAP, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | GLfloat data = GL_NEAREST; | 
|  | TexParameterfvImmediate& cmd2 = | 
|  | *GetImmediateAs<TexParameterfvImmediate>(); | 
|  | cmd2.Init(GL_TEXTURE_CUBE_MAP, | 
|  | GL_TEXTURE_MAG_FILTER, | 
|  | &data); | 
|  | EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd2, sizeof(data))); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, NoDefaultTexParameteriv) { | 
|  | InitState init; | 
|  | InitDecoder(init); | 
|  |  | 
|  | { | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_2D, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | GLfloat data = GL_NEAREST; | 
|  | TexParameterfvImmediate& cmd2 = | 
|  | *GetImmediateAs<TexParameterfvImmediate>(); | 
|  | cmd2.Init(GL_TEXTURE_2D, | 
|  | GL_TEXTURE_MAG_FILTER, | 
|  | &data); | 
|  | EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd2, sizeof(data))); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | { | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_CUBE_MAP, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_CUBE_MAP, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | GLfloat data = GL_NEAREST; | 
|  | TexParameterfvImmediate& cmd2 = | 
|  | *GetImmediateAs<TexParameterfvImmediate>(); | 
|  | cmd2.Init(GL_TEXTURE_CUBE_MAP, | 
|  | GL_TEXTURE_MAG_FILTER, | 
|  | &data); | 
|  | EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd2, sizeof(data))); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, NoDefaultTexImage2D) { | 
|  | InitState init; | 
|  | InitDecoder(init); | 
|  |  | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_2D, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | TexImage2D cmd2; | 
|  | cmd2.Init(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | 2, | 
|  | 2, | 
|  | GL_RGBA, | 
|  | GL_UNSIGNED_BYTE, | 
|  | kSharedMemoryId, | 
|  | kSharedMemoryOffset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, NoDefaultTexSubImage2D) { | 
|  | InitState init; | 
|  | InitDecoder(init); | 
|  |  | 
|  | BindTexture cmd1; | 
|  | cmd1.Init(GL_TEXTURE_2D, 0); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, 0)); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | TexSubImage2D cmd2; | 
|  | cmd2.Init(GL_TEXTURE_2D, | 
|  | 0, | 
|  | 1, | 
|  | 1, | 
|  | 1, | 
|  | 1, | 
|  | GL_RGBA, | 
|  | GL_UNSIGNED_BYTE, | 
|  | kSharedMemoryId, | 
|  | kSharedMemoryOffset, | 
|  | GL_FALSE); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, ARBTextureRectangleBindTexture) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ARB_texture_rectangle"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_P(GLES2DecoderManualInitTest, ARBTextureRectangleGetBinding) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ARB_texture_rectangle"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_t)result->GetData()[0]); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, ARBTextureRectangleTextureDefaults) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ARB_texture_rectangle"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_P(GLES2DecoderManualInitTest, ARBTextureRectangleTextureParam) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ARB_texture_rectangle"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | 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_P(GLES2DecoderManualInitTest, ARBTextureRectangleTextureParamInvalid) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ARB_texture_rectangle"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | 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_P(GLES2DecoderManualInitTest, ARBTextureRectangleTexImage2D) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ARB_texture_rectangle"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | GLenum target = GL_TEXTURE_RECTANGLE_ARB; | 
|  | GLint level = 0; | 
|  | GLenum internal_format = GL_RGBA; | 
|  | GLsizei width = 2; | 
|  | GLsizei height = 4; | 
|  | 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, | 
|  | format, | 
|  | type, | 
|  | kSharedMemoryId, | 
|  | kSharedMemoryOffset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  |  | 
|  | EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, ARBTextureRectangleTexImage2DInvalid) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ARB_texture_rectangle"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | GLenum target = GL_TEXTURE_RECTANGLE_ARB; | 
|  | GLint level = 1; | 
|  | GLenum internal_format = GL_RGBA; | 
|  | GLsizei width = 2; | 
|  | GLsizei height = 4; | 
|  | 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, | 
|  | format, | 
|  | type, | 
|  | kSharedMemoryId, | 
|  | kSharedMemoryOffset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  |  | 
|  | EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, TexSubImage2DClearsAfterTexImage2DNULL) { | 
|  | InitState init; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.has_alpha = true; | 
|  | init.has_depth = true; | 
|  | init.request_alpha = true; | 
|  | init.request_depth = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | 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); | 
|  | SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId, | 
|  | GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA, | 
|  | GL_RGBA, GL_UNSIGNED_BYTE, 0, 1, 2, 1); | 
|  | EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, 1, GL_RGBA, | 
|  | GL_UNSIGNED_BYTE, shared_memory_address_)) | 
|  | .Times(2) | 
|  | .RetiresOnSaturation(); | 
|  | TexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE, | 
|  | kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 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, 0, 1, 1, 1, GL_RGBA, | 
|  | GL_UNSIGNED_BYTE, shared_memory_address_)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | TEST_P(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_P( | 
|  | GLES2DecoderManualInitTest, | 
|  | TexSubImage2DDoesNotClearAfterTexImage2DNULLThenDataWithTexImage2DIsFaster) { | 
|  | base::CommandLine command_line(0, NULL); | 
|  | command_line.AppendSwitchASCII( | 
|  | switches::kGpuDriverBugWorkarounds, | 
|  | base::IntToString(gpu::TEXSUBIMAGE_FASTER_THAN_TEXIMAGE)); | 
|  | InitState init; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoderWithCommandLine(init, &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(); | 
|  | TexImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | 2, | 
|  | 2, | 
|  | 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_P(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, 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. | 
|  | SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId, | 
|  | GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA, | 
|  | GL_RGBA, GL_UNSIGNED_BYTE, 0, 1, 2, 1); | 
|  | EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, 1, GL_RGBA, | 
|  | GL_UNSIGNED_BYTE, shared_memory_address_)) | 
|  | .Times(2) | 
|  | .RetiresOnSaturation(); | 
|  | TexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE, | 
|  | kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, | 
|  | kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | TEST_P(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); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  |  | 
|  | EXPECT_TRUE(texture->SafeToRenderFrom()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, CopyTexSubImage2DTwiceMarksTextureAsCleared) { | 
|  | 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); | 
|  |  | 
|  | // This will initialize the top part. | 
|  | { | 
|  | EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 1)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | CopyTexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 1); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | // This will initialize the bottom part. | 
|  | { | 
|  | EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 1, 0, 0, 2, 1)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | CopyTexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 1, 0, 0, 2, 1); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | TextureManager* manager = group().texture_manager(); | 
|  | TextureRef* texture_ref = manager->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  | EXPECT_TRUE(texture->SafeToRenderFrom()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, CopyTexSubImage2DTwiceClearsUnclearedTexture) { | 
|  | 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); | 
|  |  | 
|  | // This will initialize the top part. | 
|  | { | 
|  | EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 1)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | CopyTexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 1); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId, | 
|  | GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA, | 
|  | GL_RGBA, GL_UNSIGNED_BYTE, 0, 1, 2, 1); | 
|  |  | 
|  | // This will clear the bottom part as a rectangle is not sufficient to keep | 
|  | // track of the initialized area. | 
|  | { | 
|  | EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 1, 1, 0, 0, 1, 1)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | CopyTexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 1, 1, 0, 0, 1, 1); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | TextureManager* manager = group().texture_manager(); | 
|  | TextureRef* texture_ref = manager->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  | EXPECT_TRUE(texture->SafeToRenderFrom()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, CopyTexSubImage2DClearsUnclearedBackBufferSizedTexture) { | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kBackBufferWidth, kBackBufferHeight, | 
|  | 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); | 
|  |  | 
|  | EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, | 
|  | kBackBufferWidth, kBackBufferHeight)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | CopyTexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kBackBufferWidth, kBackBufferHeight); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  |  | 
|  | TextureManager* manager = group().texture_manager(); | 
|  | TextureRef* texture_ref = manager->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  | EXPECT_TRUE(texture->SafeToRenderFrom()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, CompressedImage2DMarksTextureAsCleared) { | 
|  | InitState init; | 
|  | init.extensions = "GL_EXT_texture_compression_s3tc"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | 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, | 
|  | 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_P(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_P(GLES2DecoderTest, ProduceAndConsumeTextureCHROMIUM) { | 
|  | Mailbox mailbox = Mailbox::Generate(); | 
|  |  | 
|  | 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()); | 
|  |  | 
|  | ProduceTextureCHROMIUMImmediate& produce_cmd = | 
|  | *GetImmediateAs<ProduceTextureCHROMIUMImmediate>(); | 
|  | produce_cmd.Init(GL_TEXTURE_2D, mailbox.name); | 
|  | EXPECT_EQ(error::kNoError, | 
|  | ExecuteImmediateCmd(produce_cmd, sizeof(mailbox.name))); | 
|  | 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, nullptr)); | 
|  | 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, nullptr)); | 
|  | 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_, BindTexture(GL_TEXTURE_2D, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, DeleteTextures(1, _)).Times(1).RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | ConsumeTextureCHROMIUMImmediate& consume_cmd = | 
|  | *GetImmediateAs<ConsumeTextureCHROMIUMImmediate>(); | 
|  | consume_cmd.Init(GL_TEXTURE_2D, mailbox.name); | 
|  | EXPECT_EQ(error::kNoError, | 
|  | ExecuteImmediateCmd(consume_cmd, sizeof(mailbox.name))); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | // Texture is redefined. | 
|  | EXPECT_TRUE( | 
|  | texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, nullptr)); | 
|  | 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, nullptr)); | 
|  | 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_P(GLES2DecoderTest, ProduceAndConsumeDirectTextureCHROMIUM) { | 
|  | Mailbox mailbox = Mailbox::Generate(); | 
|  |  | 
|  | 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()); | 
|  |  | 
|  | ProduceTextureDirectCHROMIUMImmediate& produce_cmd = | 
|  | *GetImmediateAs<ProduceTextureDirectCHROMIUMImmediate>(); | 
|  | produce_cmd.Init(client_texture_id_, GL_TEXTURE_2D, mailbox.name); | 
|  | EXPECT_EQ(error::kNoError, | 
|  | ExecuteImmediateCmd(produce_cmd, sizeof(mailbox.name))); | 
|  | 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, nullptr)); | 
|  | 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, nullptr)); | 
|  | 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()); | 
|  |  | 
|  | // Consume the texture into a new client ID. | 
|  | GLuint new_texture_id = kNewClientId; | 
|  | CreateAndConsumeTextureINTERNALImmediate& consume_cmd = | 
|  | *GetImmediateAs<CreateAndConsumeTextureINTERNALImmediate>(); | 
|  | consume_cmd.Init(GL_TEXTURE_2D, new_texture_id, mailbox.name); | 
|  | EXPECT_EQ(error::kNoError, | 
|  | ExecuteImmediateCmd(consume_cmd, sizeof(mailbox.name))); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | // Make sure the new client ID is associated with the produced service ID. | 
|  | texture_ref = group().texture_manager()->GetTexture(new_texture_id); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | texture = texture_ref->texture(); | 
|  | EXPECT_EQ(kServiceTextureId, texture->service_id()); | 
|  |  | 
|  | DoBindTexture(GL_TEXTURE_2D, kNewClientId, kServiceTextureId); | 
|  |  | 
|  | // Texture is redefined. | 
|  | EXPECT_TRUE( | 
|  | texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, nullptr)); | 
|  | 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, nullptr)); | 
|  | 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); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, ProduceTextureCHROMIUMInvalidTarget) { | 
|  | Mailbox mailbox = Mailbox::Generate(); | 
|  |  | 
|  | DoBindTexture(GL_TEXTURE_CUBE_MAP, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D( | 
|  | GL_TEXTURE_CUBE_MAP_POSITIVE_X, 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()); | 
|  |  | 
|  | ProduceTextureDirectCHROMIUMImmediate& produce_cmd = | 
|  | *GetImmediateAs<ProduceTextureDirectCHROMIUMImmediate>(); | 
|  | produce_cmd.Init(client_texture_id_, GL_TEXTURE_2D, mailbox.name); | 
|  | EXPECT_EQ(error::kNoError, | 
|  | ExecuteImmediateCmd(produce_cmd, sizeof(mailbox.name))); | 
|  |  | 
|  | // ProduceTexture should fail it the texture and produce targets don't match. | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, CreateAndConsumeTextureCHROMIUMInvalidMailbox) { | 
|  | // Attempt to consume the mailbox when no texture has been produced with it. | 
|  | Mailbox mailbox = Mailbox::Generate(); | 
|  | GLuint new_texture_id = kNewClientId; | 
|  |  | 
|  | EXPECT_CALL(*gl_, GenTextures(1, _)) | 
|  | .WillOnce(SetArgumentPointee<1>(kNewServiceId)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, _)) | 
|  | .Times(2) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | CreateAndConsumeTextureINTERNALImmediate& consume_cmd = | 
|  | *GetImmediateAs<CreateAndConsumeTextureINTERNALImmediate>(); | 
|  | consume_cmd.Init(GL_TEXTURE_2D, new_texture_id, mailbox.name); | 
|  | EXPECT_EQ(error::kNoError, | 
|  | ExecuteImmediateCmd(consume_cmd, sizeof(mailbox.name))); | 
|  |  | 
|  | // CreateAndConsumeTexture should fail if the mailbox isn't associated with a | 
|  | // texture. | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  |  | 
|  | // Make sure the new client_id is associated with a texture ref even though | 
|  | // CreateAndConsumeTexture failed. | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(new_texture_id); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  | // New texture should have the correct target type. | 
|  | EXPECT_TRUE(texture->target() == GL_TEXTURE_2D); | 
|  | // New texture should have a valid service_id. | 
|  | EXPECT_EQ(kNewServiceId, texture->service_id()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, CreateAndConsumeTextureCHROMIUMInvalidTarget) { | 
|  | Mailbox mailbox = Mailbox::Generate(); | 
|  |  | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  |  | 
|  | ProduceTextureDirectCHROMIUMImmediate& produce_cmd = | 
|  | *GetImmediateAs<ProduceTextureDirectCHROMIUMImmediate>(); | 
|  | produce_cmd.Init(client_texture_id_, GL_TEXTURE_2D, mailbox.name); | 
|  | EXPECT_EQ(error::kNoError, | 
|  | ExecuteImmediateCmd(produce_cmd, sizeof(mailbox.name))); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GenTextures(1, _)) | 
|  | .WillOnce(SetArgumentPointee<1>(kNewServiceId)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_CUBE_MAP, _)) | 
|  | .Times(2) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | // Attempt to consume the mailbox with a different target. | 
|  | GLuint new_texture_id = kNewClientId; | 
|  | CreateAndConsumeTextureINTERNALImmediate& consume_cmd = | 
|  | *GetImmediateAs<CreateAndConsumeTextureINTERNALImmediate>(); | 
|  | consume_cmd.Init(GL_TEXTURE_CUBE_MAP, new_texture_id, mailbox.name); | 
|  | EXPECT_EQ(error::kNoError, | 
|  | ExecuteImmediateCmd(consume_cmd, sizeof(mailbox.name))); | 
|  |  | 
|  | // CreateAndConsumeTexture should fail if the produced texture had a different | 
|  | // target. | 
|  | EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); | 
|  |  | 
|  | // Make sure the new client_id is associated with a texture ref even though | 
|  | // CreateAndConsumeTexture failed. | 
|  | texture_ref = group().texture_manager()->GetTexture(new_texture_id); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  | // New texture should have the correct target type. | 
|  | EXPECT_TRUE(texture->target() == GL_TEXTURE_CUBE_MAP); | 
|  | // New texture should have a valid service_id. | 
|  | EXPECT_EQ(kNewServiceId, texture->service_id()); | 
|  |  | 
|  | // Make sure the client_id did not become associated with the produced texture | 
|  | // service_id. | 
|  | EXPECT_NE(kServiceTextureId, texture->service_id()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, DepthTextureBadArgs) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ANGLE_depth_texture"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.has_depth = true; | 
|  | init.has_stencil = true; | 
|  | init.request_depth = true; | 
|  | init.request_stencil = true; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | 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, | 
|  | 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, | 
|  | 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); | 
|  | 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_P(GLES2DecoderManualInitTest, GenerateMipmapDepthTexture) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ANGLE_depth_texture"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.has_depth = true; | 
|  | init.has_stencil = true; | 
|  | init.request_depth = true; | 
|  | init.request_stencil = true; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | 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_P(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()); | 
|  |  | 
|  | scoped_refptr<gl::GLImage> image(new gl::GLImageStub); | 
|  | GetImageManager()->AddImage(image.get(), 1); | 
|  | EXPECT_FALSE(GetImageManager()->LookupImage(1) == NULL); | 
|  |  | 
|  | GLsizei width; | 
|  | GLsizei height; | 
|  | GLenum type; | 
|  | GLenum internal_format; | 
|  |  | 
|  | EXPECT_TRUE( | 
|  | texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, nullptr)); | 
|  | 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. | 
|  | DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1); | 
|  | EXPECT_TRUE( | 
|  | texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, nullptr)); | 
|  | // 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, nullptr)); | 
|  | // Image should no longer be set. | 
|  | EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, BindTexImage2DCHROMIUMCubeMapNotAllowed) { | 
|  | scoped_refptr<gl::GLImage> image(new gl::GLImageStub); | 
|  | GetImageManager()->AddImage(image.get(), 1); | 
|  | DoBindTexture(GL_TEXTURE_CUBE_MAP, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | BindTexImage2DCHROMIUM bind_tex_image_2d_cmd; | 
|  | bind_tex_image_2d_cmd.Init(GL_TEXTURE_CUBE_MAP, 1); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(bind_tex_image_2d_cmd)); | 
|  | EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, OrphanGLImageWithTexImage2D) { | 
|  | scoped_refptr<gl::GLImage> image(new gl::GLImageStub); | 
|  | GetImageManager()->AddImage(image.get(), 1); | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1); | 
|  |  | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  |  | 
|  | EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == image.get()); | 
|  | DoTexImage2D( | 
|  | GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); | 
|  | EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, GLImageAttachedAfterSubTexImage2D) { | 
|  | // Specifically tests that TexSubImage2D is not optimized to TexImage2D | 
|  | // in the presence of image attachments. | 
|  | ASSERT_FALSE( | 
|  | feature_info()->workarounds().texsubimage_faster_than_teximage); | 
|  |  | 
|  | scoped_refptr<gl::GLImage> image(new gl::GLImageStub); | 
|  | GetImageManager()->AddImage(image.get(), 1); | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | GLenum target = GL_TEXTURE_2D; | 
|  | GLint level = 0; | 
|  | GLint xoffset = 0; | 
|  | GLint yoffset = 0; | 
|  | GLsizei width = 1; | 
|  | GLsizei height = 1; | 
|  | GLint border = 0; | 
|  | GLenum format = GL_RGBA; | 
|  | GLenum type = GL_UNSIGNED_BYTE; | 
|  | uint32_t pixels_shm_id = kSharedMemoryId; | 
|  | uint32_t pixels_shm_offset = kSharedMemoryOffset; | 
|  | GLboolean internal = 0; | 
|  |  | 
|  | // Define texture first. | 
|  | DoTexImage2D(target, level, format, width, height, border, format, type, | 
|  | pixels_shm_id, pixels_shm_offset); | 
|  |  | 
|  | // Bind texture to GLImage. | 
|  | DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1); | 
|  |  | 
|  | // Check binding. | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  | EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == image.get()); | 
|  |  | 
|  | // TexSubImage2D should not unbind GLImage. | 
|  | EXPECT_CALL(*gl_, TexSubImage2D(target, level, xoffset, yoffset, width, | 
|  | height, format, type, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | TexSubImage2D tex_sub_image_2d_cmd; | 
|  | tex_sub_image_2d_cmd.Init(target, level, xoffset, yoffset, width, height, | 
|  | format, type, pixels_shm_id, pixels_shm_offset, | 
|  | internal); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(tex_sub_image_2d_cmd)); | 
|  | EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == image.get()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, GLImageAttachedAfterClearLevel) { | 
|  | scoped_refptr<gl::GLImage> image(new gl::GLImageStub); | 
|  | GetImageManager()->AddImage(image.get(), 1); | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  |  | 
|  | GLenum target = GL_TEXTURE_2D; | 
|  | GLint level = 0; | 
|  | GLint xoffset = 0; | 
|  | GLint yoffset = 0; | 
|  | GLsizei width = 1; | 
|  | GLsizei height = 1; | 
|  | GLint border = 0; | 
|  | GLenum format = GL_RGBA; | 
|  | GLenum type = GL_UNSIGNED_BYTE; | 
|  | uint32_t pixels_shm_id = kSharedMemoryId; | 
|  | uint32_t pixels_shm_offset = kSharedMemoryOffset; | 
|  |  | 
|  | // Define texture first. | 
|  | DoTexImage2D(target, level, format, width, height, border, format, type, | 
|  | pixels_shm_id, pixels_shm_offset); | 
|  |  | 
|  | // Bind texture to GLImage. | 
|  | DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1); | 
|  |  | 
|  | // Check binding. | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  | EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == image.get()); | 
|  |  | 
|  | // ClearLevel should use glTexSubImage2D to avoid unbinding GLImage. | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) | 
|  | .Times(2) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexSubImage2D(target, level, xoffset, yoffset, width, | 
|  | height, format, type, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | GetDecoder()->ClearLevel(texture, target, level, format, type, 0, 0, width, | 
|  | height); | 
|  | EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == image.get()); | 
|  | } | 
|  |  | 
|  | TEST_P(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()); | 
|  |  | 
|  | scoped_refptr<gl::GLImage> image(new gl::GLImageStub); | 
|  | GetImageManager()->AddImage(image.get(), 1); | 
|  | EXPECT_FALSE(GetImageManager()->LookupImage(1) == NULL); | 
|  |  | 
|  | GLsizei width; | 
|  | GLsizei height; | 
|  | GLenum type; | 
|  | GLenum internal_format; | 
|  |  | 
|  | EXPECT_TRUE( | 
|  | texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, nullptr)); | 
|  | 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. | 
|  | DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1); | 
|  | EXPECT_TRUE( | 
|  | texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, nullptr)); | 
|  | // 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, nullptr)); | 
|  | // Image should no longer be set. | 
|  | EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); | 
|  | } | 
|  |  | 
|  | class MockGLImage : public gl::GLImage { | 
|  | public: | 
|  | MockGLImage() {} | 
|  |  | 
|  | // Overridden from gl::GLImage: | 
|  | MOCK_METHOD0(GetSize, gfx::Size()); | 
|  | MOCK_METHOD0(GetInternalFormat, unsigned()); | 
|  | MOCK_METHOD1(Destroy, void(bool)); | 
|  | MOCK_METHOD1(BindTexImage, bool(unsigned)); | 
|  | MOCK_METHOD1(ReleaseTexImage, void(unsigned)); | 
|  | MOCK_METHOD1(CopyTexImage, bool(unsigned)); | 
|  | MOCK_METHOD3(CopyTexSubImage, | 
|  | bool(unsigned, const gfx::Point&, const gfx::Rect&)); | 
|  | MOCK_METHOD5(ScheduleOverlayPlane, bool(gfx::AcceleratedWidget, | 
|  | int, | 
|  | gfx::OverlayTransform, | 
|  | const gfx::Rect&, | 
|  | const gfx::RectF&)); | 
|  | MOCK_METHOD3(OnMemoryDump, | 
|  | void(base::trace_event::ProcessMemoryDump*, | 
|  | uint64_t, | 
|  | const std::string&)); | 
|  | void Flush() override {} | 
|  |  | 
|  | protected: | 
|  | virtual ~MockGLImage() {} | 
|  | }; | 
|  |  | 
|  | TEST_P(GLES2DecoderWithShaderTest, CopyTexImage) { | 
|  | 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_t kImageId = 1; | 
|  | scoped_refptr<MockGLImage> image(new MockGLImage); | 
|  | GetImageManager()->AddImage(image.get(), kImageId); | 
|  |  | 
|  | // Bind image to texture. | 
|  | EXPECT_CALL(*image.get(), BindTexImage(GL_TEXTURE_2D)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(false)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*image.get(), GetSize()) | 
|  | .Times(1) | 
|  | .WillOnce(Return(gfx::Size(1, 1))) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*image.get(), GetInternalFormat()) | 
|  | .Times(1) | 
|  | .WillOnce(Return(GL_RGBA)) | 
|  | .RetiresOnSaturation(); | 
|  | // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. | 
|  | DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId); | 
|  |  | 
|  | 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)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)).Times(2).RetiresOnSaturation(); | 
|  | EXPECT_CALL(*image.get(), CopyTexImage(GL_TEXTURE_2D)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(true)) | 
|  | .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()); | 
|  |  | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | // Re-bind image to texture. | 
|  | ReleaseTexImage2DCHROMIUM release_tex_image_2d_cmd; | 
|  | release_tex_image_2d_cmd.Init(GL_TEXTURE_2D, kImageId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(release_tex_image_2d_cmd)); | 
|  | EXPECT_CALL(*image.get(), BindTexImage(GL_TEXTURE_2D)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(false)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*image.get(), GetSize()) | 
|  | .Times(1) | 
|  | .WillOnce(Return(gfx::Size(1, 1))) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*image.get(), GetInternalFormat()) | 
|  | .Times(1) | 
|  | .WillOnce(Return(GL_RGBA)) | 
|  | .RetiresOnSaturation(); | 
|  | DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId); | 
|  |  | 
|  | 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(); | 
|  | EXPECT_CALL(*image.get(), CopyTexImage(GL_TEXTURE_2D)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(true)) | 
|  | .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()); | 
|  |  | 
|  | EXPECT_CALL(*image.get(), Destroy(true)).Times(1).RetiresOnSaturation(); | 
|  | image = nullptr; | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, DrawWithGLImageExternal) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_EGL_image_external"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | init.has_alpha = true; | 
|  | init.has_depth = true; | 
|  | init.request_alpha = true; | 
|  | init.request_depth = true; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | TextureRef* texture_ref = GetTexture(client_texture_id_); | 
|  | scoped_refptr<MockGLImage> image(new MockGLImage); | 
|  | group().texture_manager()->SetTarget(texture_ref, GL_TEXTURE_EXTERNAL_OES); | 
|  | group().texture_manager()->SetLevelInfo(texture_ref, GL_TEXTURE_EXTERNAL_OES, | 
|  | 0, GL_RGBA, 0, 0, 1, 0, GL_RGBA, | 
|  | GL_UNSIGNED_BYTE, gfx::Rect()); | 
|  | group().texture_manager()->SetLevelImage(texture_ref, GL_TEXTURE_EXTERNAL_OES, | 
|  | 0, image.get(), Texture::BOUND); | 
|  |  | 
|  | 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(*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()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, TexImage2DFloatOnGLES2) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_texture_float"; | 
|  | init.gl_version = "opengl es 2.0"; | 
|  | InitDecoder(init); | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 17, 0, GL_RGBA, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 17, 0, GL_RGB, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D( | 
|  | GL_TEXTURE_2D, 0, GL_LUMINANCE, 16, 17, 0, GL_LUMINANCE, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 17, 0, GL_ALPHA, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_LUMINANCE_ALPHA, | 
|  | 16, | 
|  | 17, | 
|  | 0, | 
|  | GL_LUMINANCE_ALPHA, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, TexImage2DFloatOnGLES3) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_texture_float GL_EXT_color_buffer_float"; | 
|  | init.gl_version = "opengl es 3.0"; | 
|  | InitDecoder(init); | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 17, 0, GL_RGBA, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 17, 0, GL_RGB, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D( | 
|  | GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 17, 0, GL_RGBA, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D( | 
|  | GL_TEXTURE_2D, 0, GL_LUMINANCE, 16, 17, 0, GL_LUMINANCE, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 17, 0, GL_ALPHA, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_LUMINANCE_ALPHA, | 
|  | 16, | 
|  | 17, | 
|  | 0, | 
|  | GL_LUMINANCE_ALPHA, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, TexSubImage2DFloatOnGLES3) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_texture_float GL_EXT_color_buffer_float"; | 
|  | init.gl_version = "opengl es 3.0"; | 
|  | InitDecoder(init); | 
|  | const int kWidth = 8; | 
|  | const int kHeight = 4; | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGBA32F, | 
|  | kWidth, | 
|  | kHeight, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0); | 
|  | EXPECT_CALL(*gl_, | 
|  | TexImage2D(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGBA32F, | 
|  | kWidth, | 
|  | kHeight, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | GL_FLOAT, | 
|  | shared_memory_address_)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | TexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, | 
|  | 0, | 
|  | 0, | 
|  | 0, | 
|  | kWidth, | 
|  | kHeight, | 
|  | GL_RGBA, | 
|  | GL_FLOAT, | 
|  | kSharedMemoryId, | 
|  | kSharedMemoryOffset, | 
|  | GL_FALSE); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, TexSubImage2DFloatDoesClearOnGLES3) { | 
|  | InitState init; | 
|  | init.extensions = "GL_OES_texture_float GL_EXT_color_buffer_float"; | 
|  | init.gl_version = "opengl es 3.0"; | 
|  | InitDecoder(init); | 
|  | const int kWidth = 8; | 
|  | const int kHeight = 4; | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGBA32F, | 
|  | kWidth, | 
|  | kHeight, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0); | 
|  | SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId, | 
|  | GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA32F, | 
|  | GL_RGBA, GL_FLOAT, 0, kHeight - 1, kWidth, 1); | 
|  | EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, _, GL_RGBA, | 
|  | GL_FLOAT, shared_memory_address_)) | 
|  | .Times(2) | 
|  | .RetiresOnSaturation(); | 
|  | TexSubImage2D cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight - 1, GL_RGBA, GL_FLOAT, | 
|  | kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | cmd.Init(GL_TEXTURE_2D, 0, 0, kHeight - 1, kWidth - 1, 1, GL_RGBA, GL_FLOAT, | 
|  | kSharedMemoryId, kSharedMemoryOffset, GL_FALSE); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, TexImage2DFloatConvertsFormatDesktop) { | 
|  | InitState init; | 
|  | init.extensions = "GL_ARB_texture_float"; | 
|  | InitDecoder(init); | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage2D( | 
|  | GL_TEXTURE_2D, 0, GL_RGBA32F, 16, 17, 0, GL_RGBA, GL_FLOAT, 0, 0); | 
|  | DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 16, 17, 0, GL_RGB, GL_FLOAT, 0, 0); | 
|  | DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | 16, | 
|  | 17, | 
|  | 0, | 
|  | GL_RGBA, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0, | 
|  | GL_RGBA32F_ARB); | 
|  | DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_RGB, | 
|  | 16, | 
|  | 17, | 
|  | 0, | 
|  | GL_RGB, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0, | 
|  | GL_RGB32F_ARB); | 
|  | DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_LUMINANCE, | 
|  | 16, | 
|  | 17, | 
|  | 0, | 
|  | GL_LUMINANCE, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0, | 
|  | GL_LUMINANCE32F_ARB); | 
|  | DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_ALPHA, | 
|  | 16, | 
|  | 17, | 
|  | 0, | 
|  | GL_ALPHA, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0, | 
|  | GL_ALPHA32F_ARB); | 
|  | DoTexImage2DConvertInternalFormat(GL_TEXTURE_2D, | 
|  | 0, | 
|  | GL_LUMINANCE_ALPHA, | 
|  | 16, | 
|  | 17, | 
|  | 0, | 
|  | GL_LUMINANCE_ALPHA, | 
|  | GL_FLOAT, | 
|  | 0, | 
|  | 0, | 
|  | GL_LUMINANCE_ALPHA32F_ARB); | 
|  | } | 
|  |  | 
|  | class GLES2DecoderCompressedFormatsTest : public GLES2DecoderManualInitTest { | 
|  | public: | 
|  | GLES2DecoderCompressedFormatsTest() {} | 
|  |  | 
|  | static bool ValueInArray(GLint value, GLint* array, GLint count) { | 
|  | for (GLint ii = 0; ii < count; ++ii) { | 
|  | if (array[ii] == value) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void CheckFormats(const char* extension, const GLenum* formats, int count) { | 
|  | InitState init; | 
|  | init.extensions = extension; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | typedef GetIntegerv::Result Result; | 
|  | Result* result = static_cast<Result*>(shared_memory_address_); | 
|  | 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(count, 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()); | 
|  |  | 
|  | for (int i = 0; i < count; ++i) { | 
|  | EXPECT_TRUE( | 
|  | ValueInArray(formats[i], result->GetData(), result->GetNumResults())); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | INSTANTIATE_TEST_CASE_P(Service, | 
|  | GLES2DecoderCompressedFormatsTest, | 
|  | ::testing::Bool()); | 
|  |  | 
|  | TEST_P(GLES2DecoderCompressedFormatsTest, GetCompressedTextureFormatsS3TC) { | 
|  | const GLenum formats[] = { | 
|  | GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, | 
|  | GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT}; | 
|  | CheckFormats("GL_EXT_texture_compression_s3tc", formats, 4); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderCompressedFormatsTest, GetCompressedTextureFormatsATC) { | 
|  | const GLenum formats[] = {GL_ATC_RGB_AMD, GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, | 
|  | GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD}; | 
|  | CheckFormats("GL_AMD_compressed_ATC_texture", formats, 3); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderCompressedFormatsTest, GetCompressedTextureFormatsPVRTC) { | 
|  | const GLenum formats[] = { | 
|  | GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, | 
|  | GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}; | 
|  | CheckFormats("GL_IMG_texture_compression_pvrtc", formats, 4); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderCompressedFormatsTest, GetCompressedTextureFormatsETC1) { | 
|  | const GLenum formats[] = {GL_ETC1_RGB8_OES}; | 
|  | CheckFormats("GL_OES_compressed_ETC1_RGB8_texture", formats, 1); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderCompressedFormatsTest, GetCompressedTextureFormatsASTC) { | 
|  | const GLenum formats[] = { | 
|  | GL_COMPRESSED_RGBA_ASTC_4x4_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_5x4_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_5x5_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_6x5_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_6x6_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_8x5_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_8x6_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_8x8_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_10x5_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_10x6_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_10x8_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_10x10_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_12x10_KHR, | 
|  | GL_COMPRESSED_RGBA_ASTC_12x12_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, | 
|  | GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}; | 
|  | CheckFormats("GL_KHR_texture_compression_astc_ldr", formats, 28); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderManualInitTest, GetNoCompressedTextureFormats) { | 
|  | InitState init; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | typedef GetIntegerv::Result Result; | 
|  | Result* result = static_cast<Result*>(shared_memory_address_); | 
|  | 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_P(GLES2DecoderManualInitTest, TexStorageInvalidLevels) { | 
|  | InitState init; | 
|  | init.gl_version = "OpenGL 4.2"; | 
|  | init.extensions = "GL_ARB_texture_rectangle GL_ARB_texture_storage"; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | DoBindTexture(GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, | 
|  | kServiceTextureId); | 
|  | TexStorage2DEXT cmd; | 
|  | cmd.Init(GL_TEXTURE_RECTANGLE_ARB, 2, GL_RGBA8, 4, 4); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, TexStorage3DValidArgs) { | 
|  | DoBindTexture(GL_TEXTURE_3D, client_texture_id_, kServiceTextureId); | 
|  | EXPECT_CALL(*gl_, TexStorage3D(GL_TEXTURE_3D, 2, GL_RGB565, 4, 5, 6)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | TexStorage3D cmd; | 
|  | cmd.Init(GL_TEXTURE_3D, 2, GL_RGB565, 4, 5, 6); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, TexImage3DValidArgs) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kLevel = 2; | 
|  | const GLint kInternalFormat = GL_RGBA8; | 
|  | const GLsizei kWidth = 2; | 
|  | const GLsizei kHeight = 2; | 
|  | const GLsizei kDepth = 2; | 
|  | const GLenum kFormat = GL_RGBA; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0, | 
|  | kFormat, kType, kSharedMemoryId, kSharedMemoryOffset); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, ClearLevel3DSingleCall) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kLevel = 0; | 
|  | const GLint kInternalFormat = GL_RGBA8; | 
|  | const GLsizei kWidth = 2; | 
|  | const GLsizei kHeight = 2; | 
|  | const GLsizei kDepth = 2; | 
|  | const GLenum kFormat = GL_RGBA; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  | const uint32_t kBufferSize = kWidth * kHeight * kDepth * 4; | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0, | 
|  | kFormat, kType, 0, 0); | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GenBuffersARB(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BufferData(GL_PIXEL_UNPACK_BUFFER, | 
|  | kBufferSize, _, GL_STATIC_DRAW)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(kTarget, kServiceTextureId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | { | 
|  | // It takes 1 call to clear the entire 3D texture. | 
|  | EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 0, | 
|  | kWidth, kHeight, kDepth, | 
|  | kFormat, kType)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(kTarget, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_TRUE(decoder_->ClearLevel3D( | 
|  | texture, kTarget, kLevel, kFormat, kType, kWidth, kHeight, kDepth)); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, ClearLevel3DMultipleLayersPerCall) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kLevel = 0; | 
|  | const GLint kInternalFormat = GL_RGBA8; | 
|  | const GLsizei kWidth = 512; | 
|  | const GLsizei kHeight = 512; | 
|  | const GLsizei kDepth = 7; | 
|  | const GLenum kFormat = GL_RGBA; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  | const uint32_t kBufferSize = 1024 * 1024 * 2;  // Max buffer size per call. | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0, | 
|  | kFormat, kType, 0, 0); | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GenBuffersARB(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BufferData(GL_PIXEL_UNPACK_BUFFER, | 
|  | kBufferSize, _, GL_STATIC_DRAW)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(kTarget, kServiceTextureId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | { | 
|  | // It takes 4 calls to clear the 3D texture, each clears 2/2/2/1 layers. | 
|  | EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 0, | 
|  | kWidth, kHeight, 2, kFormat, kType)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 2, | 
|  | kWidth, kHeight, 2, kFormat, kType)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 4, | 
|  | kWidth, kHeight, 2, kFormat, kType)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 6, | 
|  | kWidth, kHeight, 1, kFormat, kType)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(kTarget, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_TRUE(decoder_->ClearLevel3D( | 
|  | texture, kTarget, kLevel, kFormat, kType, kWidth, kHeight, kDepth)); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, ClearLevel3DMultipleCallsPerLayer) { | 
|  | const GLenum kTarget = GL_TEXTURE_3D; | 
|  | const GLint kLevel = 0; | 
|  | const GLint kInternalFormat = GL_RGBA8; | 
|  | const GLsizei kWidth = 1024; | 
|  | const GLsizei kHeight = 1000; | 
|  | const GLsizei kDepth = 2; | 
|  | const GLenum kFormat = GL_RGBA; | 
|  | const GLenum kType = GL_UNSIGNED_BYTE; | 
|  | const uint32_t kBufferSize = 1024 * 1024 * 2;  // Max buffer size per call. | 
|  |  | 
|  | DoBindTexture(kTarget, client_texture_id_, kServiceTextureId); | 
|  | DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0, | 
|  | kFormat, kType, 0, 0); | 
|  | TextureRef* texture_ref = | 
|  | group().texture_manager()->GetTexture(client_texture_id_); | 
|  | ASSERT_TRUE(texture_ref != NULL); | 
|  | Texture* texture = texture_ref->texture(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GenBuffersARB(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BufferData(GL_PIXEL_UNPACK_BUFFER, | 
|  | kBufferSize, _, GL_STATIC_DRAW)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(kTarget, kServiceTextureId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | for (GLint zz = 0; zz < 2; ++zz) { | 
|  | // It takes two calls to clear one layer of the 3D texture, | 
|  | // each clears 512/488 rows. | 
|  | // Layer 1. | 
|  | EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, zz, | 
|  | kWidth, 512, 1, kFormat, kType)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 512, zz, | 
|  | kWidth, 488, 1, kFormat, kType)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(kTarget, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_TRUE(decoder_->ClearLevel3D( | 
|  | texture, kTarget, kLevel, kFormat, kType, kWidth, kHeight, kDepth)); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES3DecoderTest, BindSamplerInvalidUnit) { | 
|  | BindSampler cmd; | 
|  | cmd.Init(kNumTextureUnits, client_texture_id_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  |  | 
|  | cmd.Init(kNumTextureUnits, 0); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); | 
|  | } | 
|  |  | 
|  | // Test that copyTexImage2D uses the emulated internal format, rather than the | 
|  | // real internal format. | 
|  | TEST_P(GLES2DecoderWithShaderTest, CHROMIUMImageEmulatingRGB) { | 
|  | const GLuint kFBOClientTextureId = 4100; | 
|  | const GLuint kFBOServiceTextureId = 4101; | 
|  | GLenum target = GL_TEXTURE_2D; | 
|  | GLint level = 0; | 
|  | GLsizei width = 1; | 
|  | GLsizei height = 1; | 
|  |  | 
|  | // Generate the source framebuffer. | 
|  | EXPECT_CALL(*gl_, GenTextures(_, _)) | 
|  | .WillOnce(SetArgPointee<1>(kFBOServiceTextureId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<GenTexturesImmediate>(kFBOClientTextureId); | 
|  | DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, | 
|  | kServiceFramebufferId); | 
|  |  | 
|  | GLenum destination_texture_formats[] = {GL_RGBA, GL_RGB}; | 
|  | for (int use_rgb_emulation = 0; use_rgb_emulation < 2; ++ use_rgb_emulation) { | 
|  | for (size_t destination_texture_index = 0; destination_texture_index < 2; | 
|  | ++destination_texture_index) { | 
|  | // Generate and bind the source image. Making a new image for each set of | 
|  | // parameters is easier than trying to reuse images. Obviously there's no | 
|  | // performance penalty. | 
|  | int image_id = use_rgb_emulation * 2 + destination_texture_index; | 
|  | scoped_refptr<gl::GLImage> image; | 
|  | if (use_rgb_emulation) | 
|  | image = new EmulatingRGBImageStub; | 
|  | else | 
|  | image = new gl::GLImageStub; | 
|  | GetImageManager()->AddImage(image.get(), image_id); | 
|  | EXPECT_FALSE(GetImageManager()->LookupImage(image_id) == NULL); | 
|  | DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId); | 
|  |  | 
|  | DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id); | 
|  | DoFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, | 
|  | kFBOClientTextureId, kFBOServiceTextureId, level, | 
|  | GL_NO_ERROR); | 
|  |  | 
|  | GLenum destination_texture_format = | 
|  | destination_texture_formats[destination_texture_index]; | 
|  | bool should_succeed = | 
|  | !use_rgb_emulation || (destination_texture_format == GL_RGB); | 
|  | if (should_succeed) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, | 
|  | CopyTexImage2D(GL_TEXTURE_2D, 0, destination_texture_format, | 
|  | 0, 0, 1, 1, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | if (destination_texture_index == 0 || !framebuffer_completeness_cache()) { | 
|  | EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) | 
|  | .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); | 
|  | CopyTexImage2D cmd; | 
|  | cmd.Init(target, level, destination_texture_format, 0, 0, width, height); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | GLenum expectation = should_succeed ? GL_NO_ERROR : GL_INVALID_OPERATION; | 
|  | EXPECT_EQ(expectation, static_cast<GLenum>(GetGLError())); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, BindTextureValidArgs) { | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | if (!feature_info()->gl_version_info().BehavesLikeGLES() && | 
|  | feature_info()->gl_version_info().IsAtLeastGL(3, 2)) { | 
|  | EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, | 
|  | GL_DEPTH_TEXTURE_MODE, | 
|  | GL_RED)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | BindTexture cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, client_texture_id_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, BindTextureValidArgsNewId) { | 
|  | EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kNewServiceId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GenTextures(1, _)) | 
|  | .WillOnce(SetArgumentPointee<1>(kNewServiceId)); | 
|  | if (!feature_info()->gl_version_info().BehavesLikeGLES() && | 
|  | feature_info()->gl_version_info().IsAtLeastGL(3, 2)) { | 
|  | EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, | 
|  | GL_DEPTH_TEXTURE_MODE, | 
|  | GL_RED)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | BindTexture cmd; | 
|  | cmd.Init(GL_TEXTURE_2D, kNewClientId); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | EXPECT_TRUE(GetTexture(kNewClientId) != NULL); | 
|  | } | 
|  |  | 
|  | TEST_P(GLES2DecoderTest, BindTextureInvalidArgs) { | 
|  | EXPECT_CALL(*gl_, BindTexture(_, _)).Times(0); | 
|  | BindTexture cmd; | 
|  | cmd.Init(GL_TEXTURE_1D, client_texture_id_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); | 
|  |  | 
|  | cmd.Init(GL_TEXTURE_3D, client_texture_id_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); | 
|  | } | 
|  |  | 
|  | // TODO(gman): Complete this test. | 
|  | // TEST_P(GLES2DecoderTest, CompressedTexImage2DGLError) { | 
|  | // } | 
|  |  | 
|  | // TODO(gman): CompressedTexImage2D | 
|  |  | 
|  | // TODO(gman): CompressedTexImage2DImmediate | 
|  |  | 
|  | // TODO(gman): CompressedTexSubImage2DImmediate | 
|  |  | 
|  | // TODO(gman): TexImage2D | 
|  |  | 
|  | // TODO(gman): TexImage2DImmediate | 
|  |  | 
|  | // TODO(gman): TexSubImage2DImmediate | 
|  |  | 
|  | }  // namespace gles2 | 
|  | }  // namespace gpu |