Commit bb7c1442 by James Darpinian Committed by Commit Bot

Fix immutable texture base level validation

Jeff's new rendering feedback loop test (https://github.com/KhronosGroup/WebGL/pull/3221) found a couple of issues with texture base level validation. For immutable textures the base level is clamped to the valid range, so setting an out of range base level does not make an immutable texture sampler incomplete, and we need to use the clamped value when checking for rendering feedback loops. Bug: angleproject:5768 Change-Id: Ie065709efd736f2cf75d4f980e8ac27999f80142 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2767901 Commit-Queue: James Darpinian <jdarpinian@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarKenneth Russell <kbr@chromium.org>
parent f6eccc20
...@@ -272,17 +272,17 @@ bool AttachmentOverlapsWithTexture(const FramebufferAttachment &attachment, ...@@ -272,17 +272,17 @@ bool AttachmentOverlapsWithTexture(const FramebufferAttachment &attachment,
return false; return false;
} }
const gl::ImageIndex &index = attachment.getTextureImageIndex(); const gl::ImageIndex &index = attachment.getTextureImageIndex();
GLuint attachmentLevel = static_cast<GLuint>(index.getLevelIndex()); GLuint attachmentLevel = static_cast<GLuint>(index.getLevelIndex());
GLuint textureBaseLevel = texture->getBaseLevel(); GLuint textureEffectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
GLuint textureMaxLevel = textureBaseLevel; GLuint textureMaxLevel = textureEffectiveBaseLevel;
if ((sampler && IsMipmapFiltered(sampler->getSamplerState().getMinFilter())) || if ((sampler && IsMipmapFiltered(sampler->getSamplerState().getMinFilter())) ||
IsMipmapFiltered(texture->getSamplerState().getMinFilter())) IsMipmapFiltered(texture->getSamplerState().getMinFilter()))
{ {
textureMaxLevel = texture->getMipmapMaxLevel(); textureMaxLevel = texture->getMipmapMaxLevel();
} }
return attachmentLevel >= textureBaseLevel && attachmentLevel <= textureMaxLevel; return attachmentLevel >= textureEffectiveBaseLevel && attachmentLevel <= textureMaxLevel;
} }
} // anonymous namespace } // anonymous namespace
......
...@@ -319,7 +319,7 @@ bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState, ...@@ -319,7 +319,7 @@ bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
return true; return true;
} }
if (mBaseLevel > mMaxLevel) if (!mImmutableFormat && mBaseLevel > mMaxLevel)
{ {
return false; return false;
} }
......
...@@ -3991,6 +3991,72 @@ void main() { ...@@ -3991,6 +3991,72 @@ void main() {
drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_INVALID_OPERATION); drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_INVALID_OPERATION);
} }
// This tests that texture base level for immutable textures is clamped to the valid range, unlike
// for non-immutable textures, for purposes of validation. Related to WebGL test
// conformance2/textures/misc/immutable-tex-render-feedback.html
TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithImmutableTextureWithOutOfRangeBaseLevel)
{
constexpr char kVS[] =
R"(#version 300 es
in vec4 aPosition;
out vec2 texCoord;
void main() {
gl_Position = aPosition;
texCoord = (aPosition.xy * 0.5) + 0.5;
})";
constexpr char kFS[] =
R"(#version 300 es
precision mediump float;
uniform sampler2D tex;
in vec2 texCoord;
out vec4 oColor;
void main() {
oColor = texture(tex, texCoord);
})";
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 4, 4);
std::vector<GLColor> texData(4 * 4, GLColor::green);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, texData.data());
// Set a base level greater than the max level. It should be clamped to the actual max level.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
ASSERT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
ANGLE_GL_PROGRAM(program, kVS, kFS);
GLint uniformLoc = glGetUniformLocation(program.get(), "tex");
ASSERT_NE(-1, uniformLoc);
glUseProgram(program.get());
glUniform1i(uniformLoc, 0);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
ASSERT_GL_NO_ERROR();
// Ensure that the texture can be used for rendering.
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, texture.get());
drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Ensure that the texture can't be used to create a feedback loop.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
glBindTexture(GL_TEXTURE_2D, texture.get());
drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// This test covers detection of rendering feedback loops between the FBO and a depth Texture. // This test covers detection of rendering feedback loops between the FBO and a depth Texture.
// Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html // Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html
TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil) TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment