Bug 1136508 - Detect CopyTexImage feedback loops. - r=mtseng draft
authorJeff Gilbert <jgilbert@mozilla.com>
Wed, 13 Jul 2016 00:48:55 -0700
changeset 387002 2567f6a324f8c4dfa3880ec3c8e88710612e24b2
parent 384060 dbb31bcad5a1f60a35b5600ea1578d9b9fa55237
child 387003 e6bc4ef8547646c04e8d158806664553ec1cc13f
push id22882
push userbmo:jgilbert@mozilla.com
push dateWed, 13 Jul 2016 08:08:18 +0000
reviewersmtseng
bugs1136508
milestone50.0a1
Bug 1136508 - Detect CopyTexImage feedback loops. - r=mtseng MozReview-Commit-ID: G1RsyyYMacp
dom/canvas/WebGLTexture.h
dom/canvas/WebGLTextureUpload.cpp
--- 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;
     }