// Copyright (c) 2012 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 #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" namespace gpu { namespace { enum CopyType { TexImage, TexSubImage }; const CopyType kCopyTypes[] = { TexImage, TexSubImage, }; } // A collection of tests that exercise the GL_CHROMIUM_copy_texture extension. class GLCopyTextureCHROMIUMTest : public testing::Test, public ::testing::WithParamInterface { protected: void SetUp() override { gl_.Initialize(GLManager::Options()); glGenTextures(2, textures_); glBindTexture(GL_TEXTURE_2D, textures_[1]); // Some drivers (NVidia/SGX) require texture settings to be a certain way or // they won't report FRAMEBUFFER_COMPLETE. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glGenFramebuffers(1, &framebuffer_id_); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures_[1], 0); } void TearDown() override { glDeleteTextures(2, textures_); glDeleteFramebuffers(1, &framebuffer_id_); gl_.Destroy(); } GLManager gl_; GLuint textures_[2]; GLuint framebuffer_id_; }; INSTANTIATE_TEST_CASE_P(CopyType, GLCopyTextureCHROMIUMTest, ::testing::ValuesIn(kCopyTypes)); // Test to ensure that the basic functionality of the extension works. TEST_P(GLCopyTextureCHROMIUMTest, Basic) { CopyType copy_type = GetParam(); uint8_t pixels[1 * 4] = {255u, 0u, 0u, 255u}; glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(glGetError() == GL_NO_ERROR); // Check the FB is still bound. GLint value = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value); GLuint fb_id = value; EXPECT_EQ(framebuffer_id_, fb_id); // Check that FB is complete. EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), glCheckFramebufferStatus(GL_FRAMEBUFFER)); GLTestHelper::CheckPixels(0, 0, 1, 1, 0, pixels); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } TEST_P(GLCopyTextureCHROMIUMTest, ImmutableTexture) { if (!GLTestHelper::HasExtension("GL_EXT_texture_storage")) { LOG(INFO) << "GL_EXT_texture_storage not supported. Skipping test..."; return; } CopyType copy_type = GetParam(); uint8_t pixels[1 * 4] = {255u, 0u, 0u, 255u}; glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, 1, 1); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, 1, 1); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures_[1], 0); EXPECT_TRUE(glGetError() == GL_NO_ERROR); if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_OPERATION); } else { glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_NO_ERROR); // Check the FB is still bound. GLint value = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value); GLuint fb_id = value; EXPECT_EQ(framebuffer_id_, fb_id); // Check that FB is complete. EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), glCheckFramebufferStatus(GL_FRAMEBUFFER)); GLTestHelper::CheckPixels(0, 0, 1, 1, 0, pixels); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } } TEST_P(GLCopyTextureCHROMIUMTest, InternalFormat) { CopyType copy_type = GetParam(); GLint src_formats[] = {GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGRA_EXT}; GLint dest_formats[] = {GL_RGB, GL_RGBA}; for (size_t src_index = 0; src_index < arraysize(src_formats); src_index++) { for (size_t dest_index = 0; dest_index < arraysize(dest_formats); dest_index++) { glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, src_formats[src_index], 1, 1, 0, src_formats[src_index], GL_UNSIGNED_BYTE, nullptr); EXPECT_TRUE(GL_NO_ERROR == glGetError()); if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], dest_formats[dest_index], GL_UNSIGNED_BYTE, false, false, false); } else { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, dest_formats[dest_index], 1, 1, 0, dest_formats[dest_index], GL_UNSIGNED_BYTE, nullptr); EXPECT_TRUE(GL_NO_ERROR == glGetError()); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()) << "src_index:" << src_index << " dest_index:" << dest_index; } } } TEST_P(GLCopyTextureCHROMIUMTest, InternalFormatNotSupported) { CopyType copy_type = GetParam(); glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); EXPECT_TRUE(GL_NO_ERROR == glGetError()); // Check unsupported format reports error. GLint unsupported_dest_formats[] = {GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA}; for (size_t dest_index = 0; dest_index < arraysize(unsupported_dest_formats); dest_index++) { if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], unsupported_dest_formats[dest_index], GL_UNSIGNED_BYTE, false, false, false); } else { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, unsupported_dest_formats[dest_index], 1, 1, 0, unsupported_dest_formats[dest_index], GL_UNSIGNED_BYTE, nullptr); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_INVALID_OPERATION == glGetError()) << "dest_index:" << dest_index; } } // Test to ensure that the destination texture is redefined if the properties // are different. TEST_F(GLCopyTextureCHROMIUMTest, RedefineDestinationTexture) { uint8_t pixels[4 * 4] = {255u, 0u, 0u, 255u, 255u, 0u, 0u, 255u, 255u, 0u, 0u, 255u, 255u, 0u, 0u, 255u}; glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, 1, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels); EXPECT_TRUE(GL_NO_ERROR == glGetError()); // GL_INVALID_OPERATION due to "intrinsic format" != "internal format". glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); EXPECT_TRUE(GL_INVALID_OPERATION == glGetError()); // GL_INVALID_VALUE due to bad dimensions. glTexSubImage2D( GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); // If the dest texture has different properties, glCopyTextureCHROMIUM() // redefines them. glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_NO_ERROR == glGetError()); // glTexSubImage2D() succeeds because textures_[1] is redefined into 2x2 // dimension and GL_RGBA format. glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexSubImage2D( GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); EXPECT_TRUE(GL_NO_ERROR == glGetError()); // Check the FB is still bound. GLint value = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value); GLuint fb_id = value; EXPECT_EQ(framebuffer_id_, fb_id); // Check that FB is complete. EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), glCheckFramebufferStatus(GL_FRAMEBUFFER)); GLTestHelper::CheckPixels(1, 1, 1, 1, 0, &pixels[12]); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } namespace { void glEnableDisable(GLint param, GLboolean value) { if (value) glEnable(param); else glDisable(param); } } // unnamed namespace // Validate that some basic GL state is not touched upon execution of // the extension. TEST_P(GLCopyTextureCHROMIUMTest, BasicStatePreservation) { CopyType copy_type = GetParam(); uint8_t pixels[1 * 4] = {255u, 0u, 0u, 255u}; glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); if (copy_type == TexSubImage) { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } GLboolean reference_settings[2] = { GL_TRUE, GL_FALSE }; for (int x = 0; x < 2; ++x) { GLboolean setting = reference_settings[x]; glEnableDisable(GL_DEPTH_TEST, setting); glEnableDisable(GL_SCISSOR_TEST, setting); glEnableDisable(GL_STENCIL_TEST, setting); glEnableDisable(GL_CULL_FACE, setting); glEnableDisable(GL_BLEND, setting); glColorMask(setting, setting, setting, setting); glDepthMask(setting); glActiveTexture(GL_TEXTURE1 + x); if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); EXPECT_EQ(setting, glIsEnabled(GL_DEPTH_TEST)); EXPECT_EQ(setting, glIsEnabled(GL_SCISSOR_TEST)); EXPECT_EQ(setting, glIsEnabled(GL_STENCIL_TEST)); EXPECT_EQ(setting, glIsEnabled(GL_CULL_FACE)); EXPECT_EQ(setting, glIsEnabled(GL_BLEND)); GLboolean bool_array[4] = { GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE }; glGetBooleanv(GL_DEPTH_WRITEMASK, bool_array); EXPECT_EQ(setting, bool_array[0]); bool_array[0] = GL_FALSE; glGetBooleanv(GL_COLOR_WRITEMASK, bool_array); EXPECT_EQ(setting, bool_array[0]); EXPECT_EQ(setting, bool_array[1]); EXPECT_EQ(setting, bool_array[2]); EXPECT_EQ(setting, bool_array[3]); GLint active_texture = 0; glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture); EXPECT_EQ(GL_TEXTURE1 + x, active_texture); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); }; // Verify that invocation of the extension does not modify the bound // texture state. TEST_P(GLCopyTextureCHROMIUMTest, TextureStatePreserved) { CopyType copy_type = GetParam(); // Setup the texture used for the extension invocation. uint8_t pixels[1 * 4] = {255u, 0u, 0u, 255u}; glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); if (copy_type == TexSubImage) { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } GLuint texture_ids[2]; glGenTextures(2, texture_ids); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture_ids[0]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture_ids[1]); if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); GLint active_texture = 0; glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture); EXPECT_EQ(GL_TEXTURE1, active_texture); GLint bound_texture = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound_texture); EXPECT_EQ(texture_ids[1], static_cast(bound_texture)); glBindTexture(GL_TEXTURE_2D, 0); bound_texture = 0; glActiveTexture(GL_TEXTURE0); glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound_texture); EXPECT_EQ(texture_ids[0], static_cast(bound_texture)); glBindTexture(GL_TEXTURE_2D, 0); glDeleteTextures(2, texture_ids); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } // Verify that invocation of the extension does not perturb the currently // bound FBO state. TEST_P(GLCopyTextureCHROMIUMTest, FBOStatePreserved) { CopyType copy_type = GetParam(); // Setup the texture used for the extension invocation. uint8_t pixels[1 * 4] = {255u, 0u, 0u, 255u}; glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); if (copy_type == TexSubImage) { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } GLuint texture_id; glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); GLuint renderbuffer_id; glGenRenderbuffers(1, &renderbuffer_id); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_id); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1, 1); GLuint framebuffer_id; glGenFramebuffers(1, &framebuffer_id); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer_id); EXPECT_TRUE( GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)); // Test that we can write to the bound framebuffer uint8_t expected_color[4] = {255u, 255u, 0, 255u}; glClearColor(1.0, 1.0, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT); GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected_color); if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); EXPECT_TRUE(glIsFramebuffer(framebuffer_id)); // Ensure that reading from the framebuffer produces correct pixels. GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected_color); uint8_t expected_color2[4] = {255u, 0, 255u, 255u}; glClearColor(1.0, 0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected_color2); GLint bound_fbo = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &bound_fbo); EXPECT_EQ(framebuffer_id, static_cast(bound_fbo)); GLint fbo_params = 0; glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &fbo_params); EXPECT_EQ(GL_TEXTURE, fbo_params); fbo_params = 0; glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &fbo_params); EXPECT_EQ(texture_id, static_cast(fbo_params)); fbo_params = 0; glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &fbo_params); EXPECT_EQ(GL_RENDERBUFFER, fbo_params); fbo_params = 0; glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &fbo_params); EXPECT_EQ(renderbuffer_id, static_cast(fbo_params)); glDeleteRenderbuffers(1, &renderbuffer_id); glDeleteTextures(1, &texture_id); glDeleteFramebuffers(1, &framebuffer_id); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } TEST_P(GLCopyTextureCHROMIUMTest, ProgramStatePreservation) { CopyType copy_type = GetParam(); // unbind the one created in setup. glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); GLManager gl2; GLManager::Options options; options.size = gfx::Size(16, 16); options.share_group_manager = &gl_; gl2.Initialize(options); gl_.MakeCurrent(); static const char* v_shader_str = "attribute vec4 g_Position;\n" "void main()\n" "{\n" " gl_Position = g_Position;\n" "}\n"; static const char* f_shader_str = "precision mediump float;\n" "void main()\n" "{\n" " gl_FragColor = vec4(0,1,0,1);\n" "}\n"; GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str); glUseProgram(program); GLuint position_loc = glGetAttribLocation(program, "g_Position"); glFlush(); // Delete program from other context. gl2.MakeCurrent(); glDeleteProgram(program); EXPECT_TRUE(GL_NO_ERROR == glGetError()); glFlush(); // Program should still be usable on this context. gl_.MakeCurrent(); GLTestHelper::SetupUnitQuad(position_loc); // test using program before uint8_t expected[] = { 0, 255, 0, 255, }; uint8_t zero[] = { 0, 0, 0, 0, }; glClear(GL_COLOR_BUFFER_BIT); EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, 1, 1, 0, zero)); glDrawArrays(GL_TRIANGLES, 0, 6); EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected)); // Call copyTextureCHROMIUM uint8_t pixels[1 * 4] = {255u, 0u, 0u, 255u}; glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } // test using program after glClear(GL_COLOR_BUFFER_BIT); EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, 1, 1, 0, zero)); glDrawArrays(GL_TRIANGLES, 0, 6); EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected)); EXPECT_TRUE(GL_NO_ERROR == glGetError()); gl2.MakeCurrent(); gl2.Destroy(); gl_.MakeCurrent(); } // Test that glCopyTextureCHROMIUM doesn't leak uninitialized textures. TEST_P(GLCopyTextureCHROMIUMTest, UninitializedSource) { CopyType copy_type = GetParam(); const GLsizei kWidth = 64, kHeight = 64; glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); if (copy_type == TexImage) { glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, 0, kWidth, kHeight, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); uint8_t pixels[kHeight][kWidth][4] = {{{1}}}; glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels); for (int x = 0; x < kWidth; ++x) { for (int y = 0; y < kHeight; ++y) { EXPECT_EQ(0, pixels[y][x][0]); EXPECT_EQ(0, pixels[y][x][1]); EXPECT_EQ(0, pixels[y][x][2]); EXPECT_EQ(0, pixels[y][x][3]); } } EXPECT_TRUE(GL_NO_ERROR == glGetError()); } TEST_F(GLCopyTextureCHROMIUMTest, CopySubTextureDimension) { glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_NO_ERROR == glGetError()); // xoffset < 0 glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], -1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); // x < 0 glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, -1, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); // xoffset + width > dest_width glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 2, 2, 0, 0, 2, 2, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); // x + width > source_width glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 1, 1, 2, 2, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); } TEST_F(GLCopyTextureCHROMIUMTest, CopyTextureInvalidTextureIds) { glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993, GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); glCopyTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); glCopyTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996, GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } TEST_F(GLCopyTextureCHROMIUMTest, CopySubTextureInvalidTextureIds) { glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993, 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1], 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996, 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } TEST_F(GLCopyTextureCHROMIUMTest, CopySubTextureOffset) { uint8_t rgba_pixels[4 * 4] = {255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, 0u, 0u, 255u, 255u, 0u, 0u, 0u, 255u}; glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba_pixels); uint8_t transparent_pixels[4 * 4] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, transparent_pixels); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_NO_ERROR); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 0, 1, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_NO_ERROR); glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 1, 0, 1, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_NO_ERROR); // Check the FB is still bound. GLint value = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value); GLuint fb_id = value; EXPECT_EQ(framebuffer_id_, fb_id); // Check that FB is complete. EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), glCheckFramebufferStatus(GL_FRAMEBUFFER)); uint8_t transparent[1 * 4] = {0u, 0u, 0u, 0u}; uint8_t red[1 * 4] = {255u, 0u, 0u, 255u}; uint8_t green[1 * 4] = {0u, 255u, 0u, 255u}; uint8_t blue[1 * 4] = {0u, 0u, 255u, 255u}; GLTestHelper::CheckPixels(0, 0, 1, 1, 0, transparent); GLTestHelper::CheckPixels(1, 1, 1, 1, 0, red); GLTestHelper::CheckPixels(1, 0, 1, 1, 0, green); GLTestHelper::CheckPixels(0, 1, 1, 1, 0, blue); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } } // namespace gpu