|
@@ -0,0 +1,381 @@
|
|
|
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
+From: Shahbaz Youssefi <[email protected]>
|
|
|
+Date: Tue, 25 Jan 2022 12:15:16 -0500
|
|
|
+Subject: M99: Vulkan: Fix texture array level redefinition
|
|
|
+
|
|
|
+When a level of a texture is redefined, all staged updates to that level
|
|
|
+should be removed, not the ones specific to the new layers. The bug
|
|
|
+fixed was that if the texture was redefined to have its number of layers
|
|
|
+changed, the staged higher-layer-count update to the image was not
|
|
|
+removed.
|
|
|
+
|
|
|
+Bug: chromium:1289383
|
|
|
+Change-Id: Iab79c38d846d1abbdd92e11b1b60a3adf0fbde4c
|
|
|
+Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3441309
|
|
|
+Reviewed-by: Lingfeng Yang <[email protected]>
|
|
|
+Reviewed-by: Jamie Madill <[email protected]>
|
|
|
+
|
|
|
+diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
|
|
+index b43f41dbae29356f1ffe4f961ed83e0f0e9cdcd2..610f720b68d37aaddf142b0dca538749386cef7e 100644
|
|
|
+--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
|
|
++++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
|
|
|
+@@ -1553,12 +1553,25 @@ angle::Result TextureVk::redefineLevel(const gl::Context *context,
|
|
|
+
|
|
|
+ if (mImage != nullptr)
|
|
|
+ {
|
|
|
+- // If there is any staged changes for this index, we can remove them since we're going to
|
|
|
++ // If there are any staged changes for this index, we can remove them since we're going to
|
|
|
+ // override them with this call.
|
|
|
+ gl::LevelIndex levelIndexGL(index.getLevelIndex());
|
|
|
+ uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
|
|
|
+- mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
|
|
|
+- index.getLayerCount());
|
|
|
++ if (gl::IsArrayTextureType(index.getType()))
|
|
|
++ {
|
|
|
++ // A multi-layer texture is being redefined, remove all updates to this level; the
|
|
|
++ // number of layers may have changed.
|
|
|
++ mImage->removeStagedUpdates(contextVk, levelIndexGL, levelIndexGL);
|
|
|
++ }
|
|
|
++ else
|
|
|
++ {
|
|
|
++ // Otherwise remove only updates to this layer. For example, cube map updates can be
|
|
|
++ // done through glTexImage2D, one per cube face (i.e. layer) and so should not remove
|
|
|
++ // updates to the other layers.
|
|
|
++ ASSERT(index.getLayerCount() == 1);
|
|
|
++ mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
|
|
|
++ index.getLayerCount());
|
|
|
++ }
|
|
|
+
|
|
|
+ if (mImage->valid())
|
|
|
+ {
|
|
|
+diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
|
|
|
+index 8a6d01ca36a84a9e294de3f6f0114ee7a54e1d9a..957a52304edc9aa245f9f21e5557cc105cbad789 100644
|
|
|
+--- a/src/tests/gl_tests/MipmapTest.cpp
|
|
|
++++ b/src/tests/gl_tests/MipmapTest.cpp
|
|
|
+@@ -1686,6 +1686,106 @@ TEST_P(MipmapTestES3, MipmapsForTexture3D)
|
|
|
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
|
|
+ }
|
|
|
+
|
|
|
++// Create a 2D array, then immediately redefine it to have fewer layers. Regression test for a bug
|
|
|
++// in the Vulkan backend where the old higher-layer-count data upload was not removed.
|
|
|
++TEST_P(MipmapTestES3, TextureArrayRedefineThenGenerateMipmap)
|
|
|
++{
|
|
|
++ int px = getWindowWidth() / 2;
|
|
|
++ int py = getWindowHeight() / 2;
|
|
|
++
|
|
|
++ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
|
|
|
++
|
|
|
++ // Fill the whole texture with red, then redefine it and fill with green
|
|
|
++ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
|
|
|
++ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
|
|
|
++ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
++ pixelsRed.data());
|
|
|
++ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
++ pixelsGreen.data());
|
|
|
++
|
|
|
++ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
|
|
++ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ // Generate mipmaps
|
|
|
++ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ glUseProgram(mArrayProgram);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ // Draw the first slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
|
|
++ drawQuad(mArrayProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
|
|
++
|
|
|
++ // Draw the second slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 1);
|
|
|
++ drawQuad(mArrayProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
|
|
++}
|
|
|
++
|
|
|
++// Create a 2D array, use it, then redefine it to have fewer layers. Regression test for a bug in
|
|
|
++// the Vulkan backend where the old higher-layer-count data upload was not removed.
|
|
|
++TEST_P(MipmapTestES3, TextureArrayUseThenRedefineThenGenerateMipmap)
|
|
|
++{
|
|
|
++ int px = getWindowWidth() / 2;
|
|
|
++ int py = getWindowHeight() / 2;
|
|
|
++
|
|
|
++ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
|
|
|
++
|
|
|
++ // Fill the whole texture with red.
|
|
|
++ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
|
|
|
++ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
++ pixelsRed.data());
|
|
|
++
|
|
|
++ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
|
|
++ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ // Generate mipmap
|
|
|
++ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ glUseProgram(mArrayProgram);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ // Draw the first slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
|
|
++ drawQuad(mArrayProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
|
|
++
|
|
|
++ // Draw the fourth slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 3);
|
|
|
++ drawQuad(mArrayProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
|
|
++
|
|
|
++ // Redefine the image and fill with green
|
|
|
++ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
|
|
|
++ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
++ pixelsGreen.data());
|
|
|
++
|
|
|
++ // Generate mipmap
|
|
|
++ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ // Draw the first slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
|
|
++ drawQuad(mArrayProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
|
|
++
|
|
|
++ // Draw the second slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 1);
|
|
|
++ drawQuad(mArrayProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
|
|
++}
|
|
|
++
|
|
|
+ // Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
|
|
|
+ // the same, and then sample levels 0 and 2.
|
|
|
+ // GLES 3.0.4 section 3.8.10:
|
|
|
+diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
|
|
|
+index 56bef0186234f59d370669c21f588ea9c5c356fc..772fe27daac3ac0b5f54b8319cef6aa9c980208a 100644
|
|
|
+--- a/src/tests/gl_tests/TextureTest.cpp
|
|
|
++++ b/src/tests/gl_tests/TextureTest.cpp
|
|
|
+@@ -1028,31 +1028,37 @@ class SamplerArrayAsFunctionParameterTest : public SamplerArrayTest
|
|
|
+ class Texture2DArrayTestES3 : public TexCoordDrawTest
|
|
|
+ {
|
|
|
+ protected:
|
|
|
+- Texture2DArrayTestES3() : TexCoordDrawTest(), m2DArrayTexture(0), mTextureArrayLocation(-1) {}
|
|
|
++ Texture2DArrayTestES3()
|
|
|
++ : TexCoordDrawTest(),
|
|
|
++ m2DArrayTexture(0),
|
|
|
++ mTextureArrayLocation(-1),
|
|
|
++ mTextureArraySliceUniformLocation(-1)
|
|
|
++ {}
|
|
|
+
|
|
|
+ const char *getVertexShaderSource() override
|
|
|
+ {
|
|
|
+- return "#version 300 es\n"
|
|
|
+- "out vec2 texcoord;\n"
|
|
|
+- "in vec4 position;\n"
|
|
|
+- "void main()\n"
|
|
|
+- "{\n"
|
|
|
+- " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
|
|
|
+- " texcoord = (position.xy * 0.5) + 0.5;\n"
|
|
|
+- "}\n";
|
|
|
++ return R"(#version 300 es
|
|
|
++out vec2 texcoord;
|
|
|
++in vec4 position;
|
|
|
++void main()
|
|
|
++{
|
|
|
++ gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
|
++ texcoord = (position.xy * 0.5) + 0.5;
|
|
|
++})";
|
|
|
+ }
|
|
|
+
|
|
|
+ const char *getFragmentShaderSource() override
|
|
|
+ {
|
|
|
+- return "#version 300 es\n"
|
|
|
+- "precision highp float;\n"
|
|
|
+- "uniform highp sampler2DArray tex2DArray;\n"
|
|
|
+- "in vec2 texcoord;\n"
|
|
|
+- "out vec4 fragColor;\n"
|
|
|
+- "void main()\n"
|
|
|
+- "{\n"
|
|
|
+- " fragColor = texture(tex2DArray, vec3(texcoord.x, texcoord.y, 0.0));\n"
|
|
|
+- "}\n";
|
|
|
++ return R"(#version 300 es
|
|
|
++precision highp float;
|
|
|
++uniform highp sampler2DArray tex2DArray;
|
|
|
++uniform int slice;
|
|
|
++in vec2 texcoord;
|
|
|
++out vec4 fragColor;
|
|
|
++void main()
|
|
|
++{
|
|
|
++ fragColor = texture(tex2DArray, vec3(texcoord, float(slice)));
|
|
|
++})";
|
|
|
+ }
|
|
|
+
|
|
|
+ void testSetUp() override
|
|
|
+@@ -1064,6 +1070,9 @@ class Texture2DArrayTestES3 : public TexCoordDrawTest
|
|
|
+ mTextureArrayLocation = glGetUniformLocation(mProgram, "tex2DArray");
|
|
|
+ ASSERT_NE(-1, mTextureArrayLocation);
|
|
|
+
|
|
|
++ mTextureArraySliceUniformLocation = glGetUniformLocation(mProgram, "slice");
|
|
|
++ ASSERT_NE(-1, mTextureArraySliceUniformLocation);
|
|
|
++
|
|
|
+ glGenTextures(1, &m2DArrayTexture);
|
|
|
+ ASSERT_GL_NO_ERROR();
|
|
|
+ }
|
|
|
+@@ -1076,6 +1085,7 @@ class Texture2DArrayTestES3 : public TexCoordDrawTest
|
|
|
+
|
|
|
+ GLuint m2DArrayTexture;
|
|
|
+ GLint mTextureArrayLocation;
|
|
|
++ GLint mTextureArraySliceUniformLocation;
|
|
|
+ };
|
|
|
+
|
|
|
+ class TextureSizeTextureArrayTest : public TexCoordDrawTest
|
|
|
+@@ -1718,28 +1728,28 @@ class Texture2DArrayIntegerTestES3 : public Texture2DArrayTestES3
|
|
|
+
|
|
|
+ const char *getVertexShaderSource() override
|
|
|
+ {
|
|
|
+- return "#version 300 es\n"
|
|
|
+- "out vec2 texcoord;\n"
|
|
|
+- "in vec4 position;\n"
|
|
|
+- "void main()\n"
|
|
|
+- "{\n"
|
|
|
+- " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
|
|
|
+- " texcoord = (position.xy * 0.5) + 0.5;\n"
|
|
|
+- "}\n";
|
|
|
++ return R"(#version 300 es
|
|
|
++out vec2 texcoord;
|
|
|
++in vec4 position;
|
|
|
++void main()
|
|
|
++{
|
|
|
++ gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
|
++ texcoord = (position.xy * 0.5) + 0.5;
|
|
|
++})";
|
|
|
+ }
|
|
|
+
|
|
|
+ const char *getFragmentShaderSource() override
|
|
|
+ {
|
|
|
+- return "#version 300 es\n"
|
|
|
+- "precision highp float;\n"
|
|
|
+- "uniform highp usampler2DArray tex2DArray;\n"
|
|
|
+- "in vec2 texcoord;\n"
|
|
|
+- "out vec4 fragColor;\n"
|
|
|
+- "void main()\n"
|
|
|
+- "{\n"
|
|
|
+- " fragColor = vec4(texture(tex2DArray, vec3(texcoord.x, texcoord.y, "
|
|
|
+- "0.0)))/255.0;\n"
|
|
|
+- "}\n";
|
|
|
++ return R"(#version 300 es
|
|
|
++precision highp float;
|
|
|
++uniform highp usampler2DArray tex2DArray;
|
|
|
++uniform int slice;
|
|
|
++in vec2 texcoord;
|
|
|
++out vec4 fragColor;
|
|
|
++void main()
|
|
|
++{
|
|
|
++ fragColor = vec4(texture(tex2DArray, vec3(texcoord, slice)))/255.0;
|
|
|
++})";
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+@@ -5112,6 +5122,94 @@ TEST_P(Texture2DArrayTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensio
|
|
|
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
|
|
|
+ }
|
|
|
+
|
|
|
++// Create a 2D array, then immediately redefine it to have fewer layers. Regression test for a bug
|
|
|
++// in the Vulkan backend where the old higher-layer-count data upload was not removed.
|
|
|
++TEST_P(Texture2DArrayTestES3, TextureArrayRedefineThenUse)
|
|
|
++{
|
|
|
++ int px = getWindowWidth() / 2;
|
|
|
++ int py = getWindowHeight() / 2;
|
|
|
++
|
|
|
++ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
|
|
|
++
|
|
|
++ // Fill the whole texture with red, then redefine it and fill with green
|
|
|
++ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
|
|
|
++ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
|
|
|
++ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
++ pixelsRed.data());
|
|
|
++ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
++ pixelsGreen.data());
|
|
|
++
|
|
|
++ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
++ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ glUseProgram(mProgram);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ // Draw the first slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
|
|
++ drawQuad(mProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
|
|
++
|
|
|
++ // Draw the second slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 1);
|
|
|
++ drawQuad(mProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
|
|
++}
|
|
|
++
|
|
|
++// Create a 2D array, use it, then redefine it to have fewer layers. Regression test for a bug in
|
|
|
++// the Vulkan backend where the old higher-layer-count data upload was not removed.
|
|
|
++TEST_P(Texture2DArrayTestES3, TextureArrayUseThenRedefineThenUse)
|
|
|
++{
|
|
|
++ int px = getWindowWidth() / 2;
|
|
|
++ int py = getWindowHeight() / 2;
|
|
|
++
|
|
|
++ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
|
|
|
++
|
|
|
++ // Fill the whole texture with red.
|
|
|
++ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
|
|
|
++ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
++ pixelsRed.data());
|
|
|
++
|
|
|
++ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
++ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ glUseProgram(mProgram);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++
|
|
|
++ // Draw the first slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
|
|
++ drawQuad(mProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
|
|
++
|
|
|
++ // Draw the fourth slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 3);
|
|
|
++ drawQuad(mProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
|
|
|
++
|
|
|
++ // Redefine the image and fill with green
|
|
|
++ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
|
|
|
++ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
|
|
++ pixelsGreen.data());
|
|
|
++
|
|
|
++ // Draw the first slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 0);
|
|
|
++ drawQuad(mProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
|
|
++
|
|
|
++ // Draw the second slice
|
|
|
++ glUniform1i(mTextureArraySliceUniformLocation, 1);
|
|
|
++ drawQuad(mProgram, "position", 0.5f);
|
|
|
++ EXPECT_GL_NO_ERROR();
|
|
|
++ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
|
|
|
++}
|
|
|
++
|
|
|
+ // Test that texture completeness is updated if texture max level changes.
|
|
|
+ // GLES 3.0.4 section 3.8.13 Texture completeness
|
|
|
+ TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)
|