Commit 13be06e6 by Jonah Ryan-Davis Committed by Commit Bot

Fix copyTexImage2D corner case with same source/target image.

When the source and target textures are the same texture but different levels, there is a corner case which makes the framebuffer incomplete on calling glCopyTexImage2D and fails conformance2/textures/misc/copy-texture-image-same-texture.html Bug: angleproject:2994 Change-Id: I906869c78aefded5688d4491e93b95dd2662175c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1697262Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jonah Ryan-Davis <jonahr@google.com>
parent 25378d6a
...@@ -625,6 +625,27 @@ angle::Result TextureGL::copyImage(const gl::Context *context, ...@@ -625,6 +625,27 @@ angle::Result TextureGL::copyImage(const gl::Context *context,
gl::Rectangle clippedArea; gl::Rectangle clippedArea;
if (ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea)) if (ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
{ {
// If fbo's read buffer and the target texture are the same texture but different levels,
// and if the read buffer is a non-base texture level, then implementations glTexImage2D
// may change the target texture and make the original texture mipmap incomplete, which in
// turn makes the fbo incomplete.
// To avoid that, we clamp BASE_LEVEL and MAX_LEVEL to the same texture level as the fbo's
// read buffer attachment. See http://crbug.com/797235
const gl::FramebufferAttachment *readBuffer = source->getReadColorAttachment();
if (readBuffer && readBuffer->type() == GL_TEXTURE)
{
TextureGL *sourceTexture = GetImplAs<TextureGL>(readBuffer->getTexture());
if (sourceTexture && sourceTexture->mTextureID == mTextureID)
{
GLuint attachedTextureLevel = readBuffer->mipLevel();
if (attachedTextureLevel != mState.getEffectiveBaseLevel())
{
ANGLE_TRY(setBaseLevel(context, attachedTextureLevel));
ANGLE_TRY(setMaxLevel(context, attachedTextureLevel));
}
}
}
LevelInfoGL levelInfo = GetLevelInfo(internalFormat, copyTexImageFormat.internalFormat); LevelInfoGL levelInfo = GetLevelInfo(internalFormat, copyTexImageFormat.internalFormat);
gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0); gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
...@@ -663,7 +684,6 @@ angle::Result TextureGL::copyImage(const gl::Context *context, ...@@ -663,7 +684,6 @@ angle::Result TextureGL::copyImage(const gl::Context *context,
clippedArea.y, clippedArea.width, clippedArea.height, 0); clippedArea.y, clippedArea.width, clippedArea.height, 0);
} }
} }
setLevelInfo(context, target, level, 1, levelInfo); setLevelInfo(context, target, level, 1, levelInfo);
} }
...@@ -1352,6 +1372,25 @@ angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLev ...@@ -1352,6 +1372,25 @@ angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLev
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result TextureGL::setMaxLevel(const gl::Context *context, GLuint maxLevel)
{
if (maxLevel != mAppliedMaxLevel)
{
const FunctionsGL *functions = GetFunctionsGL(context);
StateManagerGL *stateManager = GetStateManagerGL(context);
mAppliedMaxLevel = maxLevel;
mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAX_LEVEL);
// Signal to the GL layer that the Impl has dirty bits.
onStateChange(angle::SubjectMessage::SubjectChanged);
stateManager->bindTexture(getType(), mTextureID);
functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAX_LEVEL, maxLevel);
}
return angle::Result::Continue;
}
void TextureGL::setMinFilter(const gl::Context *context, GLenum filter) void TextureGL::setMinFilter(const gl::Context *context, GLenum filter)
{ {
if (filter != mAppliedSampler.getMinFilter()) if (filter != mAppliedSampler.getMinFilter())
......
...@@ -188,6 +188,7 @@ class TextureGL : public TextureImpl ...@@ -188,6 +188,7 @@ class TextureGL : public TextureImpl
bool hasAnyDirtyBit() const; bool hasAnyDirtyBit() const;
angle::Result setBaseLevel(const gl::Context *context, GLuint baseLevel) override; angle::Result setBaseLevel(const gl::Context *context, GLuint baseLevel) override;
angle::Result setMaxLevel(const gl::Context *context, GLuint maxLevel);
angle::Result initializeContents(const gl::Context *context, angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override; const gl::ImageIndex &imageIndex) override;
......
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