summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorvmiura@chromium.org <vmiura@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-18 01:54:52 +0000
committervmiura@chromium.org <vmiura@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-18 01:54:52 +0000
commit81f20a622340adc5077e6379de5012ebdc9461e4 (patch)
tree4449b7638e6f6899e67dc2975b436badc77307b7 /gpu
parent648221d60d3cb7dfc87e2816e2d52bdaf1663894 (diff)
downloadchromium_src-81f20a622340adc5077e6379de5012ebdc9461e4.zip
chromium_src-81f20a622340adc5077e6379de5012ebdc9461e4.tar.gz
chromium_src-81f20a622340adc5077e6379de5012ebdc9461e4.tar.bz2
Restore bound VAO in ContextState::RestoreState().
BUG=363407, 281565 Review URL: https://codereview.chromium.org/237893004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@264705 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r--gpu/command_buffer/service/context_state.cc111
-rw-r--r--gpu/command_buffer/service/context_state.h6
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc28
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc14
-rw-r--r--gpu/command_buffer/tests/gl_manager.cc8
-rw-r--r--gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc169
8 files changed, 279 insertions, 59 deletions
diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc
index 6c81655..2eb3f99 100644
--- a/gpu/command_buffer/service/context_state.cc
+++ b/gpu/command_buffer/service/context_state.cc
@@ -188,29 +188,87 @@ void ContextState::RestoreActiveTextureUnitBinding(unsigned int target) const {
glBindTexture(target, GetServiceId(texture_unit, target));
}
-void ContextState::RestoreAttribute(GLuint attrib_index) const {
- const VertexAttrib* attrib =
- vertex_attrib_manager->GetVertexAttrib(attrib_index);
- const void* ptr = reinterpret_cast<const void*>(attrib->offset());
- Buffer* buffer = attrib->buffer();
- glBindBuffer(GL_ARRAY_BUFFER, buffer ? buffer->service_id() : 0);
- glVertexAttribPointer(
- attrib_index, attrib->size(), attrib->type(), attrib->normalized(),
- attrib->gl_stride(), ptr);
- if (attrib->divisor())
- glVertexAttribDivisorANGLE(attrib_index, attrib->divisor());
- // Never touch vertex attribute 0's state (in particular, never
- // disable it) when running on desktop GL because it will never be
- // re-enabled.
- if (attrib_index != 0 ||
- gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
- if (attrib->enabled()) {
- glEnableVertexAttribArray(attrib_index);
+void ContextState::RestoreVertexAttribValues() const {
+ for (size_t attrib = 0; attrib < vertex_attrib_manager->num_attribs();
+ ++attrib) {
+ glVertexAttrib4fv(attrib, attrib_values[attrib].v);
+ }
+}
+
+void ContextState::RestoreVertexAttribArrays(
+ const scoped_refptr<VertexAttribManager> attrib_manager) const {
+ // This is expected to be called only for VAO with service_id 0,
+ // either to restore the default VAO or a virtual VAO with service_id 0.
+ GLuint vao_service_id = attrib_manager->service_id();
+ DCHECK(vao_service_id == 0);
+
+ // Bind VAO if supported.
+ if (feature_info_->feature_flags().native_vertex_array_object)
+ glBindVertexArrayOES(vao_service_id);
+
+ // Restore vertex attrib arrays.
+ for (size_t attrib_index = 0; attrib_index < attrib_manager->num_attribs();
+ ++attrib_index) {
+ const VertexAttrib* attrib = attrib_manager->GetVertexAttrib(attrib_index);
+
+ // Restore vertex array.
+ Buffer* buffer = attrib->buffer();
+ GLuint buffer_service_id = buffer ? buffer->service_id() : 0;
+ glBindBuffer(GL_ARRAY_BUFFER, buffer_service_id);
+ const void* ptr = reinterpret_cast<const void*>(attrib->offset());
+ glVertexAttribPointer(attrib_index,
+ attrib->size(),
+ attrib->type(),
+ attrib->normalized(),
+ attrib->gl_stride(),
+ ptr);
+
+ // Restore attrib divisor if supported.
+ if (feature_info_->feature_flags().angle_instanced_arrays)
+ glVertexAttribDivisorANGLE(attrib_index, attrib->divisor());
+
+ // Never touch vertex attribute 0's state (in particular, never
+ // disable it) when running on desktop GL because it will never be
+ // re-enabled.
+ if (attrib_index != 0 ||
+ gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ if (attrib->enabled()) {
+ glEnableVertexAttribArray(attrib_index);
+ } else {
+ glDisableVertexAttribArray(attrib_index);
+ }
+ }
+ }
+}
+
+void ContextState::RestoreVertexAttribs() const {
+ // Restore Vertex Attrib Arrays
+ // TODO: This if should not be needed. RestoreState is getting called
+ // before GLES2Decoder::Initialize which is a bug.
+ if (vertex_attrib_manager.get()) {
+ // Restore VAOs.
+ if (feature_info_->feature_flags().native_vertex_array_object) {
+ // If default VAO is still using shared id 0 instead of unique ids
+ // per-context, default VAO state must be restored.
+ GLuint default_vao_service_id =
+ default_vertex_attrib_manager->service_id();
+ if (default_vao_service_id == 0)
+ RestoreVertexAttribArrays(default_vertex_attrib_manager);
+
+ // Restore the current VAO binding, unless it's the same as the
+ // default above.
+ GLuint curr_vao_service_id = vertex_attrib_manager->service_id();
+ if (curr_vao_service_id != 0)
+ glBindVertexArrayOES(curr_vao_service_id);
} else {
- glDisableVertexAttribArray(attrib_index);
+ // If native VAO isn't supported, emulated VAOs are used.
+ // Restore to the currently bound VAO.
+ RestoreVertexAttribArrays(vertex_attrib_manager);
}
}
- glVertexAttrib4fv(attrib_index, attrib_values[attrib_index].v);
+
+ // glVertexAttrib4fv aren't part of VAO state and must be restored.
+ RestoreVertexAttribValues();
}
void ContextState::RestoreGlobalState(const ContextState* prev_state) const {
@@ -220,18 +278,7 @@ void ContextState::RestoreGlobalState(const ContextState* prev_state) const {
void ContextState::RestoreState(const ContextState* prev_state) const {
RestoreAllTextureUnitBindings(prev_state);
-
- // Restore Attrib State
- // TODO: This if should not be needed. RestoreState is getting called
- // before GLES2Decoder::Initialize which is a bug.
- if (vertex_attrib_manager.get()) {
- // TODO(gman): Move this restoration to VertexAttribManager.
- for (size_t attrib = 0; attrib < vertex_attrib_manager->num_attribs();
- ++attrib) {
- RestoreAttribute(attrib);
- }
- }
-
+ RestoreVertexAttribs();
RestoreBufferBindings();
RestoreRenderbufferBindings();
RestoreProgramBindings();
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index d68700f..83818e9 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -108,7 +108,10 @@ struct GPU_EXPORT ContextState {
void RestoreActiveTexture() const;
void RestoreAllTextureUnitBindings(const ContextState* prev_state) const;
void RestoreActiveTextureUnitBinding(unsigned int target) const;
- void RestoreAttribute(GLuint index) const;
+ void RestoreVertexAttribValues() const;
+ void RestoreVertexAttribArrays(
+ const scoped_refptr<VertexAttribManager> attrib_manager) const;
+ void RestoreVertexAttribs() const;
void RestoreBufferBindings() const;
void RestoreGlobalState(const ContextState* prev_state) const;
void RestoreProgramBindings() const;
@@ -146,6 +149,7 @@ struct GPU_EXPORT ContextState {
// Class that manages vertex attribs.
scoped_refptr<VertexAttribManager> vertex_attrib_manager;
+ scoped_refptr<VertexAttribManager> default_vertex_attrib_manager;
// The program in use by glUseProgram
scoped_refptr<Program> current_program;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index d0b040b..6a1fa24 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -612,9 +612,6 @@ class GLES2DecoderImpl : public GLES2Decoder,
unsigned int target) const OVERRIDE {
state_.RestoreActiveTextureUnitBinding(target);
}
- virtual void RestoreAttribute(unsigned index) const OVERRIDE {
- state_.RestoreAttribute(index);
- }
virtual void RestoreBufferBindings() const OVERRIDE {
state_.RestoreBufferBindings();
}
@@ -1662,9 +1659,6 @@ class GLES2DecoderImpl : public GLES2Decoder,
bool unpack_premultiply_alpha_;
bool unpack_unpremultiply_alpha_;
- // Default vertex attribs manager, used when no VAOs are bound.
- scoped_refptr<VertexAttribManager> default_vertex_attrib_manager_;
-
// The buffer we bind to attrib 0 since OpenGL requires it (ES does not).
GLuint attrib_0_buffer_id_;
@@ -2363,12 +2357,12 @@ bool GLES2DecoderImpl::Initialize(
disallowed_features_ = disallowed_features;
state_.attrib_values.resize(group_->max_vertex_attribs());
- default_vertex_attrib_manager_ = new VertexAttribManager();
- default_vertex_attrib_manager_->Initialize(
+ state_.default_vertex_attrib_manager = new VertexAttribManager();
+ state_.default_vertex_attrib_manager->Initialize(
group_->max_vertex_attribs(),
feature_info_->workarounds().init_vertex_attributes);
- // vertex_attrib_manager is set to default_vertex_attrib_manager_ by this call
+ // vertex_attrib_manager is set to default_vertex_attrib_manager by this call
DoBindVertexArrayOES(0);
query_manager_.reset(new QueryManager(this, feature_info_.get()));
@@ -3319,7 +3313,7 @@ void GLES2DecoderImpl::Destroy(bool have_context) {
// Unbind everything.
state_.vertex_attrib_manager = NULL;
- default_vertex_attrib_manager_ = NULL;
+ state_.default_vertex_attrib_manager = NULL;
state_.texture_units.clear();
state_.bound_array_buffer = NULL;
state_.current_queries.clear();
@@ -3914,6 +3908,11 @@ void GLES2DecoderImpl::RestoreTextureState(unsigned service_id) const {
}
void GLES2DecoderImpl::ClearAllAttributes() const {
+ // Must use native VAO 0, as RestoreAllAttributes can't fully restore
+ // other VAOs.
+ if (feature_info_->feature_flags().native_vertex_array_object)
+ glBindVertexArrayOES(0);
+
for (uint32 i = 0; i < group_->max_vertex_attribs(); ++i) {
if (i != 0) // Never disable attribute 0
glDisableVertexAttribArray(i);
@@ -3923,8 +3922,7 @@ void GLES2DecoderImpl::ClearAllAttributes() const {
}
void GLES2DecoderImpl::RestoreAllAttributes() const {
- for (uint32 i = 0; i < group_->max_vertex_attribs(); ++i)
- RestoreAttribute(i);
+ state_.RestoreVertexAttribs();
}
void GLES2DecoderImpl::OnFboChanged() const {
@@ -4497,7 +4495,7 @@ bool GLES2DecoderImpl::GetHelper(
*num_written = 1;
if (params) {
if (state_.vertex_attrib_manager.get() !=
- default_vertex_attrib_manager_.get()) {
+ state_.default_vertex_attrib_manager.get()) {
GLuint client_id = 0;
vertex_array_manager_->GetClientId(
state_.vertex_attrib_manager->service_id(), &client_id);
@@ -7095,7 +7093,7 @@ error::Error GLES2DecoderImpl::HandleVertexAttribPointer(
if (!state_.bound_array_buffer.get() ||
state_.bound_array_buffer->IsDeleted()) {
if (state_.vertex_attrib_manager.get() ==
- default_vertex_attrib_manager_.get()) {
+ state_.default_vertex_attrib_manager.get()) {
LOCAL_SET_GL_ERROR(
GL_INVALID_VALUE, "glVertexAttribPointer", "no array buffer bound");
return error::kNoError;
@@ -9686,7 +9684,7 @@ void GLES2DecoderImpl::DoBindVertexArrayOES(GLuint client_id) {
service_id = vao->service_id();
}
} else {
- vao = default_vertex_attrib_manager_.get();
+ vao = state_.default_vertex_attrib_manager.get();
}
// Only set the VAO state if it's changed
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 03a4b54..c573b23 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -142,7 +142,6 @@ class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr<GLES2Decoder>,
virtual void RestoreAllTextureUnitBindings(
const ContextState* prev_state) const = 0;
virtual void RestoreActiveTextureUnitBinding(unsigned int target) const = 0;
- virtual void RestoreAttribute(unsigned index) const = 0;
virtual void RestoreBufferBindings() const = 0;
virtual void RestoreFramebufferBindings() const = 0;
virtual void RestoreGlobalState() const = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index ff678c9..8043514 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -61,7 +61,6 @@ class MockGLES2Decoder : public GLES2Decoder {
RestoreAllTextureUnitBindings, void(const ContextState* state));
MOCK_CONST_METHOD1(
RestoreActiveTextureUnitBinding, void(unsigned int target));
- MOCK_CONST_METHOD1(RestoreAttribute, void(unsigned index));
MOCK_CONST_METHOD0(RestoreBufferBindings, void());
MOCK_CONST_METHOD0(RestoreFramebufferBindings, void());
MOCK_CONST_METHOD0(RestoreGlobalState, void());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index b367e5c..eece250 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -9241,6 +9241,20 @@ TEST_F(GLES2DecoderRestoreStateTest, DefaultUnit1) {
GetDecoder()->RestoreAllTextureUnitBindings(&prev_state);
}
+// TODO(vmiura): Tests for VAO restore.
+
+// TODO(vmiura): Tests for ContextState::RestoreAttribute().
+
+// TODO(vmiura): Tests for ContextState::RestoreBufferBindings().
+
+// TODO(vmiura): Tests for ContextState::RestoreProgramBindings().
+
+// TODO(vmiura): Tests for RestoreRenderbufferBindings().
+
+// TODO(vmiura): Tests for RestoreProgramBindings().
+
+// TODO(vmiura): Tests for RestoreGlobalState().
+
TEST_F(GLES2DecoderManualInitTest, ClearUniformsBeforeFirstProgramUse) {
CommandLine command_line(0, NULL);
command_line.AppendSwitchASCII(
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 473ac6f..3211a35 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -142,15 +142,15 @@ void GLManager::Initialize(const GLManager::Options& options) {
surface_ = gfx::GLSurface::CreateOffscreenGLSurface(options.size);
ASSERT_TRUE(surface_.get() != NULL) << "could not create offscreen surface";
- if (real_gl_context) {
+ if (base_context_) {
context_ = scoped_refptr<gfx::GLContext>(new gpu::GLContextVirtual(
- share_group_.get(), real_gl_context, decoder_->AsWeakPtr()));
+ share_group_.get(), base_context_->get(), decoder_->AsWeakPtr()));
ASSERT_TRUE(context_->Initialize(
surface_.get(), gfx::PreferIntegratedGpu));
} else {
- if (base_context_) {
+ if (real_gl_context) {
context_ = scoped_refptr<gfx::GLContext>(new gpu::GLContextVirtual(
- share_group_.get(), base_context_->get(), decoder_->AsWeakPtr()));
+ share_group_.get(), real_gl_context, decoder_->AsWeakPtr()));
ASSERT_TRUE(context_->Initialize(
surface_.get(), gfx::PreferIntegratedGpu));
} else {
diff --git a/gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc b/gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc
index 1776ff1..17cfa9f 100644
--- a/gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc
+++ b/gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc
@@ -21,6 +21,11 @@ class GLVirtualContextsTest : public testing::Test {
static const int kSize1 = 8;
static const int kSize2 = 16;
+ static const GLfloat kFloatRed[4];
+ static const GLfloat kFloatGreen[4];
+ static const uint8 kExpectedRed[4];
+ static const uint8 kExpectedGreen[4];
+
virtual void SetUp() {
GLManager::Options options;
options.size = gfx::Size(kSize0, kSize0);
@@ -40,15 +45,61 @@ class GLVirtualContextsTest : public testing::Test {
gl_real_.Destroy();
}
+ GLuint SetupColoredVertexProgram() {
+ static const char* v_shader_str = SHADER(
+ attribute vec4 a_position;
+ attribute vec4 a_color;
+ varying vec4 v_color;
+ void main()
+ {
+ gl_Position = a_position;
+ v_color = a_color;
+ }
+ );
+
+ static const char* f_shader_str = SHADER(
+ precision mediump float;
+ varying vec4 v_color;
+ void main()
+ {
+ gl_FragColor = v_color;
+ }
+ );
+
+ GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
+ glUseProgram(program);
+ return program;
+ }
+
+ void SetUpColoredUnitQuad(const GLfloat* color) {
+ GLuint program1 = SetupColoredVertexProgram();
+ GLuint position_loc1 = glGetAttribLocation(program1, "a_position");
+ GLuint color_loc1 = glGetAttribLocation(program1, "a_color");
+ GLTestHelper::SetupUnitQuad(position_loc1);
+ GLTestHelper::SetupColorsForUnitQuad(color_loc1, color, GL_STATIC_DRAW);
+ }
+
GLManager gl_real_;
GLManager gl_real_shared_;
GLManager gl1_;
GLManager gl2_;
};
+const GLfloat GLVirtualContextsTest::kFloatRed[4] = {
+ 1.0f, 0.0f, 0.0f, 1.0f,
+};
+const GLfloat GLVirtualContextsTest::kFloatGreen[4] = {
+ 0.0f, 1.0f, 0.0f, 1.0f,
+};
+const uint8 GLVirtualContextsTest::kExpectedRed[4] = {
+ 255, 0, 0, 255,
+};
+const uint8 GLVirtualContextsTest::kExpectedGreen[4] = {
+ 0, 255, 0, 255,
+};
+
namespace {
-#if !defined(OS_ANDROID)
void SetupSimpleShader(const uint8* color) {
static const char* v_shader_str = SHADER(
attribute vec4 a_Position;
@@ -91,12 +142,9 @@ void TestDraw(int size) {
glDrawArrays(GL_TRIANGLES, 0, 6);
}
-#endif // !defined(OS_ANDROID)
-
} // anonymous namespace
// http://crbug.com/281565
-#if !defined(OS_ANDROID)
TEST_F(GLVirtualContextsTest, Basic) {
struct TestInfo {
int size;
@@ -139,7 +187,118 @@ TEST_F(GLVirtualContextsTest, Basic) {
GLTestHelper::CheckGLError("no errors", __LINE__);
}
}
-#endif
+
+// http://crbug.com/363407
+TEST_F(GLVirtualContextsTest, VertexArrayObjectRestore) {
+ GLuint vao1 = 0, vao2 = 0;
+
+ gl1_.MakeCurrent();
+ // Set up red quad in vao1.
+ glGenVertexArraysOES(1, &vao1);
+ glBindVertexArrayOES(vao1);
+ SetUpColoredUnitQuad(kFloatRed);
+ glFinish();
+
+ gl2_.MakeCurrent();
+ // Set up green quad in vao2.
+ glGenVertexArraysOES(1, &vao2);
+ glBindVertexArrayOES(vao2);
+ SetUpColoredUnitQuad(kFloatGreen);
+ glFinish();
+
+ gl1_.MakeCurrent();
+ // Test to ensure that vao1 is still the active VAO for this context.
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kSize1, kSize1, 0, kExpectedRed));
+ glFinish();
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+
+ gl2_.MakeCurrent();
+ // Test to ensure that vao2 is still the active VAO for this context.
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, kSize2, kSize2, 0, kExpectedGreen));
+ glFinish();
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+}
+
+// http://crbug.com/363407
+TEST_F(GLVirtualContextsTest, VertexArrayObjectRestoreRebind) {
+ GLuint vao1 = 0, vao2 = 0;
+
+ gl1_.MakeCurrent();
+ // Set up red quad in vao1.
+ glGenVertexArraysOES(1, &vao1);
+ glBindVertexArrayOES(vao1);
+ SetUpColoredUnitQuad(kFloatRed);
+ glFinish();
+
+ gl2_.MakeCurrent();
+ // Set up green quad in new vao2.
+ glGenVertexArraysOES(1, &vao2);
+ glBindVertexArrayOES(vao2);
+ SetUpColoredUnitQuad(kFloatGreen);
+ glFinish();
+
+ gl1_.MakeCurrent();
+ // Test to ensure that vao1 hasn't been corrupted after rebinding.
+ // Bind 0 is required so that bind vao1 is not optimized away in the service.
+ glBindVertexArrayOES(0);
+ glBindVertexArrayOES(vao1);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kSize1, kSize1, 0, kExpectedRed));
+ glFinish();
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+
+ gl2_.MakeCurrent();
+ // Test to ensure that vao1 hasn't been corrupted after rebinding.
+ // Bind 0 is required so that bind vao2 is not optimized away in the service.
+ glBindVertexArrayOES(0);
+ glBindVertexArrayOES(vao2);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, kSize2, kSize2, 0, kExpectedGreen));
+ glFinish();
+
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+}
+
+// http://crbug.com/363407
+TEST_F(GLVirtualContextsTest, VertexArrayObjectRestoreDefault) {
+ gl1_.MakeCurrent();
+ // Set up red quad in default VAO.
+ SetUpColoredUnitQuad(kFloatRed);
+ glFinish();
+
+ gl2_.MakeCurrent();
+ // Set up green quad in default VAO.
+ SetUpColoredUnitQuad(kFloatGreen);
+ glFinish();
+
+ // Gen & bind a non-default VAO.
+ GLuint vao;
+ glGenVertexArraysOES(1, &vao);
+ glBindVertexArrayOES(vao);
+ glFinish();
+
+ gl1_.MakeCurrent();
+ // Test to ensure that default VAO on gl1_ is still valid.
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kSize1, kSize1, 0, kExpectedRed));
+ glFinish();
+
+ gl2_.MakeCurrent();
+ // Test to ensure that default VAO on gl2_ is still valid.
+ // This tests that a default VAO is restored even when it's not currently
+ // bound during the context switch.
+ glBindVertexArrayOES(0);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, kSize2, kSize2, 0, kExpectedGreen));
+ glFinish();
+
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+}
} // namespace gpu