Backed out 14 changesets (bug 1322746) for unexpected passes on Win8
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 01 Sep 2017 22:28:49 -0700
changeset 378351 3e55e4de032f16f2e6cda431c602d600f2d87f75
parent 378350 a9a24a28013bb346dc75044d02d4266842349e6c
child 378352 59ea29d58ab0b297fd57c3ac1595d770d1f389d6
push id94472
push userphilringnalda@gmail.com
push dateSat, 02 Sep 2017 05:29:00 +0000
treeherdermozilla-inbound@3e55e4de032f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1322746
milestone57.0a1
backs outa10fcb139377f16ea02e1c63e1bd7bbf4517bffc
992b2173bda73b4c462e8dbe7b58af0f632f06f6
88a28c4ebc6be81ab8685157e3d0d4a104747d90
c5bd6bbf565342cbc93b7381d184ce3abcd605d3
882cd05b7064a3b6e400f6768670fb43d3553e0d
87e7f25a089ca782419210434b89ebf75bf96aff
2ed5b75a6f5ee566096163105b83506a236f1e3d
6d1dd5775850846864638abca9c8fab1de0d4182
b97bb7a2e55563fae345dfb256765fe631cb9003
ab8352ffd2ca6227d537a28fca570bb5e9831e4b
a4901ec3c32731bfe8fc5d276dfaa8d0aa1bf6a6
61c7478af98c04eb81486f605cc053521353925f
b202e9377e24fe3d49fe2eaa5562afe7999f6754
cf739e7c76b860c6f4b9dacb2fae564e40c1cdfc
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 14 changesets (bug 1322746) for unexpected passes on Win8 Backed out changeset a10fcb139377 (bug 1322746) Backed out changeset 992b2173bda7 (bug 1322746) Backed out changeset 88a28c4ebc6b (bug 1322746) Backed out changeset c5bd6bbf5653 (bug 1322746) Backed out changeset 882cd05b7064 (bug 1322746) Backed out changeset 87e7f25a089c (bug 1322746) Backed out changeset 2ed5b75a6f5e (bug 1322746) Backed out changeset 6d1dd5775850 (bug 1322746) Backed out changeset b97bb7a2e555 (bug 1322746) Backed out changeset ab8352ffd2ca (bug 1322746) Backed out changeset a4901ec3c327 (bug 1322746) Backed out changeset 61c7478af98c (bug 1322746) Backed out changeset b202e9377e24 (bug 1322746) Backed out changeset cf739e7c76b8 (bug 1322746) MozReview-Commit-ID: CesCbY4ABvS
dom/base/test/test_anonymousContent_canvas.html
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/TexUnpackBlob.cpp
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLTextureUpload.cpp
dom/canvas/test/reftest/reftest.list
dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
dom/canvas/test/webgl-mochitest/mochitest.ini
dom/media/ipc/VideoDecoderManagerParent.cpp
dom/media/ipc/VideoDecoderParent.cpp
gfx/2d/MacIOSurface.cpp
gfx/2d/MacIOSurface.h
gfx/angle/src/libANGLE/Stream.cpp
gfx/angle/src/libANGLE/Stream.h
gfx/angle/src/libANGLE/renderer/StreamProducerImpl.h
gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp
gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h
gfx/angle/src/libANGLE/validationEGL.cpp
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLBlitHelper.h
gfx/gl/GLBlitHelperD3D.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextEGL.h
gfx/gl/GLLibraryEGL.cpp
gfx/gl/GLLibraryEGL.h
gfx/gl/HeapCopyOfStackArray.h
gfx/gl/ScopedGLHelpers.cpp
gfx/gl/ScopedGLHelpers.h
gfx/gl/SharedSurface.cpp
gfx/gl/SharedSurfaceD3D11Interop.cpp
gfx/gl/moz.build
gfx/layers/D3D11YCbCrImage.cpp
gfx/layers/D3D11YCbCrImage.h
gfx/layers/GLImages.cpp
gfx/layers/GPUVideoImage.h
gfx/layers/client/GPUVideoTextureClient.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/d3d11/TextureD3D11.h
gfx/layers/ipc/LayersSurfaces.ipdlh
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
--- a/dom/base/test/test_anonymousContent_canvas.html
+++ b/dom/base/test/test_anonymousContent_canvas.html
@@ -38,22 +38,20 @@ https://bugzilla.mozilla.org/show_bug.cg
         "Context is null for unknown context type");
 
     SimpleTest.doesThrow(
       () => anonymousContent.getCanvasContext("foo", "2d"),
       "NS_ERROR_NOT_AVAILABLE",
       "Get a context using unexisting id should throw"
     );
 
-    const normalWebGL = document.createElement('canvas').getContext('webgl');
-    if (normalWebGL) {
-      let webgl = anonymousContent.getCanvasContext("canvas-webgl", "webgl");
+    let webgl = anonymousContent.getCanvasContext("canvas-webgl", "webgl");
 
-      is(webgl.toString(), "[object WebGLRenderingContext]",
-          "WebGL Context is returned properly");
+    is(webgl.toString(), "[object WebGLRenderingContext]",
+        "WebGL Context is returned properly");
 
-      is(webgl.canvas, null,
-          "WebGL context's canvas property is null in anonymous content");
-    }
+    is(webgl.canvas, null,
+        "WebGL context's canvas property is null in anonymous content");
+
     chromeDocument.removeAnonymousContent(anonymousContent);
   </script>
 </body>
 </html>
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5179,16 +5179,117 @@ CanvasRenderingContext2D::DrawImage(cons
     }
 
     srcSurf =
      CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize, mIsSkiaGL);
   }
 
   nsLayoutUtils::DirectDrawInfo drawInfo;
 
+#ifdef USE_SKIA_GPU
+  if (mRenderingMode == RenderingMode::OpenGLBackendMode &&
+      mIsSkiaGL &&
+      !srcSurf &&
+      aImage.IsHTMLVideoElement() &&
+      AllowOpenGLCanvas()) {
+    mozilla::gl::GLContext* gl = gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext();
+    MOZ_ASSERT(gl);
+
+    HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
+    if (!video) {
+      return;
+    }
+
+    if (video->ContainsRestrictedContent()) {
+      aError.Throw(NS_ERROR_NOT_AVAILABLE);
+      return;
+    }
+
+    uint16_t readyState;
+    if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
+        readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
+      // still loading, just return
+      return;
+    }
+
+    // If it doesn't have a principal, just bail
+    nsCOMPtr<nsIPrincipal> principal = video->GetCurrentVideoPrincipal();
+    if (!principal) {
+      aError.Throw(NS_ERROR_NOT_AVAILABLE);
+      return;
+    }
+
+    mozilla::layers::ImageContainer* container = video->GetImageContainer();
+    if (!container) {
+      aError.Throw(NS_ERROR_NOT_AVAILABLE);
+      return;
+    }
+
+    AutoLockImage lockImage(container);
+    layers::Image* srcImage = lockImage.GetImage();
+    if (!srcImage) {
+      aError.Throw(NS_ERROR_NOT_AVAILABLE);
+      return;
+    }
+
+    {
+      if (!gl->MakeCurrent()) {
+        aError.Throw(NS_ERROR_NOT_AVAILABLE);
+        return;
+      }
+      GLuint videoTexture = 0;
+      gl->fGenTextures(1, &videoTexture);
+      // skiaGL expect upload on drawing, and uses texture 0 for texturing,
+      // so we must active texture 0 and bind the texture for it.
+      gl->fActiveTexture(LOCAL_GL_TEXTURE0);
+      const gl::ScopedBindTexture scopeBindTexture(gl, videoTexture);
+
+      gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGB, srcImage->GetSize().width, srcImage->GetSize().height, 0, LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT_5_6_5, nullptr);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+
+      const gl::OriginPos destOrigin = gl::OriginPos::TopLeft;
+      bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage, srcImage->GetSize(),
+                                                     videoTexture, LOCAL_GL_TEXTURE_2D,
+                                                     destOrigin);
+      if (ok) {
+        NativeSurface texSurf;
+        texSurf.mType = NativeSurfaceType::OPENGL_TEXTURE;
+        texSurf.mFormat = SurfaceFormat::R5G6B5_UINT16;
+        texSurf.mSize.width = srcImage->GetSize().width;
+        texSurf.mSize.height = srcImage->GetSize().height;
+        texSurf.mSurface = (void*)((uintptr_t)videoTexture);
+
+        srcSurf = mTarget->CreateSourceSurfaceFromNativeSurface(texSurf);
+        if (!srcSurf) {
+          gl->fDeleteTextures(1, &videoTexture);
+        }
+        imgSize.width = srcImage->GetSize().width;
+        imgSize.height = srcImage->GetSize().height;
+
+        int32_t displayWidth = video->VideoWidth();
+        int32_t displayHeight = video->VideoHeight();
+        aSw *= (double)imgSize.width / (double)displayWidth;
+        aSh *= (double)imgSize.height / (double)displayHeight;
+      } else {
+        gl->fDeleteTextures(1, &videoTexture);
+      }
+    }
+
+    srcImage = nullptr;
+
+    if (mCanvasElement) {
+      CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement,
+                                            principal, false,
+                                            video->GetCORSMode() != CORS_NONE);
+    }
+  }
+#endif
   if (!srcSurf) {
     // The canvas spec says that drawImage should draw the first frame
     // of animated images. We also don't want to rasterize vector images.
     uint32_t sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE |
                         nsLayoutUtils::SFE_NO_RASTERIZING_VECTORS;
 
     nsLayoutUtils::SurfaceFromElementResult res =
       CanvasRenderingContext2D::CachedSurfaceFromElement(element);
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -634,20 +634,16 @@ TexUnpackImage::TexOrSubImage(bool isSub
     }
 
     const char* fallbackReason;
     do {
         if (mDepth != 1) {
             fallbackReason = "depth is not 1";
             break;
         }
-        if (xOffset != 0 || yOffset != 0 || zOffset != 0) {
-            fallbackReason = "x/y/zOffset is not 0";
-            break;
-        }
 
         if (webgl->mPixelStore_UnpackSkipPixels ||
             webgl->mPixelStore_UnpackSkipRows ||
             webgl->mPixelStore_UnpackSkipImages)
         {
             fallbackReason = "non-zero UNPACK_SKIP_* not yet supported";
             break;
         }
@@ -700,17 +696,19 @@ TexUnpackImage::TexOrSubImage(bool isSub
         if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
             fallbackReason = "bug: failed to confirm FB for blit";
             break;
         }
 
         const gfx::IntSize destSize(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, destSize, scopedFB.FB(),
+                                                      dstOrigin))
+        {
             fallbackReason = "likely bug: failed to blit";
             break;
         }
 
         // Blitting was successful, so we're done!
         *out_error = 0;
         return true;
     } while (false);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -716,22 +716,16 @@ WebGLContext::InitAndValidateGL(FailureR
 
     if (IsWebGL2() &&
         !InitWebGL2(out_failReason))
     {
         // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
         return false;
     }
 
-    if (!gl->IsSupported(GLFeature::vertex_array_object)) {
-        *out_failReason = { "FEATURE_FAILURE_WEBGL_VAOS",
-                            "Requires vertex_array_object." };
-        return false;
-    }
-
     mDefaultVertexArray = WebGLVertexArray::Create(this);
     mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
     mBoundVertexArray = mDefaultVertexArray;
 
     // OpenGL core profiles remove the default VAO object from version
     // 4.0.0. We create a default VAO for all core profiles,
     // regardless of version.
     //
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1828,21 +1828,18 @@ ScopedCopyTexImageSource::ScopedCopyTexI
         MOZ_CRASH("GFX: Temp framebuffer is not complete.");
     }
 
     // Restore RB binding.
     scopedRB.Unwrap(); // This function should really have a better name.
 
     // Draw-blit rgbaTex into rgbaFB.
     const gfx::IntSize srcSize(srcWidth, srcHeight);
-    {
-        const gl::ScopedBindFramebuffer bindFB(gl, rgbaFB);
-        gl->BlitHelper()->DrawBlitTextureToFramebuffer(scopedTex.Texture(), srcSize,
-                                                       srcSize);
-    }
+    gl->BlitHelper()->DrawBlitTextureToFramebuffer(scopedTex.Texture(), rgbaFB,
+                                                   srcSize, srcSize);
 
     // Restore Tex2D binding and destroy the temp tex.
     scopedBindTex.Unwrap();
     scopedTex.Unwrap();
 
     // Leave RB and FB alive, and FB bound.
     mRB = rgbaRB;
     mFB = rgbaFB;
--- a/dom/canvas/test/reftest/reftest.list
+++ b/dom/canvas/test/reftest/reftest.list
@@ -171,9 +171,9 @@ include filters/reftest.list
 # Bug 1305963
 == mozCurrentTransform.html mozCurrentTransform-ref.html
 == mozCurrentTransformInverse.html mozCurrentTransform-ref.html
 
 # Bug 1366027
 == clipped-dash-stroke-rect.html clipped-dash-stroke-rect-ref.html
 
 # Bug 1377303
-skip-if(Android) == visible-occluded.html visible-occluded-ref.html
+== visible-occluded.html visible-occluded-ref.html
--- a/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
+++ b/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
@@ -45,20 +45,16 @@ function ok(val, text) {
 }
 
 function todo(val, text) {
   var status = val ? 'Test <font color=\\'orange\\'>UNEXPECTED PASS</font>: '
                    : 'Test <font color=\\'blue\\'  >todo</font>: ';
   debug(status + text);
 }
 
-function addLoadEvent(func) {
-  window.addEventListener('load', func, false);
-}
-
 SimpleTest = {
   waitForExplicitFinish: function() {},
   finish: function() {},
   requestFlakyTimeout: function() {},
 };
 </script>
 <div id='mochi-to-testcase-output'></div>
 
--- a/dom/canvas/test/webgl-mochitest/mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest/mochitest.ini
@@ -95,17 +95,17 @@ skip-if = toolkit == 'android' #bug 8654
 [test_webgl2_not_exposed.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [test_webgl2_invalidate_framebuffer.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [test_webgl2_alpha_luminance.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [test_fuzzing_bugs.html]
 [test_video_fastpath_mp4.html]
-fail-if = (os == 'win' && !(e10s && os_version == '6.1')) # no fast path on windows yet (bug 1373165 or 1373770), and mac (bug 1373669)
+fail-if = (os == 'mac') || (os == 'win' && !(e10s && os_version == '6.1')) # no fast path on windows yet (bug 1373165 or 1373770), and mac (bug 1373669)
 [test_video_fastpath_theora.html]
 fail-if = (os == 'win' && os_version != '6.1') # no fast path on windows yet (bug 1373192), and mac (bug 1373702)
 [test_video_fastpath_vp8.html]
 fail-if = (os == 'win' && os_version != '6.1') # no fast path on windows yet (bug 1373192), and mac (bug 1373702)
 [test_video_fastpath_vp9.html]
 fail-if = (os == 'win' && os_version != '6.1') # no fast path on windows yet (bug 1373192), and mac (bug 1373702)
 [test_webglcontextcreationerror.html]
 [test_webgl_fingerprinting_resistance.html]
--- a/dom/media/ipc/VideoDecoderManagerParent.cpp
+++ b/dom/media/ipc/VideoDecoderManagerParent.cpp
@@ -34,22 +34,19 @@ namespace dom {
 
 using namespace ipc;
 using namespace layers;
 using namespace gfx;
 
 SurfaceDescriptorGPUVideo
 VideoDecoderManagerParent::StoreImage(Image* aImage, TextureClient* aTexture)
 {
-  SurfaceDescriptorGPUVideo ret;
-  aTexture->GPUVideoDesc(&ret);
-
-  mImageMap[ret.handle()] = aImage;
-  mTextureMap[ret.handle()] = aTexture;
-  return Move(ret);
+  mImageMap[aTexture->GetSerial()] = aImage;
+  mTextureMap[aTexture->GetSerial()] = aTexture;
+  return SurfaceDescriptorGPUVideo(aTexture->GetSerial());
 }
 
 StaticRefPtr<nsIThread> sVideoDecoderManagerThread;
 StaticRefPtr<TaskQueue> sManagerTaskQueue;
 
 class VideoDecoderManagerThreadHolder
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderManagerThreadHolder)
--- a/dom/media/ipc/VideoDecoderParent.cpp
+++ b/dom/media/ipc/VideoDecoderParent.cpp
@@ -194,17 +194,17 @@ VideoDecoderParent::ProcessDecodedData(
     VideoDataIPDL output(
       MediaDataIPDL(data->mOffset, data->mTime.ToMicroseconds(),
                     data->mTimecode.ToMicroseconds(),
                     data->mDuration.ToMicroseconds(),
                     data->mFrames, data->mKeyframe),
       video->mDisplay,
       texture ? texture->GetSize() : IntSize(),
       texture ? mParent->StoreImage(video->mImage, texture)
-              : SurfaceDescriptorGPUVideo(0, null_t()),
+              : SurfaceDescriptorGPUVideo(0),
       video->mFrameID);
     Unused << SendOutput(output);
   }
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderParent::RecvFlush()
 {
--- a/gfx/2d/MacIOSurface.cpp
+++ b/gfx/2d/MacIOSurface.cpp
@@ -183,17 +183,17 @@ CFStringRef MacIOSurfaceLib::GetIOConst(
     return nullptr;
 
   return *address;
 }
 
 void MacIOSurfaceLib::LoadLibrary() {
   if (isLoaded) {
     return;
-  }
+  } 
   isLoaded = true;
   sIOSurfaceFramework = dlopen(IOSURFACE_FRAMEWORK_PATH,
                             RTLD_LAZY | RTLD_LOCAL);
   sOpenGLFramework = dlopen(OPENGL_FRAMEWORK_PATH,
                             RTLD_LAZY | RTLD_LOCAL);
 
   sCoreGraphicsFramework = dlopen(COREGRAPHICS_FRAMEWORK_PATH,
                             RTLD_LAZY | RTLD_LOCAL);
@@ -273,17 +273,17 @@ void MacIOSurfaceLib::CloseLibrary() {
   if (sCoreVideoFramework) {
     dlclose(sCoreVideoFramework);
   }
   sIOSurfaceFramework = nullptr;
   sOpenGLFramework = nullptr;
   sCoreVideoFramework = nullptr;
 }
 
-MacIOSurface::MacIOSurface(IOSurfacePtr aIOSurfacePtr,
+MacIOSurface::MacIOSurface(const void* aIOSurfacePtr,
                            double aContentsScaleFactor, bool aHasAlpha)
   : mIOSurfacePtr(aIOSurfacePtr)
   , mContentsScaleFactor(aContentsScaleFactor)
   , mHasAlpha(aHasAlpha)
 {
   CFRetain(mIOSurfacePtr);
   IncrementUseCount();
 }
@@ -317,20 +317,20 @@ already_AddRefed<MacIOSurface> MacIOSurf
   CFNumberRef cfHeight = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aHeight);
   CFNumberRef cfBytesPerElem = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &bytesPerElem);
   ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropWidth,
                                 cfWidth);
   ::CFRelease(cfWidth);
   ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropHeight,
                                 cfHeight);
   ::CFRelease(cfHeight);
-  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropBytesPerElem,
+  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropBytesPerElem, 
                                 cfBytesPerElem);
   ::CFRelease(cfBytesPerElem);
-  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropIsGlobal,
+  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropIsGlobal, 
                                 kCFBooleanTrue);
 
   IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceCreate(props);
   ::CFRelease(props);
 
   if (!surfaceRef)
     return nullptr;
 
@@ -343,17 +343,17 @@ already_AddRefed<MacIOSurface> MacIOSurf
   // Release the IOSurface because MacIOSurface retained it
   CFRelease(surfaceRef);
 
   return ioSurface.forget();
 }
 
 already_AddRefed<MacIOSurface> MacIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID,
                                                        double aContentsScaleFactor,
-                                                       bool aHasAlpha) {
+                                                       bool aHasAlpha) { 
   if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0)
     return nullptr;
 
   IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceLookup(aIOSurfaceID);
   if (!surfaceRef)
     return nullptr;
 
   RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha);
@@ -363,21 +363,21 @@ already_AddRefed<MacIOSurface> MacIOSurf
   }
 
   // Release the IOSurface because MacIOSurface retained it
   CFRelease(surfaceRef);
 
   return ioSurface.forget();
 }
 
-IOSurfaceID MacIOSurface::GetIOSurfaceID() {
+IOSurfaceID MacIOSurface::GetIOSurfaceID() { 
   return MacIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr);
 }
 
-void* MacIOSurface::GetBaseAddress() {
+void* MacIOSurface::GetBaseAddress() { 
   return MacIOSurfaceLib::IOSurfaceGetBaseAddress(mIOSurfacePtr);
 }
 
 void* MacIOSurface::GetBaseAddressOfPlane(size_t aPlaneIndex)
 {
   return MacIOSurfaceLib::IOSurfaceGetBaseAddressOfPlane(mIOSurfacePtr,
                                                          aPlaneIndex);
 }
@@ -506,28 +506,16 @@ MacIOSurface::GetReadFormat()
   } else if (pixelFormat == '2vuy') {
     return SurfaceFormat::R8G8B8X8;
   } else  {
     return HasAlpha() ? SurfaceFormat::R8G8B8A8 : SurfaceFormat::R8G8B8X8;
   }
 }
 
 CGLError
-MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx,
-                                     GLenum target, GLenum internalFormat,
-                                     GLsizei width, GLsizei height,
-                                     GLenum format, GLenum type,
-                                     GLuint plane) const
-{
-  return MacIOSurfaceLib::CGLTexImageIOSurface2D(ctx, target, internalFormat, width,
-                                                 height, format, type, mIOSurfacePtr,
-                                                 plane);
-}
-
-CGLError
 MacIOSurface::CGLTexImageIOSurface2D(mozilla::gl::GLContext* aGL,
                                      CGLContextObj ctx,
                                      size_t plane,
                                      mozilla::gfx::SurfaceFormat* aOutReadFormat)
 {
   MOZ_ASSERT(plane >= 0);
   bool isCompatibilityProfile = aGL->IsCompatibilityProfile();
   OSType pixelFormat = GetPixelFormat();
@@ -584,19 +572,25 @@ MacIOSurface::CGLTexImageIOSurface2D(moz
     format = LOCAL_GL_BGRA;
     type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
     if (aOutReadFormat) {
       *aOutReadFormat = HasAlpha() ? mozilla::gfx::SurfaceFormat::R8G8B8A8
                                   : mozilla::gfx::SurfaceFormat::R8G8B8X8;
     }
   }
 
-  return CGLTexImageIOSurface2D(ctx, LOCAL_GL_TEXTURE_RECTANGLE_ARB, internalFormat,
-                                GetDevicePixelWidth(plane), GetDevicePixelHeight(plane),
-                                format, type, plane);
+  return MacIOSurfaceLib::CGLTexImageIOSurface2D(ctx,
+                                                 LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                                                 internalFormat,
+                                                 GetDevicePixelWidth(plane),
+                                                 GetDevicePixelHeight(plane),
+                                                 format,
+                                                 type,
+                                                 mIOSurfacePtr,
+                                                 plane);
 }
 
 static
 CGColorSpaceRef CreateSystemColorSpace() {
   CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID());
   if (!cspace) {
     cspace = ::CGColorSpaceCreateDeviceRGB();
   }
--- a/gfx/2d/MacIOSurface.h
+++ b/gfx/2d/MacIOSurface.h
@@ -92,17 +92,17 @@ public:
   static already_AddRefed<MacIOSurface> CreateIOSurface(int aWidth, int aHeight,
                                                              double aContentsScaleFactor = 1.0,
                                                              bool aHasAlpha = true);
   static void ReleaseIOSurface(MacIOSurface *aIOSurface);
   static already_AddRefed<MacIOSurface> LookupSurface(IOSurfaceID aSurfaceID,
                                                            double aContentsScaleFactor = 1.0,
                                                            bool aHasAlpha = true);
 
-  explicit MacIOSurface(IOSurfacePtr aIOSurfacePtr,
+  explicit MacIOSurface(const void *aIOSurfacePtr,
                         double aContentsScaleFactor = 1.0,
                         bool aHasAlpha = true);
   ~MacIOSurface();
   IOSurfaceID GetIOSurfaceID();
   void *GetBaseAddress();
   void *GetBaseAddressOfPlane(size_t planeIndex);
   size_t GetPlaneCount();
   OSType GetPixelFormat();
@@ -125,36 +125,31 @@ public:
   mozilla::gfx::SurfaceFormat GetReadFormat();
 
   // We would like to forward declare NSOpenGLContext, but it is an @interface
   // and this file is also used from c++, so we use a void *.
   CGLError CGLTexImageIOSurface2D(mozilla::gl::GLContext* aGL,
                                   CGLContextObj ctxt,
                                   size_t plane,
                                   mozilla::gfx::SurfaceFormat* aOutReadFormat = nullptr);
-  CGLError CGLTexImageIOSurface2D(CGLContextObj ctxt,
-                                  GLenum target, GLenum internalFormat,
-                                  GLsizei width, GLsizei height,
-                                  GLenum format, GLenum type,
-                                  GLuint plane) const;
   already_AddRefed<SourceSurface> GetAsSurface();
   CGContextRef CreateIOSurfaceContext();
 
   // FIXME This doesn't really belong here
   static CGImageRef CreateImageFromIOSurfaceContext(CGContextRef aContext);
   static already_AddRefed<MacIOSurface> IOSurfaceContextGetSurface(CGContextRef aContext,
                                                                         double aContentsScaleFactor = 1.0,
                                                                         bool aHasAlpha = true);
   static size_t GetMaxWidth();
   static size_t GetMaxHeight();
   const void* GetIOSurfacePtr() { return mIOSurfacePtr; }
 
 private:
   friend class nsCARenderer;
-  const IOSurfacePtr mIOSurfacePtr;
+  const void* mIOSurfacePtr;
   double mContentsScaleFactor;
   bool mHasAlpha;
 };
 
 class MacIOSurfaceLib {
 public:
   MacIOSurfaceLib() = delete;
   static void                        *sIOSurfaceFramework;
--- a/gfx/angle/src/libANGLE/Stream.cpp
+++ b/gfx/angle/src/libANGLE/Stream.cpp
@@ -120,17 +120,17 @@ Error Stream::createConsumerGLTextureExt
     const auto &glState = context->getGLState();
     EGLenum bufferType = attributes.getAsInt(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
     if (bufferType == EGL_RGB_BUFFER)
     {
         mPlanes[0].texture = glState.getTargetTexture(GL_TEXTURE_EXTERNAL_OES);
         ASSERT(mPlanes[0].texture != nullptr);
         mPlanes[0].texture->bindStream(this);
         mConsumerType = ConsumerType::GLTextureRGB;
-        mPlaneCount = 1;
+        mPlaneCount   = 1;
     }
     else
     {
         mPlaneCount = attributes.getAsInt(EGL_YUV_NUMBER_OF_PLANES_EXT, 2);
         ASSERT(mPlaneCount <= 3);
         for (EGLint i = 0; i < mPlaneCount; i++)
         {
             // Fetch all the textures
@@ -158,29 +158,28 @@ Error Stream::createConsumerGLTextureExt
     mState   = EGL_STREAM_STATE_CONNECTING_KHR;
 
     return Error(EGL_SUCCESS);
 }
 
 Error Stream::createProducerD3D11TextureNV12(const AttributeMap &attributes)
 {
     ASSERT(mState == EGL_STREAM_STATE_CONNECTING_KHR);
-    ASSERT(mConsumerType == ConsumerType::GLTextureRGB ||
-           mConsumerType == ConsumerType::GLTextureYUV);
+    ASSERT(mConsumerType == ConsumerType::GLTextureYUV);
     ASSERT(mProducerType == ProducerType::NoProducer);
+    ASSERT(mPlaneCount == 2);
 
     mProducerImplementation = mDisplay->getImplementation()->createStreamProducerD3DTextureNV12(
         mConsumerType, attributes);
     mProducerType = ProducerType::D3D11TextureNV12;
     mState        = EGL_STREAM_STATE_EMPTY_KHR;
 
     return Error(EGL_SUCCESS);
 }
 
-
 // Called when the consumer of this stream starts using the stream
 Error Stream::consumerAcquire()
 {
     ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR ||
            mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR);
     ASSERT(mConsumerType == ConsumerType::GLTextureRGB ||
            mConsumerType == ConsumerType::GLTextureYUV);
     ASSERT(mProducerType == ProducerType::D3D11TextureNV12);
@@ -222,24 +221,24 @@ Error Stream::consumerRelease()
 }
 
 bool Stream::isConsumerBoundToContext(const gl::Context *context) const
 {
     ASSERT(context != nullptr);
     return (context == mContext);
 }
 
-Error Stream::validateD3D11NV12Texture(void *texture, const AttributeMap &attributes) const
+Error Stream::validateD3D11NV12Texture(void *texture) const
 {
     ASSERT(mConsumerType == ConsumerType::GLTextureRGB ||
            mConsumerType == ConsumerType::GLTextureYUV);
     ASSERT(mProducerType == ProducerType::D3D11TextureNV12);
     ASSERT(mProducerImplementation != nullptr);
 
-    return mProducerImplementation->validateD3DNV12Texture(texture, attributes);
+    return mProducerImplementation->validateD3DNV12Texture(texture);
 }
 
 Error Stream::postD3D11NV12Texture(void *texture, const AttributeMap &attributes)
 {
     ASSERT(mConsumerType == ConsumerType::GLTextureRGB ||
            mConsumerType == ConsumerType::GLTextureYUV);
     ASSERT(mProducerType == ProducerType::D3D11TextureNV12);
 
--- a/gfx/angle/src/libANGLE/Stream.h
+++ b/gfx/angle/src/libANGLE/Stream.h
@@ -90,17 +90,17 @@ class Stream final : angle::NonCopyable
     Error consumerAcquire();
     Error consumerRelease();
 
     // Some consumers are bound to GL contexts. This validates that a given context is bound to the
     // stream's consumer
     bool isConsumerBoundToContext(const gl::Context *context) const;
 
     // Producer methods
-    Error validateD3D11NV12Texture(void *texture, const AttributeMap &attributes) const;
+    Error validateD3D11NV12Texture(void *texture) const;
     Error postD3D11NV12Texture(void *texture, const AttributeMap &attributes);
 
   private:
     // Associated display
     Display *mDisplay;
 
     // Producer Implementation
     rx::StreamProducerImpl *mProducerImplementation;
--- a/gfx/angle/src/libANGLE/renderer/StreamProducerImpl.h
+++ b/gfx/angle/src/libANGLE/renderer/StreamProducerImpl.h
@@ -18,17 +18,17 @@ namespace rx
 class StreamProducerImpl : angle::NonCopyable
 {
   public:
     explicit StreamProducerImpl() {}
     virtual ~StreamProducerImpl() {}
 
     // Validates the ability for the producer to accept an arbitrary pointer to a frame. All
     // pointers should be validated through this function before being used to produce a frame.
-    virtual egl::Error validateD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) const = 0;
+    virtual egl::Error validateD3DNV12Texture(void *pointer) const = 0;
 
     // Constructs a frame from an arbitrary external pointer that points to producer specific frame
     // data. Replaces the internal frame with the new one.
     virtual void postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) = 0;
 
     // Returns an OpenGL texture interpretation of some frame attributes for the purpose of
     // constructing an OpenGL texture from a frame. Depending on the producer and consumer, some
     // frames may have multiple "planes" with different OpenGL texture representations.
--- a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp
@@ -10,143 +10,88 @@
 
 #include "common/utilities.h"
 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
 
 namespace rx
 {
 
-static egl::Stream::GLTextureDescription getGLDescFromTex(ID3D11Texture2D* tex,
-                                                          UINT planeIndex,
-                                                          const char** const out_error)
-{
-    *out_error = "Undocumented error";
-
-    egl::Stream::GLTextureDescription ret = { 0 };
-    if (!tex)
-    {
-        *out_error = "Texture is null";
-        return ret;
-    }
-
-    D3D11_TEXTURE2D_DESC desc;
-    tex->GetDesc(&desc);
-
-    if (desc.Width < 1 || desc.Height < 1)
-    {
-        *out_error = "Width or height < 1";
-        return ret;
-    }
-
-    ret.width = desc.Width;
-    ret.height = desc.Height;
-    ret.mipLevels = 0;
-
-    UINT maxPlaneIndex = 0;
-    switch (desc.Format) {
-    case DXGI_FORMAT_NV12:
-        // The UV plane of NV12 textures has half the width/height of the Y plane
-        if ((desc.Width % 2) != 0 || (desc.Height % 2) != 0)
-        {
-            *out_error = "NV12 tetxures must have even width and height.";
-            break; // Bad width/height.
-        }
-
-        maxPlaneIndex = 1;
-        if (planeIndex == 0)
-        {
-            ret.internalFormat = GL_R8;
-        }
-        else
-        {
-            ret.internalFormat = GL_RG8;
-            ret.width  /= 2;
-            ret.height /= 2;
-        }
-        break;
-
-    case DXGI_FORMAT_R8_UNORM:
-        ret.internalFormat = GL_R8;
-        break;
-    case DXGI_FORMAT_R8G8_UNORM:
-        ret.internalFormat = GL_RG8;
-        break;
-    case DXGI_FORMAT_R8G8B8A8_UNORM:
-        ret.internalFormat = GL_RGBA8;
-        break;
-
-    default:
-        *out_error = "Unsupported format";
-        return ret;
-    }
-
-    if (planeIndex > maxPlaneIndex)
-    {
-        // Just kidding, there's no plane out there.
-        ret.internalFormat = 0;
-        *out_error = "Plane out of range";
-    }
-
-    return ret;
-}
-
-
 StreamProducerNV12::StreamProducerNV12(Renderer11 *renderer)
-    : mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mPlaneOffset(0)
+    : mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mTextureWidth(0), mTextureHeight(0)
 {
 }
 
 StreamProducerNV12::~StreamProducerNV12()
 {
     SafeRelease(mTexture);
 }
 
-egl::Error StreamProducerNV12::validateD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) const
+egl::Error StreamProducerNV12::validateD3DNV12Texture(void *pointer) const
 {
     ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(pointer);
 
     // Check that the texture originated from our device
     ID3D11Device *device;
     textureD3D->GetDevice(&device);
     if (device != mRenderer->getDevice())
     {
         return egl::Error(EGL_BAD_PARAMETER, "Texture not created on ANGLE D3D device");
     }
 
-    const auto planeId = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
-    const char* errorText;
-    const auto glDesc = getGLDescFromTex(textureD3D, planeId, &errorText);
-    if (!glDesc.internalFormat)
+    // Get the description and validate it
+    D3D11_TEXTURE2D_DESC desc;
+    textureD3D->GetDesc(&desc);
+    if (desc.Format != DXGI_FORMAT_NV12)
     {
-        return egl::Error(EGL_BAD_PARAMETER, errorText);
+        return egl::Error(EGL_BAD_PARAMETER, "Texture format not DXGI_FORMAT_NV12");
     }
-
+    if (desc.Width < 1 || desc.Height < 1)
+    {
+        return egl::Error(EGL_BAD_PARAMETER, "Texture is of size 0");
+    }
+    if ((desc.Width % 2) != 0 || (desc.Height % 2) != 0)
+    {
+        return egl::Error(EGL_BAD_PARAMETER, "Texture dimensions are not even");
+    }
     return egl::Error(EGL_SUCCESS);
 }
 
 void StreamProducerNV12::postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes)
 {
     ASSERT(pointer != nullptr);
     ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(pointer);
 
+    // Check that the texture originated from our device
+    ID3D11Device *device;
+    textureD3D->GetDevice(&device);
+
+    // Get the description
+    D3D11_TEXTURE2D_DESC desc;
+    textureD3D->GetDesc(&desc);
+
     // Release the previous texture if there is one
     SafeRelease(mTexture);
 
     mTexture = textureD3D;
     mTexture->AddRef();
-    mPlaneOffset = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
-    mArraySlice = static_cast<UINT>(attributes.get(EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0));
+    mTextureWidth  = desc.Width;
+    mTextureHeight = desc.Height;
+    mArraySlice    = static_cast<UINT>(attributes.get(EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0));
 }
 
 egl::Stream::GLTextureDescription StreamProducerNV12::getGLFrameDescription(int planeIndex)
 {
-    const char* errorText;
-    return getGLDescFromTex(mTexture, static_cast<UINT>(planeIndex + mPlaneOffset),
-                            &errorText);
+    // The UV plane of NV12 textures has half the width/height of the Y plane
+    egl::Stream::GLTextureDescription desc;
+    desc.width          = (planeIndex == 0) ? mTextureWidth : (mTextureWidth / 2);
+    desc.height         = (planeIndex == 0) ? mTextureHeight : (mTextureHeight / 2);
+    desc.internalFormat = (planeIndex == 0) ? GL_R8 : GL_RG8;
+    desc.mipLevels      = 0;
+    return desc;
 }
 
 ID3D11Texture2D *StreamProducerNV12::getD3DTexture()
 {
     return mTexture;
 }
 
 UINT StreamProducerNV12::getArraySlice()
--- a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h
@@ -16,28 +16,29 @@ namespace rx
 class Renderer11;
 
 class StreamProducerNV12 : public StreamProducerImpl
 {
   public:
     StreamProducerNV12(Renderer11 *renderer);
     ~StreamProducerNV12() override;
 
-    egl::Error validateD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) const override;
+    egl::Error validateD3DNV12Texture(void *pointer) const override;
     void postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) override;
     egl::Stream::GLTextureDescription getGLFrameDescription(int planeIndex) override;
 
     // Gets a pointer to the internal D3D texture
     ID3D11Texture2D *getD3DTexture();
 
     // Gets the slice index for the D3D texture that the frame is in
     UINT getArraySlice();
 
   private:
     Renderer11 *mRenderer;
 
     ID3D11Texture2D *mTexture;
     UINT mArraySlice;
-    UINT mPlaneOffset;
+    UINT mTextureWidth;
+    UINT mTextureHeight;
 };
 }  // namespace rx
 
 #endif  // LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_
--- a/gfx/angle/src/libANGLE/validationEGL.cpp
+++ b/gfx/angle/src/libANGLE/validationEGL.cpp
@@ -1510,32 +1510,19 @@ Error ValidateCreateStreamProducerD3DTex
         return Error(EGL_BAD_ATTRIBUTE, "Invalid attribute");
     }
 
     if (stream->getState() != EGL_STREAM_STATE_CONNECTING_KHR)
     {
         return Error(EGL_BAD_STATE_KHR, "Stream not in connecting state");
     }
 
-    switch (stream->getConsumerType()) {
-    case Stream::ConsumerType::GLTextureYUV:
-        if (stream->getPlaneCount() != 2)
-        {
-            return Error(EGL_BAD_MATCH, "Incompatible stream consumer type");
-        }
-        break;
-
-    case Stream::ConsumerType::GLTextureRGB:
-        if (stream->getPlaneCount() != 1)
-        {
-            return Error(EGL_BAD_MATCH, "Incompatible stream consumer type");
-        }
-        break;
-
-    default:
+    if (stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV ||
+        stream->getPlaneCount() != 2)
+    {
         return Error(EGL_BAD_MATCH, "Incompatible stream consumer type");
     }
 
     return Error(EGL_SUCCESS);
 }
 
 Error ValidateStreamPostD3DTextureNV12ANGLE(const Display *display,
                                             const Stream *stream,
@@ -1560,22 +1547,16 @@ Error ValidateStreamPostD3DTextureNV12AN
         switch (attribute)
         {
             case EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE:
                 if (value < 0)
                 {
                     return Error(EGL_BAD_PARAMETER, "Invalid subresource index");
                 }
                 break;
-            case EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG:
-                if (value < 0)
-                {
-                    return Error(EGL_BAD_PARAMETER, "Invalid plane offset");
-                }
-                break;
             default:
                 return Error(EGL_BAD_ATTRIBUTE, "Invalid attribute");
         }
     }
 
     if (stream->getState() != EGL_STREAM_STATE_EMPTY_KHR &&
         stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
         stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
@@ -1588,17 +1569,17 @@ Error ValidateStreamPostD3DTextureNV12AN
         return Error(EGL_BAD_MATCH, "Incompatible stream producer");
     }
 
     if (texture == nullptr)
     {
         return egl::Error(EGL_BAD_PARAMETER, "Texture is null");
     }
 
