Bug 1395497 - Use mat3s to transform tex coords in GLBlitHelper. - r=daoshengmu draft
authorJeff Gilbert <jgilbert@mozilla.com>
Thu, 28 Sep 2017 19:07:46 -0700
changeset 674936 eaf08f6eed2942e3a16f23e3b14b57627eb03dc7
parent 674935 1dcb6aea3bc094a2e303a121edcbfc09f1e803e8
child 674937 6e884353d16e0f7ddfb43b70a59aa5ba16848b11
push id82975
push userbmo:snorp@snorp.net
push dateWed, 04 Oct 2017 15:19:09 +0000
reviewersdaoshengmu
bugs1395497
milestone58.0a1
Bug 1395497 - Use mat3s to transform tex coords in GLBlitHelper. - r=daoshengmu MozReview-Commit-ID: 9AjnrOY4Rrc
dom/canvas/TexUnpackBlob.cpp
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLBlitHelper.h
gfx/gl/GLBlitHelperD3D.cpp
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -697,20 +697,20 @@ TexUnpackImage::TexOrSubImage(bool isSub
         }
 
         const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
         if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
             fallbackReason = "bug: failed to confirm FB for blit";
             break;
         }
 
-        const gfx::IntSize destSize(mWidth, mHeight);
+        const gfx::IntSize dstSize(mWidth, mHeight);
         const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
                                                          : gl::OriginPos::BottomLeft);
-        if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, dstOrigin)) {
+        if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, dstSize, dstOrigin)) {
             fallbackReason = "likely bug: failed to blit";
             break;
         }
 
         // Blitting was successful, so we're done!
         *out_error = 0;
         return true;
     } while (false);
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -113,16 +113,93 @@ const char* const kFragBody_PlanarYUV = 
                         1.0);                                                \n\
         vec4 rgb = uColorMatrix * yuv;                                       \n\
         FRAG_COLOR = vec4(rgb.rgb, 1.0);                                     \n\
     }                                                                        \n\
 ";
 
 // --
 
+template<uint8_t N>
+/*static*/ Mat<N>
+Mat<N>::Zero()
+{
+    Mat<N> ret;
+    for (auto& x : ret.m) {
+        x = 0.0f;
+    }
+    return ret;
+}
+
+template<uint8_t N>
+/*static*/ Mat<N>
+Mat<N>::I()
+{
+    auto ret = Mat<N>::Zero();
+    for (uint8_t i = 0; i < N; i++) {
+        ret.at(i,i) = 1.0f;
+    }
+    return ret;
+}
+
+template<uint8_t N>
+Mat<N>
+Mat<N>::operator*(const Mat<N>& r) const
+{
+    Mat<N> ret;
+    for (uint8_t x = 0; x < N; x++) {
+        for (uint8_t y = 0; y < N; y++) {
+            float sum = 0.0f;
+            for (uint8_t i = 0; i < N; i++) {
+                sum += at(i,y) * r.at(x,i);
+            }
+            ret.at(x,y) = sum;
+        }
+    }
+    return ret;
+}
+
+Mat3
+SubRectMat3(const float x, const float y, const float w, const float h)
+{
+    auto ret = Mat3::Zero();
+    ret.at(0,0) = w;
+    ret.at(1,1) = h;
+    ret.at(2,0) = x;
+    ret.at(2,1) = y;
+    ret.at(2,2) = 1.0f;
+    return ret;
+}
+
+Mat3
+SubRectMat3(const gfx::IntRect& subrect, const gfx::IntSize& size)
+{
+    return SubRectMat3(subrect.x / size.width,
+                       subrect.y / size.height,
+                       subrect.width / size.width,
+                       subrect.height / size.height);
+}
+
+Mat3
+SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize,
+            const gfx::IntSize& divisors)
+{
+    const float x = float(bigSubrect.x) / divisors.width;
+    const float y = float(bigSubrect.y) / divisors.height;
+    const float w = float(bigSubrect.width) / divisors.width;
+    const float h = float(bigSubrect.height) / divisors.height;
+    return SubRectMat3(x / smallSize.width,
+                       y / smallSize.height,
+                       w / smallSize.width,
+                       h / smallSize.height);
+}
+
+
+// --
+
 ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl, const uint8_t texCount,
                                        const GLenum texTarget)
     : mGL(*gl)
     , mTexCount(texCount)
     , mTexTarget(texTarget)
     , mOldTexUnit(mGL.GetIntAs<GLenum>(LOCAL_GL_ACTIVE_TEXTURE))
 {
     GLenum texBinding;
@@ -261,16 +338,17 @@ public:
             // adds RASTERIZER_DISCARD.
             rasterizerDiscard = Some(mGL.PushEnabled(LOCAL_GL_RASTERIZER_DISCARD, false));
         }
 
         mGL.fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask);
         mGL.fColorMask(true, true, true, true);
 
         mGL.fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
