Bug 1305832 - CopyTex[Sub]Image should specify using TexImage to convince the driver to use the right internal format. - r=ethlin draft
authorJeff Gilbert <jdashg@gmail.com>
Wed, 07 Dec 2016 14:56:52 -1000
changeset 447845 16e8874ba87f7b055aae1f32e90a1c20ccbc33d3
parent 446533 f97b53fd3b7e0728c555efd145765879bda1b950
child 448304 0a2d81b9f4065d25a8cfec010d96a9e34c7decab
push id38190
push userbmo:jgilbert@mozilla.com
push dateThu, 08 Dec 2016 03:08:37 +0000
reviewersethlin
bugs1305832
milestone53.0a1
Bug 1305832 - CopyTex[Sub]Image should specify using TexImage to convince the driver to use the right internal format. - r=ethlin MozReview-Commit-ID: JmhmNtqeA9V
dom/canvas/WebGLTextureUpload.cpp
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1925,16 +1925,87 @@ WebGLTexture::ValidateCopyTexImageForFee
                                             " READ_BUFFER-selected COLOR_ATTACHMENT%u.",
                                             funcName, attach->mAttachmentPoint);
             return false;
         }
     }
     return true;
 }
 
+static bool
+DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage,
+                    const WebGLTexture* tex, TexImageTarget target, GLint level,
+                    GLint xWithinSrc, GLint yWithinSrc,
+                    uint32_t srcTotalWidth, uint32_t srcTotalHeight,
+                    const webgl::FormatUsageInfo* srcUsage,
+                    GLint xOffset, GLint yOffset, GLint zOffset,
+                    uint32_t dstWidth, uint32_t dstHeight,
+                    const webgl::FormatUsageInfo* dstUsage)
+{
+    gl::GLContext* gl = webgl->gl;
+    gl->MakeCurrent();
+
+    ////
+
+    uint32_t readX, readY;
+    uint32_t writeX, writeY;
+    uint32_t rwWidth, rwHeight;
+    Intersect(srcTotalWidth, xWithinSrc, dstWidth, &readX, &writeX, &rwWidth);
+    Intersect(srcTotalHeight, yWithinSrc, dstHeight, &readY, &writeY, &rwHeight);
+
+    ////
+
+    GLenum error = 0;
+    do {
+        const auto& idealUnpack = dstUsage->idealUnpack;
+        if (!isSubImage) {
+            const auto& pi = idealUnpack->ToPacking();
+            const auto& bpp = BytesPerPixel(pi);
+            const UniqueBuffer zeros(calloc(1, dstWidth * dstHeight * bpp));
+            if (!zeros.get()) {
+                webgl->ErrorOutOfMemory("%s: Ran out of memory allocating zeros.",
+                                        funcName);
+                return false;
+            }
+            error = DoTexImage(gl, target, level, idealUnpack, dstWidth, dstHeight, 1,
+                               zeros.get());
+            if (error)
+                break;
+        }
+
+        if (!rwWidth || !rwHeight) {
+            // There aren't any pixels to copy, so we're 'done'.
+            return true;
+        }
+
+        const auto& srcFormat = srcUsage->format;
+        ScopedCopyTexImageSource maybeSwizzle(webgl, funcName, srcTotalWidth,
+                                              srcTotalHeight, srcFormat, dstUsage);
+
+        const uint8_t zOffset = 0;
+        error = DoCopyTexSubImage(gl, target, level, writeX, writeY, zOffset, readX,
+                                  readY, rwWidth, rwHeight);
+        if (error)
+            break;
+
+        return true;
+    } while (false);
+
+    if (error == LOCAL_GL_OUT_OF_MEMORY) {
+        webgl->ErrorOutOfMemory("%s: Ran out of memory during texture copy.", funcName);
+        return false;
+    }
+
+    MOZ_RELEASE_ASSERT(false, "GFX: We should have caught all other errors.");
+    webgl->GenerateWarning("%s: Unexpected error during texture copy. Context lost.",
+                           funcName);
+    webgl->ForceLoseContext();
+    return false;
+}
+
 // There is no CopyTexImage3D.
 void
 WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
                              GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeight,
                              GLint border)
 {
     const char funcName[] = "copyTexImage2D";
 
@@ -1955,107 +2026,57 @@ WebGLTexture::CopyTexImage2D(TexImageTar
         return;
     }
     MOZ_ASSERT(imageInfo);
 
     ////////////////////////////////////
     // Get source info
 
     const webgl::FormatUsageInfo* srcUsage;
-    uint32_t srcWidth;
-    uint32_t srcHeight;
-    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight))
+    uint32_t srcTotalWidth;
+    uint32_t srcTotalHeight;
+    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcTotalWidth,
+                                        &srcTotalHeight))
+    {
         return;
-    auto srcFormat = srcUsage->format;
+    }
 
     if (!ValidateCopyTexImageForFeedback(funcName, level))
         return;
 
     ////////////////////////////////////
     // Check that source and dest info are compatible
 
+    const auto& srcFormat = srcUsage->format;
     const auto dstUsage = ValidateCopyDestUsage(funcName, mContext, srcFormat,
                                                 internalFormat);
     if (!dstUsage)
         return;
 
-    const auto dstFormat = dstUsage->format;
-
+    const auto& dstFormat = dstUsage->format;
     if (!ValidateTargetForFormat(funcName, mContext, target, dstFormat))
         return;
 
     if (!mContext->IsWebGL2() && dstFormat->d) {
         mContext->ErrorInvalidOperation("%s: Function may not be called with format %s.",
                                         funcName, dstFormat->name);
         return;
     }
 
     if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
         return;
 
     ////////////////////////////////////
     // Do the thing!
 