-    return stream->validateD3D11NV12Texture(texture, attribs);
+    return stream->validateD3D11NV12Texture(texture);
 }
 
 Error ValidateSwapBuffersWithDamageEXT(const Display *display,
                                        const Surface *surface,
                                        EGLint *rects,
                                        EGLint n_rects)
 {
     Error error = ValidateSurface(display, surface);
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -7,21 +7,18 @@
 #include "gfxUtils.h"
 #include "GLBlitHelper.h"
 #include "GLContext.h"
 #include "GLScreenBuffer.h"
 #include "ScopedGLHelpers.h"
 #include "mozilla/Preferences.h"
 #include "ImageContainer.h"
 #include "HeapCopyOfStackArray.h"
-#include "mozilla/ArrayUtils.h"
-#include "mozilla/gfx/Logging.h"
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/UniquePtr.h"
-#include "GPUVideoImage.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidSurfaceTexture.h"
 #include "GLImages.h"
 #include "GLLibraryEGL.h"
 #endif
 
 #ifdef XP_MACOSX
@@ -30,1051 +27,992 @@
 #endif
 
 using mozilla::layers::PlanarYCbCrImage;
 using mozilla::layers::PlanarYCbCrData;
 
 namespace mozilla {
 namespace gl {
 
-// --
-
-const char* const kFragHeader_Tex2D = "\
-    #define SAMPLER sampler2D                                                \n\
-    #if __VERSION__ >= 130                                                   \n\
-        #define TEXTURE texture                                              \n\
-    #else                                                                    \n\
-        #define TEXTURE texture2D                                            \n\
-    #endif                                                                   \n\
-";
-const char* const kFragHeader_Tex2DRect = "\
-    #define SAMPLER sampler2DRect                                            \n\
-    #if __VERSION__ >= 130                                                   \n\
-        #define TEXTURE texture                                              \n\
-    #else                                                                    \n\
-        #define TEXTURE texture2DRect                                        \n\
-    #endif                                                                   \n\
-";
-const char* const kFragHeader_TexExt = "\
-    #extension GL_OES_EGL_image_external : require                           \n\
-    #define SAMPLER samplerExternalOES                                       \n\
-    #define TEXTURE texture2D                                                \n\
-";
-
-const char* const kFragBody_RGBA = "\
-    VARYING vec2 vTexCoord0;                                                 \n\
-    uniform SAMPLER uTex0;                                                   \n\
-                                                                             \n\
-    void main(void)                                                          \n\
-    {                                                                        \n\
-        FRAG_COLOR = TEXTURE(uTex0, vTexCoord0);                             \n\
-    }                                                                        \n\
-";
-const char* const kFragBody_CrYCb = "\
-    VARYING vec2 vTexCoord0;                                                 \n\
-    uniform SAMPLER uTex0;                                                   \n\
-    uniform mat4 uColorMatrix;                                               \n\
-                                                                             \n\
-    void main(void)                                                          \n\
-    {                                                                        \n\
-        vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).gbr,                      \n\
-                        1.0);                                                \n\
-        vec4 rgb = uColorMatrix * yuv;                                       \n\
-        FRAG_COLOR = vec4(rgb.rgb, 1.0);                                     \n\
-    }                                                                        \n\
-";
-const char* const kFragBody_NV12 = "\
-    VARYING vec2 vTexCoord0;                                                 \n\
-    VARYING vec2 vTexCoord1;                                                 \n\
-    uniform SAMPLER uTex0;                                                   \n\
-    uniform SAMPLER uTex1;                                                   \n\
-    uniform mat4 uColorMatrix;                                               \n\
-                                                                             \n\
-    void main(void)                                                          \n\
-    {                                                                        \n\
-        vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x,                        \n\
-                        TEXTURE(uTex1, vTexCoord1).xy,                       \n\
-                        1.0);                                                \n\
-        vec4 rgb = uColorMatrix * yuv;                                       \n\
-        FRAG_COLOR = vec4(rgb.rgb, 1.0);                                     \n\
-    }                                                                        \n\
-";
-const char* const kFragBody_PlanarYUV = "\
-    VARYING vec2 vTexCoord0;                                                 \n\
-    VARYING vec2 vTexCoord1;                                                 \n\
-    uniform SAMPLER uTex0;                                                   \n\
-    uniform SAMPLER uTex1;                                                   \n\
-    uniform SAMPLER uTex2;                                                   \n\
-    uniform mat4 uColorMatrix;                                               \n\
-                                                                             \n\
-    void main(void)                                                          \n\
-    {                                                                        \n\
-        vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x,                        \n\
-                        TEXTURE(uTex1, vTexCoord1).x,                        \n\
-                        TEXTURE(uTex2, vTexCoord1).x,                        \n\
-                        1.0);                                                \n\
-        vec4 rgb = uColorMatrix * yuv;                                       \n\
-        FRAG_COLOR = vec4(rgb.rgb, 1.0);                                     \n\
-    }                                                                        \n\
-";
-
-// --
-
-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;
-    switch (mTexTarget) {
-    case LOCAL_GL_TEXTURE_2D:
-        texBinding = LOCAL_GL_TEXTURE_BINDING_2D;
-        break;
-    case LOCAL_GL_TEXTURE_RECTANGLE:
-        texBinding = LOCAL_GL_TEXTURE_BINDING_RECTANGLE;
-        break;
-    case LOCAL_GL_TEXTURE_EXTERNAL:
-        texBinding = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
-        break;
-    default:
-        gfxCriticalError() << "Unhandled texTarget: " << texTarget;
-    }
-
-    for (uint8_t i = 0; i < mTexCount; i++) {
-        mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i);
-        if (mGL.IsSupported(GLFeature::sampler_objects)) {
-            mOldTexSampler[i] = mGL.GetIntAs<GLuint>(LOCAL_GL_SAMPLER_BINDING);
-            mGL.fBindSampler(i, 0);
-        }
-        mOldTex[i] = mGL.GetIntAs<GLuint>(texBinding);
-    }
-}
-
-ScopedSaveMultiTex::~ScopedSaveMultiTex()
-{
-    for (uint8_t i = 0; i < mTexCount; i++) {
-        mGL.fActiveTexture(LOCAL_GL_TEXTURE0 + i);
-        if (mGL.IsSupported(GLFeature::sampler_objects)) {
-            mGL.fBindSampler(i, mOldTexSampler[i]);
-        }
-        mGL.fBindTexture(mTexTarget, mOldTex[i]);
-    }
-    mGL.fActiveTexture(mOldTexUnit);
-}
-
-// --
-
-class ScopedBindArrayBuffer final
-{
-    GLContext& mGL;
-    const GLuint mOldVBO;
-
-public:
-    ScopedBindArrayBuffer(GLContext* const gl, const GLuint vbo)
-        : mGL(*gl)
-        , mOldVBO(mGL.GetIntAs<GLuint>(LOCAL_GL_ARRAY_BUFFER_BINDING))
-    {
-        mGL.fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
-    }
-
-    ~ScopedBindArrayBuffer()
-    {
-        mGL.fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mOldVBO);
-    }
-};
-
-// --
-
-class ScopedBindVAO final
-{
-    GLContext& mGL;
-    const GLuint mOldVAO;
-
-public:
-    ScopedBindVAO(GLContext* const gl, const GLuint vao)
-        : mGL(*gl)
-        , mOldVAO(mGL.GetIntAs<GLuint>(LOCAL_GL_VERTEX_ARRAY_BINDING))
-    {
-        mGL.fBindVertexArray(vao);
-    }
-
-    ~ScopedBindVAO()
-    {
-        mGL.fBindVertexArray(mOldVAO);
-    }
-};
-
-// --
-
-class ScopedShader final
-{
-    GLContext& mGL;
-    const GLuint mName;
-
-public:
-    ScopedShader(GLContext* const gl, const GLenum shaderType)
-        : mGL(*gl)
-        , mName(mGL.fCreateShader(shaderType))
-    { }
-
-    ~ScopedShader()
-    {
-        mGL.fDeleteShader(mName);
-    }
-
-    operator GLuint() const { return mName; }
-};
-
-// --
-
-class SaveRestoreCurrentProgram final
+GLBlitHelper::GLBlitHelper(GLContext* gl)
+    : mGL(gl)
+    , mTexBlit_Buffer(0)
+    , mTexBlit_VertShader(0)
+    , mTex2DBlit_FragShader(0)
+    , mTex2DRectBlit_FragShader(0)
+    , mTex2DBlit_Program(0)
+    , mTex2DRectBlit_Program(0)
+    , mYFlipLoc(-1)
+    , mTextureTransformLoc(-1)
+    , mTexExternalBlit_FragShader(0)
+    , mTexYUVPlanarBlit_FragShader(0)
+    , mTexNV12PlanarBlit_FragShader(0)
+    , mTexExternalBlit_Program(0)
+    , mTexYUVPlanarBlit_Program(0)
+    , mTexNV12PlanarBlit_Program(0)
+    , mFBO(0)
+    , mSrcTexY(0)
+    , mSrcTexCb(0)
+    , mSrcTexCr(0)
+    , mSrcTexEGL(0)
+    , mYTexScaleLoc(-1)
+    , mCbCrTexScaleLoc(-1)
+    , mYuvColorMatrixLoc(-1)
+    , mTexWidth(0)
+    , mTexHeight(0)
+    , mCurYScale(1.0f)
+    , mCurCbCrScale(1.0f)
 {
-    GLContext& mGL;
-    const GLuint mOld;
-
-public:
-    explicit SaveRestoreCurrentProgram(GLContext* const gl)
-        : mGL(*gl)
-        , mOld(mGL.GetIntAs<GLuint>(LOCAL_GL_CURRENT_PROGRAM))
-    { }
-
-    ~SaveRestoreCurrentProgram()
-    {
-        mGL.fUseProgram(mOld);
-    }
-};
-
-// --
-
-class ScopedDrawBlitState final
-{
-    GLContext& mGL;
-
-    const bool blend;
-    const bool cullFace;
-    const bool depthTest;
-    const bool dither;
-    const bool polyOffsFill;
-    const bool sampleAToC;
-    const bool sampleCover;
-    const bool scissor;
-    const bool stencil;
-    Maybe<bool> rasterizerDiscard;
-
-    realGLboolean colorMask[4];
-    GLint viewport[4];
-
-public:
-    ScopedDrawBlitState(GLContext* const gl, const gfx::IntSize& destSize)
-        : mGL(*gl)
-        , blend       (mGL.PushEnabled(LOCAL_GL_BLEND,                    false))
-        , cullFace    (mGL.PushEnabled(LOCAL_GL_CULL_FACE,                false))
-        , depthTest   (mGL.PushEnabled(LOCAL_GL_DEPTH_TEST,               false))
-        , dither      (mGL.PushEnabled(LOCAL_GL_DITHER,                   true))
-        , polyOffsFill(mGL.PushEnabled(LOCAL_GL_POLYGON_OFFSET_FILL,      false))
-        , sampleAToC  (mGL.PushEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false))
-        , sampleCover (mGL.PushEnabled(LOCAL_GL_SAMPLE_COVERAGE,          false))
-        , scissor     (mGL.PushEnabled(LOCAL_GL_SCISSOR_TEST,             false))
-        , stencil     (mGL.PushEnabled(LOCAL_GL_STENCIL_TEST,             false))
-    {
-        if (mGL.IsSupported(GLFeature::transform_feedback2)) {
-            // Technically transform_feedback2 requires transform_feedback, which actually
-            // 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);
-        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   );
-        mGL.SetEnabled(LOCAL_GL_DITHER,                   dither      );
-        mGL.SetEnabled(LOCAL_GL_POLYGON_OFFSET_FILL,      polyOffsFill);
-        mGL.SetEnabled(LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, sampleAToC  );
-        mGL.SetEnabled(LOCAL_GL_SAMPLE_COVERAGE,          sampleCover );
-        mGL.SetEnabled(LOCAL_GL_SCISSOR_TEST,             scissor     );
-        mGL.SetEnabled(LOCAL_GL_STENCIL_TEST,             stencil     );
-        if (rasterizerDiscard) {
-            mGL.SetEnabled(LOCAL_GL_RASTERIZER_DISCARD, rasterizerDiscard.value());
-        }
-
-        mGL.fColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
-        mGL.fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
-    }
-};
-
-// --
-
-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_uColorMatrix(mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix"))
-{
-    MOZ_ASSERT(mLoc_u1ForYFlip != -1);
-    MOZ_ASSERT(mLoc_uSrcRect != -1);
-    MOZ_ASSERT(mLoc_uTexSize0 != -1);
-    if (mLoc_uColorMatrix != -1) {
-        MOZ_ASSERT(mLoc_uTexSize1 != -1);
-        MOZ_ASSERT(mLoc_uDivisors != -1);
-    }
-}
-
-DrawBlitProg::~DrawBlitProg()
-{
-    const auto& gl = mParent.mGL;
-    if (!gl->MakeCurrent())
-        return;
-
-    gl->fDeleteProgram(mProg);
-}
-
-void
-DrawBlitProg::Draw(const BaseArgs& args, const YUVArgs* const argsYUV) const
-{
-    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);
-
-    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);
-        const auto& colorMatrix = gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV->colorSpace);
-        gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
-    }
-
-    // --
-
-    const ScopedDrawBlitState drawState(gl, args.destSize);
-    const ScopedBindVAO bindVAO(gl, mParent.mQuadVAO);
-    gl->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
-}
-
-// --
-
-GLBlitHelper::GLBlitHelper(GLContext* const gl)
-    : mGL(gl)
-    , mQuadVAO(0)
-    , mDrawBlitProg_VertShader(mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER))
-    , mYuvUploads{0}
-    , mYuvUploads_YSize(0, 0)
-    , mYuvUploads_UVSize(0, 0)
-{
-    if (!mGL->IsSupported(GLFeature::vertex_array_object)) {
-        gfxCriticalError() << "GLBlitHelper requires vertex_array_object.";
-        return;
-    }
-
-    GLuint vbo = 0;
-    mGL->fGenBuffers(1, &vbo);
-    {
-        const ScopedBindArrayBuffer bindVBO(mGL, vbo);
-
-        const float quadData[] = {
-            0, 0,
-            1, 0,
-            0, 1,
-            1, 1
-        };
-        const HeapCopyOfStackArray<float> heapQuadData(quadData);
-        mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, heapQuadData.ByteLength(),
-                         heapQuadData.Data(), LOCAL_GL_STATIC_DRAW);
-
-        mGL->fGenVertexArrays(1, &mQuadVAO);
-        const ScopedBindVAO bindVAO(mGL, mQuadVAO);
-        mGL->fEnableVertexAttribArray(0);
-        mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, false, 0, 0);
-    }
-    mGL->fDeleteBuffers(1, &vbo);
-
-    // --
-
-    if (!mGL->IsGLES()) {
-        const auto glslVersion = mGL->ShadingLanguageVersion();
-        if (glslVersion >= 130) {
-            mDrawBlitProg_VersionLine = nsPrintfCString("#version %u\n", glslVersion);
-        }
-    }
-
-    const char kVertSource[] = "\
-        #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\
-                                                                             \n\
-        uniform float u1ForYFlip;                                            \n\
-        uniform vec4 uSrcRect;                                               \n\
-        uniform vec2 uTexSize0;                                              \n\
-        uniform vec2 uTexSize1;                                              \n\
-        uniform vec2 uDivisors;                                              \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\
-                                                                             \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\
-        }                                                                    \n\
-    ";
-
-    const char* const parts[] = {
-        mDrawBlitProg_VersionLine.get(),
-        kVertSource
-    };
-    mGL->fShaderSource(mDrawBlitProg_VertShader, ArrayLength(parts), parts, nullptr);
-    mGL->fCompileShader(mDrawBlitProg_VertShader);
 }
 
 GLBlitHelper::~GLBlitHelper()
 {
-    for (const auto& pair : mDrawBlitProgs) {
-        const auto& ptr = pair.second;
-        delete ptr;
-    }
-    mDrawBlitProgs.clear();
-
     if (!mGL->MakeCurrent())
         return;
 
-    mGL->fDeleteShader(mDrawBlitProg_VertShader);
-    mGL->fDeleteVertexArrays(1, &mQuadVAO);
-}
-
-// --
+    DeleteTexBlitProgram();
 
