Update from chromium https://crrev.com/304586

Review URL: https://codereview.chromium.org/732423002
diff --git a/gpu/command_buffer/client/fenced_allocator.cc b/gpu/command_buffer/client/fenced_allocator.cc
index 8003857..6db6e50 100644
--- a/gpu/command_buffer/client/fenced_allocator.cc
+++ b/gpu/command_buffer/client/fenced_allocator.cc
@@ -14,23 +14,22 @@
 
 namespace {
 
-// Allocation alignment, must be a power of two.
-const unsigned int kAllocAlignment = 16;
-
 // Round down to the largest multiple of kAllocAlignment no greater than |size|.
 unsigned int RoundDown(unsigned int size) {
-  return size & ~(kAllocAlignment - 1);
+  return size & ~(FencedAllocator::kAllocAlignment - 1);
 }
 
 // Round up to the smallest multiple of kAllocAlignment no smaller than |size|.
 unsigned int RoundUp(unsigned int size) {
-  return (size + (kAllocAlignment - 1)) & ~(kAllocAlignment - 1);
+  return (size + (FencedAllocator::kAllocAlignment - 1)) &
+      ~(FencedAllocator::kAllocAlignment - 1);
 }
 
 }  // namespace
 
 #ifndef _MSC_VER
 const FencedAllocator::Offset FencedAllocator::kInvalidOffset;
+const unsigned int FencedAllocator::kAllocAlignment;
 #endif
 
 FencedAllocator::FencedAllocator(unsigned int size,
diff --git a/gpu/command_buffer/client/fenced_allocator.h b/gpu/command_buffer/client/fenced_allocator.h
index 8e222e1..578870d 100644
--- a/gpu/command_buffer/client/fenced_allocator.h
+++ b/gpu/command_buffer/client/fenced_allocator.h
@@ -35,6 +35,9 @@
   // Invalid offset, returned by Alloc in case of failure.
   static const Offset kInvalidOffset = 0xffffffffU;
 
+  // Allocation alignment, must be a power of two.
+  static const unsigned int kAllocAlignment = 16;
+
   // Creates a FencedAllocator. Note that the size of the buffer is passed, but
   // not its base address: everything is handled as offsets into the buffer.
   FencedAllocator(unsigned int size,
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index fc6ca5d..1919879 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -26,7 +26,7 @@
 MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper,
                                          const base::Closure& poll_callback,
                                          size_t unused_memory_reclaim_limit)
-    : chunk_size_multiple_(1),
+    : chunk_size_multiple_(FencedAllocator::kAllocAlignment),
       helper_(helper),
       poll_callback_(poll_callback),
       allocated_memory_(0),
diff --git a/gpu/command_buffer/client/mapped_memory.h b/gpu/command_buffer/client/mapped_memory.h
index 789e69c..10ac639 100644
--- a/gpu/command_buffer/client/mapped_memory.h
+++ b/gpu/command_buffer/client/mapped_memory.h
@@ -135,6 +135,7 @@
   }
 
   void set_chunk_size_multiple(unsigned int multiple) {
+    DCHECK(multiple % FencedAllocator::kAllocAlignment == 0);
     chunk_size_multiple_ = multiple;
   }
 
@@ -201,4 +202,3 @@
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
-
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 4013c3a..1c43029 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -44,6 +44,8 @@
     "feature_info.cc",
     "framebuffer_manager.h",
     "framebuffer_manager.cc",
+    "gles2_cmd_clear_framebuffer.cc",
+    "gles2_cmd_clear_framebuffer.h",
     "gles2_cmd_copy_texture_chromium.cc",
     "gles2_cmd_copy_texture_chromium.h",
     "gles2_cmd_decoder.h",
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 24e1f92..6dd1f34 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -848,6 +848,9 @@
   if (workarounds_.disable_egl_khr_fence_sync) {
     gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync = false;
   }
+  if (workarounds_.disable_egl_khr_wait_sync) {
+    gfx::g_driver_egl.ext.b_EGL_KHR_wait_sync = false;
+  }
 #endif
   if (workarounds_.disable_arb_sync)
     gfx::g_driver_gl.ext.b_GL_ARB_sync = false;
