// 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 #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_t kExpectedRed[4]; static const uint8_t kExpectedGreen[4]; void SetUp() override { 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); } void TearDown() override { 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_t GLVirtualContextsTest::kExpectedRed[4] = { 255, 0, 0, 255, }; const uint8_t GLVirtualContextsTest::kExpectedGreen[4] = { 0, 255, 0, 255, }; namespace { void SetupSimpleShader(const uint8_t* 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_t 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_t 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__); } TEST_F(GLVirtualContextsTest, VirtualQueries) { const GLenum query_targets[] = { GL_ANY_SAMPLES_PASSED_EXT, GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, GL_COMMANDS_COMPLETED_CHROMIUM, GL_COMMANDS_ISSUED_CHROMIUM, GL_GET_ERROR_QUERY_CHROMIUM, GL_LATENCY_QUERY_CHROMIUM, GL_TIME_ELAPSED_EXT, }; for (GLenum query_target : query_targets) { GLuint query1 = 0; gl1_.MakeCurrent(); glGenQueriesEXT(1, &query1); glBeginQueryEXT(query_target, query1); const GLenum begin_error = glGetError(); if (GL_INVALID_OPERATION == begin_error) { // Not supported, simply skip. glDeleteQueriesEXT(1, &query1); continue; } ASSERT_TRUE(GL_NO_ERROR == begin_error); GLuint query2 = 0; gl2_.MakeCurrent(); glGenQueriesEXT(1, &query2); glBeginQueryEXT(query_target, query2); EXPECT_TRUE(GL_NO_ERROR == glGetError()) << "Virtualized Query " << query_target << " failed."; gl1_.MakeCurrent(); glEndQueryEXT(query_target); glFinish(); GLuint query1_available = 0; glGetQueryObjectuivEXT(query1, GL_QUERY_RESULT_AVAILABLE_EXT, &query1_available); EXPECT_TRUE(query1_available); glDeleteQueriesEXT(1, &query1); GLTestHelper::CheckGLError("no errors", __LINE__); gl2_.MakeCurrent(); glEndQueryEXT(query_target); glFinish(); GLuint query2_available = 0; glGetQueryObjectuivEXT(query2, GL_QUERY_RESULT_AVAILABLE_EXT, &query2_available); EXPECT_TRUE(query2_available); glDeleteQueriesEXT(1, &query2); GLTestHelper::CheckGLError("no errors", __LINE__); } } } // namespace gpu