diff options
author | vmiura@chromium.org <vmiura@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-18 01:54:52 +0000 |
---|---|---|
committer | vmiura@chromium.org <vmiura@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-18 01:54:52 +0000 |
commit | 81f20a622340adc5077e6379de5012ebdc9461e4 (patch) | |
tree | 4449b7638e6f6899e67dc2975b436badc77307b7 /gpu | |
parent | 648221d60d3cb7dfc87e2816e2d52bdaf1663894 (diff) | |
download | chromium_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.cc | 111 | ||||
-rw-r--r-- | gpu/command_buffer/service/context_state.h | 6 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 28 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.h | 1 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_mock.h | 1 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc | 14 | ||||
-rw-r--r-- | gpu/command_buffer/tests/gl_manager.cc | 8 | ||||
-rw-r--r-- | gpu/command_buffer/tests/gl_virtual_contexts_unittest.cc | 169 |
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 |