text: // 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 <algorithm>
  #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/common/value_state.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_implementation.h"
  #include "ui/gl/gl_mock.h"
  #include "ui/gl/test/gl_surface_test_support.h"
  
  using ::gfx::MockGLInterface;
  using ::testing::_;
  using ::testing::AnyNumber;
  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::SetArgumentPointee;
  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 kMaxColorAttachments = 16;
  const uint32 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_valuebuffer_id_(125),
        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)) {
    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) {}
  
  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() == ' ');
    gfx::SetGLGetProcAddressProc(gfx::MockGLInterface::GetGLProcAddress);
    gfx::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
  
    gl_.reset(new StrictMock<MockGLInterface>());
    ::gfx::MockGLInterface::SetGLInterface(gl_.get());
  
    SetupMockGLBehaviors();
  
    scoped_refptr<FeatureInfo> feature_info;
    if (command_line)
      feature_info = new FeatureInfo(*command_line);
    group_ = scoped_refptr<ContextGroup>(
        new ContextGroup(NULL, memory_tracker_, new ShaderTranslatorCache,
                         new FramebufferCompletenessCache, feature_info.get(),
                         new SubscriptionRefSet, new ValueStateMap,
                         normalized_init.bind_generates_resource));
    bool use_default_textures = normalized_init.bind_generates_resource;
  
    InSequence sequence;
  
    surface_ = new gfx::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());
    gfx::GLSurfaceTestSupport::InitializeDynamicMockBindings(context_.get());
  
    TestHelper::SetupContextGroupInitExpectations(
        gl_.get(),
        DisallowedFeatures(),
        normalized_init.extensions.c_str(),
        normalized_init.gl_version.c_str(),
        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(SetArgumentPointee<1>(kMaxColorAttachments))
          .RetiresOnSaturation();
      EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_DRAW_BUFFERS, _))
          .WillOnce(SetArgumentPointee<1>(kMaxDrawBuffers))
          .RetiresOnSaturation();
    }
  
    if (group_->feature_info()->feature_flags().native_vertex_array_object) {
      EXPECT_CALL(*gl_, GenVertexArraysOES(1, _))
          .WillOnce(SetArgumentPointee<1>(kServiceVertexArrayId))
          .RetiresOnSaturation();
      EXPECT_CALL(*gl_, BindVertexArrayOES(_)).Times(1).RetiresOnSaturation();
    }
  
    if (group_->feature_info()->workarounds().init_vertex_attributes)
      AddExpectationsForVertexAttribManager();
  
    AddExpectationsForBindVertexArrayOES();
  
    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) {
        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();
    EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _))
        .WillOnce(SetArgumentPointee<1>(normalized_init.has_alpha ? 8 : 0))
        .RetiresOnSaturation();
    EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _))
        .WillOnce(SetArgumentPointee<1>(normalized_init.has_depth ? 24 : 0))
        .RetiresOnSaturation();
    EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _))
        .WillOnce(SetArgumentPointee<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();
    }
  
    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();
  
    SetupInitCapabilitiesExpectations(group_->feature_info()->IsES3Capable());
    SetupInitStateExpectations();
  
    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();
  
    // 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*>(buffer->memory()) + shared_memory_offset_;
    shared_memory_id_ = kSharedMemoryId;
    shared_memory_base_ = buffer->memory();
  
    static const int32 kLoseContextWhenOutOfMemory = 0x10002;
    static const int32 kWebGLVersion = 0x10003;
  
    int32 attributes[] = {EGL_ALPHA_SIZE,
                          normalized_init.request_alpha ? 8 : 0,
                          EGL_DEPTH_SIZE,
                          normalized_init.request_depth ? 24 : 0,
                          EGL_STENCIL_SIZE,
                          normalized_init.request_stencil ? 8 : 0,
                          kLoseContextWhenOutOfMemory,
                          normalized_init.lose_context_when_out_of_memory ? 1 : 0,
                          kWebGLVersion,
                          init.context_type};
    std::vector<int32> attribs(attributes, attributes + arraysize(attributes));
  
    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,
                                     surface_->GetSize(), 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(SetArgumentPointee<1>(kServiceBufferId))
        .RetiresOnSaturation();
    GenHelper<cmds::GenBuffersImmediate>(client_buffer_id_);
    EXPECT_CALL(*gl_, GenFramebuffersEXT(_, _))
        .WillOnce(SetArgumentPointee<1>(kServiceFramebufferId))
        .RetiresOnSaturation();
    GenHelper<cmds::GenFramebuffersImmediate>(client_framebuffer_id_);
    EXPECT_CALL(*gl_, GenRenderbuffersEXT(_, _))
        .WillOnce(SetArgumentPointee<1>(kServiceRenderbufferId))
        .RetiresOnSaturation();
    GenHelper<cmds::GenRenderbuffersImmediate>(client_renderbuffer_id_);
    EXPECT_CALL(*gl_, GenTextures(_, _))
        .WillOnce(SetArgumentPointee<1>(kServiceTextureId))
        .RetiresOnSaturation();
    GenHelper<cmds::GenTexturesImmediate>(client_texture_id_);
    EXPECT_CALL(*gl_, GenBuffersARB(_, _))
        .WillOnce(SetArgumentPointee<1>(kServiceElementBufferId))
        .RetiresOnSaturation();
    GenHelper<cmds::GenBuffersImmediate>(client_element_buffer_id_);
  
    DoCreateProgram(client_program_id_, kServiceProgramId);
    DoCreateShader(GL_VERTEX_SHADER, client_shader_id_, kServiceShaderId);
  
    // Unsafe commands.
    bool reset_unsafe_es3_apis_enabled = false;
    if (!decoder_->unsafe_es3_apis_enabled()) {
      decoder_->set_unsafe_es3_apis_enabled(true);
      reset_unsafe_es3_apis_enabled = true;
    }
  
    const gfx::GLVersionInfo* version = context_->GetVersionInfo();
    if (version->IsAtLeastGL(3, 3) || version->IsAtLeastGLES(3, 0)) {
      EXPECT_CALL(*gl_, GenSamplers(_, _))
          .WillOnce(SetArgumentPointee<1>(kServiceSamplerId))
          .RetiresOnSaturation();
      GenHelper<cmds::GenSamplersImmediate>(client_sampler_id_);
    }
    if (version->IsAtLeastGL(4, 0) || version->IsAtLeastGLES(3, 0)) {
      EXPECT_CALL(*gl_, GenTransformFeedbacks(_, _))
          .WillOnce(SetArgumentPointee<1>(kServiceTransformFeedbackId))
          .RetiresOnSaturation();
      GenHelper<cmds::GenTransformFeedbacksImmediate>(
          client_transformfeedback_id_);
    }
  
    if (init.extensions.find("GL_ARB_sync ") != std::string::npos ||
        version->IsAtLeastGL(3, 2) || version->IsAtLeastGLES(3, 0)) {
      DoFenceSync(client_sync_id_, kServiceSyncId);
    }
  
    if (reset_unsafe_es3_apis_enabled) {
      decoder_->set_unsafe_es3_apis_enabled(false);
    }
  
    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());
  
    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();
    }
  
    decoder_->EndDecoding();
    decoder_->Destroy(true);
    decoder_.reset();
    group_->Destroy(mock_decoder_.get(), false);
    engine_.reset();
    ::gfx::MockGLInterface::SetGLInterface(NULL);
    gl_.reset();
    gfx::ClearGLBindings();
  }
  
  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::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 bucket_id, const char* str) {
    SetBucketData(bucket_id, str, str ? (strlen(str) + 1) : 0);
  }
  
  void GLES2DecoderTestBase::SetBucketAsCStrings(
      uint32 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;
    scoped_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_READ_FRAMEBUFFER_EXT, 0))
          .Times(1)
          .RetiresOnSaturation();
      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();
      EXPECT_CALL(*gl_, StencilMask(static_cast<GLuint>(-1)))
          .Times(1)
          .RetiresOnSaturation();
    }
    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_READ_FRAMEBUFFER_EXT, read_framebuffer_service_id))
          .Times(1)
          .RetiresOnSaturation();
      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();
    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();
    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 shared_memory_id, uint32 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 shared_memory_id, uint32 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 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::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);
    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();
    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));
  }
  
  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(SetArgumentPointee<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 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 ||
        gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
  
        // 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::kServiceSyncId;
  
  const int32 GLES2DecoderTestBase::kSharedMemoryId;
  const size_t GLES2DecoderTestBase::kSharedBufferSize;
  const uint32 GLES2DecoderTestBase::kSharedMemoryOffset;
  const int32 GLES2DecoderTestBase::kInvalidSharedMemoryId;
  const uint32 GLES2DecoderTestBase::kInvalidSharedMemoryOffset;
  const uint32 GLES2DecoderTestBase::kInitialResult;
  const uint8 GLES2DecoderTestBase::kInitialMemoryValue;
  
  const uint32 GLES2DecoderTestBase::kNewClientId;
  const uint32 GLES2DecoderTestBase::kNewServiceId;
  const uint32 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::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::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::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 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::kUniformCubemapType;
  const GLint GLES2DecoderTestBase::kInvalidUniformLocation;
  const GLint GLES2DecoderTestBase::kBadUniformIndex;
  
  #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";
  
  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 },
      };
      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) {
    {
      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::SetupShader(
          gl_.get(), attribs, num_attribs, uniforms, num_uniforms,
          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);
    TestHelper::SetShaderStates(
        gl_.get(), GetShader(fragment_shader_client_id), true);
  
    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));
  
    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::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));
  }
  
  GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::
  MockCommandBufferEngine() {
  
    scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
    shm->CreateAndMapAnonymous(kSharedBufferSize);
    valid_buffer_ = MakeBufferFromSharedMemory(shm.Pass(), kSharedBufferSize);
  
    ClearSharedMemory();
  }
  
  GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::
  ~MockCommandBufferEngine() {}
  
  scoped_refptr<gpu::Buffer>
  GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::GetSharedMemoryBuffer(
      int32 shm_id) {
    return shm_id == kSharedMemoryId ? valid_buffer_ : invalid_buffer_;
  }
  
  void GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::set_token(
      int32 token) {
    DCHECK(false);
  }
  
  bool GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::SetGetBuffer(
      int32 /* transfer_buffer_id */) {
    DCHECK(false);
    return false;
  }
  
  bool GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::SetGetOffset(
     int32 offset) {
    DCHECK(false);
    return false;
  }
  
  int32 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
  