-const DrawBlitProg*
-GLBlitHelper::GetDrawBlitProg(const DrawBlitProg::Key& key) const
-{
-    const auto& res = mDrawBlitProgs.insert({key, nullptr});
-    auto& pair = *(res.first);
-    const auto& didInsert = res.second;
-    if (didInsert) {
-        pair.second = CreateDrawBlitProg(pair.first);
+    GLuint tex[] = {
+        mSrcTexY,
+        mSrcTexCb,
+        mSrcTexCr,
+        mSrcTexEGL,
+    };
+
+    mSrcTexY = mSrcTexCb = mSrcTexCr = mSrcTexEGL = 0;
+    mGL->fDeleteTextures(ArrayLength(tex), tex);
+
+    if (mFBO) {
+        mGL->fDeleteFramebuffers(1, &mFBO);
     }
-    return pair.second;
+    mFBO = 0;
 }
 
-
-const DrawBlitProg*
-GLBlitHelper::CreateDrawBlitProg(const DrawBlitProg::Key& key) const
+// Allowed to be destructive of state we restore in functions below.
+bool
+GLBlitHelper::InitTexQuadProgram(BlitType target)
 {
-    const char kFragHeader_Global[] = "\
-        #ifdef GL_ES                                                         \n\
-            #ifdef GL_FRAGMENT_PRECISION_HIGH                                \n\
-                precision highp float;                                       \n\
-            #else                                                            \n\
-                precision mediump float;                                     \n\
-            #endif                                                           \n\
-        #endif                                                               \n\
-                                                                             \n\
-        #if __VERSION__ >= 130                                               \n\
-            #define VARYING in                                               \n\
-            #define FRAG_COLOR oFragColor                                    \n\
-                                                                             \n\
-            out vec4 FRAG_COLOR;                                             \n\
-        #else                                                                \n\
-            #define VARYING varying                                          \n\
-            #define FRAG_COLOR gl_FragColor                                  \n\
-        #endif                                                               \n\
+    const char kTexBlit_VertShaderSource[] = "\
+        #version 100                                  \n\
+        #ifdef GL_ES                                  \n\
+        precision mediump float;                      \n\
+        #endif                                        \n\
+        attribute vec2 aPosition;                     \n\
+                                                      \n\
+        uniform float uYflip;                         \n\
+        varying vec2 vTexCoord;                       \n\
+                                                      \n\
+        void main(void)                               \n\
+        {                                             \n\
+            vTexCoord = aPosition;                    \n\
+            vTexCoord.y = abs(vTexCoord.y - uYflip);  \n\
+            vec2 vertPos = aPosition * 2.0 - 1.0;     \n\
+            gl_Position = vec4(vertPos, 0.0, 1.0);    \n\
+        }                                             \n\
+    ";
+
+    const char kTex2DBlit_FragShaderSource[] = "\
+        #version 100                                        \n\
+        #ifdef GL_ES                                        \n\
+        #ifdef GL_FRAGMENT_PRECISION_HIGH                   \n\
+            precision highp float;                          \n\
+        #else                                               \n\
+            precision mediump float;                        \n\
+        #endif                                              \n\
+        #endif                                              \n\
+        uniform sampler2D uTexUnit;                         \n\
+                                                            \n\
+        varying vec2 vTexCoord;                             \n\
+                                                            \n\
+        void main(void)                                     \n\
+        {                                                   \n\
+            gl_FragColor = texture2D(uTexUnit, vTexCoord);  \n\
+        }                                                   \n\
+    ";
+
+    const char kTex2DRectBlit_FragShaderSource[] = "\
+        #version 100                                                  \n\
+        #ifdef GL_FRAGMENT_PRECISION_HIGH                             \n\
+            precision highp float;                                    \n\
+        #else                                                         \n\
+            precision mediump float;                                  \n\
+        #endif                                                        \n\
+                                                                      \n\
+        uniform sampler2D uTexUnit;                                   \n\
+        uniform vec2 uTexCoordMult;                                   \n\
+                                                                      \n\
+        varying vec2 vTexCoord;                                       \n\
+                                                                      \n\
+        void main(void)                                               \n\
+        {                                                             \n\
+            gl_FragColor = texture2DRect(uTexUnit,                    \n\
+                                         vTexCoord * uTexCoordMult);  \n\
+        }                                                             \n\
+    ";
+#ifdef ANDROID /* MOZ_WIDGET_ANDROID */
+    const char kTexExternalBlit_FragShaderSource[] = "\
+        #version 100                                                    \n\
+        #extension GL_OES_EGL_image_external : require                  \n\
+        #ifdef GL_FRAGMENT_PRECISION_HIGH                               \n\
+            precision highp float;                                      \n\
+        #else                                                           \n\
+            precision mediump float;                                    \n\
+        #endif                                                          \n\
+        varying vec2 vTexCoord;                                         \n\
+        uniform mat4 uTextureTransform;                                 \n\
+        uniform samplerExternalOES uTexUnit;                            \n\
+                                                                        \n\
+        void main()                                                     \n\
+        {                                                               \n\
+            gl_FragColor = texture2D(uTexUnit,                          \n\
+                (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy);    \n\
+        }                                                               \n\
+    ";
+#endif
+    /* From Rec601:
+    [R]   [1.1643835616438356,  0.0,                 1.5960267857142858]      [ Y -  16]
+    [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708]    x [Cb - 128]
+    [B]   [1.1643835616438356,  2.017232142857143,   8.862867620416422e-17]   [Cr - 128]
+
+    For [0,1] instead of [0,255], and to 5 places:
+    [R]   [1.16438,  0.00000,  1.59603]   [ Y - 0.06275]
+    [G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
+    [B]   [1.16438,  2.01723,  0.00000]   [Cr - 0.50196]
+
+    From Rec709:
+    [R]   [1.1643835616438356,  4.2781193979771426e-17, 1.7927410714285714]     [ Y -  16]
+    [G] = [1.1643835616438358, -0.21324861427372963,   -0.532909328559444]    x [Cb - 128]
+    [B]   [1.1643835616438356,  2.1124017857142854,     0.0]                    [Cr - 128]
+
+    For [0,1] instead of [0,255], and to 5 places:
+    [R]   [1.16438,  0.00000,  1.79274]   [ Y - 0.06275]
+    [G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
+    [B]   [1.16438,  2.11240,  0.00000]   [Cr - 0.50196]
+    */
+    const char kTexYUVPlanarBlit_FragShaderSource[] = "\
+        #version 100                                                        \n\
+        #ifdef GL_ES                                                        \n\
+        precision mediump float;                                            \n\
+        #endif                                                              \n\
+        varying vec2 vTexCoord;                                             \n\
+        uniform sampler2D uYTexture;                                        \n\
+        uniform sampler2D uCbTexture;                                       \n\
+        uniform sampler2D uCrTexture;                                       \n\
+        uniform vec2 uYTexScale;                                            \n\
+        uniform vec2 uCbCrTexScale;                                         \n\
+        uniform mat3 uYuvColorMatrix;                                       \n\
+        void main()                                                         \n\
+        {                                                                   \n\
+            float y = texture2D(uYTexture, vTexCoord * uYTexScale).r;       \n\
+            float cb = texture2D(uCbTexture, vTexCoord * uCbCrTexScale).r;  \n\
+            float cr = texture2D(uCrTexture, vTexCoord * uCbCrTexScale).r;  \n\
+            y = y - 0.06275;                                                \n\
+            cb = cb - 0.50196;                                              \n\
+            cr = cr - 0.50196;                                              \n\
+            vec3 yuv = vec3(y, cb, cr);                                     \n\
+            gl_FragColor.rgb = uYuvColorMatrix * yuv;                       \n\
+            gl_FragColor.a = 1.0;                                           \n\
+        }                                                                   \n\
     ";
 
-    const ScopedShader fs(mGL, LOCAL_GL_FRAGMENT_SHADER);
-    const char* const parts[] = {
-        mDrawBlitProg_VersionLine.get(),
-        key.fragHeader,
-        kFragHeader_Global,
-        key.fragBody
-    };
-    mGL->fShaderSource(fs, ArrayLength(parts), parts, nullptr);
-    mGL->fCompileShader(fs);
+#ifdef XP_MACOSX
+    const char kTexNV12PlanarBlit_FragShaderSource[] = "\
+        #version 100                                                             \n\
+        #extension GL_ARB_texture_rectangle : require                            \n\
+        #ifdef GL_ES                                                             \n\
+        precision mediump float                                                  \n\
+        #endif                                                                   \n\
+        varying vec2 vTexCoord;                                                  \n\
+        uniform sampler2DRect uYTexture;                                         \n\
+        uniform sampler2DRect uCbCrTexture;                                      \n\
+        uniform vec2 uYTexScale;                                                 \n\
+        uniform vec2 uCbCrTexScale;                                              \n\
+        void main()                                                              \n\
+        {                                                                        \n\
+            float y = texture2DRect(uYTexture, vTexCoord * uYTexScale).r;        \n\
+            float cb = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).r; \n\
+            float cr = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).a; \n\
+            y = (y - 0.06275) * 1.16438;                                         \n\
+            cb = cb - 0.50196;                                                   \n\
+            cr = cr - 0.50196;                                                   \n\
+            gl_FragColor.r = y + cr * 1.59603;                                   \n\
+            gl_FragColor.g = y - 0.81297 * cr - 0.39176 * cb;                    \n\
+            gl_FragColor.b = y + cb * 2.01723;                                   \n\
+            gl_FragColor.a = 1.0;                                                \n\
+        }                                                                        \n\
+    ";
+#endif
 
-    const auto prog = mGL->fCreateProgram();
-    mGL->fAttachShader(prog, mDrawBlitProg_VertShader);
-    mGL->fAttachShader(prog, fs);
-
-    mGL->fBindAttribLocation(prog, 0, "aPosition");
-    mGL->fLinkProgram(prog);
+    bool success = false;
 
-    GLenum status = 0;
-    mGL->fGetProgramiv(prog, LOCAL_GL_LINK_STATUS, (GLint*)&status);
-    if (status == LOCAL_GL_TRUE) {
-        const SaveRestoreCurrentProgram oldProg(mGL);
-        mGL->fUseProgram(prog);
-        const char* samplerNames[] = {
-            "uTex0",
-            "uTex1",
-            "uTex2"
-        };
-        for (int i = 0; i < 3; i++) {
-            const auto loc = mGL->fGetUniformLocation(prog, samplerNames[i]);
-            if (loc == -1)
-                break;
-            mGL->fUniform1i(loc, i);
-        }
-
-        return new DrawBlitProg(this, prog);
+    GLuint* programPtr;
+    GLuint* fragShaderPtr;
+    const char* fragShaderSource;
+    switch (target) {
+    case ConvertEGLImage:
+    case BlitTex2D:
+        programPtr = &mTex2DBlit_Program;
+        fragShaderPtr = &mTex2DBlit_FragShader;
+        fragShaderSource = kTex2DBlit_FragShaderSource;
+        break;
+    case BlitTexRect:
+        programPtr = &mTex2DRectBlit_Program;
+        fragShaderPtr = &mTex2DRectBlit_FragShader;
+        fragShaderSource = kTex2DRectBlit_FragShaderSource;
+        break;
+#ifdef ANDROID
+    case ConvertSurfaceTexture:
+        programPtr = &mTexExternalBlit_Program;
+        fragShaderPtr = &mTexExternalBlit_FragShader;
+        fragShaderSource = kTexExternalBlit_FragShaderSource;
+        break;
+#endif
+    case ConvertPlanarYCbCr:
+        programPtr = &mTexYUVPlanarBlit_Program;
+        fragShaderPtr = &mTexYUVPlanarBlit_FragShader;
+        fragShaderSource = kTexYUVPlanarBlit_FragShaderSource;
+        break;
+#ifdef XP_MACOSX
+    case ConvertMacIOSurfaceImage:
+        programPtr = &mTexNV12PlanarBlit_Program;
+        fragShaderPtr = &mTexNV12PlanarBlit_FragShader;
+        fragShaderSource = kTexNV12PlanarBlit_FragShaderSource;
+        break;
+#endif
+    default:
+        return false;
     }
 
-    GLuint progLogLen = 0;
-    mGL->fGetProgramiv(prog, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&progLogLen);
-    const UniquePtr<char[]> progLog(new char[progLogLen+1]);
-    mGL->fGetProgramInfoLog(prog, progLogLen, nullptr, progLog.get());
-    progLog[progLogLen] = 0;
+    GLuint& program = *programPtr;
+    GLuint& fragShader = *fragShaderPtr;
+
+    // Use do-while(false) to let us break on failure
+    do {
+        if (program) {
+            // Already have it...
+            success = true;
+            break;
+        }
+
+        if (!mTexBlit_Buffer) {
+
+            /* CCW tri-strip:
+             * 2---3
+             * | \ |
+             * 0---1
+             */
+            GLfloat verts[] = {
+                0.0f, 0.0f,
+                1.0f, 0.0f,
+                0.0f, 1.0f,
+                1.0f, 1.0f
+            };
+            HeapCopyOfStackArray<GLfloat> vertsOnHeap(verts);
+
+            MOZ_ASSERT(!mTexBlit_Buffer);
+            mGL->fGenBuffers(1, &mTexBlit_Buffer);
+            mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
+
+            // Make sure we have a sane size.
+            mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, vertsOnHeap.ByteLength(), vertsOnHeap.Data(), LOCAL_GL_STATIC_DRAW);
+        }
+
+        if (!mTexBlit_VertShader) {
+
+            const char* vertShaderSource = kTexBlit_VertShaderSource;
+
+            mTexBlit_VertShader = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER);
+            mGL->fShaderSource(mTexBlit_VertShader, 1, &vertShaderSource, nullptr);
+            mGL->fCompileShader(mTexBlit_VertShader);
+        }
 
-    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;
+        MOZ_ASSERT(!fragShader);
+        fragShader = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
+        mGL->fShaderSource(fragShader, 1, &fragShaderSource, nullptr);
+        mGL->fCompileShader(fragShader);
+
+        program = mGL->fCreateProgram();
+        mGL->fAttachShader(program, mTexBlit_VertShader);
+        mGL->fAttachShader(program, fragShader);
+        mGL->fBindAttribLocation(program, 0, "aPosition");
+        mGL->fLinkProgram(program);
+
+        if (GLContext::ShouldSpew()) {
+            GLint status = 0;
+            mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status);
+            if (status != LOCAL_GL_TRUE) {
+                NS_ERROR("Vert shader compilation failed.");
+
+                GLint length = 0;
+                mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
+                if (!length) {
+                    printf_stderr("No shader info log available.\n");
+                    break;
+                }
+
+                auto buffer = MakeUnique<char[]>(length);
+                mGL->fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer.get());
+
+                printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
+                break;
+            }
+
+            status = 0;
+            mGL->fGetShaderiv(fragShader, LOCAL_GL_COMPILE_STATUS, &status);
+            if (status != LOCAL_GL_TRUE) {
+                NS_ERROR("Frag shader compilation failed.");
+
+                GLint length = 0;
+                mGL->fGetShaderiv(fragShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
+                if (!length) {
+                    printf_stderr("No shader info log available.\n");
+                    break;
+                }
+
+                auto buffer = MakeUnique<char[]>(length);
+                mGL->fGetShaderInfoLog(fragShader, length, nullptr, buffer.get());
+
+                printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
+                break;
+            }
+        }
 
-    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;
+        GLint status = 0;
+        mGL->fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &status);
+        if (status != LOCAL_GL_TRUE) {
+            if (GLContext::ShouldSpew()) {
+                NS_ERROR("Linking blit program failed.");
+                GLint length = 0;
+                mGL->fGetProgramiv(program, LOCAL_GL_INFO_LOG_LENGTH, &length);
+                if (!length) {
+                    printf_stderr("No program info log available.\n");
+                    break;
+                }
+
+                auto buffer = MakeUnique<char[]>(length);
+                mGL->fGetProgramInfoLog(program, length, nullptr, buffer.get());
+
+                printf_stderr("Program info log (%d bytes): %s\n", length, buffer.get());
+            }
+            break;
+        }
+
+        // Cache and set attribute and uniform
+        mGL->fUseProgram(program);
+        switch (target) {
+#ifdef ANDROID
+            case ConvertSurfaceTexture:
+#endif
+            case BlitTex2D:
+            case BlitTexRect:
+            case ConvertEGLImage: {
+                GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
+                MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
+                mGL->fUniform1i(texUnitLoc, 0);
+                break;
+            }
+            case ConvertPlanarYCbCr: {
+                GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
+                GLint texCb = mGL->fGetUniformLocation(program, "uCbTexture");
+                GLint texCr = mGL->fGetUniformLocation(program, "uCrTexture");
+                mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
+                mCbCrTexScaleLoc = mGL->fGetUniformLocation(program, "uCbCrTexScale");
+                mYuvColorMatrixLoc = mGL->fGetUniformLocation(program, "uYuvColorMatrix");
+
+                DebugOnly<bool> hasUniformLocations = texY != -1 &&
+                                                      texCb != -1 &&
+                                                      texCr != -1 &&
+                                                      mYTexScaleLoc != -1 &&
+                                                      mCbCrTexScaleLoc != -1 &&
+                                                      mYuvColorMatrixLoc != -1;
+                MOZ_ASSERT(hasUniformLocations, "uniforms not found");
 
-    gfxCriticalError() << "DrawBlitProg link failed:\n"
-                       << "progLog: " << progLog.get() << "\n"
-                       << "vsLog: " << vsLog.get() << "\n"
-                       << "fsLog: " << fsLog.get() << "\n";
-    return nullptr;
+                mGL->fUniform1i(texY, Channel_Y);
+                mGL->fUniform1i(texCb, Channel_Cb);
+                mGL->fUniform1i(texCr, Channel_Cr);
+                break;
+            }
+            case ConvertMacIOSurfaceImage: {
+#ifdef XP_MACOSX
+                GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
+                GLint texCbCr = mGL->fGetUniformLocation(program, "uCbCrTexture");
+                mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
+                mCbCrTexScaleLoc= mGL->fGetUniformLocation(program, "uCbCrTexScale");
+
+                DebugOnly<bool> hasUniformLocations = texY != -1 &&
+                                                      texCbCr != -1 &&
+                                                      mYTexScaleLoc != -1 &&
+                                                      mCbCrTexScaleLoc != -1;
+                MOZ_ASSERT(hasUniformLocations, "uniforms not found");
+
+                mGL->fUniform1i(texY, Channel_Y);
+                mGL->fUniform1i(texCbCr, Channel_Cb);
+#endif
+                break;
+            }
+            default:
+                return false;
+        }
+        MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0);
+        mYFlipLoc = mGL->fGetUniformLocation(program, "uYflip");
+        MOZ_ASSERT(mYFlipLoc != -1, "uniform: uYflip not found");
+        mTextureTransformLoc = mGL->fGetUniformLocation(program, "uTextureTransform");
+        if (mTextureTransformLoc >= 0) {
+            // Set identity matrix as default
+            gfx::Matrix4x4 identity;
+            mGL->fUniformMatrix4fv(mTextureTransformLoc, 1, false, &identity._11);
+        }
+        success = true;
+    } while (false);
+
+    if (!success) {
+        // Clean up:
+        DeleteTexBlitProgram();
+        return false;
+    }
+
+    mGL->fUseProgram(program);
+    mGL->fEnableVertexAttribArray(0);
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
+    mGL->fVertexAttribPointer(0,
+                              2,
+                              LOCAL_GL_FLOAT,
+                              false,
+                              0,
+                              nullptr);
+    return true;
 }
 
-// -----------------------------------------------------------------------------
-
 bool
-GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
-                                     const gfx::IntSize& destSize,
-                                     OriginPos destOrigin)
+GLBlitHelper::UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize)
 {
-    switch (srcImage->GetFormat()) {
-    case ImageFormat::PLANAR_YCBCR:
-        return BlitImage(static_cast<PlanarYCbCrImage*>(srcImage), destSize, destOrigin);
+    if (!InitTexQuadProgram(target)) {
+        return false;
+    }
 
-#ifdef MOZ_WIDGET_ANDROID
-    case ImageFormat::SURFACE_TEXTURE:
-        return BlitImage(static_cast<layers::SurfaceTextureImage*>(srcImage), destSize,
-                         destOrigin);
+    if (target == BlitTexRect) {
+        GLint texCoordMultLoc = mGL->fGetUniformLocation(mTex2DRectBlit_Program, "uTexCoordMult");
+        MOZ_ASSERT(texCoordMultLoc != -1, "uniform not found");
+        mGL->fUniform2f(texCoordMultLoc, srcSize.width, srcSize.height);
+    }
+
+    return true;
+}
 
-    case ImageFormat::EGLIMAGE:
-        return BlitImage(static_cast<layers::EGLImageImage*>(srcImage), destSize,
-                         destOrigin);
-#endif
-#ifdef XP_MACOSX
-    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);
-    case ImageFormat::D3D9_RGB32_TEXTURE:
-        return false; // todo
-#endif
-    default:
-        gfxCriticalError() << "Unhandled srcImage->GetFormat(): "
-                           << uint32_t(srcImage->GetFormat());
-        return false;
+void
+GLBlitHelper::DeleteTexBlitProgram()
+{
+    if (mTexBlit_Buffer) {
+        mGL->fDeleteBuffers(1, &mTexBlit_Buffer);
+        mTexBlit_Buffer = 0;
+    }
+    if (mTexBlit_VertShader) {
+        mGL->fDeleteShader(mTexBlit_VertShader);
+        mTexBlit_VertShader = 0;
+    }
+    if (mTex2DBlit_FragShader) {
+        mGL->fDeleteShader(mTex2DBlit_FragShader);
+        mTex2DBlit_FragShader = 0;
+    }
+    if (mTex2DRectBlit_FragShader) {
+        mGL->fDeleteShader(mTex2DRectBlit_FragShader);
+        mTex2DRectBlit_FragShader = 0;
+    }
+    if (mTex2DBlit_Program) {
+        mGL->fDeleteProgram(mTex2DBlit_Program);
+        mTex2DBlit_Program = 0;
+    }
+    if (mTex2DRectBlit_Program) {
+        mGL->fDeleteProgram(mTex2DRectBlit_Program);
+        mTex2DRectBlit_Program = 0;
+    }
+    if (mTexExternalBlit_FragShader) {
+        mGL->fDeleteShader(mTexExternalBlit_FragShader);
+        mTexExternalBlit_FragShader = 0;
+    }
+    if (mTexYUVPlanarBlit_FragShader) {
+        mGL->fDeleteShader(mTexYUVPlanarBlit_FragShader);
+        mTexYUVPlanarBlit_FragShader = 0;
+    }
+    if (mTexNV12PlanarBlit_FragShader) {
+        mGL->fDeleteShader(mTexNV12PlanarBlit_FragShader);
+        mTexNV12PlanarBlit_FragShader = 0;
+    }
+    if (mTexExternalBlit_Program) {
+        mGL->fDeleteProgram(mTexExternalBlit_Program);
+        mTexExternalBlit_Program = 0;
+    }
+    if (mTexYUVPlanarBlit_Program) {
+        mGL->fDeleteProgram(mTexYUVPlanarBlit_Program);
+        mTexYUVPlanarBlit_Program = 0;
+    }
+    if (mTexNV12PlanarBlit_Program) {
+        mGL->fDeleteProgram(mTexNV12PlanarBlit_Program);
+        mTexNV12PlanarBlit_Program = 0;
     }
 }
 
-// -------------------------------------
+void
+GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
+                                           const gfx::IntSize& srcSize,
+                                           const gfx::IntSize& destSize,
+                                           bool internalFBs)
+{
+    MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
+    MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
+
+    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
+
+    ScopedBindFramebuffer boundFB(mGL);
+    ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
+
+    if (internalFBs) {
+        mGL->Screen()->BindReadFB_Internal(srcFB);
+        mGL->Screen()->BindDrawFB_Internal(destFB);
+    } else {
+        mGL->BindReadFB(srcFB);
+        mGL->BindDrawFB(destFB);
+    }
+
+    mGL->fBlitFramebuffer(0, 0,  srcSize.width,  srcSize.height,
+                          0, 0, destSize.width, destSize.height,
+                          LOCAL_GL_COLOR_BUFFER_BIT,
+                          LOCAL_GL_NEAREST);
+}
+
+void
+GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
+                                           const gfx::IntSize& srcSize,
+                                           const gfx::IntSize& destSize,
+                                           const GLFormats& srcFormats,
+                                           bool internalFBs)
+{
+    MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
+    MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
+
+    if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
+        BlitFramebufferToFramebuffer(srcFB, destFB,
+                                     srcSize, destSize,
+                                     internalFBs);
+        return;
+    }
+
+    GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize);
+    MOZ_ASSERT(tex);
+
+    BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize, internalFBs);
+    BlitTextureToFramebuffer(tex, destFB, srcSize, destSize, internalFBs);
+
+    mGL->fDeleteTextures(1, &tex);
+}
+
+void
+GLBlitHelper::BindAndUploadYUVTexture(Channel which,
+                                      uint32_t width,
+                                      uint32_t height,
+                                      void* data,
+                                      bool needsAllocation)
+{
+    MOZ_ASSERT(which < Channel_Max, "Invalid channel!");
+    GLuint* srcTexArr[3] = {&mSrcTexY, &mSrcTexCb, &mSrcTexCr};
+    GLuint& tex = *srcTexArr[which];
+
+    // RED textures aren't valid in GLES2, and ALPHA textures are not valid in desktop GL Core Profiles.
+    // So use R8 textures on GL3.0+ and GLES3.0+, but LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise.
+    GLenum format;
+    GLenum internalFormat;
+    if (mGL->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) ||
+        mGL->IsAtLeast(gl::ContextProfile::OpenGLES, 300)) {
+        format = LOCAL_GL_RED;
+        internalFormat = LOCAL_GL_R8;
+    } else {
+        format = LOCAL_GL_LUMINANCE;
+        internalFormat = LOCAL_GL_LUMINANCE;
+    }
+
+    if (!tex) {
+        MOZ_ASSERT(needsAllocation);
+        tex = CreateTexture(mGL, internalFormat, format, LOCAL_GL_UNSIGNED_BYTE,
+                            gfx::IntSize(width, height), false);
+    }
+    mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + which);
+
+    mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
+    if (!needsAllocation) {
+        mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
+                            0,
+                            0,
+                            0,
+                            width,
+                            height,
+                            format,
+                            LOCAL_GL_UNSIGNED_BYTE,
+                            data);
+    } else {
+        mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
+                         0,
+                         internalFormat,
+                         width,
+                         height,
+                         0,
+                         format,
+                         LOCAL_GL_UNSIGNED_BYTE,
+                         data);
+    }
+}
+
+void
+GLBlitHelper::BindAndUploadEGLImage(EGLImage image, GLuint target)
+{
+    MOZ_ASSERT(image != EGL_NO_IMAGE, "Bad EGLImage");
+
+    if (!mSrcTexEGL) {
+        mGL->fGenTextures(1, &mSrcTexEGL);
+        mGL->fBindTexture(target, mSrcTexEGL);
+        mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+        mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+        mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
+        mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
+    } else {
+        mGL->fBindTexture(target, mSrcTexEGL);
+    }
+    mGL->fEGLImageTargetTexture2D(target, image);
+}
 
 #ifdef MOZ_WIDGET_ANDROID
+
+#define ATTACH_WAIT_MS 50
+
 bool
-GLBlitHelper::BlitImage(layers::SurfaceTextureImage* srcImage, const gfx::IntSize&,
-                        const OriginPos) const
+GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage)
 {
     // FIXME
-    const auto& srcOrigin = srcImage->GetOriginPos();
-    (void)srcOrigin;
-    gfxCriticalError() << "BlitImage(SurfaceTextureImage) not implemented.";
     return false;
 }
 
 bool
-GLBlitHelper::BlitImage(layers::EGLImageImage* const srcImage,
-                        const gfx::IntSize& destSize, const OriginPos destOrigin) const
+GLBlitHelper::BlitEGLImageImage(layers::EGLImageImage* image)
 {
-    const EGLImage eglImage = srcImage->GetImage();
-    const EGLSync eglSync = srcImage->GetSync();
+    EGLImage eglImage = image->GetImage();
+    EGLSync eglSync = image->GetSync();
+
     if (eglSync) {
         EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), eglSync, 0, LOCAL_EGL_FOREVER);
         if (status != LOCAL_EGL_CONDITION_SATISFIED) {
             return false;
         }
     }
 
-    GLuint tex = 0;
-    mGL->fGenTextures(1, &tex);
+    ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
+
+    int oldBinding = 0;
+    mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldBinding);
+
+    BindAndUploadEGLImage(eglImage, LOCAL_GL_TEXTURE_2D);
+
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+
+    mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldBinding);
+    return true;
+}
+
+#endif
+
+bool
+GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage)
+{
+    ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
+    const PlanarYCbCrData* yuvData = yuvImage->GetData();
 
-    const ScopedSaveMultiTex saveTex(mGL, 1, LOCAL_GL_TEXTURE_2D);
-    mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
-    mGL->TexParams_SetClampNoMips();
-    mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, eglImage);
+    bool needsAllocation = false;
+    if (mTexWidth != yuvData->mYStride || mTexHeight != yuvData->mYSize.height) {
+        mTexWidth = yuvData->mYStride;
+        mTexHeight = yuvData->mYSize.height;
+        needsAllocation = true;
+    }
+
+    GLint oldTex[3];
+    for (int i = 0; i < 3; i++) {
+        mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+        mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
+    }
+
+    {
+        const ResetUnpackState reset(mGL);
+        BindAndUploadYUVTexture(Channel_Y, yuvData->mYStride, yuvData->mYSize.height, yuvData->mYChannel, needsAllocation);
+        BindAndUploadYUVTexture(Channel_Cb, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCbChannel, needsAllocation);
+        BindAndUploadYUVTexture(Channel_Cr, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCrChannel, needsAllocation);
+    }
+
+    if (needsAllocation) {
+        mGL->fUniform2f(mYTexScaleLoc, (float)yuvData->mYSize.width/yuvData->mYStride, 1.0f);
+        mGL->fUniform2f(mCbCrTexScaleLoc, (float)yuvData->mCbCrSize.width/yuvData->mCbCrStride, 1.0f);
+    }
+
+    const auto& yuvToRgb = gfxUtils::YuvToRgbMatrix3x3ColumnMajor(yuvData->mYUVColorSpace);
+    mGL->fUniformMatrix3fv(mYuvColorMatrixLoc, 1, 0, yuvToRgb);
 
-    const auto& srcOrigin = srcImage->GetOriginPos();
-    const bool yFlip = destOrigin != srcOrigin;
-    const gfx::IntRect srcRect(0, 0, 1, 1);
-    const gfx::IntSize srcSize(1, 1);
-    const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, srcRect, srcSize };
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+    for (int i = 0; i < 3; i++) {
+        mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+        mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
+    }
+    return true;
+}
+
+#ifdef XP_MACOSX
+bool
+GLBlitHelper::BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage)
+{
+    ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
+    MacIOSurface* surf = ioImage->GetSurface();
+
+    GLint oldTex[2];
+    for (int i = 0; i < 2; i++) {
+        mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+        mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
+    }
+
+    GLuint textures[2];
+    mGL->fGenTextures(2, textures);
 
-    const auto& prog = GetDrawBlitProg({kFragHeader_Tex2D, kFragBody_RGBA});
-    MOZ_RELEASE_ASSERT(prog);
-    prog->Draw(baseArgs);
+    mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
+    mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[0]);
+    mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+    mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+    surf->CGLTexImageIOSurface2D(mGL,
+                                 gl::GLContextCGL::Cast(mGL)->GetCGLContext(),
+                                 0);
+    mGL->fUniform2f(mYTexScaleLoc, surf->GetWidth(0), surf->GetHeight(0));
 
-    mGL->fDeleteTextures(1, &tex);
+    mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
+    mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[1]);
+    mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+    mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+    surf->CGLTexImageIOSurface2D(mGL,
+                                 gl::GLContextCGL::Cast(mGL)->GetCGLContext(),
+                                 1);
+    mGL->fUniform2f(mCbCrTexScaleLoc, surf->GetWidth(1), surf->GetHeight(1));
+
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+    for (int i = 0; i < 2; i++) {
+        mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+        mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
+    }
+
+    mGL->fDeleteTextures(2, textures);
     return true;
 }
 #endif
 
-// -------------------------------------
-
 bool
-GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
-              gfx::IntSize* const out_divisors)
+GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
+                                     const gfx::IntSize& destSize,
+                                     GLuint destFB,
+                                     OriginPos destOrigin)
 {
-    const gfx::IntSize divisors((ySize.width  == uvSize.width ) ? 1 : 2,
-                                (ySize.height == uvSize.height) ? 1 : 2);
-    if (uvSize.width  * divisors.width != ySize.width ||
-        uvSize.height * divisors.height != ySize.height)
-    {
-        return false;
-    }
-    *out_divisors = divisors;
-    return true;
-}
+    ScopedGLDrawState autoStates(mGL);
 
-bool
-GLBlitHelper::BlitImage(layers::PlanarYCbCrImage* const yuvImage,
-                        const gfx::IntSize& destSize, const OriginPos destOrigin)
-{
-    const auto& prog = GetDrawBlitProg({kFragHeader_Tex2D, kFragBody_PlanarYUV});
-    MOZ_RELEASE_ASSERT(prog);
+    BlitType type;
+    OriginPos srcOrigin;
 
-    if (!mYuvUploads[0]) {
-        mGL->fGenTextures(3, mYuvUploads);
-        const ScopedBindTexture bindTex(mGL, mYuvUploads[0]);
-        mGL->TexParams_SetClampNoMips();
-        mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[1]);
-        mGL->TexParams_SetClampNoMips();
-        mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[2]);
-        mGL->TexParams_SetClampNoMips();
-    }
-
-    // --
-
-    const PlanarYCbCrData* const yuvData = yuvImage->GetData();
+    switch (srcImage->GetFormat()) {
+    case ImageFormat::PLANAR_YCBCR:
+        type = ConvertPlanarYCbCr;
+#if defined(MOZ_WIDGET_ANDROID)
+        srcOrigin = OriginPos::TopLeft;
+#else
+        srcOrigin = OriginPos::BottomLeft;
+#endif // defined(MOZ_WIDGET_ANDROID)
+        break;
 
-    if (yuvData->mYSkip || yuvData->mCbSkip || yuvData->mCrSkip ||
-        yuvData->mYSize.width < 0 || yuvData->mYSize.height < 0 ||
-        yuvData->mCbCrSize.width < 0 || yuvData->mCbCrSize.height < 0 ||
-        yuvData->mYStride < 0 || yuvData->mCbCrStride < 0)
-    {
-        gfxCriticalError() << "Unusual PlanarYCbCrData: "
-                           << yuvData->mYSkip << ","
-                           << yuvData->mCbSkip << ","
-                           << yuvData->mCrSkip << ", "
-                           << yuvData->mYSize.width << ","
-                           << yuvData->mYSize.height << ", "
-                           << yuvData->mCbCrSize.width << ","
-                           << yuvData->mCbCrSize.height << ", "
-                           << yuvData->mYStride << ","
-                           << yuvData->mCbCrStride;
+#ifdef MOZ_WIDGET_ANDROID
+    case ImageFormat::SURFACE_TEXTURE:
+        type = ConvertSurfaceTexture;
+        srcOrigin = srcImage->AsSurfaceTextureImage()->GetOriginPos();
+        break;
+    case ImageFormat::EGLIMAGE:
+        type = ConvertEGLImage;
+        srcOrigin = srcImage->AsEGLImageImage()->GetOriginPos();
+        break;
+#endif
+#ifdef XP_MACOSX
+    case ImageFormat::MAC_IOSURFACE:
+        type = ConvertMacIOSurfaceImage;
+        srcOrigin = OriginPos::TopLeft;
+        break;
+#endif
+
+    default:
         return false;
     }
 
-    const gfx::IntSize yTexSize(yuvData->mYStride, yuvData->mYSize.height);
-    const gfx::IntSize uvTexSize(yuvData->mCbCrStride, yuvData->mCbCrSize.height);
-    gfx::IntSize divisors;
-    if (!GuessDivisors(yTexSize, uvTexSize, &divisors)) {
-        gfxCriticalError() << "GuessDivisors failed:"
-                           << yTexSize.width << ","
-                           << yTexSize.height << ", "
-                           << uvTexSize.width << ","
-                           << uvTexSize.height;
+    bool init = InitTexQuadProgram(type);
+    if (!init) {
         return false;
     }
 
-    // --
+    const bool needsYFlip = (srcOrigin != destOrigin);
+    mGL->fUniform1f(mYFlipLoc, needsYFlip ? (float)1.0 : (float)0.0);
 
-    // RED textures aren't valid in GLES2, and ALPHA textures are not valid in desktop GL Core Profiles.
-    // So use R8 textures on GL3.0+ and GLES3.0+, but LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise.
-    GLenum internalFormat;
-    GLenum unpackFormat;
-    if (mGL->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) ||
-        mGL->IsAtLeast(gl::ContextProfile::OpenGLES, 300))
-    {
-        internalFormat = LOCAL_GL_R8;
-        unpackFormat = LOCAL_GL_RED;
-    } else {
-        internalFormat = LOCAL_GL_LUMINANCE;
-        unpackFormat = LOCAL_GL_LUMINANCE;
-    }
-
-    // --
-
-    const ScopedSaveMultiTex saveTex(mGL, 3, LOCAL_GL_TEXTURE_2D);
-    const ResetUnpackState reset(mGL);
-
-    if (yTexSize != mYuvUploads_YSize ||
-        uvTexSize != mYuvUploads_UVSize)
-    {
-        mYuvUploads_YSize = yTexSize;
-        mYuvUploads_UVSize = uvTexSize;
+    ScopedBindFramebuffer boundFB(mGL, destFB);
+    mGL->fColorMask(LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE);
+    mGL->fViewport(0, 0, destSize.width, destSize.height);
 
-        mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
-        mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[0]);
-        mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat,
-                         yTexSize.width, yTexSize.height, 0,
-                         unpackFormat, LOCAL_GL_UNSIGNED_BYTE, nullptr);
-        for (int i = 1; i < 3; i++) {
-            mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
-            mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[i]);
-            mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat,
-                             uvTexSize.width, uvTexSize.height, 0,
-                             unpackFormat, LOCAL_GL_UNSIGNED_BYTE, nullptr);
-        }
-    }
-
-    // --
+    switch (type) {
+    case ConvertPlanarYCbCr:
+        return BlitPlanarYCbCrImage(static_cast<PlanarYCbCrImage*>(srcImage));
 
-    mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
-    mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[0]);
-    mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
-                        yTexSize.width, yTexSize.height,
-                        unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mYChannel);
-    mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
-    mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mYuvUploads[1]);
-    mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
-                        uvTexSize.width, uvTexSize.height,
-                        unpackFormat, LOCAL_GL_UNSIGNED_BYTE, yuvData->mCbChannel);
-    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);
+#ifdef MOZ_WIDGET_ANDROID
+    case ConvertSurfaceTexture:
+        return BlitSurfaceTextureImage(static_cast<layers::SurfaceTextureImage*>(srcImage));
 
-    // --
-
-    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 };
-
-    prog->Draw(baseArgs, &yuvArgs);
-    return true;
-}
-
-// -------------------------------------
+    case ConvertEGLImage:
+        return BlitEGLImageImage(static_cast<layers::EGLImageImage*>(srcImage));
+#endif
 
 #ifdef XP_MACOSX
-bool
-GLBlitHelper::BlitImage(layers::MacIOSurfaceImage* const srcImage,
-                        const gfx::IntSize& destSize, const OriginPos destOrigin) const
-{
-    MacIOSurface* const iosurf = srcImage->GetSurface();
-    if (mGL->GetContextType() != GLContextType::CGL) {
-        MOZ_ASSERT(false);
+    case ConvertMacIOSurfaceImage:
+        return BlitMacIOSurfaceImage(srcImage->AsMacIOSurfaceImage());
+#endif
+
+    default:
         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 };
-    const DrawBlitProg::YUVArgs* pYuvArgs = nullptr;
-
-    auto planes = iosurf->GetPlaneCount();
-    if (!planes) {
-        planes = 1; // Bad API. No cookie.
-    }
-
-    const GLenum texTarget = LOCAL_GL_TEXTURE_RECTANGLE;
-    const char* const fragHeader = kFragHeader_Tex2DRect;
-
-    const ScopedSaveMultiTex saveTex(mGL, planes, texTarget);
-    const ScopedTexture tex0(mGL);
-    const ScopedTexture tex1(mGL);
-    const ScopedTexture tex2(mGL);
-    const GLuint texs[3] = {
-        tex0,
-        tex1,
-        tex2
-    };
-
-    const auto pixelFormat = iosurf->GetPixelFormat();
-    const auto formatChars = (const char*)&pixelFormat;
-    const char formatStr[] = {
-        formatChars[3],
-        formatChars[2],
-        formatChars[1],
-        formatChars[0],
-        0
-    };
-    if (mGL->ShouldSpew()) {
-        printf_stderr("iosurf format: %s (0x%08x)\n", formatStr, uint32_t(pixelFormat));
-    }
+}
 
-    const char* fragBody;
-    GLenum internalFormats[3] = {0, 0, 0};
-    GLenum unpackFormats[3] = {0, 0, 0};
-    GLenum unpackTypes[3] = { LOCAL_GL_UNSIGNED_BYTE,
-                              LOCAL_GL_UNSIGNED_BYTE,
-                              LOCAL_GL_UNSIGNED_BYTE };
-    switch (planes) {
-    case 1:
-        fragBody = kFragBody_RGBA;
-        internalFormats[0] = LOCAL_GL_RGBA;
-        unpackFormats[0] = LOCAL_GL_RGBA;
-        break;
-    case 2:
-        fragBody = kFragBody_NV12;
-        if (mGL->Version() >= 300) {
-            internalFormats[0] = LOCAL_GL_R8;
-            unpackFormats[0] = LOCAL_GL_RED;
-            internalFormats[1] = LOCAL_GL_RG8;
-            unpackFormats[1] = LOCAL_GL_RG;
-        } else {
-            internalFormats[0] = LOCAL_GL_LUMINANCE;
-            unpackFormats[0] = LOCAL_GL_LUMINANCE;
-            internalFormats[1] = LOCAL_GL_LUMINANCE_ALPHA;
-            unpackFormats[1] = LOCAL_GL_LUMINANCE_ALPHA;
-        }
-        pYuvArgs = &yuvArgs;
-        break;
-    case 3:
-        fragBody = kFragBody_PlanarYUV;
-        if (mGL->Version() >= 300) {
-            internalFormats[0] = LOCAL_GL_R8;
-            unpackFormats[0] = LOCAL_GL_RED;
-        } else {
-            internalFormats[0] = LOCAL_GL_LUMINANCE;
-            unpackFormats[0] = LOCAL_GL_LUMINANCE;
-        }
-        internalFormats[1] = internalFormats[0];
-        internalFormats[2] = internalFormats[0];
-        unpackFormats[1] = unpackFormats[0];
-        unpackFormats[2] = unpackFormats[0];
-        pYuvArgs = &yuvArgs;
-        break;
-    default:
-        gfxCriticalError() << "Unexpected plane count: " << planes;
-        return false;
-    }
-
-    if (pixelFormat == '2vuy') {
-        fragBody = kFragBody_CrYCb;
-        // APPLE_rgb_422 adds RGB_RAW_422_APPLE for `internalFormat`, but only RGB seems
-        // to work?
-        internalFormats[0] = LOCAL_GL_RGB;
-        unpackFormats[0] = LOCAL_GL_RGB_422_APPLE;
-        unpackTypes[0] = LOCAL_GL_UNSIGNED_SHORT_8_8_APPLE;
-        pYuvArgs = &yuvArgs;
-    }
-
-    for (uint32_t p = 0; p < planes; p++) {
-        mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + p);
-        mGL->fBindTexture(texTarget, texs[p]);
-        mGL->TexParams_SetClampNoMips(texTarget);
-
-        const auto width = iosurf->GetDevicePixelWidth(p);
-        const auto height = iosurf->GetDevicePixelHeight(p);
-        auto err = iosurf->CGLTexImageIOSurface2D(cglContext, texTarget,
-                                                  internalFormats[p], width, height,
-                                                  unpackFormats[p], unpackTypes[p], p);
-        if (err) {
-            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;
-        }
-    }
-
-    const auto& prog = GetDrawBlitProg({fragHeader, fragBody});
-    if (!prog)
+bool
+GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
+                                 const gfx::IntSize& destSize,
+                                 GLuint destTex,
+                                 GLenum destTarget,
+                                 OriginPos destOrigin)
+{
+    ScopedFramebufferForTexture autoFBForTex(mGL, destTex, destTarget);
+    if (!autoFBForTex.IsComplete())
         return false;
 
-    prog->Draw(baseArgs, pYuvArgs);
-    return true;
-}
-#endif
-
-// -----------------------------------------------------------------------------
-
-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;
-    switch (srcTarget) {
-    case LOCAL_GL_TEXTURE_2D:
-        key = {kFragHeader_Tex2D, kFragBody_RGBA};
-        texSizeDivisor = srcSize;
-        break;
-    case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
-        key = {kFragHeader_Tex2DRect, kFragBody_RGBA};
-        texSizeDivisor = gfx::IntSize(1, 1);
-        break;
-    default:
-        gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
-        return;
-    }
-    const auto& prog = GetDrawBlitProg(key);
-    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 };
-    prog->Draw(baseArgs);
-}
-
-// -----------------------------------------------------------------------------
-
-void
-GLBlitHelper::BlitFramebuffer(const gfx::IntSize& srcSize,
-                              const gfx::IntSize& destSize) const
-{
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
-
-    const ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
-    mGL->fBlitFramebuffer(0, 0,  srcSize.width,  srcSize.height,
-                          0, 0, destSize.width, destSize.height,
-                          LOCAL_GL_COLOR_BUFFER_BIT,
-                          LOCAL_GL_NEAREST);
-}
-
-// --
-
-void
-GLBlitHelper::BlitFramebufferToFramebuffer(const GLuint srcFB, const GLuint destFB,
-                                           const gfx::IntSize& srcSize,
-                                           const gfx::IntSize& destSize) const
-{
-    MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
-    MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
-    MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
-
-    const ScopedBindFramebuffer boundFB(mGL);
-    mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcFB);
-    mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destFB);
-
-    BlitFramebuffer(srcSize, destSize);
+    return BlitImageToFramebuffer(srcImage, destSize, autoFBForTex.FB(), destOrigin);
 }
 
 void
-GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize,
+GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
+                                       const gfx::IntSize& srcSize,
                                        const gfx::IntSize& destSize,
-                                       GLenum srcTarget) const
+                                       GLenum srcTarget,
+                                       bool internalFBs)
 {
     MOZ_ASSERT(mGL->fIsTexture(srcTex));
+    MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
 
     if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
-        const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
-        const ScopedBindFramebuffer bindFB(mGL);
-        mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcWrapper.FB());
-        BlitFramebuffer(srcSize, destSize);
+        ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
+        MOZ_DIAGNOSTIC_ASSERT(srcWrapper.IsComplete());
+
+        BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB,
+                                     srcSize, destSize,
+                                     internalFBs);
         return;
     }
 
-    DrawBlitTextureToFramebuffer(srcTex, srcSize, destSize, srcTarget);
+    DrawBlitTextureToFramebuffer(srcTex, destFB, srcSize, destSize, srcTarget,
+                                 internalFBs);
+}
+
+
+void
+GLBlitHelper::DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
+                                           const gfx::IntSize& srcSize,
+                                           const gfx::IntSize& destSize,
+                                           GLenum srcTarget,
+                                           bool internalFBs)
+{
+    BlitType type;
+    switch (srcTarget) {
+    case LOCAL_GL_TEXTURE_2D:
+        type = BlitTex2D;
+        break;
+    case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
+        type = BlitTexRect;
+        break;
+    default:
+        MOZ_CRASH("GFX: Fatal Error: Bad `srcTarget`.");
+        break;
+    }
+
+    ScopedGLDrawState autoStates(mGL);
+    const ScopedBindFramebuffer bindFB(mGL);
+    if (internalFBs) {
+        mGL->Screen()->BindFB_Internal(destFB);
+    } else {
+        mGL->BindFB(destFB);
+    }
+
+    // Does destructive things to (only!) what we just saved above.
+    bool good = UseTexQuadProgram(type, srcSize);
+    if (!good) {
+        // We're up against the wall, so bail.
+        MOZ_DIAGNOSTIC_ASSERT(false,
+                              "Error: Failed to prepare to blit texture->framebuffer.\n");
+        mGL->fScissor(0, 0, destSize.width, destSize.height);
+        mGL->fColorMask(1, 1, 1, 1);
+        mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
+        return;
+    }
+
+    const ScopedBindTexture bindTex(mGL, srcTex, srcTarget);
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
 }
 
 void
-GLBlitHelper::BlitFramebufferToTexture(GLuint destTex,
+GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
                                        const gfx::IntSize& srcSize,
                                        const gfx::IntSize& destSize,
-                                       GLenum destTarget) const
+                                       GLenum destTarget,
+                                       bool internalFBs)
 {
+    // On the Android 4.3 emulator, IsFramebuffer may return false incorrectly.
+    MOZ_ASSERT_IF(mGL->Renderer() != GLRenderer::AndroidEmulator, !srcFB || mGL->fIsFramebuffer(srcFB));
     MOZ_ASSERT(mGL->fIsTexture(destTex));
 
     if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
-        const ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
-        const ScopedBindFramebuffer bindFB(mGL);
-        mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destWrapper.FB());
-        BlitFramebuffer(srcSize, destSize);
+        ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
+
+        BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(),
+                                     srcSize, destSize,
+                                     internalFBs);
         return;
     }
 
     ScopedBindTexture autoTex(mGL, destTex, destTarget);
