Commit d787149a by Jamie Madill Committed by Commit Bot

Allow rendering to unused levels of bound Textures.

This CL refines the feedback loop check to allow rendering to non- sampled levels of currently bound textures. This is a technique sometimes used to initialize a mip chain of a texture. Also adds a regression test that fails on Vulkan. Bug: angleproject:4500 Bug: angleproject:4690 Change-Id: I5fd370e36a2919c82170abcbd2b0897c075bdcc7 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2367314 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 53ee431e
...@@ -262,6 +262,28 @@ angle::Result InitAttachment(const Context *context, FramebufferAttachment *atta ...@@ -262,6 +262,28 @@ angle::Result InitAttachment(const Context *context, FramebufferAttachment *atta
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
bool AttachmentOverlapsWithTexture(const FramebufferAttachment &attachment,
const Texture *texture,
const Sampler *sampler)
{
if (!attachment.isTextureWithId(texture->id()))
{
return false;
}
const gl::ImageIndex &index = attachment.getTextureImageIndex();
GLuint attachmentLevel = static_cast<GLuint>(index.getLevelIndex());
GLuint textureBaseLevel = texture->getBaseLevel();
GLuint textureMaxLevel = textureBaseLevel;
if ((sampler && IsMipmapFiltered(sampler->getSamplerState())) ||
IsMipmapFiltered(texture->getSamplerState()))
{
textureMaxLevel = texture->getMipmapMaxLevel();
}
return attachmentLevel >= textureBaseLevel && attachmentLevel <= textureMaxLevel;
}
} // anonymous namespace } // anonymous namespace
// This constructor is only used for default framebuffers. // This constructor is only used for default framebuffers.
...@@ -1920,9 +1942,25 @@ bool Framebuffer::formsRenderingFeedbackLoopWith(const Context *context) const ...@@ -1920,9 +1942,25 @@ bool Framebuffer::formsRenderingFeedbackLoopWith(const Context *context) const
if (texture && texture->isSamplerComplete(context, sampler) && if (texture && texture->isSamplerComplete(context, sampler) &&
texture->isBoundToFramebuffer(mState.mFramebufferSerial)) texture->isBoundToFramebuffer(mState.mFramebufferSerial))
{ {
// TODO(jmadill): Subresource check. http://anglebug.com/4500 // Check for level overlap.
for (const FramebufferAttachment &attachment : mState.mColorAttachments)
{
if (AttachmentOverlapsWithTexture(attachment, texture, sampler))
{
return true;
}
}
if (AttachmentOverlapsWithTexture(mState.mDepthAttachment, texture, sampler))
{
return true; return true;
} }
if (AttachmentOverlapsWithTexture(mState.mStencilAttachment, texture, sampler))
{
return true;
}
}
} }
return false; return false;
......
...@@ -5077,6 +5077,53 @@ TEST_P(WebGLCompatibilityTest, DrawWithNoProgram) ...@@ -5077,6 +5077,53 @@ TEST_P(WebGLCompatibilityTest, DrawWithNoProgram)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
// Ensures that rendering to different texture levels of a sampled texture is supported.
TEST_P(WebGL2CompatibilityTest, RenderToLevelsOfSampledTexture)
{
// TODO: Fix on Vulkan back-end. http://anglebug.com/4690
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr GLsizei kTexSize = 2;
constexpr GLsizei kTexLevels = 2;
std::vector<GLColor> texData(kTexSize * kTexSize, GLColor::green);
GLTexture sourceTexture;
glBindTexture(GL_TEXTURE_2D, sourceTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, kTexLevels, GL_RGBA8, kTexSize, kTexSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize, GL_RGBA, GL_UNSIGNED_BYTE,
texData.data());
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture, 1);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glViewport(0, 0, kTexSize / 2, kTexSize / 2);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
ASSERT_GL_NO_ERROR();
// Should work - drawing from level 0 to level 1.
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Should not work - drawing from levels [0,1] to level 1.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// Should work - drawing with levels [0,1] to default FBO.
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, getWindowWidth(), getWindowHeight());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest);
......
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