Vulkan: Add test for filament gltf usage case
filament gltf sample code is rendering to a level that is excluded from
[base_level, max_level]. This is allowed by OpenGL spec. We are crashing
right not. This CL adds tests for the exact usage pattern for filament.
Bug: b/181800403
Test: FramebufferTest_ES3.RenderAndInvalidateImmutableTextureWithBeyondMaxLevel
Test: FramebufferTest_ES3.RenderAndInvalidateImmutableTextureWithSubImageWithBeyondMaxLevel
Test: FramebufferTest_ES3.RenderAndInvalidateImmutableTextureWithBellowBaseLevelLOD
Change-Id: I69bab8bc3961bbc2dcc78ba2db3c8759f277416b
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2752897
Commit-Queue: Charlie Lao <cclao@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Tim Van Patten <timvp@google.com>
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp
index 94619e6..0602bec 100644
--- a/src/tests/gl_tests/FramebufferTest.cpp
+++ b/src/tests/gl_tests/FramebufferTest.cpp
@@ -2538,6 +2538,167 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
}
+// Test render to a texture level that is excluded from [base_level, max_level]. This specific test
+// renders to an immutable texture at the level that is bigger than GL_TEXTURE_MAX_LEVEL. The
+// texture itself has not been initialized with any data before rendering (TexSubImage call may
+// initialize a VkImage object).
+TEST_P(FramebufferTest_ES3, RenderAndInvalidateImmutableTextureWithBeyondMaxLevel)
+{
+ // ToDo: https://issuetracker.google.com/181800403
+ ANGLE_SKIP_TEST_IF(IsVulkan() || IsMetal());
+
+ constexpr GLuint kLevel0Size = 4;
+ constexpr GLuint kLevel1Size = kLevel0Size / 2;
+
+ GLTexture colorTexture;
+ glBindTexture(GL_TEXTURE_2D, colorTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, kLevel0Size, kLevel0Size);
+ // set max_level to 0
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+
+ // Attach level 1 to a FBO
+ GLFramebuffer framebuffer;
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 1);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ // Render to FBO
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ const GLenum discard[] = {GL_COLOR_ATTACHMENT0};
+ glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discard);
+ glViewport(0, 0, kLevel1Size, kLevel1Size);
+ glScissor(0, 0, kLevel1Size, kLevel1Size);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glDisable(GL_BLEND);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
+ glUseProgram(program);
+ drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ ASSERT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+}
+
+// Test render to a texture level that is excluded from [base_level, max_level]. This specific test
+// renders to an immutable texture at the level that is bigger than GL_TEXTURE_MAX_LEVEL. The
+// texture itself has been initialized with data before rendering.
+TEST_P(FramebufferTest_ES3, RenderAndInvalidateImmutableTextureWithSubImageWithBeyondMaxLevel)
+{
+ // ToDo: https://issuetracker.google.com/181800403
+ ANGLE_SKIP_TEST_IF(IsVulkan() || IsMetal());
+
+ constexpr GLuint kLevel0Size = 4;
+ constexpr GLuint kLevel1Size = kLevel0Size / 2;
+ std::array<GLColor, kLevel0Size * kLevel0Size> gData;
+
+ GLTexture colorTexture;
+ glBindTexture(GL_TEXTURE_2D, colorTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, kLevel0Size, kLevel0Size);
+ // set max_level to 0
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ // Initialize with TexSubImage call
+ gData.fill(GLColor::blue);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kLevel0Size, kLevel0Size, GL_RGBA, GL_UNSIGNED_BYTE,
+ gData.data());
+
+ // Attach level 1 to a FBO
+ GLFramebuffer framebuffer;
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 1);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ // Render to FBO
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ const GLenum discard[] = {GL_COLOR_ATTACHMENT0};
+ glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discard);
+ glViewport(0, 0, kLevel1Size, kLevel1Size);
+ glScissor(0, 0, kLevel1Size, kLevel1Size);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glDisable(GL_BLEND);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
+ glUseProgram(program);
+ drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ ASSERT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+}
+
+// Test render to a texture level that is excluded from [base_level, max_level]. This specific test
+// renders to an immutable texture at the level that is smaller than GL_TEXTURE_BASE_LEVEL. The
+// texture itself has been initialized with data before rendering. Filament is using it this way
+// https://issuetracker.google.com/181800403.
+TEST_P(FramebufferTest_ES3, RenderAndInvalidateImmutableTextureWithBellowBaseLevelLOD)
+{
+ // ToDo: https://issuetracker.google.com/181800403
+ ANGLE_SKIP_TEST_IF(IsVulkan() || IsMetal());
+
+ constexpr GLuint kLevel0Size = 4;
+ constexpr GLuint kLevel1Size = kLevel0Size / 2;
+ std::array<GLColor, kLevel0Size * kLevel0Size> gData;
+
+ GLTexture colorTexture;
+ glBindTexture(GL_TEXTURE_2D, colorTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, kLevel0Size, kLevel0Size);
+ // set base_level to 1
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ gData.fill(GLColor::blue);
+ glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kLevel1Size, kLevel1Size, GL_RGBA, GL_UNSIGNED_BYTE,
+ gData.data());
+
+ // Attach level 0 to a FBO
+ GLFramebuffer framebuffer;
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ // Render to FBO
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ const GLenum discard[] = {GL_COLOR_ATTACHMENT0};
+ glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discard);
+ glViewport(0, 0, kLevel0Size, kLevel0Size);
+ glScissor(0, 0, kLevel0Size, kLevel0Size);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glDisable(GL_BLEND);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
+ glUseProgram(program);
+ drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ ASSERT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+}
+
// Covers a bug in ANGLE's Vulkan back-end. Our VkFramebuffer cache would in some cases forget to
// check the draw states when computing a cache key.
TEST_P(FramebufferTest_ES3, DisabledAttachmentRedefinition)