+
+    ScopedBindFramebuffer boundFB(mGL);
+    if (internalFBs) {
+        mGL->Screen()->BindFB_Internal(srcFB);
+    } else {
+        mGL->BindFB(srcFB);
+    }
+
     ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
     mGL->fCopyTexSubImage2D(destTarget, 0,
-                            0, 0,
-                            0, 0,
-                            srcSize.width, srcSize.height);
+                       0, 0,
+                       0, 0,
+                       srcSize.width, srcSize.height);
 }
 
 void
 GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex,
                                    const gfx::IntSize& srcSize,
                                    const gfx::IntSize& destSize,
-                                   GLenum srcTarget, GLenum destTarget) const
+                                   GLenum srcTarget, GLenum destTarget)
 {
     MOZ_ASSERT(mGL->fIsTexture(srcTex));
     MOZ_ASSERT(mGL->fIsTexture(destTex));
 
-    // Start down the CopyTexSubImage path, not the DrawBlit path.
-    const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
-    const ScopedBindFramebuffer bindFB(mGL, srcWrapper.FB());
-    BlitFramebufferToTexture(destTex, srcSize, destSize, destTarget);
+    // Generally, just use the CopyTexSubImage path
+    ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
+
+    BlitFramebufferToTexture(srcWrapper.FB(), destTex,
+                             srcSize, destSize, destTarget);
 }
 
 } // namespace gl
 } // namespace mozilla
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -5,202 +5,160 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GLBLITHELPER_H_
 #define GLBLITHELPER_H_
 
 #include "GLContextTypes.h"
 #include "GLConsts.h"
 #include "nsSize.h"
-#include "ipc/IPCMessageUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/gfx/Point.h"
-#include "../layers/ImageTypes.h"
-
-#ifdef XP_WIN
-#include <windows.h>
-#endif
 
 namespace mozilla {
 
 namespace layers {
-class D3D11YCbCrImage;
 class Image;
-class GPUVideoImage;
 class PlanarYCbCrImage;
 class SurfaceTextureImage;
 class MacIOSurfaceImage;
 class EGLImageImage;
-class SurfaceDescriptorD3D10;
-class SurfaceDescriptorDXGIYCbCr;
 } // namespace layers
 
 namespace gl {
 
-class BindAnglePlanes;
 class GLContext;
 
-bool
-GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
-              gfx::IntSize* const out_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_uColorMatrix;
-
-public:
-    struct Key final {
-        const char* fragHeader;
-        const char* 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;
-        bool yFlip;
-        gfx::IntRect srcRect;
-        gfx::IntSize texSize0;
-    };
-    struct YUVArgs final {
-        gfx::IntSize texSize1;
-        gfx::IntSize divisors;
-        YUVColorSpace colorSpace;
-    };
-
-    void Draw(const BaseArgs& args, const YUVArgs* argsYUV = nullptr) const;
-};
-
-class ScopedSaveMultiTex final
-{
-    GLContext& mGL;
-    const uint8_t mTexCount;
-    const GLenum mTexTarget;
-    const GLuint mOldTexUnit;
-    GLuint mOldTexSampler[3];
-    GLuint mOldTex[3];
-
-public:
-    ScopedSaveMultiTex(GLContext* gl, uint8_t texCount, GLenum texTarget);
-    ~ScopedSaveMultiTex();
-};
-
 /** Buffer blitting helper */
 class GLBlitHelper final
 {
-    friend class BindAnglePlanes;
-    friend class DrawBlitProg;
-    friend class GLContext;
+    enum Channel
+    {
+        Channel_Y = 0,
+        Channel_Cb,
+        Channel_Cr,
+        Channel_Max,
+    };
 
-    GLContext* const mGL;
-    mutable std::map<DrawBlitProg::Key, const DrawBlitProg*> mDrawBlitProgs;
-
-    GLuint mQuadVAO;
-    nsCString mDrawBlitProg_VersionLine;
-    const GLuint mDrawBlitProg_VertShader;
+    /**
+     * BlitTex2D is used to copy blit the content of a GL_TEXTURE_2D object,
+     * BlitTexRect is used to copy blit the content of a GL_TEXTURE_RECT object,
+     * The difference between BlitTex2D and BlitTexRect is the texture type, which affect
+     * the fragment shader a bit.
+     *
+     * ConvertPlnarYcbCr is used to color convert copy blit the PlanarYCbCrImage
+     * into a normal RGB texture by create textures of each color channel, and
+     * convert it in GPU.
+     * Convert type is created for canvas.
+     */
+    enum BlitType
+    {
+        BlitTex2D,
+        BlitTexRect,
+        ConvertPlanarYCbCr,
+        ConvertSurfaceTexture,
+        ConvertEGLImage,
+        ConvertMacIOSurfaceImage
+    };
+    // The GLContext is the sole owner of the GLBlitHelper.
+    GLContext* mGL;
 
-    GLuint mYuvUploads[3];
-    gfx::IntSize mYuvUploads_YSize;
-    gfx::IntSize mYuvUploads_UVSize;
+    GLuint mTexBlit_Buffer;
+    GLuint mTexBlit_VertShader;
+    GLuint mTex2DBlit_FragShader;
+    GLuint mTex2DRectBlit_FragShader;
+    GLuint mTex2DBlit_Program;
+    GLuint mTex2DRectBlit_Program;
 
-#ifdef XP_WIN
-    mutable RefPtr<ID3D11Device> mD3D11;
+    GLint mYFlipLoc;
+
+    GLint mTextureTransformLoc;
 
-    ID3D11Device* GetD3D11() const;
-#endif
+    // Data for image blit path
+    GLuint mTexExternalBlit_FragShader;
+    GLuint mTexYUVPlanarBlit_FragShader;
+    GLuint mTexNV12PlanarBlit_FragShader;
+    GLuint mTexExternalBlit_Program;
+    GLuint mTexYUVPlanarBlit_Program;
+    GLuint mTexNV12PlanarBlit_Program;
+    GLuint mFBO;
+    GLuint mSrcTexY;
+    GLuint mSrcTexCb;
+    GLuint mSrcTexCr;
+    GLuint mSrcTexEGL;
+    GLint mYTexScaleLoc;
+    GLint mCbCrTexScaleLoc;
+    GLint mYuvColorMatrixLoc;
+    int mTexWidth;
+    int mTexHeight;
 
-    const DrawBlitProg* GetDrawBlitProg(const DrawBlitProg::Key& key) const;
-private:
-    const DrawBlitProg* CreateDrawBlitProg(const DrawBlitProg::Key& key) const;
-public:
+    // Cache some uniform values
+    float mCurYScale;
+    float mCurCbCrScale;
+
+    void UseBlitProgram();
+    void SetBlitFramebufferForDestTexture(GLuint aTexture);
 
-    bool BlitImage(layers::PlanarYCbCrImage* yuvImage, const gfx::IntSize& destSize,
-                   OriginPos destOrigin);
+    bool UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize);
+    bool InitTexQuadProgram(BlitType target = BlitTex2D);
+    void DeleteTexBlitProgram();
+    void BindAndUploadYUVTexture(Channel which, uint32_t width, uint32_t height, void* data, bool allocation);
+    void BindAndUploadEGLImage(EGLImage image, GLuint target);
+
+    bool BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage);
 #ifdef MOZ_WIDGET_ANDROID
     // Blit onto the current FB.
-    bool BlitImage(layers::SurfaceTextureImage* stImage, const gfx::IntSize& destSize,
-                   OriginPos destOrigin) const;
-    bool BlitImage(layers::EGLImageImage* eglImage, const gfx::IntSize& destSize,
-                   OriginPos destOrigin) const;
+    bool BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage);
+    bool BlitEGLImageImage(layers::EGLImageImage* eglImage);
 #endif
 #ifdef XP_MACOSX
-    bool BlitImage(layers::MacIOSurfaceImage* srcImage, const gfx::IntSize& destSize,
-                   OriginPos destOrigin) const;
+    bool BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage);
 #endif
 
     explicit GLBlitHelper(GLContext* gl);
+
+    friend class GLContext;
+
 public:
     ~GLBlitHelper();
 
-    void BlitFramebuffer(const gfx::IntSize& srcSize,
-                         const gfx::IntSize& destSize) const;
+    // If you don't have |srcFormats| for the 2nd definition,
+    // then you'll need the framebuffer_blit extensions to use
+    // the first BlitFramebufferToFramebuffer.
+    void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
+                                      const gfx::IntSize& srcSize,
+                                      const gfx::IntSize& destSize,
+                                      bool internalFBs = false);
     void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
                                       const gfx::IntSize& srcSize,
-                                      const gfx::IntSize& destSize) const;
-    void BlitFramebufferToTexture(GLuint destTex, const gfx::IntSize& srcSize,
+                                      const gfx::IntSize& destSize,
+                                      const GLFormats& srcFormats,
+                                      bool internalFBs = false);
+    void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
+                                  const gfx::IntSize& srcSize,
                                   const gfx::IntSize& destSize,
-                                  GLenum destTarget = LOCAL_GL_TEXTURE_2D) const;
-    void BlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize,
+                                  GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
+                                  bool internalFBs = false);
+    void DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
+                                      const gfx::IntSize& srcSize,
+                                      const gfx::IntSize& destSize,
+                                      GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
+                                      bool internalFBs = false);
+    void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
+                                  const gfx::IntSize& srcSize,
                                   const gfx::IntSize& destSize,
-                                  GLenum srcTarget = LOCAL_GL_TEXTURE_2D) const;
+                                  GLenum destTarget = LOCAL_GL_TEXTURE_2D,
+                                  bool internalFBs = false);
     void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
                               const gfx::IntSize& srcSize,
                               const gfx::IntSize& destSize,
                               GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
-                              GLenum destTarget = LOCAL_GL_TEXTURE_2D) const;
-
-
-    void DrawBlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize,
-                                      const gfx::IntSize& destSize,
-                                      GLenum srcTarget = LOCAL_GL_TEXTURE_2D) const;
-
+                              GLenum destTarget = LOCAL_GL_TEXTURE_2D);
     bool BlitImageToFramebuffer(layers::Image* srcImage, const gfx::IntSize& destSize,
-                                OriginPos destOrigin);
-
-private:
-#ifdef XP_WIN
-    // GLBlitHelperD3D.cpp:
-    bool BlitImage(layers::GPUVideoImage* srcImage, const gfx::IntSize& destSize,
-                   OriginPos destOrigin) const;
-    bool BlitImage(layers::D3D11YCbCrImage* srcImage, const gfx::IntSize& destSize,
-                   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;
-
-    bool BlitAnglePlanes(uint8_t numPlanes, const RefPtr<ID3D11Texture2D>* texD3DList,
-                         const DrawBlitProg* prog, const DrawBlitProg::BaseArgs& baseArgs,
-                         const DrawBlitProg::YUVArgs* const yuvArgs) const;
-#endif
+                                GLuint destFB, OriginPos destOrigin);
+    bool BlitImageToTexture(layers::Image* srcImage, const gfx::IntSize& destSize,
+                            GLuint destTex, GLenum destTarget, OriginPos destOrigin);
 };
 
-extern const char* const kFragHeader_Tex2D;
-extern const char* const kFragHeader_Tex2DRect;
-extern const char* const kFragHeader_TexExt;
-extern const char* const kFragBody_RGBA;
-extern const char* const kFragBody_CrYCb;
-extern const char* const kFragBody_NV12;
-extern const char* const kFragBody_PlanarYUV;
-
 } // namespace gl
 } // namespace mozilla
 
 #endif // GLBLITHELPER_H_
deleted file mode 100644
--- a/gfx/gl/GLBlitHelperD3D.cpp
+++ /dev/null
@@ -1,334 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set ts=8 sts=4 et sw=4 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "GLBlitHelper.h"
-
-#include <d3d11.h>
-
-#include "GLContext.h"
-#include "GLLibraryEGL.h"
-#include "GPUVideoImage.h"
-#include "ScopedGLHelpers.h"
-
-#include "mozilla/layers/D3D11YCbCrImage.h"
-#include "mozilla/layers/TextureD3D11.h"
-
-namespace mozilla {
-namespace gl {
-
-static EGLStreamKHR
-StreamFromD3DTexture(ID3D11Texture2D* const texD3D,
-                     const EGLAttrib* const postAttribs)
-{
-    auto& egl = sEGLLibrary;
-    const auto& display = egl.Display();
-    const auto stream = egl.fCreateStreamKHR(display, nullptr);
-    MOZ_ASSERT(stream);
-    if (!stream)
-        return 0;
-    bool ok = true;
-    MOZ_ALWAYS_TRUE( ok &= bool(egl.fStreamConsumerGLTextureExternalAttribsNV(display,
-                                                                              stream,
-                                                                              nullptr)) );
-    MOZ_ALWAYS_TRUE( ok &= bool(egl.fCreateStreamProducerD3DTextureNV12ANGLE(display,
-                                                                             stream,
-                                                                             nullptr)) );
-    MOZ_ALWAYS_TRUE( ok &= bool(egl.fStreamPostD3DTextureNV12ANGLE(display, stream,
-                                                                   texD3D,
-                                                                   postAttribs)) );
-    if (ok)
-        return stream;
-
-    (void)egl.fDestroyStreamKHR(display, stream);
-    return 0;
-}
-
-static RefPtr<ID3D11Texture2D>
-OpenSharedTexture(ID3D11Device* const d3d, const WindowsHandle handle)
-{
-    RefPtr<ID3D11Texture2D> tex;
-    auto hr = d3d->OpenSharedResource((HANDLE)handle, __uuidof(ID3D11Texture2D),
-                                      (void**)(ID3D11Texture2D**)getter_AddRefs(tex));
-    if (FAILED(hr)) {
-        MOZ_ASSERT(false, "OpenSharedResource should not fail");
-        return nullptr;
-    }
-    return tex;
-}
-
-// -------------------------------------
-
-class BindAnglePlanes final
-{
-    const GLBlitHelper& mParent;
-    const uint8_t mNumPlanes;
-    const ScopedSaveMultiTex mMultiTex;
-    GLuint mTempTexs[3];
-    EGLStreamKHR mStreams[3];
-    RefPtr<IDXGIKeyedMutex> mMutexList[3];
-    bool mSuccess;
-
-public:
-    BindAnglePlanes(const GLBlitHelper* const parent, const uint8_t numPlanes,
-                    const RefPtr<ID3D11Texture2D>* const texD3DList,
-                    const EGLAttrib* const* postAttribsList = nullptr)
-        : mParent(*parent)
-        , mNumPlanes(numPlanes)
-        , mMultiTex(mParent.mGL, mNumPlanes, LOCAL_GL_TEXTURE_EXTERNAL)
-        , mTempTexs{0}
-        , mStreams{0}
-        , mSuccess(true)
-    {
-        MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3);
-
-        const auto& gl = mParent.mGL;
-        auto& egl = sEGLLibrary;
-        const auto& display = egl.Display();
-
-        gl->fGenTextures(numPlanes, mTempTexs);
-
-        for (uint8_t i = 0; i < mNumPlanes; i++) {
-            gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
-            gl->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTempTexs[i]);
-            const EGLAttrib* postAttribs = nullptr;
-            if (postAttribsList) {
-                postAttribs = postAttribsList[i];
-            }
-            mStreams[i] = StreamFromD3DTexture(texD3DList[i], postAttribs);
-            mSuccess &= bool(mStreams[i]);
-        }
-
-        if (mSuccess) {
-            for (uint8_t i = 0; i < mNumPlanes; i++) {
-                MOZ_ALWAYS_TRUE( egl.fStreamConsumerAcquireKHR(display, mStreams[i]) );
-
-                auto& mutex = mMutexList[i];
-                texD3DList[i]->QueryInterface(_uuidof(IDXGIKeyedMutex),
-                                              (void**)getter_AddRefs(mutex));
-                if (mutex) {
-                    const auto hr = mutex->AcquireSync(0, 100);
-                    if (FAILED(hr)) {
-                        NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex.");
-                        mSuccess = false;
-                    }
-                }
-            }
-        }
-    }
-
-    ~BindAnglePlanes()
-    {
-        const auto& gl = mParent.mGL;
-        auto& egl = sEGLLibrary;
-        const auto& display = egl.Display();
-
-        if (mSuccess) {
-            for (uint8_t i = 0; i < mNumPlanes; i++) {
-                MOZ_ALWAYS_TRUE( egl.fStreamConsumerReleaseKHR(display, mStreams[i]) );
-                if (mMutexList[i]) {
-                    mMutexList[i]->ReleaseSync(0);
-                }
-            }
-        }
-
-        for (uint8_t i = 0; i < mNumPlanes; i++) {
-            (void)egl.fDestroyStreamKHR(display, mStreams[i]);
-        }
-
-        gl->fDeleteTextures(mNumPlanes, mTempTexs);
-    }
-
-    const bool& Success() const { return mSuccess; }
-};
-
-// -------------------------------------
-
-ID3D11Device*
-GLBlitHelper::GetD3D11() const
-{
-    if (mD3D11)
-        return mD3D11;
-
-    if (!mGL->IsANGLE())
-        return nullptr;
-
-    auto& egl = sEGLLibrary;
-    EGLDeviceEXT deviceEGL = 0;
-    MOZ_ALWAYS_TRUE( egl.fQueryDisplayAttribEXT(egl.Display(), LOCAL_EGL_DEVICE_EXT,
-                                                (EGLAttrib*)&deviceEGL) );
-    if (!egl.fQueryDeviceAttribEXT(deviceEGL, LOCAL_EGL_D3D11_DEVICE_ANGLE,
-                                   (EGLAttrib*)(ID3D11Device**)getter_AddRefs(mD3D11)))
-    {
-        MOZ_ASSERT(false, "d3d9?");
-        return nullptr;
-    }
-    return mD3D11;
-}
-
-// -------------------------------------
-
-bool
-GLBlitHelper::BlitImage(layers::GPUVideoImage* const srcImage,
-                        const gfx::IntSize& destSize, const OriginPos destOrigin) const
-{
-    const auto& data = srcImage->GetData();
-    if (!data)
-        return false;
-
-    const auto& desc = data->SD();
-    const auto& subdescUnion = desc.subdesc();
-    switch (subdescUnion.type()) {
-    case subdescUnion.TSurfaceDescriptorD3D10:
-        {
-            const auto& subdesc = subdescUnion.get_SurfaceDescriptorD3D10();
-            return BlitDescriptor(subdesc, destSize, destOrigin);
-        }
-    case subdescUnion.TSurfaceDescriptorDXGIYCbCr:
-        {
-            const auto& subdesc = subdescUnion.get_SurfaceDescriptorDXGIYCbCr();
-
-            const auto& clipSize = subdesc.size();
-            const auto& ySize = subdesc.sizeY();
-            const auto& uvSize = subdesc.sizeCbCr();
-
-            const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
-            const auto colorSpace = YUVColorSpace::BT601;
-
-            const WindowsHandle handles[3] = {
-                subdesc.handleY(),
-                subdesc.handleCb(),
-                subdesc.handleCr()
-            };
-            return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destSize,
-                                  destOrigin);
-        }
-    default:
-        gfxCriticalError() << "Unhandled subdesc type: " << uint32_t(subdescUnion.type());
-        return false;
-    }
-}
-
-// -------------------------------------
-
-bool
-GLBlitHelper::BlitImage(layers::D3D11YCbCrImage* const srcImage,
-                        const gfx::IntSize& destSize, const OriginPos destOrigin) const
-{
-    const auto& data = srcImage->GetData();
-    if (!data)
-        return false;
-
-    const auto& clipRect = srcImage->mPictureRect;
-    const auto& colorSpace = srcImage->mColorSpace;
-
-    const WindowsHandle handles[3] = {
-        (WindowsHandle)data->mHandles[0],
-        (WindowsHandle)data->mHandles[1],
-        (WindowsHandle)data->mHandles[2]
-    };
-    return BlitAngleYCbCr(handles, srcImage->mPictureRect, srcImage->mYSize,
-                          srcImage->mCbCrSize, srcImage->mColorSpace, destSize,
-                          destOrigin);
-}
-
-// -------------------------------------
-
-bool
-GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
-                             const gfx::IntSize& destSize, 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();
-
-    const auto srcOrigin = OriginPos::BottomLeft;
-    const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
-    const auto colorSpace = YUVColorSpace::BT601;
-
-    if (format != gfx::SurfaceFormat::NV12) {
-        gfxCriticalError() << "Non-NV12 format for SurfaceDescriptorD3D10: "
-                           << uint32_t(format);
-        return nullptr;
-    }
-
-    const auto tex = OpenSharedTexture(d3d, handle);
-    const RefPtr<ID3D11Texture2D> texList[2] = { tex, tex };
-    const EGLAttrib postAttribs0[] = {
-        LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0,
-        LOCAL_EGL_NONE
-    };
-    const EGLAttrib postAttribs1[] = {
-        LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1,
-        LOCAL_EGL_NONE
-    };
-    const EGLAttrib* const postAttribsList[2] = { postAttribs0, postAttribs1 };
-    // /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12.
-    //return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin);
-
-    const BindAnglePlanes bindPlanes(this, 2, texList, postAttribsList);
-
-    D3D11_TEXTURE2D_DESC texDesc = {0};
-    tex->GetDesc(&texDesc);
-
-    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 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 auto& d3d = GetD3D11();
-    if (!d3d)
-        return false;
-
-    const auto srcOrigin = OriginPos::BottomLeft;
-
-    gfx::IntSize divisors;
-    if (!GuessDivisors(ySize, uvSize, &divisors))
-        return false;
-
-    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 auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_PlanarYUV});
-    MOZ_RELEASE_ASSERT(prog);
-    prog->Draw(baseArgs, &yuvArgs);
-    return true;
-}
-
-} // namespace gl
-} // namespace mozilla
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -1412,32 +1412,16 @@ public:
 
     realGLboolean fIsEnabled(GLenum capability) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsEnabled(capability);
         AFTER_GL_CALL;
         return retval;
     }
 
