// // Copyright 2020 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // ActiveTextureCacheTest.cpp: Regression tests of ANGLE's ActiveTextureCache inside gl::State. #include "test_utils/ANGLETest.h" #include "test_utils/gl_raii.h" namespace angle { class ActiveTextureCacheTest : public ANGLETest<> { protected: ActiveTextureCacheTest() { setWindowWidth(128); setWindowHeight(128); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); } void testSetUp() override { constexpr char kVS[] = "precision highp float;\n" "\n" "void main()\n" "{\n" " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n" "}\n"; constexpr char k2DFS[] = "precision highp float;\n" "uniform sampler2D tex2D;\n" "uniform samplerCube texCube;\n" "\n" "void main()\n" "{\n" " gl_FragColor = texture2D(tex2D, vec2(0.0, 0.0)) + textureCube(texCube, vec3(0.0, " "0.0, 0.0));\n" "}\n"; mProgram = CompileProgram(kVS, k2DFS); ASSERT_NE(0u, mProgram); m2DTextureLocation = glGetUniformLocation(mProgram, "tex2D"); ASSERT_NE(-1, m2DTextureLocation); mCubeTextureLocation = glGetUniformLocation(mProgram, "texCube"); ASSERT_NE(-1, mCubeTextureLocation); } void testTearDown() override { glDeleteProgram(mProgram); } GLuint mProgram = 0; GLint m2DTextureLocation = -1; GLint mCubeTextureLocation = -1; }; // Regression test for a bug that causes the ActiveTexturesCache to get out of sync with the // currently bound textures when changing program uniforms in such a way that the program becomes // invalid. TEST_P(ActiveTextureCacheTest, UniformChangeUpdatesActiveTextureCache) { glUseProgram(mProgram); // Generate two textures and reset the texture binding GLuint tex0 = 0; glGenTextures(1, &tex0); glBindTexture(GL_TEXTURE_2D, tex0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); GLuint tex1 = 0; glGenTextures(1, &tex1); glBindTexture(GL_TEXTURE_2D, tex1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindTexture(GL_TEXTURE_2D, 0); // Set the active texture to 1 and bind tex0. glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tex0); // Point the program's 2D sampler at texture binding 1. The texture will be added to the // ActiveTexturesCache because it matches the program's sampler type for this texture binding. glUniform1i(m2DTextureLocation, 1); // Point the program's cube sampler to texture binding 1 as well. This causes the program's // samplers become invalid and the ActiveTexturesCache is NOT updated. glUniform1i(mCubeTextureLocation, 1); // Bind tex1. ActiveTexturesCache is NOT updated (still contains tex0). The current texture // bindings do not match ActiveTexturesCache's state. glBindTexture(GL_TEXTURE_2D, tex1); // Delete tex0. The ActiveTexturesCache entry that points to tex0 is not cleared because tex0 is // not currently bound. glDeleteTextures(1, &tex0); // Use-after-free occurs during context destruction when the ActiveTexturesCache is cleared. } // Use this to select which configurations (e.g. which renderer, which GLES major version) these // tests should be run against. ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ActiveTextureCacheTest); } // namespace angle