Commit f695a3a1 by Jamie Madill Committed by Commit Bot

WebGL: Validate texture copying feedback loops.

This adds basic validation for catching CopyTex{Sub}Image calls whose source and destination textures overlap. It does not yet implement full support for ES3 types (3D textures, array textures). BUG=angleproject:1685 Change-Id: I83e7b1998df5575057fed8f99f7ee9970fb38df0 Reviewed-on: https://chromium-review.googlesource.com/425491 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 7e735e48
...@@ -1018,4 +1018,26 @@ bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const ...@@ -1018,4 +1018,26 @@ bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
return false; return false;
} }
bool Framebuffer::formsCopyingFeedbackLoopWith(GLuint copyTextureID, GLint copyTextureLevel) const
{
if (mId == 0)
{
// It seems impossible to form a texture copying feedback loop with the default FBO.
return false;
}
const FramebufferAttachment *readAttachment = getReadColorbuffer();
ASSERT(readAttachment);
if (readAttachment->isTextureWithId(copyTextureID))
{
// TODO(jmadill): 3D/Array texture layers.
if (readAttachment->getTextureImageIndex().mipIndex == copyTextureLevel)
{
return true;
}
}
return false;
}
} // namespace gl } // namespace gl
...@@ -214,6 +214,7 @@ class Framebuffer final : public LabeledObject, public angle::SignalReceiver ...@@ -214,6 +214,7 @@ class Framebuffer final : public LabeledObject, public angle::SignalReceiver
void signal(angle::SignalToken token) override; void signal(angle::SignalToken token) override;
bool formsRenderingFeedbackLoopWith(const State &state) const; bool formsRenderingFeedbackLoopWith(const State &state) const;
bool formsCopyingFeedbackLoopWith(GLuint copyTextureID, GLint copyTextureLevel) const;
private: private:
void detachResourceById(GLenum resourceType, GLuint resourceId); void detachResourceById(GLenum resourceType, GLuint resourceId);
......
...@@ -3124,6 +3124,19 @@ bool ValidateCopyTexImageParametersBase(ValidationContext *context, ...@@ -3124,6 +3124,19 @@ bool ValidateCopyTexImageParametersBase(ValidationContext *context,
{ {
*textureFormatOut = texture->getFormat(target, level); *textureFormatOut = texture->getFormat(target, level);
} }
// Detect texture copying feedback loops for WebGL.
if (context->getExtensions().webglCompatibility)
{
if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level))
{
context->handleError(Error(GL_INVALID_OPERATION,
"Texture copying feedback loop formed between Framebuffer "
"and specified Texture level."));
return false;
}
}
return true; return true;
} }
......
...@@ -528,6 +528,67 @@ TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop) ...@@ -528,6 +528,67 @@ TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
} }
// Test tests that texture copying feedback loops are properly rejected in WebGL.
// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
{
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture.get());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLTexture texture2;
glBindTexture(GL_TEXTURE_2D, texture2.get());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
// framebuffer should be FRAMEBUFFER_COMPLETE.
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
// testing copyTexImage2D
// copyTexImage2D to same texture but different level
glBindTexture(GL_TEXTURE_2D, texture.get());
glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
EXPECT_GL_NO_ERROR();
// copyTexImage2D to same texture same level, invalid feedback loop
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// copyTexImage2D to different texture
glBindTexture(GL_TEXTURE_2D, texture2.get());
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
EXPECT_GL_NO_ERROR();
// testing copyTexSubImage2D
// copyTexSubImage2D to same texture but different level
glBindTexture(GL_TEXTURE_2D, texture.get());
glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
EXPECT_GL_NO_ERROR();
// copyTexSubImage2D to same texture same level, invalid feedback loop
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// copyTexSubImage2D to different texture
glBindTexture(GL_TEXTURE_2D, texture2.get());
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
EXPECT_GL_NO_ERROR();
}
// 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(WebGLCompatibilityTest, ANGLE_INSTANTIATE_TEST(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