-    void SetEnabled(const GLenum cap, const bool val) {
-        if (val) {
-            fEnable(cap);
-        } else {
-            fDisable(cap);
-        }
-    }
-
-    bool PushEnabled(const GLenum cap, const bool newVal) {
-        const bool oldVal = fIsEnabled(cap);
-        if (oldVal != newVal) {
-            SetEnabled(cap, newVal);
-        }
-        return oldVal;
-    }
-
     realGLboolean fIsProgram(GLuint program) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsProgram(program);
         AFTER_GL_CALL;
         return retval;
     }
 
     realGLboolean fIsShader(GLuint shader) {
--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -109,17 +109,17 @@ public:
                                      const SurfaceCaps& minCaps,
                                      nsACString* const out_FailureId);
 
 protected:
     friend class GLContextProviderEGL;
     friend class GLContextEGLFactory;
 
 public:
-    const EGLConfig mConfig;
+    const EGLConfig  mConfig;
 protected:
     EGLSurface mSurface;
 public:
     const EGLContext mContext;
 protected:
     EGLSurface mSurfaceOverride;
     RefPtr<gfxASurface> mThebesSurface;
     bool mBound;
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -605,17 +605,16 @@ GLLibraryEGL::EnsureInitialized(bool for
         if (!fnLoadSymbols(streamSymbols)) {
             NS_ERROR("EGL supports KHR_stream without exposing its functions!");
             MarkExtensionUnsupported(KHR_stream);
         }
     }
 
     if (IsExtensionSupported(KHR_stream_consumer_gltexture)) {
         const GLLibraryLoader::SymLoadStruct streamConsumerSymbols[] = {
-            SYMBOL(StreamConsumerGLTextureExternalKHR),
             SYMBOL(StreamConsumerAcquireKHR),
             SYMBOL(StreamConsumerReleaseKHR),
             END_OF_SYMBOLS
         };
         if (!fnLoadSymbols(streamConsumerSymbols)) {
             NS_ERROR("EGL supports KHR_stream_consumer_gltexture without exposing its functions!");
             MarkExtensionUnsupported(KHR_stream_consumer_gltexture);
         }
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -295,19 +295,16 @@ public:
 
     EGLBoolean  fDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) const
         WRAP(   fDestroyStreamKHR(dpy, stream) )
 
     EGLBoolean  fQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint* value) const
         WRAP(   fQueryStreamKHR(dpy, stream, attribute, value) )
 
     // KHR_stream_consumer_gltexture
-    EGLBoolean  fStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) const
-        WRAP(   fStreamConsumerGLTextureExternalKHR(dpy, stream) )
-
     EGLBoolean  fStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) const
         WRAP(   fStreamConsumerAcquireKHR(dpy, stream) )
 
     EGLBoolean  fStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) const
         WRAP(   fStreamConsumerReleaseKHR(dpy, stream) )
 
     // EXT_device_query
     EGLBoolean  fQueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, EGLAttrib* value) const
@@ -465,18 +462,16 @@ private:
         //KHR_stream
         EGLStreamKHR (GLAPIENTRY * fCreateStreamKHR)(EGLDisplay dpy, const EGLint* attrib_list);
         EGLBoolean (GLAPIENTRY * fDestroyStreamKHR)(EGLDisplay dpy, EGLStreamKHR stream);
         EGLBoolean (GLAPIENTRY * fQueryStreamKHR)(EGLDisplay dpy,
                                                   EGLStreamKHR stream,
                                                   EGLenum attribute,
                                                   EGLint* value);
         // KHR_stream_consumer_gltexture
-        EGLBoolean (GLAPIENTRY * fStreamConsumerGLTextureExternalKHR)(EGLDisplay dpy,
-                                                                      EGLStreamKHR stream);
         EGLBoolean (GLAPIENTRY * fStreamConsumerAcquireKHR)(EGLDisplay dpy,
                                                             EGLStreamKHR stream);
         EGLBoolean (GLAPIENTRY * fStreamConsumerReleaseKHR)(EGLDisplay dpy,
                                                             EGLStreamKHR stream);
         // EXT_device_query
         EGLBoolean (GLAPIENTRY * fQueryDisplayAttribEXT)(EGLDisplay dpy,
                                                          EGLint attribute,
                                                          EGLAttrib* value);
--- a/gfx/gl/HeapCopyOfStackArray.h
+++ b/gfx/gl/HeapCopyOfStackArray.h
@@ -18,17 +18,17 @@ namespace mozilla {
 // Useful to retain the convenience of declaring static arrays, while
 // avoiding passing stack pointers to the GL (see bug 1005658).
 
 template <typename ElemType>
 class HeapCopyOfStackArray
 {
 public:
   template<size_t N>
-  MOZ_IMPLICIT HeapCopyOfStackArray(const ElemType (&array)[N])
+  MOZ_IMPLICIT HeapCopyOfStackArray(ElemType (&array)[N])
     : mArrayLength(N)
     , mArrayData(MakeUnique<ElemType[]>(N))
   {
     memcpy(mArrayData.get(), &array[0], N * sizeof(ElemType));
   }
 
   ElemType* Data() const { return mArrayData.get(); }
   size_t ArrayLength() const { return mArrayLength; }
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -418,16 +418,85 @@ ScopedVertexAttribPointer::UnwrapImpl()
     mGL->fVertexAttribPointer(mAttribIndex, mAttribSize, mAttribType, mAttribNormalized, mAttribStride, mAttribPointer);
     if (mAttribEnabled)
         mGL->fEnableVertexAttribArray(mAttribIndex);
     else
         mGL->fDisableVertexAttribArray(mAttribIndex);
     mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundBuffer);
 }
 
+ScopedGLDrawState::ScopedGLDrawState(GLContext* aGL)
+    : blend       (aGL, LOCAL_GL_BLEND,      false)
+    , cullFace    (aGL, LOCAL_GL_CULL_FACE,  false)
+    , depthTest   (aGL, LOCAL_GL_DEPTH_TEST, false)
+    , dither      (aGL, LOCAL_GL_DITHER,     false)
+    , polyOffsFill(aGL, LOCAL_GL_POLYGON_OFFSET_FILL,      false)
+    , sampleAToC  (aGL, LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false)
+    , sampleCover (aGL, LOCAL_GL_SAMPLE_COVERAGE, false)
+    , scissor     (aGL, LOCAL_GL_SCISSOR_TEST,    false)
+    , stencil     (aGL, LOCAL_GL_STENCIL_TEST,    false)
+    , mGL(aGL)
+{
+    mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram);
+    mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer);
+    mGL->GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &maxAttrib);
+    attrib_enabled = MakeUnique<GLint[]>(maxAttrib);
+
+    for (GLuint i = 0; i < maxAttrib; i++) {
+        mGL->fGetVertexAttribiv(i, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib_enabled[i]);
+        mGL->fDisableVertexAttribArray(i);
+    }
+    // Only Attrib0's client side state affected
+    mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib0_size);
+    mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib0_stride);
+    mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib0_type);
+    mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib0_normalized);
+    mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &attrib0_bufferBinding);
+    mGL->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib0_pointer);
+    mGL->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask);
+    mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
+    mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, scissorBox);
+}
+
+ScopedGLDrawState::~ScopedGLDrawState()
+{
+    MOZ_ASSERT(mGL->IsCurrent());
+
+    mGL->fScissor(scissorBox[0], scissorBox[1],
+                  scissorBox[2], scissorBox[3]);
+
+    mGL->fViewport(viewport[0], viewport[1],
+                   viewport[2], viewport[3]);
+
+    mGL->fColorMask(colorMask[0],
+                    colorMask[1],
+                    colorMask[2],
+                    colorMask[3]);
+
+    for (unsigned int i = 0; i < maxAttrib; i++) {
+        if (attrib_enabled[i])
+            mGL->fEnableVertexAttribArray(i);
+        else
+            mGL->fDisableVertexAttribArray(i);
+    }
+
+
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0_bufferBinding);
+    mGL->fVertexAttribPointer(0,
+                              attrib0_size,
+                              attrib0_type,
+                              attrib0_normalized,
+                              attrib0_stride,
+                              attrib0_pointer);
+
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer);
+
+    mGL->fUseProgram(boundProgram);
+}
+
 ////////////////////////////////////////////////////////////////////////
 // ScopedPackState
 
 ScopedPackState::ScopedPackState(GLContext* gl)
     : ScopedGLWrapper<ScopedPackState>(gl)
 {
     mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment);
 
--- a/gfx/gl/ScopedGLHelpers.h
+++ b/gfx/gl/ScopedGLHelpers.h
@@ -117,19 +117,17 @@ struct ScopedTexture
 {
     friend struct ScopedGLWrapper<ScopedTexture>;
 
 protected:
     GLuint mTexture;
 
 public:
     explicit ScopedTexture(GLContext* aGL);
-
-    GLuint Texture() const { return mTexture; }
-    operator GLuint() const { return mTexture; }
+    GLuint Texture() { return mTexture; }
 
 protected:
     void UnwrapImpl();
 };
 
 
 struct ScopedFramebuffer
     : public ScopedGLWrapper<ScopedFramebuffer>
@@ -306,16 +304,49 @@ public:
                               GLsizei stride, GLuint buffer, const GLvoid* pointer);
     explicit ScopedVertexAttribPointer(GLContext* aGL, GLuint index);
 
 protected:
     void WrapImpl(GLuint index);
     void UnwrapImpl();
 };
 
+struct ScopedGLDrawState
+{
+    explicit ScopedGLDrawState(GLContext* gl);
+    ~ScopedGLDrawState();
+
+    GLuint boundProgram;
+    GLuint boundBuffer;
+
+    ScopedGLState blend;
+    ScopedGLState cullFace;
+    ScopedGLState depthTest;
+    ScopedGLState dither;
+    ScopedGLState polyOffsFill;
+    ScopedGLState sampleAToC;
+    ScopedGLState sampleCover;
+    ScopedGLState scissor;
+    ScopedGLState stencil;
+
+    GLuint maxAttrib;
+    UniquePtr<GLint[]> attrib_enabled;
+    GLint attrib0_size;
+    GLint attrib0_stride;
+    GLint attrib0_type;
+    GLint attrib0_normalized;
+    GLint attrib0_bufferBinding;
+    void* attrib0_pointer;
+
+    realGLboolean colorMask[4];
+    GLint viewport[4];
+    GLint scissorBox[4];
+    GLContext* const mGL;
+};
+
 struct ScopedPackState
     : public ScopedGLWrapper<ScopedPackState>
 {
     friend struct ScopedGLWrapper<ScopedPackState>;
 
 protected:
     GLint mAlignment;
 
--- a/gfx/gl/SharedSurface.cpp
+++ b/gfx/gl/SharedSurface.cpp
@@ -60,30 +60,30 @@ SharedSurface::ProdCopy(SharedSurface* s
             src->LockProd();
             srcNeedsUnlock = true;
         }
 
         if (dest->mAttachType == AttachmentType::GLTexture) {
             GLuint destTex = dest->ProdTexture();
             GLenum destTarget = dest->ProdTextureTarget();
 
-            const ScopedBindFramebuffer bindFB(gl, 0);
-
-            gl->BlitHelper()->BlitFramebufferToTexture(destTex,
+            gl->BlitHelper()->BlitFramebufferToTexture(0, destTex,
                                                        src->mSize,
                                                        dest->mSize,
-                                                       destTarget);
+                                                       destTarget,
+                                                       true);
         } else if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
             GLuint destRB = dest->ProdRenderbuffer();
             ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
 
             gl->BlitHelper()->BlitFramebufferToFramebuffer(0,
                                                            destWrapper.FB(),
                                                            src->mSize,
-                                                           dest->mSize);
+                                                           dest->mSize,
+                                                           true);
         } else {
             MOZ_CRASH("GFX: Unhandled dest->mAttachType 1.");
         }
 
         if (srcNeedsUnlock)
             src->UnlockProd();
 
         if (origNeedsRelock)
@@ -105,30 +105,30 @@ SharedSurface::ProdCopy(SharedSurface* s
             dest->LockProd();
             destNeedsUnlock = true;
         }
 
         if (src->mAttachType == AttachmentType::GLTexture) {
             GLuint srcTex = src->ProdTexture();
             GLenum srcTarget = src->ProdTextureTarget();
 
-            const ScopedBindFramebuffer bindFB(gl, 0);
-
-            gl->BlitHelper()->BlitTextureToFramebuffer(srcTex,
+            gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, 0,
                                                        src->mSize,
                                                        dest->mSize,
-                                                       srcTarget);
+                                                       srcTarget,
+                                                       !!gl->Screen());
         } else if (src->mAttachType == AttachmentType::GLRenderbuffer) {
             GLuint srcRB = src->ProdRenderbuffer();
             ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
 
             gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(),
                                                            0,
                                                            src->mSize,
-                                                           dest->mSize);
+                                                           dest->mSize,
+                                                           true);
         } else {
             MOZ_CRASH("GFX: Unhandled src->mAttachType 2.");
         }
 
         if (destNeedsUnlock)
             dest->UnlockProd();
 
         if (origNeedsRelock)
@@ -153,37 +153,36 @@ SharedSurface::ProdCopy(SharedSurface* s
                                                    srcTarget, destTarget);
 
             return;
         }
 
         if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
             GLuint destRB = dest->ProdRenderbuffer();
             ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