@@ -855,12 +858,14 @@
   UMA_HISTOGRAM_BOOLEAN("GPU.FenceSupport", ui_gl_fence_works);
 
   feature_flags_.map_buffer_range =
-      is_es3 || extensions.Contains("GL_ARB_map_buffer_range");
+      is_es3 || extensions.Contains("GL_ARB_map_buffer_range") ||
+      extensions.Contains("GL_EXT_map_buffer_range");
 
   // Really it's part of core OpenGL 2.1 and up, but let's assume the
   // extension is still advertised.
   bool has_pixel_buffers =
-      is_es3 || extensions.Contains("GL_ARB_pixel_buffer_object");
+      is_es3 || extensions.Contains("GL_ARB_pixel_buffer_object") ||
+      extensions.Contains("GL_NV_pixel_buffer_object");
 
   // We will use either glMapBuffer() or glMapBufferRange() for async readbacks.
   if (has_pixel_buffers && ui_gl_fence_works &&
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index 88a0a37..53dbf6c 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -134,6 +134,7 @@
 #undef GPU_OP
   EXPECT_EQ(0, info_->workarounds().max_texture_size);
   EXPECT_EQ(0, info_->workarounds().max_cube_map_texture_size);
+  EXPECT_FALSE(info_->workarounds().gl_clear_broken);
 
   // Test good types.
   {
diff --git a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc
new file mode 100644
index 0000000..765dcb9
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc
@@ -0,0 +1,188 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h"
+
+#include "base/basictypes.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+namespace {
+
+#define SHADER(src)            \
+  "#ifdef GL_ES\n"             \
+  "precision mediump float;\n" \
+  "#endif\n" #src
+
+const char* g_vertex_shader_source = {
+  SHADER(
+    uniform float u_clear_depth;
+    attribute vec4 a_position;
+    void main(void) {
+      gl_Position = vec4(a_position.x, a_position.y, u_clear_depth, 1.0);
+    }
+  ),
+};
+
+const char* g_fragment_shader_source = {
+  SHADER(
+    uniform vec4 u_clear_color;
+    void main(void) {
+      gl_FragColor = u_clear_color;
+    }
+  ),
+};
+
+void CompileShader(GLuint shader, const char* shader_source) {
+  glShaderSource(shader, 1, &shader_source, 0);
+  glCompileShader(shader);
+#if DCHECK_IS_ON
+  GLint compile_status = GL_FALSE;
+  glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+  if (GL_TRUE != compile_status) {
+    char buffer[1024];
+    GLsizei length = 0;
+    glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer);
+    std::string log(buffer, length);
+    DLOG(ERROR) << "Error compiling shader: " << log;
+    DLOG(ERROR) << "Shader compilation failure.";
+  }
+#endif
+}
+
+}  // namespace
+
+namespace gpu {
+
+ClearFramebufferResourceManager::ClearFramebufferResourceManager(
+    const gles2::GLES2Decoder* decoder)
+    : initialized_(false), program_(0u), buffer_id_(0u) {
+  Initialize(decoder);
+}
+
+ClearFramebufferResourceManager::~ClearFramebufferResourceManager() {
+  Destroy();
+  DCHECK(!buffer_id_);
+}
+
+void ClearFramebufferResourceManager::Initialize(
+    const gles2::GLES2Decoder* decoder) {
+  COMPILE_ASSERT(
+      kVertexPositionAttrib == 0u,
+      Position_attribs_must_be_0);
+  DCHECK(!buffer_id_);
+
+  glGenBuffersARB(1, &buffer_id_);
+  glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
+  const GLfloat kQuadVertices[] = {-1.0f, -1.0f,
+                                    1.0f, -1.0f,
+                                    1.0f,  1.0f,
+                                   -1.0f,  1.0f};
+  glBufferData(
+      GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
+  decoder->RestoreBufferBindings();
+  initialized_ = true;
+}
+
+void ClearFramebufferResourceManager::Destroy() {
+  if (!initialized_)
+    return;
+
+  glDeleteProgram(program_);
+  glDeleteBuffersARB(1, &buffer_id_);
+  buffer_id_ = 0;
+}
+
+void ClearFramebufferResourceManager::ClearFramebuffer(
+    const gles2::GLES2Decoder* decoder,
+    const gfx::Size& framebuffer_size,
+    GLbitfield mask,
+    GLfloat clear_color_red,
+    GLfloat clear_color_green,
+    GLfloat clear_color_blue,
+    GLfloat clear_color_alpha,
+    GLfloat clear_depth_value,
+    GLint clear_stencil_value) {
+  if (!initialized_) {
+    DLOG(ERROR) << "Uninitialized manager.";
+    return;
+  }
+
+  if (!program_) {
+    program_ = glCreateProgram();
+    GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+    CompileShader(vertex_shader, g_vertex_shader_source);
+    glAttachShader(program_, vertex_shader);
+    GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+    CompileShader(fragment_shader, g_fragment_shader_source);
+    glAttachShader(program_, fragment_shader);
+    glBindAttribLocation(program_, kVertexPositionAttrib, "a_position");
+    glLinkProgram(program_);
+#if DCHECK_IS_ON
+    GLint linked = GL_FALSE;
+    glGetProgramiv(program_, GL_LINK_STATUS, &linked);
+    if (GL_TRUE != linked)
+      DLOG(ERROR) << "Program link failure.";
+#endif
+    depth_handle_ = glGetUniformLocation(program_, "u_clear_depth");
+    color_handle_ = glGetUniformLocation(program_, "u_clear_color");
+    glDeleteShader(fragment_shader);
+    glDeleteShader(vertex_shader);
+  }
+  glUseProgram(program_);
+
+#if DCHECK_IS_ON
+  glValidateProgram(program_);
+  GLint validation_status = GL_FALSE;
+  glGetProgramiv(program_, GL_VALIDATE_STATUS, &validation_status);
+  if (GL_TRUE != validation_status)
+    DLOG(ERROR) << "Invalid shader.";
+#endif
+
+  decoder->ClearAllAttributes();
+  glEnableVertexAttribArray(kVertexPositionAttrib);
+
+  glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
+  glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+  glUniform1f(depth_handle_, clear_depth_value);
+  glUniform4f(color_handle_, clear_color_red, clear_color_green,
+              clear_color_blue, clear_color_alpha);
+
+  if (!(mask & GL_COLOR_BUFFER_BIT)) {
+    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+  }
+
+  if (mask & GL_DEPTH_BUFFER_BIT) {
+    glEnable(GL_DEPTH_TEST);
+    glDepthFunc(GL_ALWAYS);
+  } else {
+    glDisable(GL_DEPTH_TEST);
+    glDepthMask(GL_FALSE);
+  }
+
+  if (mask & GL_STENCIL_BUFFER_BIT) {
+    glEnable(GL_STENCIL_TEST);
+    glStencilFunc(GL_ALWAYS, clear_stencil_value, 0xFF);
+    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+  } else {
+    glDisable(GL_STENCIL_TEST);
+    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+    glStencilMask(0);
+  }
+
+  glDisable(GL_CULL_FACE);
+  glDisable(GL_BLEND);
+  glDisable(GL_POLYGON_OFFSET_FILL);
+
+  glViewport(0, 0, framebuffer_size.width(), framebuffer_size.height());
+  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+  decoder->RestoreAllAttributes();
+  decoder->RestoreProgramBindings();
+  decoder->RestoreBufferBindings();
+  decoder->RestoreGlobalState();
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
new file mode 100644
index 0000000..6b533f5
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
@@ -0,0 +1,54 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_CLEAR_FRAMEBUFFER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_CLEAR_FRAMEBUFFER_H_
+
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace gpu {
+namespace gles2 {
+class GLES2Decoder;
+}
+
+class GPU_EXPORT ClearFramebufferResourceManager {
+ public:
+  ClearFramebufferResourceManager(const gles2::GLES2Decoder* decoder);
+  ~ClearFramebufferResourceManager();
+
+
+  void ClearFramebuffer(const gles2::GLES2Decoder* decoder,
+                        const gfx::Size& framebuffer_size,
+                        GLbitfield mask,
+                        GLfloat clear_color_red,
+                        GLfloat clear_color_green,
+                        GLfloat clear_color_blue,
+                        GLfloat clear_color_alpha,
+                        GLfloat clear_depth_value,
+                        GLint clear_stencil_value);
+
+ private:
+  void Initialize(const gles2::GLES2Decoder* decoder);
+  void Destroy();
+
+  // The attributes used during invocation of the extension.
+  static const GLuint kVertexPositionAttrib = 0;
+
+  bool initialized_;
+  GLuint program_;
+  GLuint depth_handle_;
+  GLuint color_handle_;
+  GLuint buffer_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClearFramebufferResourceManager);
+};
+
+}  // namespace gpu.
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_CLEAR_FRAMEBUFFER_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 4d54739..dec594b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -41,6 +41,7 @@
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
 #include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h"
 #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
 #include "gpu/command_buffer/service/gles2_cmd_validation.h"
 #include "gpu/command_buffer/service/gpu_state_tracer.h"
@@ -1840,6 +1841,7 @@
 #endif
 
   scoped_ptr<CopyTextureCHROMIUMResourceManager> copy_texture_CHROMIUM_;
+  scoped_ptr<ClearFramebufferResourceManager> clear_framebuffer_blit_;
 
   // Cached values of the currently assigned viewport dimensions.
   GLsizei viewport_max_width_;
@@ -2764,6 +2766,14 @@
       AsyncPixelTransferManager::Create(context.get()));
   async_pixel_transfer_manager_->Initialize(texture_manager());
 
+  if (workarounds().gl_clear_broken) {
+    DCHECK(!clear_framebuffer_blit_.get());
+    LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glClearWorkaroundInit");
+    clear_framebuffer_blit_.reset(new ClearFramebufferResourceManager(this));
+    if (LOCAL_PEEK_GL_ERROR("glClearWorkaroundInit") != GL_NO_ERROR)
+      return false;
+  }
+
   framebuffer_manager()->AddObserver(this);
 
   return true;
@@ -3549,6 +3559,8 @@
       copy_texture_CHROMIUM_.reset();
     }
 
