// 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 #include #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" #define SHADER(Src) #Src namespace gpu { class GLVirtualContextsTest : public testing::Test { protected: static const int kSize0 = 4; 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); gl_real_.Initialize(options); gl_real_shared_.Initialize(options); options.virtual_manager = &gl_real_shared_; options.size = gfx::Size(kSize1, kSize1); gl1_.Initialize(options); options.size = gfx::Size(kSize2, kSize2); gl2_.Initialize(options); } virtual void TearDown() { gl1_.Destroy(); gl2_.Destroy(); gl_real_shared_.Destroy(); 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 { void SetupSimpleShader(const uint8* color) { static const char* v_shader_str = SHADER( attribute vec4 a_Position; void main() { gl_Position = a_Position; } ); static const char* f_shader_str = SHADER( precision mediump float; uniform vec4 u_color; void main() { gl_FragColor = u_color; } ); GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str); glUseProgram(program); GLuint position_loc = glGetAttribLocation(program, "a_Position"); GLTestHelper::SetupUnitQuad(position_loc); GLuint color_loc = glGetUniformLocation(program, "u_color"); glUniform4f( color_loc, color[0] / 255.0f, color[1] / 255.0f, color[2] / 255.0f, color[3] / 255.0f); } void TestDraw(int size) { uint8 expected_clear[] = { 127, 0, 255, 0, }; glClearColor(0.5f, 0.0f, 1.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, size, size, 1, expected_clear)); glDrawArrays(GL_TRIANGLES, 0, 6); } } // anonymous namespace // http://crbug.com/281565 TEST_F(GLVirtualContextsTest, Basic) { struct TestInfo { int size; uint8 color[4]; GLManager* manager; }; const int kNumTests = 3; TestInfo tests[] = { { kSize0, { 255, 0, 0, 0, }, &gl_real_, }, { kSize1, { 0, 255, 0, 0, }, &gl1_, }, { kSize2, { 0, 0, 255, 0, }, &gl2_, }, }; for (int ii = 0; ii < kNumTests; ++ii) { const TestInfo& test = tests[ii]; GLManager* gl_manager = test.manager; gl_manager->MakeCurrent(); SetupSimpleShader(test.color); } for (int ii = 0; ii < kNumTests; ++ii) { const TestInfo& test = tests[ii]; GLManager* gl_manager = test.manager; gl_manager->MakeCurrent(); TestDraw(test.size); } for (int ii = 0; ii < kNumTests; ++ii) { const TestInfo& test = tests[ii]; GLManager* gl_manager = test.manager; gl_manager->MakeCurrent(); EXPECT_TRUE(GLTestHelper::CheckPixels( 0, 0, test.size, test.size, 0, test.color)); } for (int ii = 0; ii < kNumTests; ++ii) { const TestInfo& test = tests[ii]; GLManager* gl_manager = test.manager; gl_manager->MakeCurrent(); GLTestHelper::CheckGLError("no errors", __LINE__); } } // 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