-            const ScopedBindFramebuffer bindFB(gl, destWrapper.FB());
-            gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, src->mSize, dest->mSize,
-                                                       srcTarget);
+
+            gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, destWrapper.FB(),
+                                                       src->mSize, dest->mSize, srcTarget);
 
             return;
         }
 
         MOZ_CRASH("GFX: Unhandled dest->mAttachType 3.");
     }
 
     if (src->mAttachType == AttachmentType::GLRenderbuffer) {
         GLuint srcRB = src->ProdRenderbuffer();
         ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
 
         if (dest->mAttachType == AttachmentType::GLTexture) {
             GLuint destTex = dest->ProdTexture();
             GLenum destTarget = dest->ProdTextureTarget();
-            const ScopedBindFramebuffer bindFB(gl, srcWrapper.FB());
 
-            gl->BlitHelper()->BlitFramebufferToTexture(destTex, src->mSize, dest->mSize,
-                                                       destTarget);
+            gl->BlitHelper()->BlitFramebufferToTexture(srcWrapper.FB(), destTex,
+                                                       src->mSize, dest->mSize, destTarget);
 
             return;
         }
 
         if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
             GLuint destRB = dest->ProdRenderbuffer();
             ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
 
--- a/gfx/gl/SharedSurfaceD3D11Interop.cpp
+++ b/gfx/gl/SharedSurfaceD3D11Interop.cpp
@@ -466,18 +466,18 @@ SharedSurface_D3D11Interop::ProducerAcqu
 }
 
 void
 SharedSurface_D3D11Interop::ProducerReleaseImpl()
 {
     MOZ_ASSERT(mLockedForGL);
 
     if (mProdTex) {
-        const ScopedBindFramebuffer bindFB(mGL, mInteropFB);
-        mGL->BlitHelper()->DrawBlitTextureToFramebuffer(mProdTex, mSize, mSize);
+        mGL->BlitHelper()->DrawBlitTextureToFramebuffer(mProdTex, mInteropFB, mSize,
+                                                        mSize);
     }
 
     if (mNeedsFinish) {
         mGL->fFinish();
     } else {
         // We probably don't even need this.
         mGL->fFlush();
     }
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -64,17 +64,16 @@ if CONFIG['MOZ_X11']:
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXPORTS += [
         'GLContextWGL.h',
         'SharedSurfaceANGLE.h', # Needs <windows.h> for `HANDLE`.
         'SharedSurfaceD3D11Interop.h',
         'WGLLibrary.h',
     ]
     UNIFIED_SOURCES += [
-        'GLBlitHelperD3D.cpp',
         'GLContextProviderWGL.cpp',
         'SharedSurfaceANGLE.cpp',
         'SharedSurfaceD3D11Interop.cpp',
     ]
 if CONFIG['MOZ_ENABLE_SKIA_GPU']:
     EXPORTS += ['SkiaGLGlue.h']
     SOURCES += [
         'SkiaGLGlue.cpp',
--- a/gfx/layers/D3D11YCbCrImage.cpp
+++ b/gfx/layers/D3D11YCbCrImage.cpp
@@ -92,41 +92,32 @@ D3D11YCbCrImage::SetData(KnowsCompositor
                          aData.mCbCrStride * aData.mCbCrSize.height);
   ctx->UpdateSubresource(textureCr,
                          0,
                          nullptr,
                          aData.mCrChannel,
                          aData.mCbCrStride,
                          aData.mCbCrStride * aData.mCbCrSize.height);
 
-
+  
   return true;
 }
 
 IntSize
 D3D11YCbCrImage::GetSize()
 {
   return mPictureRect.Size();
 }
 
 TextureClient*
 D3D11YCbCrImage::GetTextureClient(KnowsCompositor* aForwarder)
 {
   return mTextureClient;
 }
 
-const DXGIYCbCrTextureData*
-D3D11YCbCrImage::GetData() const
-{
-  if (!mTextureClient)
-    return nullptr;
-
-  return static_cast<DXGIYCbCrTextureData*>(mTextureClient->GetInternalData());
-}
-
 already_AddRefed<SourceSurface>
 D3D11YCbCrImage::GetAsSourceSurface()
 {
   if (!mTextureClient) {
     gfxWarning()
       << "GetAsSourceSurface() called on uninitialized D3D11YCbCrImage.";
     return nullptr;
   }
--- a/gfx/layers/D3D11YCbCrImage.h
+++ b/gfx/layers/D3D11YCbCrImage.h
@@ -7,24 +7,20 @@
 #define GFX_D3D11_YCBCR_IMAGE_H
 
 #include "d3d11.h"
 #include "mozilla/layers/TextureClientRecycleAllocator.h"
 #include "mozilla/Maybe.h"
 #include "ImageContainer.h"
 
 namespace mozilla {
-namespace gl {
-class GLBlitHelper;
-}
 namespace layers {
 
 class ImageContainer;
 class DXGIYCbCrTextureClient;
-class DXGIYCbCrTextureData;
 
 class D3D11YCbCrRecycleAllocator : public TextureClientRecycleAllocator
 {
 public:
   explicit D3D11YCbCrRecycleAllocator(KnowsCompositor* aAllocator,
                                       ID3D11Device* aDevice)
     : TextureClientRecycleAllocator(aAllocator)
     , mDevice(aDevice)
@@ -45,17 +41,16 @@ protected:
 
   RefPtr<ID3D11Device> mDevice;
   Maybe<gfx::IntSize> mYSize;
   Maybe<gfx::IntSize> mCbCrSize;
 };
 
 class D3D11YCbCrImage : public Image
 {
-  friend class gl::GLBlitHelper;
 public:
   D3D11YCbCrImage();
   virtual ~D3D11YCbCrImage();
 
   // Copies the surface into a sharable texture's surface, and initializes
   // the image.
   bool SetData(KnowsCompositor* aAllocator,
                ImageContainer* aContainer,
@@ -65,18 +60,16 @@ public:
 
   already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
 
   TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override;
 
   gfx::IntRect GetPictureRect() override { return mPictureRect; }
 
 private:
-  const DXGIYCbCrTextureData* GetData() const;
-
   gfx::IntSize mYSize;
   gfx::IntSize mCbCrSize;
   gfx::IntRect mPictureRect;
   YUVColorSpace mColorSpace;
   RefPtr<TextureClient> mTextureClient;
 };
 
 } // namepace layers
--- a/gfx/layers/GLImages.cpp
+++ b/gfx/layers/GLImages.cpp
@@ -73,21 +73,22 @@ GLImage::GetAsSourceSurface()
 
   ScopedFramebufferForTexture autoFBForTex(sSnapshotContext, scopedTex.Texture());
   if (!autoFBForTex.IsComplete()) {
       gfxCriticalError() << "GetAsSourceSurface: ScopedFramebufferForTexture failed.";
       return nullptr;
   }
 
   const gl::OriginPos destOrigin = gl::OriginPos::TopLeft;
+
+  if (!sSnapshotContext->BlitHelper()->BlitImageToFramebuffer(this, size,
+                                                              autoFBForTex.FB(),
+                                                              destOrigin))
   {
-    const ScopedBindFramebuffer bindFB(sSnapshotContext, autoFBForTex.FB());
-    if (!sSnapshotContext->BlitHelper()->BlitImageToFramebuffer(this, size, destOrigin)) {
-      return nullptr;
-    }
+    return nullptr;
   }
 
   RefPtr<gfx::DataSourceSurface> source =
         gfx::Factory::CreateDataSourceSurface(size, gfx::SurfaceFormat::B8G8R8A8);
   if (NS_WARN_IF(!source)) {
     return nullptr;
   }
 
--- a/gfx/layers/GPUVideoImage.h
+++ b/gfx/layers/GPUVideoImage.h
@@ -11,25 +11,21 @@
 #include "mozilla/layers/GPUVideoTextureClient.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 
 namespace mozilla {
 namespace dom {
 class VideoDecoderManagerChild;
 }
-namespace gl {
-class GLBlitHelper;
-}
 namespace layers {
 
 // Image class that refers to a decoded video frame within
 // the GPU process.
 class GPUVideoImage final : public Image {
-  friend class gl::GLBlitHelper;
 public:
   GPUVideoImage(dom::VideoDecoderManagerChild* aManager,
                 const SurfaceDescriptorGPUVideo& aSD,
                 const gfx::IntSize& aSize)
     : Image(nullptr, ImageFormat::GPU_VIDEO)
     , mSize(aSize)
   {
     // Create the TextureClient immediately since the GPUVideoTextureData
@@ -44,31 +40,22 @@ public:
                                     TextureFlags::RECYCLE,
                                     ImageBridgeChild::GetSingleton().get());
   }
 
   ~GPUVideoImage() override {}
 
   gfx::IntSize GetSize() override { return mSize; }
 
-private:
-  GPUVideoTextureData* GetData() const {
+  virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override
+  {
     if (!mTextureClient) {
       return nullptr;
     }
-    return mTextureClient->GetInternalData()->AsGPUVideoTextureData();
-  }
-
-public:
-  virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override
-  {
-    GPUVideoTextureData* data = GetData();
-    if (!data) {
-      return nullptr;
-    }
+    GPUVideoTextureData* data = mTextureClient->GetInternalData()->AsGPUVideoTextureData();
     return data->GetAsSourceSurface();
   }
 
   virtual TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override
   {
     MOZ_ASSERT(aForwarder == ImageBridgeChild::GetSingleton(), "Must only use GPUVideo on ImageBridge");
     return mTextureClient;
   }
--- a/gfx/layers/client/GPUVideoTextureClient.h
+++ b/gfx/layers/client/GPUVideoTextureClient.h
@@ -43,17 +43,14 @@ public:
   {
     return this;
   }
 
 protected:
   RefPtr<dom::VideoDecoderManagerChild> mManager;
   SurfaceDescriptorGPUVideo mSD;
   gfx::IntSize mSize;
-
-public:
-  const decltype(mSD)& SD() const { return mSD; }
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // MOZILLA_GFX_GPUVIDEOTEXTURECLIENT_H
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -157,17 +157,17 @@ private:
   // The locking pattern of TextureClient may in some case upset deadlock detection
   // tools such as TSan.
   // Typically our tile rendering code will lock all of its tiles, render into them
   // and unlock them all right after that, which looks something like:
   //
   // Lock tile A
   // Lock tile B
   // Lock tile C
-  // Apply drawing commands to tiles A, B and C
+  // Apply drawing commands to tiles A, B and C 
   // Unlock tile A
   // Unlock tile B
   // Unlock tile C
   //
   // And later, we may end up rendering a tile buffer that has the same tiles,
   // in a different order, for example:
   //
   // Lock tile B
@@ -1397,28 +1397,16 @@ TextureClient::PrintInfo(std::stringstre
     RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface();
     if (dSurf) {
       aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
     }
   }
 #endif
 }
 
-void
-TextureClient::GPUVideoDesc(SurfaceDescriptorGPUVideo* const aOutDesc)
-{
-  const auto handle = GetSerial();
-
-  GPUVideoSubDescriptor subDesc = null_t();
-  MOZ_RELEASE_ASSERT(mData);
-  mData->GetSubDescriptor(&subDesc);
-
-  *aOutDesc = SurfaceDescriptorGPUVideo(handle, Move(subDesc));
-}
-
 class MemoryTextureReadLock : public NonBlockingTextureReadLock {
 public:
   MemoryTextureReadLock();
 
   ~MemoryTextureReadLock();
 
   virtual bool ReadLock() override;
 
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -261,17 +261,16 @@ public:
   virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; }
 
   virtual void Deallocate(LayersIPCChannel* aAllocator) = 0;
 
   /// Depending on the texture's flags either Deallocate or Forget is called.
   virtual void Forget(LayersIPCChannel* aAllocator) {}
 
   virtual bool Serialize(SurfaceDescriptor& aDescriptor) = 0;
-  virtual void GetSubDescriptor(GPUVideoSubDescriptor* aOutDesc) { }
 
   virtual TextureData*
   CreateSimilar(LayersIPCChannel* aAllocator,
                 LayersBackend aLayersBackend,
                 TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const { return nullptr; }
 
   virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) { return false; };
@@ -594,23 +593,22 @@ public:
   ITextureClientRecycleAllocator* GetRecycleAllocator() { return mRecycleAllocator; }
   void SetRecycleAllocator(ITextureClientRecycleAllocator* aAllocator);
 
   /// If you add new code that uses this method, you are probably doing something wrong.
   TextureData* GetInternalData() { return mData; }
   const TextureData* GetInternalData() const { return mData; }
 
   uint64_t GetSerial() const { return mSerial; }
-  void GPUVideoDesc(SurfaceDescriptorGPUVideo* aOutDesc);
 
   void CancelWaitForRecycle();
 
   /**
    * Set last transaction id of CompositableForwarder.
-   *
+   * 
    * Called when TextureClient has TextureFlags::RECYCLE flag.
    * When CompositableForwarder forwards the TextureClient with
    * TextureFlags::RECYCLE, it holds TextureClient's ref until host side
    * releases it. The host side sends TextureClient release message.
    * The id is used to check if the message is for the last TextureClient
    * forwarding.
    */
   void SetLastFwdTransactionId(uint64_t aTransactionId)
@@ -639,32 +637,32 @@ public:
   void AddPaintThreadRef();
 
   // Mark that the TextureClient is no longer in use by the PaintThread. This
   // must only be called from the PaintThread.
   void DropPaintThreadRef();
 
 private:
   static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure);
-
+ 
   // Internal helpers for creating texture clients using the actual forwarder instead
   // of KnowsCompositor. TextureClientPool uses these to let it cache texture clients
   // per-process instead of per ShadowLayerForwarder, but everyone else should
   // use the public functions instead.
   friend class TextureClientPool;
   static already_AddRefed<TextureClient>
   CreateForDrawing(TextureForwarder* aAllocator,
                    gfx::SurfaceFormat aFormat,
                    gfx::IntSize aSize,
                    LayersBackend aLayersBackend,
                    int32_t aMaxTextureSize,
                    BackendSelector aSelector,
                    TextureFlags aTextureFlags,
                    TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
-
+  
   static already_AddRefed<TextureClient>
   CreateForRawBufferAccess(LayersIPCChannel* aAllocator,
                            gfx::SurfaceFormat aFormat,
                            gfx::IntSize aSize,
                            gfx::BackendType aMoz2dBackend,
                            LayersBackend aLayersBackend,
                            TextureFlags aTextureFlags,
                            TextureAllocationFlags flags = ALLOC_DEFAULT);
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -368,55 +368,34 @@ D3D11TextureData::SyncWithObject(SyncObj
   }
 
   MOZ_ASSERT(aSyncObject->GetSyncType() == SyncObjectClient::SyncType::D3D11);
   SyncObjectD3D11Client* sync = static_cast<SyncObjectD3D11Client*>(aSyncObject);
   sync->RegisterTexture(mTexture);
 }
 
 bool
-DXGITextureData::SerializeSpecific(SurfaceDescriptorD3D10* const aOutDesc)
+DXGITextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
 {
   RefPtr<IDXGIResource> resource;
   GetDXGIResource((IDXGIResource**)getter_AddRefs(resource));
   if (!resource) {
     return false;
   }
   HANDLE sharedHandle;
   HRESULT hr = resource->GetSharedHandle(&sharedHandle);
   if (FAILED(hr)) {
     LOGD3D11("Error getting shared handle for texture.");
     return false;
   }
 
-  *aOutDesc = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle, mFormat, mSize);
+  aOutDescriptor = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle, mFormat, mSize);
   return true;
 }
 
-bool
-DXGITextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
-{
-  SurfaceDescriptorD3D10 desc;
-  if (!SerializeSpecific(&desc))
-    return false;
-
-  aOutDescriptor = Move(desc);
-  return true;
-}
-
-void
-DXGITextureData::GetSubDescriptor(GPUVideoSubDescriptor* const aOutDesc)
-{
-  SurfaceDescriptorD3D10 ret;
-  if (!SerializeSpecific(&ret))
-    return;
-
-  *aOutDesc = Move(ret);
-}
-
 DXGITextureData*
 DXGITextureData::Create(IntSize aSize, SurfaceFormat aFormat, TextureAllocationFlags aFlags)
 {
   if (aFormat == SurfaceFormat::A8) {
     // Currently we don't support A8 surfaces. Fallback.
     return nullptr;
   }
 
@@ -675,45 +654,27 @@ DXGIYCbCrTextureData::FillInfo(TextureDa
 {
   aInfo.size = mSize;
   aInfo.format = gfx::SurfaceFormat::YUV;
   aInfo.supportsMoz2D = false;
   aInfo.hasIntermediateBuffer = false;
   aInfo.hasSynchronization = false;
 }
 
-void
-DXGIYCbCrTextureData::SerializeSpecific(SurfaceDescriptorDXGIYCbCr* const aOutDesc)
-{
-  *aOutDesc = SurfaceDescriptorDXGIYCbCr(
-    (WindowsHandle)mHandles[0], (WindowsHandle)mHandles[1], (WindowsHandle)mHandles[2],
-    mSize, mSizeY, mSizeCbCr
-  );
-}
-
 bool
 DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
 {
-  SurfaceDescriptorDXGIYCbCr desc;
-  SerializeSpecific(&desc);
-
-  aOutDescriptor = Move(desc);
+  aOutDescriptor = SurfaceDescriptorDXGIYCbCr(
+    (WindowsHandle)mHandles[0], (WindowsHandle)mHandles[1], (WindowsHandle)mHandles[2],
+    mSize, mSizeY, mSizeCbCr
+  );
   return true;
 }
 
 void
-DXGIYCbCrTextureData::GetSubDescriptor(GPUVideoSubDescriptor* const aOutDesc)
-{
-  SurfaceDescriptorDXGIYCbCr desc;
-  SerializeSpecific(&desc);
-
-  *aOutDesc = Move(desc);
-}
-
-void
 DXGIYCbCrTextureData::Deallocate(LayersIPCChannel*)
 {
   mD3D9Textures[0] = nullptr;
   mD3D9Textures[1] = nullptr;
   mD3D9Textures[2] = nullptr;
   mD3D11Textures[0] = nullptr;
   mD3D11Textures[1] = nullptr;
   mD3D11Textures[2] = nullptr;
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -13,20 +13,16 @@
 #include "mozilla/layers/TextureHost.h"
 #include "gfxWindowsPlatform.h"
 #include "mozilla/GfxMessageUtils.h"
 #include <d3d11.h>
 #include "d3d9.h"
 #include <vector>
 
 namespace mozilla {
-namespace gl {
-class GLBlitHelper;
-}
-
 namespace layers {
 
 class MOZ_RAII AutoTextureLock
 {
 public:
   AutoTextureLock(IDXGIKeyedMutex* aMutex, HRESULT& aResult,
                   uint32_t aTimeout = 0);
   ~AutoTextureLock();
@@ -38,19 +34,17 @@ private:
 
 class CompositorD3D11;
 
 class DXGITextureData : public TextureData
 {
 public:
   virtual void FillInfo(TextureData::Info& aInfo) const override;
 
-  bool SerializeSpecific(SurfaceDescriptorD3D10* aOutDesc);
   virtual bool Serialize(SurfaceDescriptor& aOutDescrptor) override;
-  virtual void GetSubDescriptor(GPUVideoSubDescriptor* aOutDesc) override;
 
   static DXGITextureData*
   Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, TextureAllocationFlags aFlags);
 
 protected:
   bool PrepareDrawTargetInLock(OpenMode aMode);
 
   DXGITextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
@@ -127,17 +121,16 @@ protected:
 already_AddRefed<TextureClient>
 CreateD3D11extureClientWithDevice(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
                                   TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags,
                                   ID3D11Device* aDevice,
                                   LayersIPCChannel* aAllocator);
 
 class DXGIYCbCrTextureData : public TextureData
 {
-  friend class gl::GLBlitHelper;
 public:
   static DXGIYCbCrTextureData*
   Create(IDirect3DTexture9* aTextureY,
          IDirect3DTexture9* aTextureCb,
          IDirect3DTexture9* aTextureCr,
          HANDLE aHandleY,
          HANDLE aHandleCb,
          HANDLE aHandleCr,
@@ -154,19 +147,17 @@ public:
          const gfx::IntSize& aSizeCbCr);
 
   virtual bool Lock(OpenMode) override { return true; }
 
   virtual void Unlock() override {}
 
   virtual void FillInfo(TextureData::Info& aInfo) const override;
 
-  void SerializeSpecific(SurfaceDescriptorDXGIYCbCr* aOutDesc);
   virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
-  virtual void GetSubDescriptor(GPUVideoSubDescriptor* aOutDesc) override;
 
   virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override { return nullptr; }
 
   virtual void Deallocate(LayersIPCChannel* aAllocator) override;
 
   virtual bool UpdateFromSurface(gfx::SourceSurface*) override { return false; }
 
   virtual TextureFlags GetTextureFlags() const override
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -75,26 +75,18 @@ struct EGLImageDescriptor {
 struct SurfaceDescriptorSharedGLTexture {
   uint32_t texture;
   uint32_t target;
   uintptr_t fence;
   IntSize size;
   bool hasAlpha;
 };
 
-
-union GPUVideoSubDescriptor {
-  SurfaceDescriptorD3D10;
-  SurfaceDescriptorDXGIYCbCr;
-  null_t;
-};
-
 struct SurfaceDescriptorGPUVideo {
   uint64_t handle;
-  GPUVideoSubDescriptor subdesc;
 };
 
 struct RGBDescriptor {
   IntSize size;
   SurfaceFormat format;
   bool hasIntermediateBuffer;
 };
 
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -1106,39 +1106,57 @@ gfxUtils::EncodeSourceSurface(SourceSurf
                               const nsAString& aOutputOptions,
                               BinaryOrData aBinaryOrData,
                               FILE* aFile)
 {
   return EncodeSourceSurfaceInternal(aSurface, aMimeType, aOutputOptions,
                                      aBinaryOrData, aFile, nullptr);
 }
 
-// https://jdashg.github.io/misc/colors/from-coeffs.html
-const float kBT601NarrowYCbCrToRGB_RowMajor[16] = {
-  1.16438f, 0.00000f, 1.59603f,-0.87420f,
-  1.16438f,-0.39176f,-0.81297f, 0.53167f,
-  1.16438f, 2.01723f, 0.00000f,-1.08563f,
-  0.00000f, 0.00000f, 0.00000f, 1.00000f
+/* From Rec601:
+[R]   [1.1643835616438356,  0.0,                 1.5960267857142858]      [ Y -  16]
+[G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708]    x [Cb - 128]
+[B]   [1.1643835616438356,  2.017232142857143,   8.862867620416422e-17]   [Cr - 128]
+
+For [0,1] instead of [0,255], and to 5 places:
+[R]   [1.16438,  0.00000,  1.59603]   [ Y - 0.06275]
+[G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
+[B]   [1.16438,  2.01723,  0.00000]   [Cr - 0.50196]
+
+From Rec709:
+[R]   [1.1643835616438356,  4.2781193979771426e-17, 1.7927410714285714]     [ Y -  16]
+[G] = [1.1643835616438358, -0.21324861427372963,   -0.532909328559444]    x [Cb - 128]
+[B]   [1.1643835616438356,  2.1124017857142854,     0.0]                    [Cr - 128]
+
+For [0,1] instead of [0,255], and to 5 places:
+[R]   [1.16438,  0.00000,  1.79274]   [ Y - 0.06275]
+[G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
+[B]   [1.16438,  2.11240,  0.00000]   [Cr - 0.50196]
+*/
+
+static const float kRec601[9] = {
+  1.16438f, 0.00000f, 1.59603f,
+  1.16438f,-0.39176f,-0.81297f,
+  1.16438f, 2.01723f, 0.00000f,
 };
-const float kBT709NarrowYCbCrToRGB_RowMajor[16] = {
-  1.16438f, 0.00000f, 1.79274f,-0.97295f,
-  1.16438f,-0.21325f,-0.53291f, 0.30148f,
-  1.16438f, 2.11240f, 0.00000f,-1.13340f,
-  0.00000f, 0.00000f, 0.00000f, 1.00000f
+static const float kRec709[9] = {
+  1.16438f, 0.00000f, 1.79274f,
+  1.16438f,-0.21325f,-0.53291f,
+  1.16438f, 2.11240f, 0.00000f,
 };
 
 /* static */ const float*
 gfxUtils::YuvToRgbMatrix4x3RowMajor(YUVColorSpace aYUVColorSpace)
 {
-  #define X(x) { x[0], x[1], x[ 2], 0.0f, \
-                 x[4], x[5], x[ 6], 0.0f, \
-                 x[8], x[9], x[10], 0.0f }
+  #define X(x) { x[0], x[1], x[2], 0.0f, \
+                 x[3], x[4], x[5], 0.0f, \
+                 x[6], x[7], x[8], 0.0f }
 
-  static const float rec601[12] = X(kBT601NarrowYCbCrToRGB_RowMajor);
-  static const float rec709[12] = X(kBT709NarrowYCbCrToRGB_RowMajor);
+  static const float rec601[12] = X(kRec601);
+  static const float rec709[12] = X(kRec709);
 
   #undef X
 
   switch (aYUVColorSpace) {
   case YUVColorSpace::BT601:
     return rec601;
   case YUVColorSpace::BT709:
     return rec709;
@@ -1146,46 +1164,22 @@ gfxUtils::YuvToRgbMatrix4x3RowMajor(YUVC
     MOZ_ASSERT(false, "unknown aYUVColorSpace");
     return rec601;
   }
 }
 
 /* static */ const float*
 gfxUtils::YuvToRgbMatrix3x3ColumnMajor(YUVColorSpace aYUVColorSpace)
 {
-  #define X(x) { x[0], x[4], x[ 8], \
-                 x[1], x[5], x[ 9], \
-                 x[2], x[6], x[10] }
-
-  static const float rec601[9] = X(kBT601NarrowYCbCrToRGB_RowMajor);
-  static const float rec709[9] = X(kBT709NarrowYCbCrToRGB_RowMajor);
-
-  #undef X
+  #define X(x) { x[0], x[3], x[6], \
+                 x[1], x[4], x[7], \
+                 x[2], x[5], x[8] }
 
-  switch (aYUVColorSpace) {
-  case YUVColorSpace::BT601:
-    return rec601;
-  case YUVColorSpace::BT709:
-    return rec709;
-  default: // YUVColorSpace::UNKNOWN
-    MOZ_ASSERT(false, "unknown aYUVColorSpace");
-    return rec601;
-  }
-}
-
-/* static */ const float*
-gfxUtils::YuvToRgbMatrix4x4ColumnMajor(YUVColorSpace aYUVColorSpace)
-{
-  #define X(x) { x[0], x[4], x[ 8], x[12], \
-                 x[1], x[5], x[ 9], x[13], \
-                 x[2], x[6], x[10], x[14], \
-                 x[3], x[7], x[11], x[15] }
-
-  static const float rec601[16] = X(kBT601NarrowYCbCrToRGB_RowMajor);
-  static const float rec709[16] = X(kBT709NarrowYCbCrToRGB_RowMajor);
+  static const float rec601[9] = X(kRec601);
+  static const float rec709[9] = X(kRec709);
 
   #undef X
 
   switch (aYUVColorSpace) {
   case YUVColorSpace::BT601:
     return rec601;
   case YUVColorSpace::BT709:
     return rec709;
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -153,17 +153,16 @@ public:
 
     /**
      * Clears surface to aColor (which defaults to transparent black).
      */
     static void ClearThebesSurface(gfxASurface* aSurface);
 
     static const float* YuvToRgbMatrix4x3RowMajor(mozilla::YUVColorSpace aYUVColorSpace);
     static const float* YuvToRgbMatrix3x3ColumnMajor(mozilla::YUVColorSpace aYUVColorSpace);
-    static const float* YuvToRgbMatrix4x4ColumnMajor(mozilla::YUVColorSpace aYUVColorSpace);
 
     /**
      * Creates a copy of aSurface, but having the SurfaceFormat aFormat.
      *
      * This function always creates a new surface. Do not call it if aSurface's
      * format is the same as aFormat. Such a non-conversion would just be an
      * unnecessary and wasteful copy (this function asserts to prevent that).
      *