+    clear_framebuffer_blit_.reset();
+
     if (state_.current_program.get()) {
       program_manager()->UnuseProgram(shader_manager(),
                                       state_.current_program.get());
@@ -3614,6 +3626,7 @@
   state_.current_program = NULL;
 
   copy_texture_CHROMIUM_.reset();
+  clear_framebuffer_blit_.reset();
 
   if (query_manager_.get()) {
     query_manager_->Destroy(have_context);
@@ -5106,6 +5119,19 @@
   if (CheckBoundFramebuffersValid("glClear")) {
     ApplyDirtyState();
     ScopedRenderTo do_render(framebuffer_state_.bound_draw_framebuffer.get());
+    if (workarounds().gl_clear_broken) {
+      ScopedGLErrorSuppressor suppressor("GLES2DecoderImpl::ClearWorkaround",
+                                         GetErrorState());
+      if (!BoundFramebufferHasDepthAttachment())
+        mask &= ~GL_DEPTH_BUFFER_BIT;
+      if (!BoundFramebufferHasStencilAttachment())
+        mask &= ~GL_STENCIL_BUFFER_BIT;
+      clear_framebuffer_blit_->ClearFramebuffer(
+          this, GetBoundReadFrameBufferSize(), mask, state_.color_clear_red,
+          state_.color_clear_green, state_.color_clear_blue,
+          state_.color_clear_alpha, state_.depth_clear, state_.stencil_clear);
+      return error::kNoError;
+    }
     glClear(mask);
   }
   return error::kNoError;
@@ -7578,6 +7604,11 @@
     } else {
       data = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
     }
+    if (!data) {
+      LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glMapBuffer",
+                         "Unable to map memory for readback.");
+      return;
+    }
     memcpy(pixels, data, pixels_size);
     // GL_PIXEL_PACK_BUFFER_ARB is currently unused, so we don't
     // have to restore the state.
