Bug 1136508 - Detect CopyTexImage feedback loops. - r=mtseng
MozReview-Commit-ID: G1RsyyYMacp
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -246,16 +246,17 @@ protected:
GLint level, GLsizei width, GLsizei height,
GLsizei depth, GLint border,
WebGLTexture::ImageInfo** const out_imageInfo);
bool ValidateTexImageSelection(const char* funcName, TexImageTarget target,
GLint level, GLint xOffset, GLint yOffset,
GLint zOffset, GLsizei width, GLsizei height,
GLsizei depth,
WebGLTexture::ImageInfo** const out_imageInfo);
+ bool ValidateCopyTexImageForFeedback(const char* funcName, uint32_t level) const;
public:
void TexStorage(const char* funcName, TexTarget target, GLsizei levels,
GLenum sizedFormat, GLsizei width, GLsizei height, GLsizei depth);
protected:
void TexImage(const char* funcName, TexImageTarget target, GLint level,
GLenum internalFormat, GLint border, GLenum unpackFormat,
GLenum unpackType, webgl::TexUnpackBlob* blob);
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1690,16 +1690,41 @@ ScopedCopyTexImageSource::~ScopedCopyTex
ToGLHandle(mWebGL->mBoundReadFramebuffer));
gl->fDeleteFramebuffers(1, &mFB);
gl->fDeleteRenderbuffers(1, &mRB);
}
////////////////////////////////////////////////////////////////////////////////
+bool
+WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t level) const
+{
+ const auto& fb = mContext->mBoundReadFramebuffer;
+ if (fb) {
+ const auto readBuffer = fb->ReadBufferMode();
+ MOZ_ASSERT(readBuffer != LOCAL_GL_NONE);
+ const uint32_t colorAttachment = readBuffer - LOCAL_GL_COLOR_ATTACHMENT0;
+ const auto& attach = fb->ColorAttachment(colorAttachment);
+
+ if (attach.Texture() == this &&
+ attach.MipLevel() == uint32_t(level))
+ {
+ // Note that the TexImageTargets *don't* have to match for this to be
+ // undefined per GLES 3.0.4 p211, thus an INVALID_OP in WebGL.
+ mContext->ErrorInvalidOperation("%s: Feedback loop detected, as this texture"
+ " is already attached to READ_FRAMEBUFFER's"
+ " READ_BUFFER-selected COLOR_ATTACHMENT%u.",
+ funcName, colorAttachment);
+ return false;
+ }
+ }
+ return true;
+}
+
// There is no CopyTexImage3D.
void
WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
GLint x, GLint y, GLsizei width, GLsizei height,
GLint border)
{
const char funcName[] = "CopyTexImage2D";
@@ -1723,16 +1748,19 @@ WebGLTexture::CopyTexImage2D(TexImageTar
uint32_t srcWidth;
uint32_t srcHeight;
GLenum srcMode;
if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight,
&srcMode))
return;
auto srcFormat = srcUsage->format;
+ if (!ValidateCopyTexImageForFeedback(funcName, level))
+ return;
+
// GLES 3.0.4 p145:
// "Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an
// INVALID_OPERATION error if any of the following conditions is true: READ_BUFFER
// is NONE"
if (srcMode == LOCAL_GL_NONE) {
mContext->ErrorInvalidOperation("%s: READ_BUFFER is NONE. ", funcName);
return;
}
@@ -1884,16 +1912,19 @@ WebGLTexture::CopyTexSubImage(const char
uint32_t srcWidth;
uint32_t srcHeight;
GLenum srcMode;
if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight,
&srcMode))
return;
auto srcFormat = srcUsage->format;
+ if (!ValidateCopyTexImageForFeedback(funcName, level))
+ return;
+
// GLES 3.0.4 p145:
// "Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an
// INVALID_OPERATION error if any of the following conditions is true: READ_BUFFER
// is NONE"
if (srcMode == LOCAL_GL_NONE) {
mContext->ErrorInvalidOperation("%s: READ_BUFFER is NONE. ", funcName);
return;
}