-    gl::GLContext* gl = mContext->gl;
-    gl->MakeCurrent();
-
-    ScopedCopyTexImageSource maybeSwizzle(mContext, funcName, srcWidth, srcHeight,
-                                          srcFormat, dstUsage);
-
-    uint32_t readX, readY;
-    uint32_t writeX, writeY;
-    uint32_t rwWidth, rwHeight;
-    Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
-    Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
-
-    const auto& idealUnpack = dstUsage->idealUnpack;
-    const auto& driverInternalFormat = idealUnpack->internalFormat;
-
-    GLenum error = DoCopyTexImage2D(gl, target, level, driverInternalFormat, x, y, width,
-                                    height);
-    do {
-        if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height))
-            break;
-
-        if (error)
-            break;
-
-        // 1. Zero the texture data.
-        // 2. CopyTexSubImage the subrect.
-
-        if (!ZeroTextureData(mContext, funcName, mGLName, target, level, dstUsage, width,
-                             height, depth))
-        {
-            mContext->ErrorOutOfMemory("%s: Failed to zero texture data.", funcName);
-            MOZ_ASSERT(false, "Failed to zero texture data.");
-            return;
-        }
-
-        if (!rwWidth || !rwHeight) {
-            // There aren't any, so we're 'done'.
-            mContext->DummyReadFramebufferOperation(funcName);
-            return;
-        }
-
-        const uint8_t zOffset = 0;
-        error = DoCopyTexSubImage(gl, target, level, writeX, writeY, zOffset, readX,
-                                  readY, rwWidth, rwHeight);
-    } while (false);
-
-    if (error == LOCAL_GL_OUT_OF_MEMORY) {
-        mContext->ErrorOutOfMemory("%s: Ran out of memory during texture copy.",
-                                   funcName);
-        return;
-    }
-    if (error) {
-        MOZ_RELEASE_ASSERT(false, "GFX: We should have caught all other errors.");
-        mContext->GenerateWarning("%s: Unexpected error during texture copy. Context"
-                                  " lost.",
-                                  funcName);
-        mContext->ForceLoseContext();
+    const bool isSubImage = false;
+    if (!DoCopyTexOrSubImage(mContext, funcName, isSubImage, this, target, level, x, y,
+                             srcTotalWidth, srcTotalHeight, srcUsage, 0, 0, 0, width,
+                             height, dstUsage))
+    {
         return;
     }
 
     ////////////////////////////////////
     // Update our specification data.
 
     const bool isDataInitialized = true;
     const ImageInfo newImageInfo(dstUsage, width, height, depth, isDataInitialized);
@@ -2082,87 +2103,63 @@ WebGLTexture::CopyTexSubImage(const char
                                    width, height, depth, &imageInfo))
     {
         return;
     }
     MOZ_ASSERT(imageInfo);
 
     auto dstUsage = imageInfo->mFormat;
     MOZ_ASSERT(dstUsage);
+
     auto dstFormat = dstUsage->format;
-
     if (!mContext->IsWebGL2() && dstFormat->d) {
         mContext->ErrorInvalidOperation("%s: Function may not be called on a texture of"
                                         " format %s.",
                                         funcName, dstFormat->name);
         return;
     }
 
     ////////////////////////////////////
     // Get source info
 
     const webgl::FormatUsageInfo* srcUsage;
-    uint32_t srcWidth;
-    uint32_t srcHeight;
-    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight))
+    uint32_t srcTotalWidth;
+    uint32_t srcTotalHeight;
+    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcTotalWidth,
+                                        &srcTotalHeight))
+    {
         return;
-    auto srcFormat = srcUsage->format;
+    }
 
     if (!ValidateCopyTexImageForFeedback(funcName, level, zOffset))
         return;
 
     ////////////////////////////////////
     // Check that source and dest info are compatible
 
+    auto srcFormat = srcUsage->format;
     if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
         return;
 
     ////////////////////////////////////
     // Do the thing!
 
-    mContext->gl->MakeCurrent();
-
-    ScopedCopyTexImageSource maybeSwizzle(mContext, funcName, srcWidth, srcHeight,
-                                          srcFormat, dstUsage);
-
-    uint32_t readX, readY;
-    uint32_t writeX, writeY;
-    uint32_t rwWidth, rwHeight;
-    Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
-    Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
-
-    if (!rwWidth || !rwHeight) {
-        // There aren't any, so we're 'done'.
-        mContext->DummyReadFramebufferOperation(funcName);
-        return;
-    }
-
     bool uploadWillInitialize;
     if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
                                              yOffset, zOffset, width, height, depth,
                                              imageInfo, &uploadWillInitialize))
     {
         return;
     }
 
-    GLenum error = DoCopyTexSubImage(mContext->gl, target, level, xOffset + writeX,
-                                     yOffset + writeY, zOffset, readX, readY, rwWidth,
-                                     rwHeight);
-
-    if (error == LOCAL_GL_OUT_OF_MEMORY) {
-        mContext->ErrorOutOfMemory("%s: Ran out of memory during texture copy.",
-                                   funcName);
-        return;
-    }
-    if (error) {
-        MOZ_RELEASE_ASSERT(false, "GFX: We should have caught all other errors.");
-        mContext->GenerateWarning("%s: Unexpected error during texture copy. Context"
-                                  " lost.",
-                                  funcName);
-        mContext->ForceLoseContext();
+    const bool isSubImage = true;
+    if (!DoCopyTexOrSubImage(mContext, funcName, isSubImage, this, target, level, x, y,
+                             srcTotalWidth, srcTotalHeight, srcUsage, xOffset, yOffset,
+                             zOffset, width, height, dstUsage))
+    {
         return;
     }
 
     ////////////////////////////////////
     // Update our specification data?
 
     if (uploadWillInitialize) {
         imageInfo->SetIsDataInitialized(true, this);