@@ -7779,7 +7810,10 @@
       GLuint buffer = 0;
       glGenBuffersARB(1, &buffer);
       glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
-      glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, GL_STREAM_READ);
+      // For ANGLE client version 2, GL_STREAM_READ is not available.
+      const GLenum usage_hint =
+          features().is_angle ? GL_STATIC_DRAW : GL_STREAM_READ;
+      glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, usage_hint);
       GLenum error = glGetError();
       if (error == GL_NO_ERROR) {
         glReadPixels(x, y, width, height, format, type, 0);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 0ef9585..ef37c90 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -666,8 +666,6 @@
 
   EXPECT_TRUE(process_success);
   EXPECT_FALSE(query->pending());
-  QuerySync* sync = static_cast<QuerySync*>(shared_memory_address_);
-  EXPECT_EQ(static_cast<GLenum>(0), static_cast<GLenum>(sync->result));
 
 #if DCHECK_IS_ON
   EXPECT_CALL(*gl_, IsSync(kGlSync))
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
index fdb5fa8..8b75333 100644
--- a/gpu/command_buffer/service/query_manager.cc
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -408,6 +408,7 @@
 
  private:
   scoped_ptr<gfx::GLFence> fence_;
+  base::TimeTicks begin_time_;
 };
 
 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