+        MOZ_ASSERT(destSize.width && destSize.height);
         mGL.fViewport(0, 0, destSize.width, destSize.height);
     }
 
     ~ScopedDrawBlitState()
     {
         mGL.SetEnabled(LOCAL_GL_BLEND,                    blend       );
         mGL.SetEnabled(LOCAL_GL_CULL_FACE,                cullFace    );
         mGL.SetEnabled(LOCAL_GL_DEPTH_TEST,               depthTest   );
@@ -289,29 +367,25 @@ public:
     }
 };
 
 // --
 
 DrawBlitProg::DrawBlitProg(const GLBlitHelper* const parent, const GLuint prog)
     : mParent(*parent)
     , mProg(prog)
-    , mLoc_u1ForYFlip(mParent.mGL->fGetUniformLocation(mProg, "u1ForYFlip"))
-    , mLoc_uSrcRect(mParent.mGL->fGetUniformLocation(mProg, "uSrcRect"))
-    , mLoc_uTexSize0(mParent.mGL->fGetUniformLocation(mProg, "uTexSize0"))
-    , mLoc_uTexSize1(mParent.mGL->fGetUniformLocation(mProg, "uTexSize1"))
-    , mLoc_uDivisors(mParent.mGL->fGetUniformLocation(mProg, "uDivisors"))
+    , mLoc_uDestMatrix(mParent.mGL->fGetUniformLocation(mProg, "uDestMatrix"))
+    , mLoc_uTexMatrix0(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix0"))
+    , mLoc_uTexMatrix1(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix1"))
     , mLoc_uColorMatrix(mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix"))
 {
-    MOZ_ASSERT(mLoc_u1ForYFlip != -1);
-    MOZ_ASSERT(mLoc_uSrcRect != -1);
-    MOZ_ASSERT(mLoc_uTexSize0 != -1);
+    MOZ_ASSERT(mLoc_uDestMatrix != -1);
+    MOZ_ASSERT(mLoc_uTexMatrix0 != -1);
     if (mLoc_uColorMatrix != -1) {
-        MOZ_ASSERT(mLoc_uTexSize1 != -1);
-        MOZ_ASSERT(mLoc_uDivisors != -1);
+        MOZ_ASSERT(mLoc_uTexMatrix1 != -1);
     }
 }
 
 DrawBlitProg::~DrawBlitProg()
 {
     const auto& gl = mParent.mGL;
     if (!gl->MakeCurrent())
         return;
@@ -324,26 +398,41 @@ DrawBlitProg::Draw(const BaseArgs& args,
 {
     const auto& gl = mParent.mGL;
 
     const SaveRestoreCurrentProgram oldProg(gl);
     gl->fUseProgram(mProg);
 
     // --
 
-    gl->fUniform1f(mLoc_u1ForYFlip, args.yFlip ? 1 : 0);
-    gl->fUniform4f(mLoc_uSrcRect,
-                   args.srcRect.x, args.srcRect.y,
-                   args.srcRect.width, args.srcRect.height);
-    gl->fUniform2f(mLoc_uTexSize0, args.texSize0.width, args.texSize0.height);
+    Mat3 destMatrix;
+    if (args.destRect) {
+        const auto& destRect = args.destRect.value();
+        destMatrix = SubRectMat3(destRect.x / args.destSize.width,
+                                 destRect.y / args.destSize.height,
+                                 destRect.width / args.destSize.width,
+                                 destRect.height / args.destSize.height);
+    } else {
+        destMatrix = Mat3::I();
+    }
+
+    if (args.yFlip) {
+        // Apply the y-flip matrix before the destMatrix.
+        // That is, flip y=[0-1] to y=[1-0] before we restrict to the destRect.
+        destMatrix.at(2,1) += destMatrix.at(1,1);
+        destMatrix.at(1,1) *= -1.0f;
+    }
+
+    gl->fUniformMatrix3fv(mLoc_uDestMatrix, 1, false, destMatrix.m);
+    gl->fUniformMatrix3fv(mLoc_uTexMatrix0, 1, false, args.texMatrix0.m);
 
     MOZ_ASSERT(bool(argsYUV) == (mLoc_uColorMatrix != -1));
     if (argsYUV) {
-        gl->fUniform2f(mLoc_uTexSize1, argsYUV->texSize1.width, argsYUV->texSize1.height);
-        gl->fUniform2f(mLoc_uDivisors, argsYUV->divisors.width, argsYUV->divisors.height);
+        gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m);
+
         const auto& colorMatrix = gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV->colorSpace);
         gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
     }
 
     // --
 
     const ScopedDrawBlitState drawState(gl, args.destSize);
 
@@ -435,41 +524,34 @@ GLBlitHelper::GLBlitHelper(GLContext* co
         #if __VERSION__ >= 130                                               \n\
             #define ATTRIBUTE in                                             \n\
             #define VARYING out                                              \n\
         #else                                                                \n\
             #define ATTRIBUTE attribute                                      \n\
             #define VARYING varying                                          \n\
         #endif                                                               \n\
                                                                              \n\
-        ATTRIBUTE vec2 aVert;                                                \n\
+        ATTRIBUTE vec2 aVert; // [0.0-1.0]                                   \n\
                                                                              \n\
-        uniform float u1ForYFlip;                                            \n\
-        uniform vec4 uSrcRect;                                               \n\
-        uniform vec2 uTexSize0;                                              \n\
-        uniform vec2 uTexSize1;                                              \n\
-        uniform vec2 uDivisors;                                              \n\
+        uniform mat3 uDestMatrix;                                            \n\
+        uniform mat3 uTexMatrix0;                                            \n\
+        uniform mat3 uTexMatrix1;                                            \n\
                                                                              \n\
         VARYING vec2 vTexCoord0;                                             \n\
         VARYING vec2 vTexCoord1;                                             \n\
                                                                              \n\
         void main(void)                                                      \n\
         {                                                                    \n\
-            vec2 vertPos = aVert * 2.0 - 1.0;                                \n\
-            gl_Position = vec4(vertPos, 0.0, 1.0);                           \n\
+            vec2 destPos = (uDestMatrix * vec3(aVert, 1.0)).xy;              \n\
+            gl_Position = vec4(destPos * 2.0 - 1.0, 0.0, 1.0);               \n\
                                                                              \n\
-            vec2 texCoord = aVert;                                           \n\
-            texCoord.y = abs(u1ForYFlip - texCoord.y);                       \n\
-            texCoord = texCoord * uSrcRect.zw + uSrcRect.xy;                 \n\
-                                                                             \n\
-            vTexCoord0 = texCoord / uTexSize0;                               \n\
-            vTexCoord1 = texCoord / (uTexSize1 * uDivisors);                 \n\
+            vTexCoord0 = (uTexMatrix0 * vec3(aVert, 1.0)).xy;                \n\
+            vTexCoord1 = (uTexMatrix1 * vec3(aVert, 1.0)).xy;                \n\
         }                                                                    \n\
     ";
-
     const char* const parts[] = {
         mDrawBlitProg_VersionLine.get(),
         kVertSource
     };
     mGL->fShaderSource(mDrawBlitProg_VertShader, ArrayLength(parts), parts, nullptr);
     mGL->fCompileShader(mDrawBlitProg_VertShader);
 }
 
@@ -573,37 +655,37 @@ GLBlitHelper::CreateDrawBlitProg(const D
     mGL->fGetProgramInfoLog(prog, progLogLen, nullptr, progLog.get());
     progLog[progLogLen] = 0;
 
     const auto& vs = mDrawBlitProg_VertShader;
     GLuint vsLogLen = 0;
     mGL->fGetShaderiv(vs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&vsLogLen);
     const UniquePtr<char[]> vsLog(new char[vsLogLen+1]);
     mGL->fGetShaderInfoLog(vs, vsLogLen, nullptr, vsLog.get());
-    progLog[progLogLen] = 0;
+    vsLog[vsLogLen] = 0;
 
     GLuint fsLogLen = 0;
     mGL->fGetShaderiv(fs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&fsLogLen);
     const UniquePtr<char[]> fsLog(new char[fsLogLen+1]);
     mGL->fGetShaderInfoLog(fs, fsLogLen, nullptr, fsLog.get());
-    progLog[progLogLen] = 0;
+    fsLog[fsLogLen] = 0;
 
     gfxCriticalError() << "DrawBlitProg link failed:\n"
                        << "progLog: " << progLog.get() << "\n"
                        << "vsLog: " << vsLog.get() << "\n"
                        << "fsLog: " << fsLog.get() << "\n";
     return nullptr;
 }
 
 // -----------------------------------------------------------------------------
 
 bool
-GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
+GLBlitHelper::BlitImageToFramebuffer(layers::Image* const srcImage,
                                      const gfx::IntSize& destSize,
-                                     OriginPos destOrigin)
+                                     const OriginPos destOrigin)
 {
     switch (srcImage->GetFormat()) {
     case ImageFormat::PLANAR_YCBCR:
         return BlitImage(static_cast<PlanarYCbCrImage*>(srcImage), destSize, destOrigin);
 
 #ifdef MOZ_WIDGET_ANDROID
     case ImageFormat::SURFACE_TEXTURE:
         return BlitImage(static_cast<layers::SurfaceTextureImage*>(srcImage), destSize,
@@ -613,18 +695,17 @@ GLBlitHelper::BlitImageToFramebuffer(lay
     case ImageFormat::MAC_IOSURFACE:
         return BlitImage(srcImage->AsMacIOSurfaceImage(), destSize, destOrigin);
 #endif
 #ifdef XP_WIN
     case ImageFormat::GPU_VIDEO:
         return BlitImage(static_cast<layers::GPUVideoImage*>(srcImage), destSize,
                          destOrigin);
     case ImageFormat::D3D11_YCBCR_IMAGE:
-        return BlitImage((layers::D3D11YCbCrImage*)srcImage, destSize,
-                         destOrigin);
+        return BlitImage((layers::D3D11YCbCrImage*)srcImage, destSize, destOrigin);
     case ImageFormat::D3D9_RGB32_TEXTURE:
         return false; // todo
 #endif
     default:
         gfxCriticalError() << "Unhandled srcImage->GetFormat(): "
                            << uint32_t(srcImage->GetFormat());
         return false;
     }
@@ -769,24 +850,28 @@ GLBlitHelper::BlitImage(layers::PlanarYC
     mGL->fActiveTexture(LOCAL_GL_TEXTURE2);
     mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[2]);
     mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
                         uvTexSize.width, uvTexSize.height,
                         unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mCrChannel);
 
     // --
 
+    const auto& clipRect = yuvData->GetPictureRect();
     const auto srcOrigin = OriginPos::BottomLeft;
     const bool yFlip = (destOrigin != srcOrigin);
-    const auto& clipRect = yuvData->GetPictureRect();
-    const auto& colorSpace = yuvData->mYUVColorSpace;
 
-    const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, yTexSize };
-    const DrawBlitProg::YUVArgs yuvArgs = { uvTexSize, divisors, colorSpace };
-
+    const DrawBlitProg::BaseArgs baseArgs = {
+        SubRectMat3(clipRect, yTexSize),
+        yFlip, destSize, Nothing()
+    };
+    const DrawBlitProg::YUVArgs yuvArgs = {
+        SubRectMat3(clipRect, uvTexSize, divisors),
+        yuvData->mYUVColorSpace
+    };
     prog->Draw(baseArgs, &yuvArgs);
     return true;
 }
 
 // -------------------------------------
 
 #ifdef XP_MACOSX
 bool
@@ -797,23 +882,24 @@ GLBlitHelper::BlitImage(layers::MacIOSur
     if (mGL->GetContextType() != GLContextType::CGL) {
         MOZ_ASSERT(false);
         return false;
     }
     const auto glCGL = static_cast<GLContextCGL*>(mGL);
     const auto cglContext = glCGL->GetCGLContext();
 
     const auto& srcOrigin = OriginPos::BottomLeft;
-    const bool yFlip = destOrigin != srcOrigin;
-    const gfx::IntRect clipRect({0, 0}, srcImage->GetSize());
-    const gfx::IntSize texRectNormFactor(1, 1);
 
-    const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect,
-                                              texRectNormFactor };
-    DrawBlitProg::YUVArgs yuvArgs = { texRectNormFactor, {2,2}, YUVColorSpace::BT601 };
+    DrawBlitProg::BaseArgs baseArgs;
+    baseArgs.yFlip = (destOrigin != srcOrigin);
+    baseArgs.destSize = destSize;
+
+    DrawBlitProg::YUVArgs yuvArgs;
+    yuvArgs.colorSpace = YUVColorSpace::BT601;
+
     const DrawBlitProg::YUVArgs* pYuvArgs = nullptr;
 
     auto planes = iosurf->GetPlaneCount();
     if (!planes) {
         planes = 1; // Bad API. No cookie.
     }
 
     const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE;
@@ -913,16 +999,21 @@ GLBlitHelper::BlitImage(layers::MacIOSur
             const nsPrintfCString errStr("CGLTexImageIOSurface2D(context, target, 0x%04x,"
                                          " %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i",
                                          internalFormats[p], uint32_t(width),
                                          uint32_t(height), unpackFormats[p],
                                          unpackTypes[p], p, err);
             gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr << ")";
             return false;
         }
+
+        if (p == 0) {
+            baseArgs.texMatrix0 = SubRectMat3(0, 0, width, height);
+            yuvArgs.texMatrix1 = SubRectMat3(0, 0, width / 2.0, height / 2.0);
+        }
     }
 
     const auto& prog = GetDrawBlitProg({fragHeader, fragBody});
     if (!prog)
         return false;
 
     prog->Draw(baseArgs, pYuvArgs);
     return true;
@@ -932,41 +1023,39 @@ GLBlitHelper::BlitImage(layers::MacIOSur
 // -----------------------------------------------------------------------------
 
 void
 GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex,
                                            const gfx::IntSize& srcSize,
                                            const gfx::IntSize& destSize,
                                            const GLenum srcTarget) const
 {
-    const gfx::IntRect clipRect(0, 0, srcSize.width, srcSize.height);
-
-    DrawBlitProg::Key key;
-    gfx::IntSize texSizeDivisor;
+    const char* fragHeader;
+    Mat3 texMatrix0;
     switch (srcTarget) {
     case LOCAL_GL_TEXTURE_2D:
-        key = {kFragHeader_Tex2D, kFragBody_RGBA};
-        texSizeDivisor = srcSize;
+        fragHeader = kFragHeader_Tex2D;
+        texMatrix0 = Mat3::I();
         break;
     case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
-        key = {kFragHeader_Tex2DRect, kFragBody_RGBA};
-        texSizeDivisor = gfx::IntSize(1, 1);
+        fragHeader = kFragHeader_Tex2DRect;
+        texMatrix0 = SubRectMat3(0, 0, srcSize.width, srcSize.height);
         break;
     default:
         gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
         return;
     }
-    const auto& prog = GetDrawBlitProg(key);
+    const auto& prog = GetDrawBlitProg({ fragHeader, kFragBody_RGBA});
     MOZ_ASSERT(prog);
 
     const ScopedSaveMultiTex saveTex(mGL, 1, srcTarget);
     mGL->fBindTexture(srcTarget, srcTex);
 
     const bool yFlip = false;
-    const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, texSizeDivisor };
+    const DrawBlitProg::BaseArgs baseArgs = { texMatrix0, yFlip, destSize, Nothing() };
     prog->Draw(baseArgs);
 }
 
 // -----------------------------------------------------------------------------
 
 void
 GLBlitHelper::BlitFramebuffer(const gfx::IntSize& srcSize,
                               const gfx::IntSize& destSize) const
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -36,51 +36,69 @@ namespace gl {
 
 class BindAnglePlanes;
 class GLContext;
 
 bool
 GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
               gfx::IntSize* const out_divisors);
 
+template<uint8_t N>
+struct Mat
+{
+    float m[N*N]; // column-major, for GL
+
+    float& at(const uint8_t x, const uint8_t y) {
+        return m[N*x+y];
+    }
+
+    static Mat<N> Zero();
+    static Mat<N> I();
+
+    Mat<N> operator*(const Mat<N>& r) const;
+};
+typedef Mat<3> Mat3;
+
+Mat3 SubRectMat3(float x, float y, float w, float h);
+Mat3 SubRectMat3(const gfx::IntRect& subrect, const gfx::IntSize& size);
+Mat3 SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize,
+                 const gfx::IntSize& divisors);
+
 class DrawBlitProg final
 {
     const GLBlitHelper& mParent;
     const GLuint mProg;
-    const GLint mLoc_u1ForYFlip;
-    const GLint mLoc_uSrcRect;
-    const GLint mLoc_uTexSize0;
-    const GLint mLoc_uTexSize1;
-    const GLint mLoc_uDivisors;
+    const GLint mLoc_uDestMatrix;
+    const GLint mLoc_uTexMatrix0;
+    const GLint mLoc_uTexMatrix1;
     const GLint mLoc_uColorMatrix;
 
 public:
     struct Key final {
-        const char* fragHeader;
-        const char* fragBody;
+        const char* const fragHeader;
+        const char* const fragBody;
 
         bool operator <(const Key& x) const {
             if (fragHeader != x.fragHeader)
                 return fragHeader < x.fragHeader;
             return fragBody < x.fragBody;
         }
     };
 
     DrawBlitProg(const GLBlitHelper* parent, GLuint prog);
     ~DrawBlitProg();
 
     struct BaseArgs final {
-        gfx::IntSize destSize;
+        Mat3 texMatrix0;
         bool yFlip;
-        gfx::IntRect srcRect;
-        gfx::IntSize texSize0;
+        gfx::IntSize destSize; // Always needed for (at least) setting the viewport.
+        Maybe<gfx::IntRect> destRect;
     };
     struct YUVArgs final {
-        gfx::IntSize texSize1;
-        gfx::IntSize divisors;
+        Mat3 texMatrix1;
         YUVColorSpace colorSpace;
     };
 
     void Draw(const BaseArgs& args, const YUVArgs* argsYUV = nullptr) const;
 };
 
 class ScopedSaveMultiTex final
 {
@@ -176,18 +194,18 @@ private:
                    OriginPos destOrigin) const;
 
     bool BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
                         const gfx::IntSize& destSize, OriginPos destOrigin) const;
 
     bool BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
                         const gfx::IntRect& clipRect,
                         const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
