|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/strings/string_split.h" | 
|  | #include "gpu/command_buffer/common/gles2_cmd_format.h" | 
|  | #include "gpu/command_buffer/common/gles2_cmd_utils.h" | 
|  | #include "gpu/command_buffer/service/cmd_buffer_engine.h" | 
|  | #include "gpu/command_buffer/service/context_group.h" | 
|  | #include "gpu/command_buffer/service/logger.h" | 
|  | #include "gpu/command_buffer/service/mailbox_manager.h" | 
|  | #include "gpu/command_buffer/service/program_manager.h" | 
|  | #include "gpu/command_buffer/service/test_helper.h" | 
|  | #include "gpu/command_buffer/service/vertex_attrib_manager.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "ui/gl/gl_mock.h" | 
|  | #include "ui/gl/init/gl_factory.h" | 
|  | #include "ui/gl/test/gl_surface_test_support.h" | 
|  |  | 
|  | using ::gl::MockGLInterface; | 
|  | using ::testing::_; | 
|  | using ::testing::AnyNumber; | 
|  | using ::testing::AtMost; | 
|  | using ::testing::DoAll; | 
|  | using ::testing::InSequence; | 
|  | using ::testing::Invoke; | 
|  | using ::testing::InvokeWithoutArgs; | 
|  | using ::testing::MatcherCast; | 
|  | using ::testing::Pointee; | 
|  | using ::testing::Return; | 
|  | using ::testing::SetArrayArgument; | 
|  | using ::testing::SetArgPointee; | 
|  | using ::testing::StrEq; | 
|  | using ::testing::StrictMock; | 
|  | using ::testing::WithArg; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | void NormalizeInitState(gpu::gles2::GLES2DecoderTestBase::InitState* init) { | 
|  | CHECK(init); | 
|  | const char* kVAOExtensions[] = { | 
|  | "GL_OES_vertex_array_object", | 
|  | "GL_ARB_vertex_array_object", | 
|  | "GL_APPLE_vertex_array_object" | 
|  | }; | 
|  | bool contains_vao_extension = false; | 
|  | for (size_t ii = 0; ii < arraysize(kVAOExtensions); ++ii) { | 
|  | if (init->extensions.find(kVAOExtensions[ii]) != std::string::npos) { | 
|  | contains_vao_extension = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (init->use_native_vao) { | 
|  | if (contains_vao_extension) | 
|  | return; | 
|  | if (!init->extensions.empty()) | 
|  | init->extensions += " "; | 
|  | if (base::StartsWith(init->gl_version, "opengl es", | 
|  | base::CompareCase::INSENSITIVE_ASCII)) { | 
|  | init->extensions += kVAOExtensions[0]; | 
|  | } else { | 
|  | #if !defined(OS_MACOSX) | 
|  | init->extensions += kVAOExtensions[1]; | 
|  | #else | 
|  | init->extensions += kVAOExtensions[2]; | 
|  | #endif  // OS_MACOSX | 
|  | } | 
|  | } else { | 
|  | // Make sure we don't set up an invalid InitState. | 
|  | CHECK(!contains_vao_extension); | 
|  | } | 
|  |  | 
|  | if (!init->extensions.empty()) | 
|  | init->extensions += " "; | 
|  | init->extensions += "GL_EXT_framebuffer_object "; | 
|  | } | 
|  |  | 
|  | const uint32_t kMaxColorAttachments = 16; | 
|  | const uint32_t kMaxDrawBuffers = 16; | 
|  |  | 
|  | }  // namespace Anonymous | 
|  |  | 
|  | namespace gpu { | 
|  | namespace gles2 { | 
|  |  | 
|  | GLES2DecoderTestBase::GLES2DecoderTestBase() | 
|  | : surface_(NULL), | 
|  | context_(NULL), | 
|  | memory_tracker_(NULL), | 
|  | client_buffer_id_(100), | 
|  | client_framebuffer_id_(101), | 
|  | client_program_id_(102), | 
|  | client_renderbuffer_id_(103), | 
|  | client_sampler_id_(104), | 
|  | client_shader_id_(105), | 
|  | client_texture_id_(106), | 
|  | client_element_buffer_id_(107), | 
|  | client_vertex_shader_id_(121), | 
|  | client_fragment_shader_id_(122), | 
|  | client_query_id_(123), | 
|  | client_vertexarray_id_(124), | 
|  | client_transformfeedback_id_(126), | 
|  | client_sync_id_(127), | 
|  | service_renderbuffer_id_(0), | 
|  | service_renderbuffer_valid_(false), | 
|  | ignore_cached_state_for_test_(GetParam()), | 
|  | cached_color_mask_red_(true), | 
|  | cached_color_mask_green_(true), | 
|  | cached_color_mask_blue_(true), | 
|  | cached_color_mask_alpha_(true), | 
|  | cached_depth_mask_(true), | 
|  | cached_stencil_front_mask_(static_cast<GLuint>(-1)), | 
|  | cached_stencil_back_mask_(static_cast<GLuint>(-1)), | 
|  | shader_language_version_(100) { | 
|  | memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_)); | 
|  | } | 
|  |  | 
|  | GLES2DecoderTestBase::~GLES2DecoderTestBase() {} | 
|  |  | 
|  | void GLES2DecoderTestBase::SetUp() { | 
|  | InitState init; | 
|  | // Autogenerated tests do not overwrite version or extension string, | 
|  | // so we have to pick something that supports everything here. | 
|  | init.gl_version = "4.4"; | 
|  | init.extensions += " GL_ARB_compatibility"; | 
|  | init.has_alpha = true; | 
|  | init.has_depth = true; | 
|  | init.request_alpha = true; | 
|  | init.request_depth = true; | 
|  | init.bind_generates_resource = true; | 
|  | InitDecoder(init); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::AddExpectationsForVertexAttribManager() { | 
|  | for (GLint ii = 0; ii < kNumVertexAttribs; ++ii) { | 
|  | EXPECT_CALL(*gl_, VertexAttrib4f(ii, 0.0f, 0.0f, 0.0f, 1.0f)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | GLES2DecoderTestBase::InitState::InitState() | 
|  | : extensions("GL_EXT_framebuffer_object"), | 
|  | gl_version("2.1"), | 
|  | has_alpha(false), | 
|  | has_depth(false), | 
|  | has_stencil(false), | 
|  | request_alpha(false), | 
|  | request_depth(false), | 
|  | request_stencil(false), | 
|  | bind_generates_resource(false), | 
|  | lose_context_when_out_of_memory(false), | 
|  | use_native_vao(true), | 
|  | context_type(CONTEXT_TYPE_OPENGLES2) {} | 
|  |  | 
|  | GLES2DecoderTestBase::InitState::InitState(const InitState& other) = default; | 
|  |  | 
|  | void GLES2DecoderTestBase::InitDecoder(const InitState& init) { | 
|  | InitDecoderWithCommandLine(init, NULL); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::InitDecoderWithCommandLine( | 
|  | const InitState& init, | 
|  | const base::CommandLine* command_line) { | 
|  | InitState normalized_init = init; | 
|  | NormalizeInitState(&normalized_init); | 
|  | // For easier substring/extension matching | 
|  | DCHECK(normalized_init.extensions.empty() || | 
|  | *normalized_init.extensions.rbegin() == ' '); | 
|  | gl::SetGLGetProcAddressProc(gl::MockGLInterface::GetGLProcAddress); | 
|  | gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings(); | 
|  |  | 
|  | gl_.reset(new StrictMock<MockGLInterface>()); | 
|  | ::gl::MockGLInterface::SetGLInterface(gl_.get()); | 
|  |  | 
|  | SetupMockGLBehaviors(); | 
|  |  | 
|  | scoped_refptr<FeatureInfo> feature_info = new FeatureInfo; | 
|  | if (command_line) { | 
|  | GpuDriverBugWorkarounds gpu_driver_bug_workaround(command_line); | 
|  | feature_info = new FeatureInfo(*command_line, gpu_driver_bug_workaround); | 
|  | } | 
|  |  | 
|  | group_ = scoped_refptr<ContextGroup>(new ContextGroup( | 
|  | gpu_preferences_, NULL, memory_tracker_, | 
|  | new ShaderTranslatorCache(gpu_preferences_), | 
|  | new FramebufferCompletenessCache, feature_info, | 
|  | normalized_init.bind_generates_resource, nullptr, nullptr)); | 
|  | bool use_default_textures = normalized_init.bind_generates_resource; | 
|  |  | 
|  | InSequence sequence; | 
|  |  | 
|  | surface_ = new gl::GLSurfaceStub; | 
|  | surface_->SetSize(gfx::Size(kBackBufferWidth, kBackBufferHeight)); | 
|  |  | 
|  | // Context needs to be created before initializing ContextGroup, which will | 
|  | // in turn initialize FeatureInfo, which needs a context to determine | 
|  | // extension support. | 
|  | context_ = new StrictMock<GLContextMock>(); | 
|  | context_->AddExtensionsString(normalized_init.extensions.c_str()); | 
|  | context_->SetGLVersionString(normalized_init.gl_version.c_str()); | 
|  |  | 
|  | context_->GLContextStubWithExtensions::MakeCurrent(surface_.get()); | 
|  |  | 
|  | TestHelper::SetupContextGroupInitExpectations( | 
|  | gl_.get(), | 
|  | DisallowedFeatures(), | 
|  | normalized_init.extensions.c_str(), | 
|  | normalized_init.gl_version.c_str(), | 
|  | init.context_type, | 
|  | normalized_init.bind_generates_resource); | 
|  |  | 
|  | // We initialize the ContextGroup with a MockGLES2Decoder so that | 
|  | // we can use the ContextGroup to figure out how the real GLES2Decoder | 
|  | // will initialize itself. | 
|  | mock_decoder_.reset(new MockGLES2Decoder()); | 
|  |  | 
|  | // Install FakeDoCommands handler so we can use individual DoCommand() | 
|  | // expectations. | 
|  | EXPECT_CALL(*mock_decoder_, DoCommands(_, _, _, _)).WillRepeatedly( | 
|  | Invoke(mock_decoder_.get(), &MockGLES2Decoder::FakeDoCommands)); | 
|  |  | 
|  | EXPECT_TRUE(group_->Initialize(mock_decoder_.get(), init.context_type, | 
|  | DisallowedFeatures())); | 
|  |  | 
|  | if (init.context_type == CONTEXT_TYPE_WEBGL2 || | 
|  | init.context_type == CONTEXT_TYPE_OPENGLES3) { | 
|  | EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_COLOR_ATTACHMENTS, _)) | 
|  | .WillOnce(SetArgPointee<1>(kMaxColorAttachments)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_DRAW_BUFFERS, _)) | 
|  | .WillOnce(SetArgPointee<1>(kMaxDrawBuffers)) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GenTransformFeedbacks(1, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceDefaultTransformFeedbackId)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTransformFeedback(GL_TRANSFORM_FEEDBACK, | 
|  | kServiceDefaultTransformFeedbackId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | if (group_->feature_info()->feature_flags().native_vertex_array_object) { | 
|  | EXPECT_CALL(*gl_, GenVertexArraysOES(1, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceVertexArrayId)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindVertexArrayOES(_)).Times(1).RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | if (group_->feature_info()->workarounds().init_vertex_attributes) | 
|  | AddExpectationsForVertexAttribManager(); | 
|  |  | 
|  | AddExpectationsForBindVertexArrayOES(); | 
|  |  | 
|  | if (!group_->feature_info()->gl_version_info().BehavesLikeGLES()) { | 
|  | EXPECT_CALL(*gl_, EnableVertexAttribArray(0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | static GLuint attrib_0_id[] = { | 
|  | kServiceAttrib0BufferId, | 
|  | }; | 
|  | static GLuint fixed_attrib_buffer_id[] = { | 
|  | kServiceFixedAttribBufferId, | 
|  | }; | 
|  | EXPECT_CALL(*gl_, GenBuffersARB(arraysize(attrib_0_id), _)) | 
|  | .WillOnce(SetArrayArgument<1>(attrib_0_id, | 
|  | attrib_0_id + arraysize(attrib_0_id))) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceAttrib0BufferId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, VertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GenBuffersARB(arraysize(fixed_attrib_buffer_id), _)) | 
|  | .WillOnce(SetArrayArgument<1>( | 
|  | fixed_attrib_buffer_id, | 
|  | fixed_attrib_buffer_id + arraysize(fixed_attrib_buffer_id))) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | for (GLint tt = 0; tt < TestHelper::kNumTextureUnits; ++tt) { | 
|  | EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0 + tt)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | if (group_->feature_info()->feature_flags().oes_egl_image_external || | 
|  | group_->feature_info() | 
|  | ->feature_flags() | 
|  | .nv_egl_stream_consumer_external) { | 
|  | EXPECT_CALL(*gl_, | 
|  | BindTexture(GL_TEXTURE_EXTERNAL_OES, | 
|  | use_default_textures | 
|  | ? TestHelper::kServiceDefaultExternalTextureId | 
|  | : 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (group_->feature_info()->feature_flags().arb_texture_rectangle) { | 
|  | EXPECT_CALL( | 
|  | *gl_, | 
|  | BindTexture(GL_TEXTURE_RECTANGLE_ARB, | 
|  | use_default_textures | 
|  | ? TestHelper::kServiceDefaultRectangleTextureId | 
|  | : 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | EXPECT_CALL(*gl_, | 
|  | BindTexture(GL_TEXTURE_CUBE_MAP, | 
|  | use_default_textures | 
|  | ? TestHelper::kServiceDefaultTextureCubemapId | 
|  | : 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL( | 
|  | *gl_, | 
|  | BindTexture( | 
|  | GL_TEXTURE_2D, | 
|  | use_default_textures ? TestHelper::kServiceDefaultTexture2dId : 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | if (group_->feature_info()->gl_version_info().is_desktop_core_profile) { | 
|  | EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT( | 
|  | GL_FRAMEBUFFER, GL_BACK_LEFT, | 
|  | GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, _)) | 
|  | .WillOnce(SetArgPointee<3>(normalized_init.has_alpha ? 8 : 0)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT( | 
|  | GL_FRAMEBUFFER, GL_DEPTH, | 
|  | GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, _)) | 
|  | .WillOnce(SetArgPointee<3>(normalized_init.has_depth ? 24 : 0)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT( | 
|  | GL_FRAMEBUFFER, GL_STENCIL, | 
|  | GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, _)) | 
|  | .WillOnce(SetArgPointee<3>(normalized_init.has_stencil ? 8 : 0)) | 
|  | .RetiresOnSaturation(); | 
|  | } else { | 
|  | EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _)) | 
|  | .WillOnce(SetArgPointee<1>(normalized_init.has_alpha ? 8 : 0)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) | 
|  | .WillOnce(SetArgPointee<1>(normalized_init.has_depth ? 24 : 0)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) | 
|  | .WillOnce(SetArgPointee<1>(normalized_init.has_stencil ? 8 : 0)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | if (!group_->feature_info()->gl_version_info().BehavesLikeGLES()) { | 
|  | EXPECT_CALL(*gl_, Enable(GL_VERTEX_PROGRAM_POINT_SIZE)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, Enable(GL_POINT_SPRITE)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } else if (group_->feature_info() | 
|  | ->gl_version_info() | 
|  | .is_desktop_core_profile) { | 
|  | EXPECT_CALL(*gl_, Enable(GL_PROGRAM_POINT_SIZE)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | if (group_->feature_info()->gl_version_info().IsAtLeastGL(3, 2)) { | 
|  | EXPECT_CALL(*gl_, Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | if (group_->feature_info()->gl_version_info().is_es) { | 
|  | EXPECT_CALL( | 
|  | *gl_, GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, _, _)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | static GLint max_viewport_dims[] = { | 
|  | kMaxViewportWidth, | 
|  | kMaxViewportHeight | 
|  | }; | 
|  | EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_VIEWPORT_DIMS, _)) | 
|  | .WillOnce(SetArrayArgument<1>( | 
|  | max_viewport_dims, max_viewport_dims + arraysize(max_viewport_dims))) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | static GLfloat line_width_range[] = { 1.0f, 2.0f }; | 
|  | EXPECT_CALL(*gl_, GetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, _)) | 
|  | .WillOnce(SetArrayArgument<1>( | 
|  | line_width_range, line_width_range + arraysize(line_width_range))) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | SetupInitCapabilitiesExpectations(group_->feature_info()->IsES3Capable()); | 
|  | SetupInitStateExpectations(group_->feature_info()->IsES3Capable()); | 
|  |  | 
|  | EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindRenderbufferEXT(GL_RENDERBUFFER, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | if (feature_info->feature_flags().desktop_srgb_support) { | 
|  | EXPECT_CALL(*gl_, Disable(GL_FRAMEBUFFER_SRGB)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | // TODO(boliu): Remove OS_ANDROID once crbug.com/259023 is fixed and the | 
|  | // workaround has been reverted. | 
|  | #if !defined(OS_ANDROID) | 
|  | if (normalized_init.has_alpha && !normalized_init.request_alpha) { | 
|  | EXPECT_CALL(*gl_, ClearColor(0, 0, 0, 1)).Times(1).RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | EXPECT_CALL(*gl_, Clear( | 
|  | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | if (normalized_init.has_alpha && !normalized_init.request_alpha) { | 
|  | EXPECT_CALL(*gl_, ClearColor(0, 0, 0, 0)).Times(1).RetiresOnSaturation(); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | engine_.reset(new StrictMock<MockCommandBufferEngine>()); | 
|  | scoped_refptr<gpu::Buffer> buffer = | 
|  | engine_->GetSharedMemoryBuffer(kSharedMemoryId); | 
|  | shared_memory_offset_ = kSharedMemoryOffset; | 
|  | shared_memory_address_ = | 
|  | reinterpret_cast<int8_t*>(buffer->memory()) + shared_memory_offset_; | 
|  | shared_memory_id_ = kSharedMemoryId; | 
|  | shared_memory_base_ = buffer->memory(); | 
|  |  | 
|  | gles2::ContextCreationAttribHelper attribs; | 
|  | attribs.alpha_size = normalized_init.request_alpha ? 8 : 0; | 
|  | attribs.depth_size = normalized_init.request_depth ? 24 : 0; | 
|  | attribs.stencil_size = normalized_init.request_stencil ? 8 : 0; | 
|  | attribs.lose_context_when_out_of_memory = | 
|  | normalized_init.lose_context_when_out_of_memory; | 
|  | attribs.context_type = init.context_type; | 
|  |  | 
|  | decoder_.reset(GLES2Decoder::Create(group_.get())); | 
|  | decoder_->SetIgnoreCachedStateForTest(ignore_cached_state_for_test_); | 
|  | decoder_->GetLogger()->set_log_synthesized_gl_errors(false); | 
|  | ASSERT_TRUE(decoder_->Initialize(surface_, context_, false, | 
|  | DisallowedFeatures(), attribs)); | 
|  |  | 
|  | EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true)); | 
|  | if (context_->WasAllocatedUsingRobustnessExtension()) { | 
|  | EXPECT_CALL(*gl_, GetGraphicsResetStatusARB()) | 
|  | .WillOnce(Return(GL_NO_ERROR)); | 
|  | } | 
|  | decoder_->MakeCurrent(); | 
|  | decoder_->set_engine(engine_.get()); | 
|  | decoder_->BeginDecoding(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GenBuffersARB(_, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceBufferId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::GenBuffersImmediate>(client_buffer_id_); | 
|  | EXPECT_CALL(*gl_, GenFramebuffersEXT(_, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceFramebufferId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::GenFramebuffersImmediate>(client_framebuffer_id_); | 
|  | EXPECT_CALL(*gl_, GenRenderbuffersEXT(_, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceRenderbufferId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::GenRenderbuffersImmediate>(client_renderbuffer_id_); | 
|  | EXPECT_CALL(*gl_, GenTextures(_, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceTextureId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::GenTexturesImmediate>(client_texture_id_); | 
|  | EXPECT_CALL(*gl_, GenBuffersARB(_, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceElementBufferId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::GenBuffersImmediate>(client_element_buffer_id_); | 
|  | GenHelper<cmds::GenQueriesEXTImmediate>(client_query_id_); | 
|  |  | 
|  | DoCreateProgram(client_program_id_, kServiceProgramId); | 
|  | DoCreateShader(GL_VERTEX_SHADER, client_shader_id_, kServiceShaderId); | 
|  |  | 
|  | if (init.context_type == CONTEXT_TYPE_WEBGL2 || | 
|  | init.context_type == CONTEXT_TYPE_OPENGLES3) { | 
|  | EXPECT_CALL(*gl_, GenSamplers(_, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceSamplerId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::GenSamplersImmediate>(client_sampler_id_); | 
|  |  | 
|  | EXPECT_CALL(*gl_, GenTransformFeedbacks(_, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceTransformFeedbackId)) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::GenTransformFeedbacksImmediate>( | 
|  | client_transformfeedback_id_); | 
|  |  | 
|  | DoFenceSync(client_sync_id_, kServiceSyncId); | 
|  | } | 
|  |  | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::ResetDecoder() { | 
|  | if (!decoder_.get()) | 
|  | return; | 
|  | // All Tests should have read all their GLErrors before getting here. | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | if (!decoder_->WasContextLost()) { | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)).Times(2).RetiresOnSaturation(); | 
|  | if (group_->feature_info()->feature_flags().native_vertex_array_object) { | 
|  | EXPECT_CALL(*gl_, | 
|  | DeleteVertexArraysOES(1, Pointee(kServiceVertexArrayId))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (group_->feature_info()->IsWebGL2OrES3Context()) { | 
|  | // fake default transform feedback. | 
|  | EXPECT_CALL(*gl_, DeleteTransformFeedbacks(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (group_->feature_info()->IsWebGL2OrES3Context()) { | 
|  | // |client_transformfeedback_id_| | 
|  | EXPECT_CALL(*gl_, DeleteTransformFeedbacks(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | decoder_->EndDecoding(); | 
|  | decoder_->Destroy(!decoder_->WasContextLost()); | 
|  | decoder_.reset(); | 
|  | group_->Destroy(mock_decoder_.get(), false); | 
|  | engine_.reset(); | 
|  | ::gl::MockGLInterface::SetGLInterface(NULL); | 
|  | gl_.reset(); | 
|  | gl::init::ShutdownGL(); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::TearDown() { | 
|  | ResetDecoder(); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::ExpectEnableDisable(GLenum cap, bool enable) { | 
|  | if (enable) { | 
|  | EXPECT_CALL(*gl_, Enable(cap)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } else { | 
|  | EXPECT_CALL(*gl_, Disable(cap)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | GLint GLES2DecoderTestBase::GetGLError() { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::GetError cmd; | 
|  | cmd.Init(shared_memory_id_, shared_memory_offset_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | return static_cast<GLint>(*GetSharedMemoryAs<GLenum*>()); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoCreateShader( | 
|  | GLenum shader_type, GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, CreateShader(shader_type)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(service_id)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::CreateShader cmd; | 
|  | cmd.Init(shader_type, client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | bool GLES2DecoderTestBase::DoIsShader(GLuint client_id) { | 
|  | return IsObjectHelper<cmds::IsShader, cmds::IsShader::Result>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoDeleteShader( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, DeleteShader(service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::DeleteShader cmd; | 
|  | cmd.Init(client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoCreateProgram( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, CreateProgram()) | 
|  | .Times(1) | 
|  | .WillOnce(Return(service_id)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::CreateProgram cmd; | 
|  | cmd.Init(client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | bool GLES2DecoderTestBase::DoIsProgram(GLuint client_id) { | 
|  | return IsObjectHelper<cmds::IsProgram, cmds::IsProgram::Result>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoDeleteProgram( | 
|  | GLuint client_id, GLuint /* service_id */) { | 
|  | cmds::DeleteProgram cmd; | 
|  | cmd.Init(client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoFenceSync( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) | 
|  | .Times(1) | 
|  | .WillOnce(Return(reinterpret_cast<GLsync>(service_id))) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::FenceSync cmd; | 
|  | cmd.Init(client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoCreateSampler( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, GenSamplers(1, _)) | 
|  | .WillOnce(SetArgPointee<1>(service_id)); | 
|  | cmds::GenSamplersImmediate* cmd = | 
|  | GetImmediateAs<cmds::GenSamplersImmediate>(); | 
|  | GLuint temp = client_id; | 
|  | cmd->Init(1, &temp); | 
|  | EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(*cmd, sizeof(temp))); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBindSampler( | 
|  | GLuint unit, GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, BindSampler(unit, service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::BindSampler cmd; | 
|  | cmd.Init(unit, client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoDeleteSampler( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, DeleteSamplers(1, Pointee(service_id))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::DeleteSamplersImmediate>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoCreateTransformFeedback( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, GenTransformFeedbacks(1, _)) | 
|  | .WillOnce(SetArgPointee<1>(service_id)); | 
|  | cmds::GenTransformFeedbacksImmediate* cmd = | 
|  | GetImmediateAs<cmds::GenTransformFeedbacksImmediate>(); | 
|  | GLuint temp = client_id; | 
|  | cmd->Init(1, &temp); | 
|  | EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(*cmd, sizeof(temp))); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBindTransformFeedback( | 
|  | GLenum target, GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, BindTransformFeedback(target, service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::BindTransformFeedback cmd; | 
|  | cmd.Init(target, client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoDeleteTransformFeedback( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, DeleteTransformFeedbacks(1, Pointee(service_id))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::DeleteTransformFeedbacksImmediate>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetBucketData( | 
|  | uint32_t bucket_id, const void* data, uint32_t data_size) { | 
|  | DCHECK(data || data_size == 0); | 
|  | cmd::SetBucketSize cmd1; | 
|  | cmd1.Init(bucket_id, data_size); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | if (data) { | 
|  | memcpy(shared_memory_address_, data, data_size); | 
|  | cmd::SetBucketData cmd2; | 
|  | cmd2.Init(bucket_id, 0, data_size, kSharedMemoryId, kSharedMemoryOffset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | ClearSharedMemory(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetBucketAsCString(uint32_t bucket_id, | 
|  | const char* str) { | 
|  | SetBucketData(bucket_id, str, str ? (strlen(str) + 1) : 0); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetBucketAsCStrings(uint32_t bucket_id, | 
|  | GLsizei count, | 
|  | const char** str, | 
|  | GLsizei count_in_header, | 
|  | char str_end) { | 
|  | uint32_t header_size = sizeof(GLint) * (count + 1); | 
|  | uint32_t total_size = header_size; | 
|  | std::unique_ptr<GLint[]> header(new GLint[count + 1]); | 
|  | header[0] = static_cast<GLint>(count_in_header); | 
|  | for (GLsizei ii = 0; ii < count; ++ii) { | 
|  | header[ii + 1] = str && str[ii] ? strlen(str[ii]) : 0; | 
|  | total_size += header[ii + 1] + 1; | 
|  | } | 
|  | cmd::SetBucketSize cmd1; | 
|  | cmd1.Init(bucket_id, total_size); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1)); | 
|  | memcpy(shared_memory_address_, header.get(), header_size); | 
|  | uint32_t offset = header_size; | 
|  | for (GLsizei ii = 0; ii < count; ++ii) { | 
|  | if (str && str[ii]) { | 
|  | size_t str_len = strlen(str[ii]); | 
|  | memcpy(reinterpret_cast<char*>(shared_memory_address_) + offset, | 
|  | str[ii], str_len); | 
|  | offset += str_len; | 
|  | } | 
|  | memcpy(reinterpret_cast<char*>(shared_memory_address_) + offset, | 
|  | &str_end, 1); | 
|  | offset += 1; | 
|  | } | 
|  | cmd::SetBucketData cmd2; | 
|  | cmd2.Init(bucket_id, 0, total_size, kSharedMemoryId, kSharedMemoryOffset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); | 
|  | ClearSharedMemory(); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupClearTextureExpectations(GLuint service_id, | 
|  | GLuint old_service_id, | 
|  | GLenum bind_target, | 
|  | GLenum target, | 
|  | GLint level, | 
|  | GLenum internal_format, | 
|  | GLenum format, | 
|  | GLenum type, | 
|  | GLint xoffset, | 
|  | GLint yoffset, | 
|  | GLsizei width, | 
|  | GLsizei height) { | 
|  | EXPECT_CALL(*gl_, BindTexture(bind_target, service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexSubImage2D(target, level, xoffset, yoffset, width, | 
|  | height, format, type, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindTexture(bind_target, old_service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForFramebufferClearing( | 
|  | GLenum target, | 
|  | GLuint clear_bits, | 
|  | GLclampf restore_red, | 
|  | GLclampf restore_green, | 
|  | GLclampf restore_blue, | 
|  | GLclampf restore_alpha, | 
|  | GLuint restore_stencil, | 
|  | GLclampf restore_depth, | 
|  | bool restore_scissor_test, | 
|  | GLint restore_scissor_x, | 
|  | GLint restore_scissor_y, | 
|  | GLsizei restore_scissor_width, | 
|  | GLsizei restore_scissor_height) { | 
|  | SetupExpectationsForFramebufferClearingMulti( | 
|  | 0, 0, target, clear_bits, restore_red, restore_green, restore_blue, | 
|  | restore_alpha, restore_stencil, restore_depth, restore_scissor_test, | 
|  | restore_scissor_x, restore_scissor_y, restore_scissor_width, | 
|  | restore_scissor_height); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForRestoreClearState( | 
|  | GLclampf restore_red, | 
|  | GLclampf restore_green, | 
|  | GLclampf restore_blue, | 
|  | GLclampf restore_alpha, | 
|  | GLuint restore_stencil, | 
|  | GLclampf restore_depth, | 
|  | bool restore_scissor_test, | 
|  | GLint restore_scissor_x, | 
|  | GLint restore_scissor_y, | 
|  | GLsizei restore_scissor_width, | 
|  | GLsizei restore_scissor_height) { | 
|  | EXPECT_CALL(*gl_, ClearColor( | 
|  | restore_red, restore_green, restore_blue, restore_alpha)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, ClearStencil(restore_stencil)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, ClearDepth(restore_depth)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | SetupExpectationsForEnableDisable(GL_SCISSOR_TEST, restore_scissor_test); | 
|  | EXPECT_CALL(*gl_, Scissor(restore_scissor_x, restore_scissor_y, | 
|  | restore_scissor_width, restore_scissor_height)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForFramebufferClearingMulti( | 
|  | GLuint read_framebuffer_service_id, | 
|  | GLuint draw_framebuffer_service_id, | 
|  | GLenum target, | 
|  | GLuint clear_bits, | 
|  | GLclampf restore_red, | 
|  | GLclampf restore_green, | 
|  | GLclampf restore_blue, | 
|  | GLclampf restore_alpha, | 
|  | GLuint restore_stencil, | 
|  | GLclampf restore_depth, | 
|  | bool restore_scissor_test, | 
|  | GLint restore_scissor_x, | 
|  | GLint restore_scissor_y, | 
|  | GLsizei restore_scissor_width, | 
|  | GLsizei restore_scissor_height) { | 
|  | // TODO(gman): Figure out why InSequence stopped working. | 
|  | // InSequence sequence; | 
|  | EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(target)) | 
|  | .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) | 
|  | .RetiresOnSaturation(); | 
|  | if (target == GL_READ_FRAMEBUFFER_EXT) { | 
|  | EXPECT_CALL(*gl_, BindFramebufferEXT( | 
|  | GL_DRAW_FRAMEBUFFER_EXT, read_framebuffer_service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if ((clear_bits & GL_COLOR_BUFFER_BIT) != 0) { | 
|  | EXPECT_CALL(*gl_, ClearColor(0.0f, 0.0f, 0.0f, 0.0f)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | SetupExpectationsForColorMask(true, true, true, true); | 
|  | } | 
|  | if ((clear_bits & GL_STENCIL_BUFFER_BIT) != 0) { | 
|  | EXPECT_CALL(*gl_, ClearStencil(0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | SetupExpectationsForStencilMask(static_cast<GLuint>(-1), | 
|  | static_cast<GLuint>(-1)); | 
|  | } | 
|  | if ((clear_bits & GL_DEPTH_BUFFER_BIT) != 0) { | 
|  | EXPECT_CALL(*gl_, ClearDepth(1.0f)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | SetupExpectationsForDepthMask(true); | 
|  | } | 
|  | SetupExpectationsForEnableDisable(GL_SCISSOR_TEST, false); | 
|  | EXPECT_CALL(*gl_, Clear(clear_bits)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | SetupExpectationsForRestoreClearState( | 
|  | restore_red, restore_green, restore_blue, restore_alpha, restore_stencil, | 
|  | restore_depth, restore_scissor_test, restore_scissor_x, restore_scissor_y, | 
|  | restore_scissor_width, restore_scissor_height); | 
|  | if (target == GL_READ_FRAMEBUFFER_EXT) { | 
|  | EXPECT_CALL(*gl_, BindFramebufferEXT( | 
|  | GL_DRAW_FRAMEBUFFER_EXT, draw_framebuffer_service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupShaderForUniform(GLenum uniform_type) { | 
|  | static AttribInfo attribs[] = { | 
|  | { "foo", 1, GL_FLOAT, 1, }, | 
|  | { "goo", 1, GL_FLOAT, 2, }, | 
|  | }; | 
|  | UniformInfo uniforms[] = { | 
|  | { "bar", 1, uniform_type, 0, 2, -1, }, | 
|  | { "car", 4, uniform_type, 1, 1, -1, }, | 
|  | }; | 
|  | const GLuint kClientVertexShaderId = 5001; | 
|  | const GLuint kServiceVertexShaderId = 6001; | 
|  | const GLuint kClientFragmentShaderId = 5002; | 
|  | const GLuint kServiceFragmentShaderId = 6002; | 
|  | SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms), | 
|  | client_program_id_, kServiceProgramId, | 
|  | kClientVertexShaderId, kServiceVertexShaderId, | 
|  | kClientFragmentShaderId, kServiceFragmentShaderId); | 
|  |  | 
|  | EXPECT_CALL(*gl_, UseProgram(kServiceProgramId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::UseProgram cmd; | 
|  | cmd.Init(client_program_id_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBindBuffer( | 
|  | GLenum target, GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, BindBuffer(target, service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | if (target == GL_PIXEL_PACK_BUFFER) { | 
|  | EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | cmds::BindBuffer cmd; | 
|  | cmd.Init(target, client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | bool GLES2DecoderTestBase::DoIsBuffer(GLuint client_id) { | 
|  | return IsObjectHelper<cmds::IsBuffer, cmds::IsBuffer::Result>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoDeleteBuffer( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, DeleteBuffersARB(1, Pointee(service_id))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::DeleteBuffersImmediate>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForColorMask(bool red, | 
|  | bool green, | 
|  | bool blue, | 
|  | bool alpha) { | 
|  | if (ignore_cached_state_for_test_ || cached_color_mask_red_ != red || | 
|  | cached_color_mask_green_ != green || cached_color_mask_blue_ != blue || | 
|  | cached_color_mask_alpha_ != alpha) { | 
|  | cached_color_mask_red_ = red; | 
|  | cached_color_mask_green_ = green; | 
|  | cached_color_mask_blue_ = blue; | 
|  | cached_color_mask_alpha_ = alpha; | 
|  | EXPECT_CALL(*gl_, ColorMask(red, green, blue, alpha)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForDepthMask(bool mask) { | 
|  | if (ignore_cached_state_for_test_ || cached_depth_mask_ != mask) { | 
|  | cached_depth_mask_ = mask; | 
|  | EXPECT_CALL(*gl_, DepthMask(mask)).Times(1).RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForStencilMask(GLuint front_mask, | 
|  | GLuint back_mask) { | 
|  | if (ignore_cached_state_for_test_ || | 
|  | cached_stencil_front_mask_ != front_mask) { | 
|  | cached_stencil_front_mask_ = front_mask; | 
|  | EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, front_mask)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | if (ignore_cached_state_for_test_ || | 
|  | cached_stencil_back_mask_ != back_mask) { | 
|  | cached_stencil_back_mask_ = back_mask; | 
|  | EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, back_mask)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForEnableDisable(GLenum cap, | 
|  | bool enable) { | 
|  | switch (cap) { | 
|  | case GL_BLEND: | 
|  | if (enable_flags_.cached_blend == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_blend = enable; | 
|  | break; | 
|  | case GL_CULL_FACE: | 
|  | if (enable_flags_.cached_cull_face == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_cull_face = enable; | 
|  | break; | 
|  | case GL_DEPTH_TEST: | 
|  | if (enable_flags_.cached_depth_test == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_depth_test = enable; | 
|  | break; | 
|  | case GL_DITHER: | 
|  | if (enable_flags_.cached_dither == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_dither = enable; | 
|  | break; | 
|  | case GL_POLYGON_OFFSET_FILL: | 
|  | if (enable_flags_.cached_polygon_offset_fill == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_polygon_offset_fill = enable; | 
|  | break; | 
|  | case GL_SAMPLE_ALPHA_TO_COVERAGE: | 
|  | if (enable_flags_.cached_sample_alpha_to_coverage == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_sample_alpha_to_coverage = enable; | 
|  | break; | 
|  | case GL_SAMPLE_COVERAGE: | 
|  | if (enable_flags_.cached_sample_coverage == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_sample_coverage = enable; | 
|  | break; | 
|  | case GL_SCISSOR_TEST: | 
|  | if (enable_flags_.cached_scissor_test == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_scissor_test = enable; | 
|  | break; | 
|  | case GL_STENCIL_TEST: | 
|  | if (enable_flags_.cached_stencil_test == enable && | 
|  | !ignore_cached_state_for_test_) | 
|  | return; | 
|  | enable_flags_.cached_stencil_test = enable; | 
|  | break; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | return; | 
|  | } | 
|  | if (enable) { | 
|  | EXPECT_CALL(*gl_, Enable(cap)).Times(1).RetiresOnSaturation(); | 
|  | } else { | 
|  | EXPECT_CALL(*gl_, Disable(cap)).Times(1).RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForApplyingDirtyState( | 
|  | bool framebuffer_is_rgb, | 
|  | bool framebuffer_has_depth, | 
|  | bool framebuffer_has_stencil, | 
|  | GLuint color_bits, | 
|  | bool depth_mask, | 
|  | bool depth_enabled, | 
|  | GLuint front_stencil_mask, | 
|  | GLuint back_stencil_mask, | 
|  | bool stencil_enabled) { | 
|  | bool color_mask_red = (color_bits & 0x1000) != 0; | 
|  | bool color_mask_green = (color_bits & 0x0100) != 0; | 
|  | bool color_mask_blue = (color_bits & 0x0010) != 0; | 
|  | bool color_mask_alpha = (color_bits & 0x0001) && !framebuffer_is_rgb; | 
|  |  | 
|  | SetupExpectationsForColorMask( | 
|  | color_mask_red, color_mask_green, color_mask_blue, color_mask_alpha); | 
|  | SetupExpectationsForDepthMask(depth_mask); | 
|  | SetupExpectationsForStencilMask(front_stencil_mask, back_stencil_mask); | 
|  | SetupExpectationsForEnableDisable(GL_DEPTH_TEST, | 
|  | framebuffer_has_depth && depth_enabled); | 
|  | SetupExpectationsForEnableDisable(GL_STENCIL_TEST, | 
|  | framebuffer_has_stencil && stencil_enabled); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupExpectationsForApplyingDefaultDirtyState() { | 
|  | SetupExpectationsForApplyingDirtyState(false,   // Framebuffer is RGB | 
|  | false,   // Framebuffer has depth | 
|  | false,   // Framebuffer has stencil | 
|  | 0x1111,  // color bits | 
|  | true,    // depth mask | 
|  | false,   // depth enabled | 
|  | 0,       // front stencil mask | 
|  | 0,       // back stencil mask | 
|  | false);  // stencil enabled | 
|  | } | 
|  |  | 
|  | GLES2DecoderTestBase::EnableFlags::EnableFlags() | 
|  | : cached_blend(false), | 
|  | cached_cull_face(false), | 
|  | cached_depth_test(false), | 
|  | cached_dither(true), | 
|  | cached_polygon_offset_fill(false), | 
|  | cached_sample_alpha_to_coverage(false), | 
|  | cached_sample_coverage(false), | 
|  | cached_scissor_test(false), | 
|  | cached_stencil_test(false) { | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBindFramebuffer( | 
|  | GLenum target, GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, BindFramebufferEXT(target, service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::BindFramebuffer cmd; | 
|  | cmd.Init(target, client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | bool GLES2DecoderTestBase::DoIsFramebuffer(GLuint client_id) { | 
|  | return IsObjectHelper<cmds::IsFramebuffer, cmds::IsFramebuffer::Result>( | 
|  | client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoDeleteFramebuffer( | 
|  | GLuint client_id, GLuint service_id, | 
|  | bool reset_draw, GLenum draw_target, GLuint draw_id, | 
|  | bool reset_read, GLenum read_target, GLuint read_id) { | 
|  | if (reset_draw) { | 
|  | EXPECT_CALL(*gl_, BindFramebufferEXT(draw_target, draw_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | if (reset_read) { | 
|  | EXPECT_CALL(*gl_, BindFramebufferEXT(read_target, read_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, Pointee(service_id))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::DeleteFramebuffersImmediate>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBindRenderbuffer( | 
|  | GLenum target, GLuint client_id, GLuint service_id) { | 
|  | service_renderbuffer_id_ = service_id; | 
|  | service_renderbuffer_valid_ = true; | 
|  | EXPECT_CALL(*gl_, BindRenderbufferEXT(target, service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::BindRenderbuffer cmd; | 
|  | cmd.Init(target, client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoRenderbufferStorageMultisampleCHROMIUM( | 
|  | GLenum target, | 
|  | GLsizei samples, | 
|  | GLenum internal_format, | 
|  | GLenum gl_format, | 
|  | GLsizei width, | 
|  | GLsizei height) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, | 
|  | RenderbufferStorageMultisampleEXT( | 
|  | target, samples, gl_format, width, height)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::RenderbufferStorageMultisampleCHROMIUM cmd; | 
|  | cmd.Init(target, samples, internal_format, width, height); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::RestoreRenderbufferBindings() { | 
|  | GetDecoder()->RestoreRenderbufferBindings(); | 
|  | service_renderbuffer_valid_ = false; | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::EnsureRenderbufferBound(bool expect_bind) { | 
|  | EXPECT_NE(expect_bind, service_renderbuffer_valid_); | 
|  |  | 
|  | if (expect_bind) { | 
|  | service_renderbuffer_valid_ = true; | 
|  | EXPECT_CALL(*gl_, | 
|  | BindRenderbufferEXT(GL_RENDERBUFFER, service_renderbuffer_id_)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } else { | 
|  | EXPECT_CALL(*gl_, BindRenderbufferEXT(_, _)).Times(0); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool GLES2DecoderTestBase::DoIsRenderbuffer(GLuint client_id) { | 
|  | return IsObjectHelper<cmds::IsRenderbuffer, cmds::IsRenderbuffer::Result>( | 
|  | client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoDeleteRenderbuffer( | 
|  | GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, Pointee(service_id))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | GenHelper<cmds::DeleteRenderbuffersImmediate>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBindTexture( | 
|  | GLenum target, GLuint client_id, GLuint service_id) { | 
|  | EXPECT_CALL(*gl_, BindTexture(target, service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | if (!group_->feature_info()->gl_version_info().BehavesLikeGLES() && | 
|  | group_->feature_info()->gl_version_info().IsAtLeastGL(3, 2)) { | 
|  | EXPECT_CALL(*gl_, TexParameteri(target, GL_DEPTH_TEXTURE_MODE, GL_RED)) | 
|  | .Times(AtMost(1)); | 
|  | } | 
|  | cmds::BindTexture cmd; | 
|  | cmd.Init(target, client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | bool GLES2DecoderTestBase::DoIsTexture(GLuint client_id) { | 
|  | return IsObjectHelper<cmds::IsTexture, cmds::IsTexture::Result>(client_id); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoDeleteTexture( | 
|  | GLuint client_id, GLuint service_id) { | 
|  |  | 
|  | { | 
|  | InSequence s; | 
|  |  | 
|  | // Calling DoDeleteTexture will unbind the texture from any texture units | 
|  | // it's currently bound to. | 
|  | EXPECT_CALL(*gl_, BindTexture(_, 0)) | 
|  | .Times(AnyNumber()); | 
|  |  | 
|  | EXPECT_CALL(*gl_, DeleteTextures(1, Pointee(service_id))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | GenHelper<cmds::DeleteTexturesImmediate>(client_id); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBindTexImage2DCHROMIUM(GLenum target, | 
|  | GLint image_id) { | 
|  | cmds::BindTexImage2DCHROMIUM bind_tex_image_2d_cmd; | 
|  | bind_tex_image_2d_cmd.Init(target, image_id); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(bind_tex_image_2d_cmd)); | 
|  | EXPECT_EQ(GL_NO_ERROR, GetGLError()); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoTexImage2D(GLenum target, | 
|  | GLint level, | 
|  | GLenum internal_format, | 
|  | GLsizei width, | 
|  | GLsizei height, | 
|  | GLint border, | 
|  | GLenum format, | 
|  | GLenum type, | 
|  | uint32_t shared_memory_id, | 
|  | uint32_t shared_memory_offset) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexImage2D(target, level, internal_format, | 
|  | width, height, border, format, type, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::TexImage2D cmd; | 
|  | cmd.Init(target, level, internal_format, width, height, format, | 
|  | type, shared_memory_id, shared_memory_offset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoTexImage2DConvertInternalFormat( | 
|  | GLenum target, | 
|  | GLint level, | 
|  | GLenum requested_internal_format, | 
|  | GLsizei width, | 
|  | GLsizei height, | 
|  | GLint border, | 
|  | GLenum format, | 
|  | GLenum type, | 
|  | uint32_t shared_memory_id, | 
|  | uint32_t shared_memory_offset, | 
|  | GLenum expected_internal_format) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexImage2D(target, level, expected_internal_format, | 
|  | width, height, border, format, type, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::TexImage2D cmd; | 
|  | cmd.Init(target, level, requested_internal_format, width, height, | 
|  | format, type, shared_memory_id, shared_memory_offset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoCompressedTexImage2D(GLenum target, | 
|  | GLint level, | 
|  | GLenum format, | 
|  | GLsizei width, | 
|  | GLsizei height, | 
|  | GLint border, | 
|  | GLsizei size, | 
|  | uint32_t bucket_id) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, CompressedTexImage2D( | 
|  | target, level, format, width, height, border, size, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | CommonDecoder::Bucket* bucket = decoder_->CreateBucket(bucket_id); | 
|  | bucket->SetSize(size); | 
|  | cmds::CompressedTexImage2DBucket cmd; | 
|  | cmd.Init( | 
|  | target, level, format, width, height, | 
|  | bucket_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoTexImage3D(GLenum target, | 
|  | GLint level, | 
|  | GLenum internal_format, | 
|  | GLsizei width, | 
|  | GLsizei height, | 
|  | GLsizei depth, | 
|  | GLint border, | 
|  | GLenum format, | 
|  | GLenum type, | 
|  | uint32_t shared_memory_id, | 
|  | uint32_t shared_memory_offset) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, TexImage3D(target, level, internal_format, | 
|  | width, height, depth, border, format, type, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::TexImage3D cmd; | 
|  | cmd.Init(target, level, internal_format, width, height, depth, format, type, | 
|  | shared_memory_id, shared_memory_offset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoRenderbufferStorage( | 
|  | GLenum target, GLenum internal_format, GLenum actual_format, | 
|  | GLsizei width, GLsizei height,  GLenum error) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, RenderbufferStorageEXT( | 
|  | target, actual_format, width, height)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(error)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::RenderbufferStorage cmd; | 
|  | cmd.Init(target, internal_format, width, height); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoFramebufferTexture2D( | 
|  | GLenum target, GLenum attachment, GLenum textarget, | 
|  | GLuint texture_client_id, GLuint texture_service_id, GLint level, | 
|  | GLenum error) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, FramebufferTexture2DEXT( | 
|  | target, attachment, textarget, texture_service_id, level)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(error)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::FramebufferTexture2D cmd; | 
|  | cmd.Init(target, attachment, textarget, texture_client_id, level); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoFramebufferRenderbuffer( | 
|  | GLenum target, | 
|  | GLenum attachment, | 
|  | GLenum renderbuffer_target, | 
|  | GLuint renderbuffer_client_id, | 
|  | GLuint renderbuffer_service_id, | 
|  | GLenum error) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { | 
|  | EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( | 
|  | target, GL_DEPTH_ATTACHMENT, renderbuffer_target, | 
|  | renderbuffer_service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(error)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( | 
|  | target, GL_STENCIL_ATTACHMENT, renderbuffer_target, | 
|  | renderbuffer_service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(error)) | 
|  | .RetiresOnSaturation(); | 
|  | } else { | 
|  | EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( | 
|  | target, attachment, renderbuffer_target, renderbuffer_service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(error)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | cmds::FramebufferRenderbuffer cmd; | 
|  | cmd.Init(target, attachment, renderbuffer_target, renderbuffer_client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | GLenum GLES2DecoderTestBase::DoCheckFramebufferStatus(GLenum target) { | 
|  | auto* result = static_cast<cmds::CheckFramebufferStatus::Result*>( | 
|  | shared_memory_address_); | 
|  | *result = 0; | 
|  | cmds::CheckFramebufferStatus cmd; | 
|  | cmd.Init(GL_FRAMEBUFFER, shared_memory_id_, shared_memory_offset_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | return *result; | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoVertexAttribPointer( | 
|  | GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset) { | 
|  | EXPECT_CALL(*gl_, | 
|  | VertexAttribPointer(index, size, type, GL_FALSE, stride, | 
|  | BufferOffset(offset))) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::VertexAttribPointer cmd; | 
|  | cmd.Init(index, size, GL_FLOAT, GL_FALSE, stride, offset); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoVertexAttribDivisorANGLE( | 
|  | GLuint index, GLuint divisor) { | 
|  | EXPECT_CALL(*gl_, | 
|  | VertexAttribDivisorANGLE(index, divisor)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::VertexAttribDivisorANGLE cmd; | 
|  | cmd.Init(index, divisor); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::AddExpectationsForGenVertexArraysOES(){ | 
|  | if (group_->feature_info()->feature_flags().native_vertex_array_object) { | 
|  | EXPECT_CALL(*gl_, GenVertexArraysOES(1, _)) | 
|  | .WillOnce(SetArgPointee<1>(kServiceVertexArrayId)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::AddExpectationsForDeleteVertexArraysOES(){ | 
|  | if (group_->feature_info()->feature_flags().native_vertex_array_object) { | 
|  | EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::AddExpectationsForDeleteBoundVertexArraysOES() { | 
|  | // Expectations are the same as a delete, followed by binding VAO 0. | 
|  | AddExpectationsForDeleteVertexArraysOES(); | 
|  | AddExpectationsForBindVertexArrayOES(); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::AddExpectationsForBindVertexArrayOES() { | 
|  | if (group_->feature_info()->feature_flags().native_vertex_array_object) { | 
|  | EXPECT_CALL(*gl_, BindVertexArrayOES(_)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } else { | 
|  | for (uint32_t vv = 0; vv < group_->max_vertex_attribs(); ++vv) { | 
|  | AddExpectationsForRestoreAttribState(vv); | 
|  | } | 
|  |  | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::AddExpectationsForRestoreAttribState(GLuint attrib) { | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, VertexAttribPointer(attrib, _, _, _, _, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(attrib, _)) | 
|  | .Times(testing::AtMost(1)) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | if (attrib != 0 || group_->feature_info()->gl_version_info().is_es) { | 
|  | // TODO(bajones): Not sure if I can tell which of these will be called | 
|  | EXPECT_CALL(*gl_, EnableVertexAttribArray(attrib)) | 
|  | .Times(testing::AtMost(1)) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | EXPECT_CALL(*gl_, DisableVertexAttribArray(attrib)) | 
|  | .Times(testing::AtMost(1)) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // GCC requires these declarations, but MSVC requires they not be present | 
|  | #ifndef COMPILER_MSVC | 
|  | const int GLES2DecoderTestBase::kBackBufferWidth; | 
|  | const int GLES2DecoderTestBase::kBackBufferHeight; | 
|  |  | 
|  | const GLint GLES2DecoderTestBase::kMaxTextureSize; | 
|  | const GLint GLES2DecoderTestBase::kMaxCubeMapTextureSize; | 
|  | const GLint GLES2DecoderTestBase::kNumVertexAttribs; | 
|  | const GLint GLES2DecoderTestBase::kNumTextureUnits; | 
|  | const GLint GLES2DecoderTestBase::kMaxTextureImageUnits; | 
|  | const GLint GLES2DecoderTestBase::kMaxVertexTextureImageUnits; | 
|  | const GLint GLES2DecoderTestBase::kMaxFragmentUniformVectors; | 
|  | const GLint GLES2DecoderTestBase::kMaxVaryingVectors; | 
|  | const GLint GLES2DecoderTestBase::kMaxVertexUniformVectors; | 
|  | const GLint GLES2DecoderTestBase::kMaxViewportWidth; | 
|  | const GLint GLES2DecoderTestBase::kMaxViewportHeight; | 
|  |  | 
|  | const GLint GLES2DecoderTestBase::kViewportX; | 
|  | const GLint GLES2DecoderTestBase::kViewportY; | 
|  | const GLint GLES2DecoderTestBase::kViewportWidth; | 
|  | const GLint GLES2DecoderTestBase::kViewportHeight; | 
|  |  | 
|  | const GLuint GLES2DecoderTestBase::kServiceAttrib0BufferId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceFixedAttribBufferId; | 
|  |  | 
|  | const GLuint GLES2DecoderTestBase::kServiceBufferId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceFramebufferId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceRenderbufferId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceSamplerId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceTextureId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceProgramId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceShaderId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceElementBufferId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceQueryId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceVertexArrayId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceTransformFeedbackId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceDefaultTransformFeedbackId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceSyncId; | 
|  |  | 
|  | const int32_t GLES2DecoderTestBase::kSharedMemoryId; | 
|  | const size_t GLES2DecoderTestBase::kSharedBufferSize; | 
|  | const uint32_t GLES2DecoderTestBase::kSharedMemoryOffset; | 
|  | const int32_t GLES2DecoderTestBase::kInvalidSharedMemoryId; | 
|  | const uint32_t GLES2DecoderTestBase::kInvalidSharedMemoryOffset; | 
|  | const uint32_t GLES2DecoderTestBase::kInitialResult; | 
|  | const uint8_t GLES2DecoderTestBase::kInitialMemoryValue; | 
|  |  | 
|  | const uint32_t GLES2DecoderTestBase::kNewClientId; | 
|  | const uint32_t GLES2DecoderTestBase::kNewServiceId; | 
|  | const uint32_t GLES2DecoderTestBase::kInvalidClientId; | 
|  |  | 
|  | const GLuint GLES2DecoderTestBase::kServiceVertexShaderId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceFragmentShaderId; | 
|  |  | 
|  | const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumShaderId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumProgramId; | 
|  |  | 
|  | const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumTextureBufferId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumVertexBufferId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumFBOId; | 
|  | const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumPositionAttrib; | 
|  | const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumTexAttrib; | 
|  | const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumSamplerLocation; | 
|  |  | 
|  | const GLsizei GLES2DecoderTestBase::kNumVertices; | 
|  | const GLsizei GLES2DecoderTestBase::kNumIndices; | 
|  | const int GLES2DecoderTestBase::kValidIndexRangeStart; | 
|  | const int GLES2DecoderTestBase::kValidIndexRangeCount; | 
|  | const int GLES2DecoderTestBase::kInvalidIndexRangeStart; | 
|  | const int GLES2DecoderTestBase::kInvalidIndexRangeCount; | 
|  | const int GLES2DecoderTestBase::kOutOfRangeIndexRangeEnd; | 
|  | const GLuint GLES2DecoderTestBase::kMaxValidIndex; | 
|  |  | 
|  | const GLint GLES2DecoderTestBase::kMaxAttribLength; | 
|  | const GLint GLES2DecoderTestBase::kAttrib1Size; | 
|  | const GLint GLES2DecoderTestBase::kAttrib2Size; | 
|  | const GLint GLES2DecoderTestBase::kAttrib3Size; | 
|  | const GLint GLES2DecoderTestBase::kAttrib1Location; | 
|  | const GLint GLES2DecoderTestBase::kAttrib2Location; | 
|  | const GLint GLES2DecoderTestBase::kAttrib3Location; | 
|  | const GLenum GLES2DecoderTestBase::kAttrib1Type; | 
|  | const GLenum GLES2DecoderTestBase::kAttrib2Type; | 
|  | const GLenum GLES2DecoderTestBase::kAttrib3Type; | 
|  | const GLint GLES2DecoderTestBase::kInvalidAttribLocation; | 
|  | const GLint GLES2DecoderTestBase::kBadAttribIndex; | 
|  |  | 
|  | const GLint GLES2DecoderTestBase::kMaxUniformLength; | 
|  | const GLint GLES2DecoderTestBase::kUniform1Size; | 
|  | const GLint GLES2DecoderTestBase::kUniform2Size; | 
|  | const GLint GLES2DecoderTestBase::kUniform3Size; | 
|  | const GLint GLES2DecoderTestBase::kUniform4Size; | 
|  | const GLint GLES2DecoderTestBase::kUniform5Size; | 
|  | const GLint GLES2DecoderTestBase::kUniform6Size; | 
|  | const GLint GLES2DecoderTestBase::kUniform7Size; | 
|  | const GLint GLES2DecoderTestBase::kUniform8Size; | 
|  | const GLint GLES2DecoderTestBase::kUniform1RealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform2RealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform2ElementRealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform3RealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform4RealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform5RealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform6RealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform7RealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform8RealLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform1FakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform2FakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform2ElementFakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform3FakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform4FakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform5FakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform6FakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform7FakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform8FakeLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform1DesiredLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform2DesiredLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform3DesiredLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform4DesiredLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform5DesiredLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform6DesiredLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform7DesiredLocation; | 
|  | const GLint GLES2DecoderTestBase::kUniform8DesiredLocation; | 
|  | const GLenum GLES2DecoderTestBase::kUniform1Type; | 
|  | const GLenum GLES2DecoderTestBase::kUniform2Type; | 
|  | const GLenum GLES2DecoderTestBase::kUniform3Type; | 
|  | const GLenum GLES2DecoderTestBase::kUniform4Type; | 
|  | const GLenum GLES2DecoderTestBase::kUniform5Type; | 
|  | const GLenum GLES2DecoderTestBase::kUniform6Type; | 
|  | const GLenum GLES2DecoderTestBase::kUniform7Type; | 
|  | const GLenum GLES2DecoderTestBase::kUniform8Type; | 
|  | const GLenum GLES2DecoderTestBase::kUniformCubemapType; | 
|  | const GLint GLES2DecoderTestBase::kInvalidUniformLocation; | 
|  | const GLint GLES2DecoderTestBase::kBadUniformIndex; | 
|  | const GLint GLES2DecoderTestBase::kOutputVariable1Size; | 
|  | const GLenum GLES2DecoderTestBase::kOutputVariable1Type; | 
|  | const GLuint GLES2DecoderTestBase::kOutputVariable1ColorName; | 
|  | const GLuint GLES2DecoderTestBase::kOutputVariable1Index; | 
|  | #endif | 
|  |  | 
|  | const char* GLES2DecoderTestBase::kAttrib1Name = "attrib1"; | 
|  | const char* GLES2DecoderTestBase::kAttrib2Name = "attrib2"; | 
|  | const char* GLES2DecoderTestBase::kAttrib3Name = "attrib3"; | 
|  | const char* GLES2DecoderTestBase::kUniform1Name = "uniform1"; | 
|  | const char* GLES2DecoderTestBase::kUniform2Name = "uniform2[0]"; | 
|  | const char* GLES2DecoderTestBase::kUniform3Name = "uniform3[0]"; | 
|  | const char* GLES2DecoderTestBase::kUniform4Name = "uniform4"; | 
|  | const char* GLES2DecoderTestBase::kUniform5Name = "uniform5"; | 
|  | const char* GLES2DecoderTestBase::kUniform6Name = "uniform6"; | 
|  | const char* GLES2DecoderTestBase::kUniform7Name = "uniform7"; | 
|  | const char* GLES2DecoderTestBase::kUniform8Name = "uniform8"; | 
|  |  | 
|  | const char* GLES2DecoderTestBase::kOutputVariable1Name = "gl_FragColor"; | 
|  | const char* GLES2DecoderTestBase::kOutputVariable1NameESSL3 = "color"; | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupDefaultProgram() { | 
|  | { | 
|  | static AttribInfo attribs[] = { | 
|  | { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, | 
|  | { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, }, | 
|  | { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, }, | 
|  | }; | 
|  | static UniformInfo uniforms[] = { | 
|  | { kUniform1Name, kUniform1Size, kUniform1Type, | 
|  | kUniform1FakeLocation, kUniform1RealLocation, | 
|  | kUniform1DesiredLocation }, | 
|  | { kUniform2Name, kUniform2Size, kUniform2Type, | 
|  | kUniform2FakeLocation, kUniform2RealLocation, | 
|  | kUniform2DesiredLocation }, | 
|  | { kUniform3Name, kUniform3Size, kUniform3Type, | 
|  | kUniform3FakeLocation, kUniform3RealLocation, | 
|  | kUniform3DesiredLocation }, | 
|  | { kUniform4Name, kUniform4Size, kUniform4Type, | 
|  | kUniform4FakeLocation, kUniform4RealLocation, | 
|  | kUniform4DesiredLocation }, | 
|  | { kUniform5Name, kUniform5Size, kUniform5Type, | 
|  | kUniform5FakeLocation, kUniform5RealLocation, | 
|  | kUniform5DesiredLocation }, | 
|  | { kUniform6Name, kUniform6Size, kUniform6Type, | 
|  | kUniform6FakeLocation, kUniform6RealLocation, | 
|  | kUniform6DesiredLocation }, | 
|  | { kUniform7Name, kUniform7Size, kUniform7Type, | 
|  | kUniform7FakeLocation, kUniform7RealLocation, | 
|  | kUniform7DesiredLocation }, | 
|  | { kUniform8Name, kUniform8Size, kUniform8Type, | 
|  | kUniform8FakeLocation, kUniform8RealLocation, | 
|  | kUniform8DesiredLocation }, | 
|  | }; | 
|  | SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms), | 
|  | client_program_id_, kServiceProgramId, | 
|  | client_vertex_shader_id_, kServiceVertexShaderId, | 
|  | client_fragment_shader_id_, kServiceFragmentShaderId); | 
|  | } | 
|  |  | 
|  | { | 
|  | EXPECT_CALL(*gl_, UseProgram(kServiceProgramId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::UseProgram cmd; | 
|  | cmd.Init(client_program_id_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupCubemapProgram() { | 
|  | { | 
|  | static AttribInfo attribs[] = { | 
|  | { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, | 
|  | { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, }, | 
|  | { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, }, | 
|  | }; | 
|  | static UniformInfo uniforms[] = { | 
|  | { kUniform1Name, kUniform1Size, kUniformCubemapType, | 
|  | kUniform1FakeLocation, kUniform1RealLocation, | 
|  | kUniform1DesiredLocation, }, | 
|  | { kUniform2Name, kUniform2Size, kUniform2Type, | 
|  | kUniform2FakeLocation, kUniform2RealLocation, | 
|  | kUniform2DesiredLocation, }, | 
|  | { kUniform3Name, kUniform3Size, kUniform3Type, | 
|  | kUniform3FakeLocation, kUniform3RealLocation, | 
|  | kUniform3DesiredLocation, }, | 
|  | { kUniform4Name, kUniform4Size, kUniform4Type, | 
|  | kUniform4FakeLocation, kUniform4RealLocation, | 
|  | kUniform4DesiredLocation, }, | 
|  | { kUniform5Name, kUniform5Size, kUniform5Type, | 
|  | kUniform5FakeLocation, kUniform5RealLocation, | 
|  | kUniform5DesiredLocation }, | 
|  | { kUniform6Name, kUniform6Size, kUniform6Type, | 
|  | kUniform6FakeLocation, kUniform6RealLocation, | 
|  | kUniform6DesiredLocation }, | 
|  | { kUniform7Name, kUniform7Size, kUniform7Type, | 
|  | kUniform7FakeLocation, kUniform7RealLocation, | 
|  | kUniform7DesiredLocation }, | 
|  | }; | 
|  | SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms), | 
|  | client_program_id_, kServiceProgramId, | 
|  | client_vertex_shader_id_, kServiceVertexShaderId, | 
|  | client_fragment_shader_id_, kServiceFragmentShaderId); | 
|  | } | 
|  |  | 
|  | { | 
|  | EXPECT_CALL(*gl_, UseProgram(kServiceProgramId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::UseProgram cmd; | 
|  | cmd.Init(client_program_id_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupSamplerExternalProgram() { | 
|  | { | 
|  | static AttribInfo attribs[] = { | 
|  | { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, | 
|  | { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, }, | 
|  | { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, }, | 
|  | }; | 
|  | static UniformInfo uniforms[] = { | 
|  | { kUniform1Name, kUniform1Size, kUniformSamplerExternalType, | 
|  | kUniform1FakeLocation, kUniform1RealLocation, | 
|  | kUniform1DesiredLocation, }, | 
|  | { kUniform2Name, kUniform2Size, kUniform2Type, | 
|  | kUniform2FakeLocation, kUniform2RealLocation, | 
|  | kUniform2DesiredLocation, }, | 
|  | { kUniform3Name, kUniform3Size, kUniform3Type, | 
|  | kUniform3FakeLocation, kUniform3RealLocation, | 
|  | kUniform3DesiredLocation, }, | 
|  | { kUniform4Name, kUniform4Size, kUniform4Type, | 
|  | kUniform4FakeLocation, kUniform4RealLocation, | 
|  | kUniform4DesiredLocation, }, | 
|  | { kUniform5Name, kUniform5Size, kUniform5Type, | 
|  | kUniform5FakeLocation, kUniform5RealLocation, | 
|  | kUniform5DesiredLocation }, | 
|  | { kUniform6Name, kUniform6Size, kUniform6Type, | 
|  | kUniform6FakeLocation, kUniform6RealLocation, | 
|  | kUniform6DesiredLocation }, | 
|  | { kUniform7Name, kUniform7Size, kUniform7Type, | 
|  | kUniform7FakeLocation, kUniform7RealLocation, | 
|  | kUniform7DesiredLocation }, | 
|  | }; | 
|  | SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms), | 
|  | client_program_id_, kServiceProgramId, | 
|  | client_vertex_shader_id_, kServiceVertexShaderId, | 
|  | client_fragment_shader_id_, kServiceFragmentShaderId); | 
|  | } | 
|  |  | 
|  | { | 
|  | EXPECT_CALL(*gl_, UseProgram(kServiceProgramId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::UseProgram cmd; | 
|  | cmd.Init(client_program_id_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderWithShaderTestBase::TearDown() { | 
|  | GLES2DecoderTestBase::TearDown(); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupShader( | 
|  | GLES2DecoderTestBase::AttribInfo* attribs, size_t num_attribs, | 
|  | GLES2DecoderTestBase::UniformInfo* uniforms, size_t num_uniforms, | 
|  | GLuint program_client_id, GLuint program_service_id, | 
|  | GLuint vertex_shader_client_id, GLuint vertex_shader_service_id, | 
|  | GLuint fragment_shader_client_id, GLuint fragment_shader_service_id) { | 
|  | static TestHelper::ProgramOutputInfo kProgramOutputsESSL1[] = {{ | 
|  | kOutputVariable1Name, kOutputVariable1Size, kOutputVariable1Type, | 
|  | kOutputVariable1ColorName, kOutputVariable1Index, | 
|  | }}; | 
|  | static TestHelper::ProgramOutputInfo kProgramOutputsESSL3[] = {{ | 
|  | kOutputVariable1NameESSL3, kOutputVariable1Size, kOutputVariable1Type, | 
|  | kOutputVariable1ColorName, kOutputVariable1Index, | 
|  | }}; | 
|  | TestHelper::ProgramOutputInfo* program_outputs = | 
|  | shader_language_version_ == 100 ? kProgramOutputsESSL1 | 
|  | : kProgramOutputsESSL3; | 
|  | const size_t kNumProgramOutputs = 1; | 
|  | const int kNumUniformBlocks = 2; | 
|  | const int kUniformBlockBinding[] = { 0, 1 }; | 
|  | const int kUniformBlockDataSize[] = { 32, 16 }; | 
|  |  | 
|  | { | 
|  | InSequence s; | 
|  |  | 
|  | EXPECT_CALL(*gl_, | 
|  | AttachShader(program_service_id, vertex_shader_service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, | 
|  | AttachShader(program_service_id, fragment_shader_service_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  |  | 
|  | TestHelper::SetupShaderExpectationsWithVaryings( | 
|  | gl_.get(), group_->feature_info(), attribs, num_attribs, uniforms, | 
|  | num_uniforms, nullptr, 0, program_outputs, kNumProgramOutputs, | 
|  | program_service_id); | 
|  | } | 
|  |  | 
|  | DoCreateShader( | 
|  | GL_VERTEX_SHADER, vertex_shader_client_id, vertex_shader_service_id); | 
|  | DoCreateShader( | 
|  | GL_FRAGMENT_SHADER, fragment_shader_client_id, | 
|  | fragment_shader_service_id); | 
|  |  | 
|  | TestHelper::SetShaderStates(gl_.get(), GetShader(vertex_shader_client_id), | 
|  | true, nullptr, nullptr, &shader_language_version_, | 
|  | nullptr, nullptr, nullptr, nullptr, nullptr, | 
|  | nullptr); | 
|  |  | 
|  | OutputVariableList frag_output_variable_list; | 
|  | frag_output_variable_list.push_back(TestHelper::ConstructOutputVariable( | 
|  | program_outputs[0].type, program_outputs[0].size, GL_MEDIUM_FLOAT, true, | 
|  | program_outputs[0].name)); | 
|  |  | 
|  | TestHelper::SetShaderStates(gl_.get(), GetShader(fragment_shader_client_id), | 
|  | true, nullptr, nullptr, &shader_language_version_, | 
|  | nullptr, nullptr, nullptr, nullptr, | 
|  | &frag_output_variable_list, nullptr); | 
|  |  | 
|  | cmds::AttachShader attach_cmd; | 
|  | attach_cmd.Init(program_client_id, vertex_shader_client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd)); | 
|  |  | 
|  | attach_cmd.Init(program_client_id, fragment_shader_client_id); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd)); | 
|  |  | 
|  | if (shader_language_version_ == 300) { | 
|  | EXPECT_CALL(*gl_, GetProgramiv( | 
|  | program_service_id, GL_ACTIVE_UNIFORM_BLOCKS, _)) | 
|  | .WillOnce(SetArgPointee<2>(kNumUniformBlocks)) | 
|  | .RetiresOnSaturation(); | 
|  | for (int ii = 0; ii < kNumUniformBlocks; ++ii) { | 
|  | EXPECT_CALL(*gl_, | 
|  | GetActiveUniformBlockiv(program_service_id, ii, | 
|  | GL_UNIFORM_BLOCK_BINDING, _)) | 
|  | .WillOnce(SetArgPointee<3>(kUniformBlockBinding[ii])) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, | 
|  | GetActiveUniformBlockiv(program_service_id, ii, | 
|  | GL_UNIFORM_BLOCK_DATA_SIZE, _)) | 
|  | .WillOnce(SetArgPointee<3>(kUniformBlockDataSize[ii])) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | cmds::LinkProgram link_cmd; | 
|  | link_cmd.Init(program_client_id); | 
|  |  | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(link_cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoEnableDisable(GLenum cap, bool enable) { | 
|  | SetupExpectationsForEnableDisable(cap, enable); | 
|  | if (enable) { | 
|  | cmds::Enable cmd; | 
|  | cmd.Init(cap); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } else { | 
|  | cmds::Disable cmd; | 
|  | cmd.Init(cap); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoEnableVertexAttribArray(GLint index) { | 
|  | EXPECT_CALL(*gl_, EnableVertexAttribArray(index)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::EnableVertexAttribArray cmd; | 
|  | cmd.Init(index); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBufferData(GLenum target, GLsizei size) { | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BufferData(target, size, _, GL_STREAM_DRAW)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::BufferData cmd; | 
|  | cmd.Init(target, size, 0, 0, GL_STREAM_DRAW); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoBufferSubData( | 
|  | GLenum target, GLint offset, GLsizei size, const void* data) { | 
|  | EXPECT_CALL(*gl_, BufferSubData(target, offset, size, | 
|  | shared_memory_address_)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | memcpy(shared_memory_address_, data, size); | 
|  | cmds::BufferSubData cmd; | 
|  | cmd.Init(target, offset, size, shared_memory_id_, shared_memory_offset_); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoScissor(GLint x, | 
|  | GLint y, | 
|  | GLsizei width, | 
|  | GLsizei height) { | 
|  | EXPECT_CALL(*gl_, Scissor(x, y, width, height)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::Scissor cmd; | 
|  | cmd.Init(x, y, width, height); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DoPixelStorei(GLenum pname, GLint param) { | 
|  | EXPECT_CALL(*gl_, PixelStorei(pname, param)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | cmds::PixelStorei cmd; | 
|  | cmd.Init(pname, param); | 
|  | EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupVertexBuffer() { | 
|  | DoEnableVertexAttribArray(1); | 
|  | DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId); | 
|  | DoBufferData(GL_ARRAY_BUFFER, kNumVertices * 2 * sizeof(GLfloat)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupAllNeededVertexBuffers() { | 
|  | DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId); | 
|  | DoBufferData(GL_ARRAY_BUFFER, kNumVertices * 16 * sizeof(float)); | 
|  | DoEnableVertexAttribArray(0); | 
|  | DoEnableVertexAttribArray(1); | 
|  | DoEnableVertexAttribArray(2); | 
|  | DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); | 
|  | DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); | 
|  | DoVertexAttribPointer(2, 2, GL_FLOAT, 0, 0); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupIndexBuffer() { | 
|  | DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER, | 
|  | client_element_buffer_id_, | 
|  | kServiceElementBufferId); | 
|  | static const GLshort indices[] = {100, 1, 2, 3, 4, 5, 6, 7, 100, 9}; | 
|  | static_assert(arraysize(indices) == kNumIndices, | 
|  | "indices should have kNumIndices elements"); | 
|  | DoBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices)); | 
|  | DoBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 2, indices); | 
|  | DoBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2, sizeof(indices) - 2, &indices[1]); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupTexture() { | 
|  | 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); | 
|  | }; | 
|  |  | 
|  | void GLES2DecoderTestBase::DeleteVertexBuffer() { | 
|  | DoDeleteBuffer(client_buffer_id_, kServiceBufferId); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::DeleteIndexBuffer() { | 
|  | DoDeleteBuffer(client_element_buffer_id_, kServiceElementBufferId); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::AddExpectationsForSimulatedAttrib0WithError( | 
|  | GLsizei num_vertices, GLuint buffer_id, GLenum error) { | 
|  | if (group_->feature_info()->gl_version_info().BehavesLikeGLES()) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | EXPECT_CALL(*gl_, GetError()) | 
|  | .WillOnce(Return(GL_NO_ERROR)) | 
|  | .WillOnce(Return(error)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceAttrib0BufferId)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BufferData(GL_ARRAY_BUFFER, | 
|  | num_vertices * sizeof(GLfloat) * 4, | 
|  | _, GL_DYNAMIC_DRAW)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | if (error == GL_NO_ERROR) { | 
|  | EXPECT_CALL(*gl_, BufferSubData( | 
|  | GL_ARRAY_BUFFER, 0, num_vertices * sizeof(GLfloat) * 4, _)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0)) | 
|  | .Times(testing::AtMost(1)) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, buffer_id)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::AddExpectationsForSimulatedAttrib0( | 
|  | GLsizei num_vertices, GLuint buffer_id) { | 
|  | AddExpectationsForSimulatedAttrib0WithError( | 
|  | num_vertices, buffer_id, GL_NO_ERROR); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupMockGLBehaviors() { | 
|  | ON_CALL(*gl_, BindVertexArrayOES(_)) | 
|  | .WillByDefault(Invoke( | 
|  | &gl_states_, | 
|  | &GLES2DecoderTestBase::MockGLStates::OnBindVertexArrayOES)); | 
|  | ON_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, _)) | 
|  | .WillByDefault(WithArg<1>(Invoke( | 
|  | &gl_states_, | 
|  | &GLES2DecoderTestBase::MockGLStates::OnBindArrayBuffer))); | 
|  | ON_CALL(*gl_, VertexAttribPointer(_, _, _, _, _, NULL)) | 
|  | .WillByDefault(InvokeWithoutArgs( | 
|  | &gl_states_, | 
|  | &GLES2DecoderTestBase::MockGLStates::OnVertexAttribNullPointer)); | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupInitStateManualExpectations(bool es3_capable) { | 
|  | if (es3_capable) { | 
|  | EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_ROW_LENGTH, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0)) | 
|  | .Times(1) | 
|  | .RetiresOnSaturation(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void GLES2DecoderTestBase::SetupInitStateManualExpectationsForDoLineWidth( | 
|  | GLfloat width) { | 
|  | EXPECT_CALL(*gl_, LineWidth(width)).Times(1).RetiresOnSaturation(); | 
|  | } | 
|  |  | 
|  | GLES2DecoderWithShaderTestBase::MockCommandBufferEngine:: | 
|  | MockCommandBufferEngine() { | 
|  | std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory()); | 
|  | shm->CreateAndMapAnonymous(kSharedBufferSize); | 
|  | valid_buffer_ = MakeBufferFromSharedMemory(std::move(shm), kSharedBufferSize); | 
|  |  | 
|  | ClearSharedMemory(); | 
|  | } | 
|  |  | 
|  | GLES2DecoderWithShaderTestBase::MockCommandBufferEngine:: | 
|  | ~MockCommandBufferEngine() {} | 
|  |  | 
|  | scoped_refptr<gpu::Buffer> | 
|  | GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::GetSharedMemoryBuffer( | 
|  | int32_t shm_id) { | 
|  | return shm_id == kSharedMemoryId ? valid_buffer_ : invalid_buffer_; | 
|  | } | 
|  |  | 
|  | void GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::set_token( | 
|  | int32_t token) { | 
|  | DCHECK(false); | 
|  | } | 
|  |  | 
|  | bool GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::SetGetBuffer( | 
|  | int32_t /* transfer_buffer_id */) { | 
|  | DCHECK(false); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::SetGetOffset( | 
|  | int32_t offset) { | 
|  | DCHECK(false); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | int32_t | 
|  | GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::GetGetOffset() { | 
|  | DCHECK(false); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void GLES2DecoderWithShaderTestBase::SetUp() { | 
|  | GLES2DecoderTestBase::SetUp(); | 
|  | SetupDefaultProgram(); | 
|  | } | 
|  |  | 
|  | // Include the auto-generated part of this file. We split this because it means | 
|  | // we can easily edit the non-auto generated parts right here in this file | 
|  | // instead of having to edit some template or the code generator. | 
|  | #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h" | 
|  |  | 
|  | }  // namespace gles2 | 
|  | }  // namespace gpu |