@@ -416,7 +417,10 @@
                                                uint32 shm_offset)
     : Query(manager, target, shm_id, shm_offset) {}
 
-bool CommandsCompletedQuery::Begin() { return true; }
+bool CommandsCompletedQuery::Begin() {
+  begin_time_ = base::TimeTicks::HighResNow();
+  return true;
+}
 
 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
   fence_.reset(gfx::GLFence::Create());
@@ -428,13 +432,11 @@
   // Note: |did_finish| guarantees that the GPU has passed the fence but
   // we cannot assume that GLFence::HasCompleted() will return true yet as
   // that's not guaranteed by all GLFence implementations.
-  //
-  // TODO(reveman): Add UMA stats to determine how common it is that glFinish()
-  // needs to be called for these queries to complete. crbug.com/431845
   if (!did_finish && fence_ && !fence_->HasCompleted())
     return true;
 
-  return MarkAsCompleted(0);
+  base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_;
+  return MarkAsCompleted(elapsed.InMicroseconds());
 }
 
 void CommandsCompletedQuery::Destroy(bool have_context) {
diff --git a/gpu/command_buffer/tests/gl_clear_framebuffer_unittest.cc b/gpu/command_buffer/tests/gl_clear_framebuffer_unittest.cc
new file mode 100644
index 0000000..8a925c8
--- /dev/null
+++ b/gpu/command_buffer/tests/gl_clear_framebuffer_unittest.cc
@@ -0,0 +1,200 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/tests/gl_manager.h"
+#include "gpu/command_buffer/tests/gl_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+// A collection of tests that exercise the glClear workaround.
+class GLClearFramebufferTest : public testing::TestWithParam<bool> {
+ public:
+  GLClearFramebufferTest() : color_handle_(0u), depth_handle_(0u) {}
+
+ protected:
+  void SetUp() override {
+    if (GetParam()) {
+      // Force the glClear() workaround so we can test it here.
+      CommandLine command_line(base::CommandLine::NO_PROGRAM);
+      command_line.AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
+                                     base::IntToString(gpu::GL_CLEAR_BROKEN));
+      gl_.InitializeWithCommandLine(GLManager::Options(), &command_line);
+      DCHECK(gl_.workarounds().gl_clear_broken);
+    } else {
+      gl_.Initialize(GLManager::Options());
+      DCHECK(!gl_.workarounds().gl_clear_broken);
+    }
+  }
+
+  void InitDraw();
+  void SetDrawColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+  void SetDrawDepth(GLfloat depth);
+  void DrawQuad();
+
+  void TearDown() override {
+    GLTestHelper::CheckGLError("no errors", __LINE__);
+    gl_.Destroy();
+  }
+
+ private:
+  GLManager gl_;
+  GLuint color_handle_;
+  GLuint depth_handle_;
+};
+
+void GLClearFramebufferTest::InitDraw() {
+  static const char* v_shader_str =
+      "attribute vec4 a_Position;\n"
+      "uniform float u_depth;\n"
+      "void main()\n"
+      "{\n"
+      "   gl_Position = a_Position;\n"
+      "   gl_Position.z = u_depth;\n"
+      "}\n";
+  static const char* f_shader_str =
+      "precision mediump float;\n"
+      "uniform vec4 u_draw_color;\n"
+      "void main()\n"
+      "{\n"
+      "  gl_FragColor = u_draw_color;\n"
+      "}\n";
+
+  GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
+  DCHECK(program);
+  glUseProgram(program);
+  GLuint position_loc = glGetAttribLocation(program, "a_Position");
+
+  GLTestHelper::SetupUnitQuad(position_loc);
+  color_handle_ = glGetUniformLocation(program, "u_draw_color");
+  DCHECK(color_handle_ != static_cast<GLuint>(-1));
+  depth_handle_ = glGetUniformLocation(program, "u_depth");
+  DCHECK(depth_handle_ != static_cast<GLuint>(-1));
+}
+
+void GLClearFramebufferTest::SetDrawColor(GLfloat r,
+                                          GLfloat g,
+                                          GLfloat b,
+                                          GLfloat a) {
+  glUniform4f(color_handle_, r, g, b, a);
+}
+
+void GLClearFramebufferTest::SetDrawDepth(GLfloat depth) {
+  glUniform1f(depth_handle_, depth);
+}
+
+void GLClearFramebufferTest::DrawQuad() {
+  glDrawArrays(GL_TRIANGLES, 0, 6);
+}
+
+INSTANTIATE_TEST_CASE_P(GLClearFramebufferTestWithParam,
+                        GLClearFramebufferTest,
+                        ::testing::Values(true, false));
+
+TEST_P(GLClearFramebufferTest, ClearColor) {
+  glClearColor(1.0f, 0.5f, 0.25f, 0.5f);
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  // Verify.
+  const uint8 expected[] = {255, 128, 64, 128};
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 1 /* tolerance */, expected));
+}
+
+TEST_P(GLClearFramebufferTest, ClearColorWithMask) {
+  glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
+  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  // Verify.
+  const uint8 expected[] = {255, 0, 0, 0};
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
+}
+
+// crbug.com/434094
+#if !defined(OS_MACOSX)
+TEST_P(GLClearFramebufferTest, ClearColorWithScissor) {
+  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  // Verify.
+  const uint8 expected[] = {255, 255, 255, 255};
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
+
+  glScissor(0, 0, 0, 0);
+  glEnable(GL_SCISSOR_TEST);
+  glClearColor(0, 0, 0, 0);
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  // Verify - no changes.
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
+}
+#endif
+
+TEST_P(GLClearFramebufferTest, ClearDepthStencil) {
+  const GLuint kStencilRef = 1 << 2;
+  InitDraw();
+  SetDrawColor(1.0f, 0.0f, 0.0f, 1.0f);
+  DrawQuad();
+  // Verify.
+  const uint8 kRed[] = {255, 0, 0, 255};
+  const uint8 kGreen[] = {0, 255, 0, 255};
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
+
+  glClearStencil(kStencilRef);
+  glClear(GL_STENCIL_BUFFER_BIT);
+  glEnable(GL_STENCIL_TEST);
+  glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+  glStencilFunc(GL_NOTEQUAL, kStencilRef, 0xFFFFFFFF);
+
+  SetDrawColor(0.0f, 1.0f, 0.0f, 1.0f);
+  DrawQuad();
+  // Verify - stencil should have failed, so still red.
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
+
+  glStencilFunc(GL_EQUAL, kStencilRef, 0xFFFFFFFF);
+  DrawQuad();
+  // Verify - stencil should have passed, so green.
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kGreen));
+
+  glEnable(GL_DEPTH_TEST);
+  glClearDepthf(0.0f);
+  glClear(GL_DEPTH_BUFFER_BIT);
+
+  SetDrawDepth(0.5f);
+  SetDrawColor(1.0f, 0.0f, 0.0f, 1.0f);
+  DrawQuad();
+  // Verify - depth test should have failed, so still green.
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kGreen));
+
+  glClearDepthf(0.9f);
+  glClear(GL_DEPTH_BUFFER_BIT);
+  DrawQuad();
+  // Verify - depth test should have passed, so red.
+  EXPECT_TRUE(
+      GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index ebd821c..c09901f 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -139,6 +139,10 @@
 }
 
 void GLManager::Initialize(const GLManager::Options& options) {
+  InitializeWithCommandLine(options, nullptr);
+}
+void GLManager::InitializeWithCommandLine(const GLManager::Options& options,
+                                          base::CommandLine* command_line) {
   const int32 kCommandBufferSize = 1024 * 1024;
   const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
   const size_t kMinTransferBufferSize = 1 * 256 * 1024;
@@ -186,14 +190,19 @@
   attrib_helper.blue_size = 8;
   attrib_helper.alpha_size = 8;
   attrib_helper.depth_size = 16;
+  attrib_helper.stencil_size = 8;
   attrib_helper.Serialize(&attribs);
 
+  DCHECK(!command_line || !context_group);
   if (!context_group) {
+    scoped_refptr<gles2::FeatureInfo> feature_info;
+    if (command_line)
+      feature_info = new gles2::FeatureInfo(*command_line);
     context_group =
         new gles2::ContextGroup(mailbox_manager_.get(),
                                 NULL,
                                 new gpu::gles2::ShaderTranslatorCache,
-                                NULL,
+                                feature_info,
                                 options.bind_generates_resource);
   }
 
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index 03ed6a1..7a3eb2c 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -13,6 +13,10 @@
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/size.h"
 
+namespace base {
+class CommandLine;
+}
+
 namespace gfx {
 
 class GLContext;
@@ -66,6 +70,8 @@
       gfx::GpuMemoryBuffer::Format format);
 
   void Initialize(const Options& options);
+  void InitializeWithCommandLine(const Options& options,
+                                 base::CommandLine* command_line);
   void Destroy();
 
   void MakeCurrent();
diff --git a/gpu/command_buffer/tests/gl_query_unittest.cc b/gpu/command_buffer/tests/gl_query_unittest.cc
index 0104430..5ea7e8d 100644
--- a/gpu/command_buffer/tests/gl_query_unittest.cc
+++ b/gpu/command_buffer/tests/gl_query_unittest.cc
@@ -63,7 +63,7 @@
   glGetQueryObjectuivEXT(commands_issue_query, GL_QUERY_RESULT_EXT, &result);
   // Sanity check - the resulting delta is shorter than the time it took to
   // run this test.
-  EXPECT_LT(result, base::TimeDelta(after - before).InMicroseconds());
+  EXPECT_LE(result, base::TimeDelta(after - before).InMicroseconds());
 
   result = 0;
   available = 0;
@@ -152,6 +152,8 @@
     return;
   }
 
+  base::TimeTicks before = base::TimeTicks::HighResNow();
+
   GLuint query;
   glGenQueriesEXT(1, &query);
   glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query);
@@ -161,7 +163,12 @@
   glFlush();
   GLuint result = 0;
   glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result);
-  EXPECT_EQ(0u, result);
+
+  base::TimeTicks after = base::TimeTicks::HighResNow();
+  // Sanity check - the resulting delta is shorter than the time it took to
+  // run this test.
+  EXPECT_LE(result, base::TimeDelta(after - before).InMicroseconds());
+
   glDeleteQueriesEXT(1, &query);
   GLTestHelper::CheckGLError("no errors", __LINE__);
 }