-                        const YUVColorSpace colorSpace,
-                        const gfx::IntSize& destSize, OriginPos destOrigin) const;
+                        const YUVColorSpace colorSpace, const gfx::IntSize& destSize,
+                        OriginPos destOrigin) const;
 
     bool BlitAnglePlanes(uint8_t numPlanes, const RefPtr<ID3D11Texture2D>* texD3DList,
                          const DrawBlitProg* prog, const DrawBlitProg::BaseArgs& baseArgs,
                          const DrawBlitProg::YUVArgs* const yuvArgs) const;
 #endif
 };
 
 extern const char* const kFragHeader_Tex2D;
--- a/gfx/gl/GLBlitHelperD3D.cpp
+++ b/gfx/gl/GLBlitHelperD3D.cpp
@@ -15,18 +15,17 @@
 
 #include "mozilla/layers/D3D11YCbCrImage.h"
 #include "mozilla/layers/TextureD3D11.h"
 
 namespace mozilla {
 namespace gl {
 
 static EGLStreamKHR
-StreamFromD3DTexture(ID3D11Texture2D* const texD3D,
-                     const EGLAttrib* const postAttribs)
+StreamFromD3DTexture(ID3D11Texture2D* const texD3D, const EGLAttrib* const postAttribs)
 {
     auto& egl = sEGLLibrary;
     if (!egl.IsExtensionSupported(GLLibraryEGL::NV_stream_consumer_gltexture_yuv) ||
         !egl.IsExtensionSupported(GLLibraryEGL::ANGLE_stream_producer_d3d_texture_nv12))
     {
         return 0;
     }
 
@@ -239,17 +238,18 @@ GLBlitHelper::BlitImage(layers::D3D11YCb
                           srcImage->mCbCrSize, srcImage->mColorSpace, destSize,
                           destOrigin);
 }
 
 // -------------------------------------
 
 bool
 GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
-                             const gfx::IntSize& destSize, OriginPos destOrigin) const
+                             const gfx::IntSize& destSize,
+                             const OriginPos destOrigin) const
 {
     const auto& d3d = GetD3D11();
     if (!d3d)
         return false;
 
     const auto& handle = desc.handle();
     const auto& format = desc.format();
     const auto& clipSize = desc.size();
@@ -290,33 +290,39 @@ GLBlitHelper::BlitDescriptor(const layer
     const gfx::IntSize ySize(texDesc.Width, texDesc.Height);
     const gfx::IntSize divisors(2, 2);
     MOZ_ASSERT(ySize.width % divisors.width == 0);
     MOZ_ASSERT(ySize.height % divisors.height == 0);
     const gfx::IntSize uvSize(ySize.width / divisors.width,
                               ySize.height / divisors.height);
 
     const bool yFlip = destOrigin != srcOrigin;
-    const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, ySize };
-    const DrawBlitProg::YUVArgs yuvArgs = { uvSize, divisors, colorSpace };
+    const DrawBlitProg::BaseArgs baseArgs = {
+        SubRectMat3(clipRect, ySize),
+        yFlip, destSize, Nothing()
+    };
+    const DrawBlitProg::YUVArgs yuvArgs = {
+        SubRectMat3(clipRect, uvSize, divisors),
+        colorSpace
+    };
 
     const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_NV12});
     MOZ_RELEASE_ASSERT(prog);
     prog->Draw(baseArgs, &yuvArgs);
     return true;
 }
 
 // --
 
 bool
 GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
                              const gfx::IntRect& clipRect,
                              const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
-                             const YUVColorSpace colorSpace,
-                             const gfx::IntSize& destSize, OriginPos destOrigin) const
+                             const YUVColorSpace colorSpace, const gfx::IntSize& destSize,
+                             const OriginPos destOrigin) const
 {
     const auto& d3d = GetD3D11();
     if (!d3d)
         return false;
 
     const auto srcOrigin = OriginPos::BottomLeft;
 
     gfx::IntSize divisors;
@@ -326,18 +332,24 @@ GLBlitHelper::BlitAngleYCbCr(const Windo
     const RefPtr<ID3D11Texture2D> texList[3] = {
         OpenSharedTexture(d3d, handleList[0]),
         OpenSharedTexture(d3d, handleList[1]),
         OpenSharedTexture(d3d, handleList[2])
     };
     const BindAnglePlanes bindPlanes(this, 3, texList);
 
     const bool yFlip = destOrigin != srcOrigin;
-    const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, ySize };
-    const DrawBlitProg::YUVArgs yuvArgs = { uvSize, divisors, colorSpace };
+    const DrawBlitProg::BaseArgs baseArgs = {
+        SubRectMat3(clipRect, ySize),
+        yFlip, destSize, Nothing()
+    };
+    const DrawBlitProg::YUVArgs yuvArgs = {
+        SubRectMat3(clipRect, uvSize, divisors),
+        colorSpace
+    };
 
     const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_PlanarYUV});
     MOZ_RELEASE_ASSERT(prog);
     prog->Draw(baseArgs, &yuvArgs);
     return true;
 }
 
 } // namespace gl