Bug 1215089 - P7: Add support for 10/12 bits YUV surface with basic compositor. r=mattwoodrow
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 29 Sep 2017 16:37:56 +0200
changeset 427272 b55e89b5df041a28c7bf34d6896224a7e2d94929
parent 427271 84bcd57f2404a4fc48a42b36e5f553c8dec001ff
child 427273 073ff4644573a77a071e158bf88ab1c6a8713ab3
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersmattwoodrow
bugs1215089
milestone58.0a1
Bug 1215089 - P7: Add support for 10/12 bits YUV surface with basic compositor. r=mattwoodrow MozReview-Commit-ID: Ej4MbvHnSk9
gfx/2d/Tools.h
gfx/2d/Types.h
gfx/layers/BufferTexture.cpp
gfx/layers/BufferTexture.h
gfx/layers/Effects.h
gfx/layers/ImageDataSerializer.cpp
gfx/layers/ImageDataSerializer.h
gfx/layers/client/ImageClient.cpp
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/client/TextureClientRecycleAllocator.cpp
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/ipc/LayersSurfaces.ipdlh
gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
gfx/tests/gtest/TestTextures.cpp
gfx/tests/gtest/TextureHelper.h
--- a/gfx/2d/Tools.h
+++ b/gfx/2d/Tools.h
@@ -87,30 +87,44 @@ Distance(Point aA, Point aB)
 
 static inline int
 BytesPerPixel(SurfaceFormat aFormat)
 {
   switch (aFormat) {
   case SurfaceFormat::A8:
     return 1;
   case SurfaceFormat::R5G6B5_UINT16:
+  case SurfaceFormat::A16:
     return 2;
   case SurfaceFormat::R8G8B8:
   case SurfaceFormat::B8G8R8:
     return 3;
   case SurfaceFormat::HSV:
   case SurfaceFormat::Lab:
     return 3 * sizeof(float);
   case SurfaceFormat::Depth:
     return sizeof(uint16_t);
   default:
     return 4;
   }
 }
 
+static inline SurfaceFormat
+SurfaceFormatForAlphaBitDepth(uint32_t aBitDepth)
+{
+  if (aBitDepth == 8) {
+    return SurfaceFormat::A8;
+  } else if (aBitDepth == 10 ||
+             aBitDepth == 12) {
+    return SurfaceFormat::A16;
+  }
+  MOZ_ASSERT_UNREACHABLE("Unsupported alpha bit depth");
+  return SurfaceFormat::UNKNOWN;
+}
+
 static inline bool
 IsOpaqueFormat(SurfaceFormat aFormat) {
   switch (aFormat) {
     case SurfaceFormat::B8G8R8X8:
     case SurfaceFormat::R8G8B8X8:
     case SurfaceFormat::X8R8G8B8:
     case SurfaceFormat::YUV:
     case SurfaceFormat::NV12:
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -51,16 +51,17 @@ enum class SurfaceFormat : int8_t {
 
   // The _UINT16 suffix here indicates that the name reflects the layout when
   // viewed as a uint16_t value. In memory these values are stored using native
   // endianness.
   R5G6B5_UINT16,                    // 0bRRRRRGGGGGGBBBBB
 
   // This one is a single-byte, so endianness isn't an issue.
   A8,
+  A16,
 
   R8G8,
 
   // These ones are their own special cases.
   YUV,
   NV12,
   YUV422,
   HSV,
--- a/gfx/layers/BufferTexture.cpp
+++ b/gfx/layers/BufferTexture.cpp
@@ -154,67 +154,83 @@ BufferTextureData::CreateInternal(Layers
     return new ShmemTextureData(aDesc, aMoz2DBackend, shm);
   }
 }
 
 BufferTextureData*
 BufferTextureData::CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
                                                 int32_t aBufferSize,
                                                 YUVColorSpace aYUVColorSpace,
+                                                uint32_t aBitDepth,
                                                 TextureFlags aTextureFlags)
 {
   if (aBufferSize == 0 || !gfx::Factory::CheckBufferSize(aBufferSize)) {
     return nullptr;
   }
 
   bool hasIntermediateBuffer = aAllocator ? ComputeHasIntermediateBuffer(gfx::SurfaceFormat::YUV,
                                                                          aAllocator->GetCompositorBackendType())
                                           : true;
 
   // Initialize the metadata with something, even if it will have to be rewritten
   // afterwards since we don't know the dimensions of the texture at this point.
-  BufferDescriptor desc = YCbCrDescriptor(gfx::IntSize(), gfx::IntSize(),
+  BufferDescriptor desc = YCbCrDescriptor(gfx::IntSize(), 0, gfx::IntSize(), 0,
                                           0, 0, 0, StereoMode::MONO,
                                           aYUVColorSpace,
+                                          aBitDepth,
                                           hasIntermediateBuffer);
 
   return CreateInternal(aAllocator ? aAllocator->GetTextureForwarder() : nullptr,
                        desc, gfx::BackendType::NONE, aBufferSize, aTextureFlags);
 }
 
 BufferTextureData*
 BufferTextureData::CreateForYCbCr(KnowsCompositor* aAllocator,
                                   gfx::IntSize aYSize,
+                                  uint32_t aYStride,
                                   gfx::IntSize aCbCrSize,
+                                  uint32_t aCbCrStride,
                                   StereoMode aStereoMode,
                                   YUVColorSpace aYUVColorSpace,
+                                  uint32_t aBitDepth,
                                   TextureFlags aTextureFlags)
 {
-  uint32_t bufSize = ImageDataSerializer::ComputeYCbCrBufferSize(aYSize, aCbCrSize);
+  uint32_t bufSize = ImageDataSerializer::ComputeYCbCrBufferSize(
+    aYSize, aYStride, aCbCrSize, aCbCrStride);
   if (bufSize == 0) {
     return nullptr;
   }
 
   uint32_t yOffset;
   uint32_t cbOffset;
   uint32_t crOffset;
-  ImageDataSerializer::ComputeYCbCrOffsets(aYSize.width, aYSize.height,
-                                          aCbCrSize.width, aCbCrSize.height,
-                                          yOffset, cbOffset, crOffset);
+  ImageDataSerializer::ComputeYCbCrOffsets(aYStride, aYSize.height,
+                                           aCbCrStride, aCbCrSize.height,
+                                           yOffset, cbOffset, crOffset);
 
-  bool hasIntermediateBuffer = aAllocator ? ComputeHasIntermediateBuffer(gfx::SurfaceFormat::YUV,
-                                                                         aAllocator->GetCompositorBackendType())
-                                          : true;
+  bool hasIntermediateBuffer =
+    aAllocator
+      ? ComputeHasIntermediateBuffer(gfx::SurfaceFormat::YUV,
+                                     aAllocator->GetCompositorBackendType())
+      : true;
 
-  YCbCrDescriptor descriptor = YCbCrDescriptor(aYSize, aCbCrSize, yOffset, cbOffset,
-                                               crOffset, aStereoMode, aYUVColorSpace,
+  YCbCrDescriptor descriptor = YCbCrDescriptor(aYSize, aYStride,
+                                               aCbCrSize, aCbCrStride,
+                                               yOffset, cbOffset, crOffset,
+                                               aStereoMode,
+                                               aYUVColorSpace,
+                                               aBitDepth,
                                                hasIntermediateBuffer);
 
- return CreateInternal(aAllocator ? aAllocator->GetTextureForwarder() : nullptr, descriptor,
-                       gfx::BackendType::NONE, bufSize, aTextureFlags);
+  return CreateInternal(aAllocator ? aAllocator->GetTextureForwarder()
+                                   : nullptr,
+                        descriptor,
+                        gfx::BackendType::NONE,
+                        bufSize,
+                        aTextureFlags);
 }
 
 void
 BufferTextureData::FillInfo(TextureData::Info& aInfo) const
 {
   aInfo.size = GetSize();
   aInfo.format = GetFormat();
   aInfo.hasSynchronization = false;
@@ -249,16 +265,22 @@ BufferTextureData::GetCbCrSize() const
 }
 
 Maybe<YUVColorSpace>
 BufferTextureData::GetYUVColorSpace() const
 {
   return ImageDataSerializer::YUVColorSpaceFromBufferDescriptor(mDescriptor);
 }
 
+Maybe<uint32_t>
+BufferTextureData::GetBitDepth() const
+{
+  return ImageDataSerializer::BitDepthFromBufferDescriptor(mDescriptor);
+}
+
 Maybe<StereoMode>
 BufferTextureData::GetStereoMode() const
 {
   return ImageDataSerializer::StereoModeFromBufferDescriptor(mDescriptor);
 }
 
 gfx::SurfaceFormat
 BufferTextureData::GetFormat() const
@@ -346,27 +368,27 @@ BufferTextureData::BorrowMappedYCbCrData
   auto ySize = desc.ySize();
   auto cbCrSize = desc.cbCrSize();
 
   aMap.stereoMode = desc.stereoMode();
   aMap.metadata = nullptr;
 
   aMap.y.data = data + desc.yOffset();
   aMap.y.size = ySize;
-  aMap.y.stride = ySize.width;
+  aMap.y.stride = desc.yStride();
   aMap.y.skip = 0;
 
   aMap.cb.data = data + desc.cbOffset();
   aMap.cb.size = cbCrSize;
-  aMap.cb.stride = cbCrSize.width;
+  aMap.cb.stride = desc.cbCrStride();
   aMap.cb.skip = 0;
 
   aMap.cr.data = data + desc.crOffset();
   aMap.cr.size = cbCrSize;
-  aMap.cr.stride = cbCrSize.width;
+  aMap.cr.stride = desc.cbCrStride();
   aMap.cr.skip = 0;
 
   return true;
 }
 
 bool
 BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
 {
--- a/gfx/layers/BufferTexture.h
+++ b/gfx/layers/BufferTexture.h
@@ -25,27 +25,31 @@ public:
                                    gfx::BackendType aMoz2DBackend,
                                    LayersBackend aLayersBackend,
                                    TextureFlags aFlags,
                                    TextureAllocationFlags aAllocFlags,
                                    LayersIPCChannel* aAllocator);
 
   static BufferTextureData* CreateForYCbCr(KnowsCompositor* aAllocator,
                                            gfx::IntSize aYSize,
+                                           uint32_t aYStride,
                                            gfx::IntSize aCbCrSize,
+                                           uint32_t aCbCrStride,
                                            StereoMode aStereoMode,
                                            YUVColorSpace aYUVColorSpace,
+                                           uint32_t aBitDepth,
                                            TextureFlags aTextureFlags);
 
   // It is generally better to use CreateForYCbCr instead.
   // This creates a half-initialized texture since we don't know the sizes and
   // offsets in the buffer.
   static BufferTextureData* CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
                                                          int32_t aSize,
                                                          YUVColorSpace aYUVColorSpace,
+                                                         uint32_t aBitDepth,
                                                          TextureFlags aTextureFlags);
 
   virtual bool Lock(OpenMode aMode) override { return true; }
 
   virtual void Unlock() override {}
 
   virtual void FillInfo(TextureData::Info& aInfo) const override;
 
@@ -62,16 +66,18 @@ public:
 
   // Don't use this.
   void SetDesciptor(const BufferDescriptor& aDesc);
 
   Maybe<gfx::IntSize> GetCbCrSize() const;
 
   Maybe<YUVColorSpace> GetYUVColorSpace() const;
 
+  Maybe<uint32_t> GetBitDepth() const;
+
   Maybe<StereoMode> GetStereoMode() const;
 
 protected:
   gfx::IntSize GetSize() const;
 
   gfx::SurfaceFormat GetFormat() const;
 
   static BufferTextureData* CreateInternal(LayersIPCChannel* aAllocator,
--- a/gfx/layers/Effects.h
+++ b/gfx/layers/Effects.h
@@ -156,24 +156,26 @@ struct EffectRGB : public TexturedEffect
     : TexturedEffect(EffectTypes::RGB, aTexture, aPremultiplied, aSamplingFilter)
   {}
 
   virtual const char* Name() { return "EffectRGB"; }
 };
 
 struct EffectYCbCr : public TexturedEffect
 {
-  EffectYCbCr(TextureSource *aSource, YUVColorSpace aYUVColorSpace, gfx::SamplingFilter aSamplingFilter)
+  EffectYCbCr(TextureSource *aSource, YUVColorSpace aYUVColorSpace, uint32_t aBitDepth, gfx::SamplingFilter aSamplingFilter)
     : TexturedEffect(EffectTypes::YCBCR, aSource, false, aSamplingFilter)
     , mYUVColorSpace(aYUVColorSpace)
+    , mBitDepth(aBitDepth)
   {}
 
   virtual const char* Name() { return "EffectYCbCr"; }
 
   YUVColorSpace mYUVColorSpace;
+  uint32_t mBitDepth;
 };
 
 struct EffectNV12 : public TexturedEffect
 {
   EffectNV12(TextureSource *aSource, gfx::SamplingFilter aSamplingFilter)
     : TexturedEffect(EffectTypes::NV12, aSource, false, aSamplingFilter)
   {}
 
@@ -265,17 +267,18 @@ CreateTexturedEffect(TextureHost* aHost,
                      bool isAlphaPremultiplied)
 {
   MOZ_ASSERT(aHost);
   MOZ_ASSERT(aSource);
 
   RefPtr<TexturedEffect> result;
   if (aHost->GetReadFormat() == gfx::SurfaceFormat::YUV) {
     MOZ_ASSERT(aHost->GetYUVColorSpace() != YUVColorSpace::UNKNOWN);
-    result = new EffectYCbCr(aSource, aHost->GetYUVColorSpace(), aSamplingFilter);
+    result = new EffectYCbCr(
+      aSource, aHost->GetYUVColorSpace(), aHost->GetBitDepth(), aSamplingFilter);
   } else {
     result = CreateTexturedEffect(aHost->GetReadFormat(),
                                   aSource,
                                   aSamplingFilter,
                                   isAlphaPremultiplied);
   }
   return result.forget();
 }
--- a/gfx/layers/ImageDataSerializer.cpp
+++ b/gfx/layers/ImageDataSerializer.cpp
@@ -66,28 +66,22 @@ ComputeYCbCrBufferSize(const gfx::IntSiz
 {
   MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
 
   if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0 ||
       !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
       !gfx::Factory::AllowedSurfaceSize(IntSize(aCbCrStride, aCbCrSize.height))) {
     return 0;
   }
+
   // Overflow checks are performed in AllowedSurfaceSize
   return GetAlignedStride<4>(aYSize.height, aYStride) +
          2 * GetAlignedStride<4>(aCbCrSize.height, aCbCrStride);
 }
 
-// Minimum required shmem size in bytes
-uint32_t
-ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, const gfx::IntSize& aCbCrSize)
-{
-  return ComputeYCbCrBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width);
-}
-
 uint32_t
 ComputeYCbCrBufferSize(uint32_t aBufferSize)
 {
   return GetAlignedStride<4>(aBufferSize, 1);
 }
 
 void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
                          int32_t cbCrStride, int32_t cbCrHeight,
@@ -132,37 +126,47 @@ Maybe<gfx::IntSize> CbCrSizeFromBufferDe
       return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
     default:
       MOZ_CRASH("GFX:  CbCrSizeFromBufferDescriptor");
   }
 }
 
 Maybe<YUVColorSpace> YUVColorSpaceFromBufferDescriptor(const BufferDescriptor& aDescriptor)
 {
-{
   switch (aDescriptor.type()) {
     case BufferDescriptor::TRGBDescriptor:
       return Nothing();
     case BufferDescriptor::TYCbCrDescriptor:
       return Some(aDescriptor.get_YCbCrDescriptor().yUVColorSpace());
     default:
-      MOZ_CRASH("GFX:  CbCrSizeFromBufferDescriptor");
+      MOZ_CRASH("GFX:  YUVColorSpaceFromBufferDescriptor");
   }
 }
+
+Maybe<uint32_t> BitDepthFromBufferDescriptor(const BufferDescriptor& aDescriptor)
+{
+  switch (aDescriptor.type()) {
+    case BufferDescriptor::TRGBDescriptor:
+      return Nothing();
+    case BufferDescriptor::TYCbCrDescriptor:
+      return Some(aDescriptor.get_YCbCrDescriptor().bitDepth());
+    default:
+      MOZ_CRASH("GFX:  BitDepthFromBufferDescriptor");
+  }
 }
 
 Maybe<StereoMode> StereoModeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
 {
   switch (aDescriptor.type()) {
     case BufferDescriptor::TRGBDescriptor:
       return Nothing();
     case BufferDescriptor::TYCbCrDescriptor:
       return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
     default:
-      MOZ_CRASH("GFX:  CbCrSizeFromBufferDescriptor");
+      MOZ_CRASH("GFX:  StereoModeFromBufferDescriptor");
   }
 }
 
 uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
 {
   return aBuffer + aDescriptor.yOffset();
 }
 
@@ -175,19 +179,16 @@ uint8_t* GetCrChannel(uint8_t* aBuffer, 
 {
   return aBuffer + aDescriptor.crOffset();
 }
 
 already_AddRefed<DataSourceSurface>
 DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor, gfx::DataSourceSurface* aSurface)
 {
   gfx::IntSize ySize = aDescriptor.ySize();
-  gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
-  int32_t yStride = ySize.width;
-  int32_t cbCrStride = cbCrSize.width;
 
   RefPtr<DataSourceSurface> result;
   if (aSurface) {
     MOZ_ASSERT(aSurface->GetSize() == ySize);
     MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
     if (aSurface->GetSize() == ySize &&
         aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
       result = aSurface;
@@ -204,24 +205,25 @@ DataSourceSurfaceFromYCbCrDescriptor(uin
 
   DataSourceSurface::MappedSurface map;
   if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
     return nullptr;
   }
 
   layers::PlanarYCbCrData ycbcrData;
   ycbcrData.mYChannel     = GetYChannel(aBuffer, aDescriptor);
-  ycbcrData.mYStride      = yStride;
+  ycbcrData.mYStride      = aDescriptor.yStride();
   ycbcrData.mYSize        = ySize;
   ycbcrData.mCbChannel    = GetCbChannel(aBuffer, aDescriptor);
   ycbcrData.mCrChannel    = GetCrChannel(aBuffer, aDescriptor);
-  ycbcrData.mCbCrStride   = cbCrStride;
-  ycbcrData.mCbCrSize     = cbCrSize;
+  ycbcrData.mCbCrStride   = aDescriptor.cbCrStride();
+  ycbcrData.mCbCrSize     = aDescriptor.cbCrSize();
   ycbcrData.mPicSize      = ySize;
   ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
+  ycbcrData.mBitDepth     = aDescriptor.bitDepth();
 
   gfx::ConvertYCbCrToRGB(ycbcrData,
                          gfx::SurfaceFormat::B8G8R8X8,
                          ySize,
                          map.mData,
                          map.mStride);
 
   result->Unmap();
@@ -232,30 +234,27 @@ void
 ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
                                    const YCbCrDescriptor& aDescriptor,
                                    const gfx::SurfaceFormat& aDestFormat,
                                    const gfx::IntSize& aDestSize,
                                    unsigned char* aDestBuffer,
                                    int32_t aStride)
 {
   MOZ_ASSERT(aBuffer);
-  gfx::IntSize ySize = aDescriptor.ySize();
-  gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
-  int32_t yStride = ySize.width;
-  int32_t cbCrStride = cbCrSize.width;
 
   layers::PlanarYCbCrData ycbcrData;
   ycbcrData.mYChannel     = GetYChannel(aBuffer, aDescriptor);
-  ycbcrData.mYStride      = yStride;
-  ycbcrData.mYSize        = ySize;
+  ycbcrData.mYStride      = aDescriptor.yStride();;
+  ycbcrData.mYSize        = aDescriptor.ySize();
   ycbcrData.mCbChannel    = GetCbChannel(aBuffer, aDescriptor);
   ycbcrData.mCrChannel    = GetCrChannel(aBuffer, aDescriptor);
-  ycbcrData.mCbCrStride   = cbCrStride;
-  ycbcrData.mCbCrSize     = cbCrSize;
-  ycbcrData.mPicSize      = ySize;
+  ycbcrData.mCbCrStride   = aDescriptor.cbCrStride();
+  ycbcrData.mCbCrSize     = aDescriptor.cbCrSize();
+  ycbcrData.mPicSize      = aDescriptor.ySize();
   ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
+  ycbcrData.mBitDepth     = aDescriptor.bitDepth();
 
   gfx::ConvertYCbCrToRGB(ycbcrData, aDestFormat, aDestSize, aDestBuffer, aStride);
 }
 
 } // namespace ImageDataSerializer
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ImageDataSerializer.h
+++ b/gfx/layers/ImageDataSerializer.h
@@ -40,33 +40,32 @@ uint32_t ComputeRGBBufferSize(gfx::IntSi
 
 ///This function is meant as a helper to know how much shared memory we need
 ///to allocate in a shmem in order to place a shared YCbCr image blob of
 ///given dimensions.
 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize,
                                 int32_t aYStride,
                                 const gfx::IntSize& aCbCrSize,
                                 int32_t aCbCrStride);
-uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize,
-                                const gfx::IntSize& aCbCrSize);
-
 uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize);
 
 void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
                          int32_t cbCrStride, int32_t cbCrHeight,
                          uint32_t& outYOffset, uint32_t& outCbOffset, uint32_t& outCrOffset);
 
 gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescriptor);
 
 gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor);
 
 Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(const BufferDescriptor& aDescriptor);
 
 Maybe<YUVColorSpace> YUVColorSpaceFromBufferDescriptor(const BufferDescriptor& aDescriptor);
 
+Maybe<uint32_t> BitDepthFromBufferDescriptor(const BufferDescriptor& aDescriptor);
+
 Maybe<StereoMode> StereoModeFromBufferDescriptor(const BufferDescriptor& aDescriptor);
 
 uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
 
 uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
 
 uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor);
 
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -96,18 +96,21 @@ ImageClient::CreateTextureClientForImage
   RefPtr<TextureClient> texture;
   if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
     PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage);
     const PlanarYCbCrData* data = ycbcr->GetData();
     if (!data) {
       return nullptr;
     }
     texture = TextureClient::CreateForYCbCr(aForwarder,
-                                            data->mYSize, data->mCbCrSize, data->mStereoMode,
+                                            data->mYSize, data->mYStride,
+                                            data->mCbCrSize, data->mCbCrStride,
+                                            data->mStereoMode,
                                             data->mYUVColorSpace,
+                                            data->mBitDepth,
                                             TextureFlags::DEFAULT);
     if (!texture) {
       return nullptr;
     }
 
     TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
     if (!autoLock.Succeeded()) {
       return nullptr;
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -1251,82 +1251,90 @@ TextureClient::CreateForRawBufferAccess(
 
   return MakeAndAddRef<TextureClient>(texData, aTextureFlags, aAllocator);
 }
 
 // static
 already_AddRefed<TextureClient>
 TextureClient::CreateForYCbCr(KnowsCompositor* aAllocator,
                               gfx::IntSize aYSize,
+                              uint32_t aYStride,
                               gfx::IntSize aCbCrSize,
+                              uint32_t aCbCrStride,
                               StereoMode aStereoMode,
                               YUVColorSpace aYUVColorSpace,
+                              uint32_t aBitDepth,
                               TextureFlags aTextureFlags)
 {
   if (!aAllocator || !aAllocator->GetLayersIPCActor()->IPCOpen()) {
     return nullptr;
   }
 
   if (!gfx::Factory::AllowedSurfaceSize(aYSize)) {
     return nullptr;
   }
 
-  TextureData* data = BufferTextureData::CreateForYCbCr(aAllocator, aYSize, aCbCrSize,
-                                                        aStereoMode, aYUVColorSpace,
-                                                        aTextureFlags);
+  TextureData* data =
+    BufferTextureData::CreateForYCbCr(aAllocator,
+                                      aYSize, aYStride,
+                                      aCbCrSize, aCbCrStride,
+                                      aStereoMode, aYUVColorSpace,
+                                      aBitDepth, aTextureFlags);
   if (!data) {
     return nullptr;
   }
 
   return MakeAndAddRef<TextureClient>(data, aTextureFlags,
                                       aAllocator->GetTextureForwarder());
 }
 
 // static
 already_AddRefed<TextureClient>
 TextureClient::CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
                                             size_t aSize,
                                             YUVColorSpace aYUVColorSpace,
+                                            uint32_t aBitDepth,
                                             TextureFlags aTextureFlags)
 {
   if (!aAllocator || !aAllocator->GetLayersIPCActor()->IPCOpen()) {
     return nullptr;
   }
 
-  TextureData* data =
-    BufferTextureData::CreateForYCbCrWithBufferSize(aAllocator, aSize, aYUVColorSpace,
-                                                    aTextureFlags);
+  TextureData* data = BufferTextureData::CreateForYCbCrWithBufferSize(
+    aAllocator, aSize, aYUVColorSpace, aBitDepth, aTextureFlags);
   if (!data) {
     return nullptr;
   }
 
   return MakeAndAddRef<TextureClient>(data, aTextureFlags,
                                       aAllocator->GetTextureForwarder());
 }
 
-TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator)
-: AtomicRefCountedWithFinalize("TextureClient")
-, mAllocator(aAllocator)
-, mActor(nullptr)
-, mData(aData)
-, mFlags(aFlags)
-, mOpenMode(OpenMode::OPEN_NONE)
+TextureClient::TextureClient(TextureData* aData,
+                             TextureFlags aFlags,
+                             LayersIPCChannel* aAllocator)
+  : AtomicRefCountedWithFinalize("TextureClient")
+  , mAllocator(aAllocator)
+  , mActor(nullptr)
+  , mData(aData)
+  , mFlags(aFlags)
+  , mOpenMode(OpenMode::OPEN_NONE)
 #ifdef DEBUG
-, mExpectedDtRefs(0)
+  , mExpectedDtRefs(0)
 #endif
-, mIsLocked(false)
-, mIsReadLocked(false)
-, mUpdated(false)
-, mAddedToCompositableClient(false)
-, mWorkaroundAnnoyingSharedSurfaceLifetimeIssues(false)
-, mWorkaroundAnnoyingSharedSurfaceOwnershipIssues(false)
-, mFwdTransactionId(0)
-, mSerial(++sSerialCounter)
+  , mIsLocked(false)
+  , mIsReadLocked(false)
+  , mUpdated(false)
+  , mAddedToCompositableClient(false)
+  , mWorkaroundAnnoyingSharedSurfaceLifetimeIssues(false)
+  , mWorkaroundAnnoyingSharedSurfaceOwnershipIssues(false)
+  , mFwdTransactionId(0)
+  , mSerial(++sSerialCounter)
 #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
-, mPoolTracker(nullptr)
+  , mPoolTracker(nullptr)
 #endif
 {
   mData->FillInfo(mInfo);
   mFlags |= mData->GetTextureFlags();
 }
 
 bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
                                         const gfx::IntRect* aRect,
@@ -1752,24 +1760,28 @@ UpdateYCbCrTextureClient(TextureClient* 
     return false;
   }
 
   MappedYCbCrTextureData srcData;
   srcData.y.data = aData.mYChannel;
   srcData.y.size = aData.mYSize;
   srcData.y.stride = aData.mYStride;
   srcData.y.skip = aData.mYSkip;
+  MOZ_ASSERT(aData.mBitDepth == 8 || (aData.mBitDepth > 8 && aData.mBitDepth <= 16));
+  srcData.y.bytesPerPixel = (aData.mBitDepth > 8) ? 2 : 1;
   srcData.cb.data = aData.mCbChannel;
   srcData.cb.size = aData.mCbCrSize;
   srcData.cb.stride = aData.mCbCrStride;
   srcData.cb.skip = aData.mCbSkip;
+  srcData.cb.bytesPerPixel = (aData.mBitDepth > 8) ? 2 : 1;
   srcData.cr.data = aData.mCrChannel;
   srcData.cr.size = aData.mCbCrSize;
   srcData.cr.stride = aData.mCbCrStride;
   srcData.cr.skip = aData.mCrSkip;
+  srcData.cr.bytesPerPixel = (aData.mBitDepth > 8) ? 2 : 1;
   srcData.metadata = nullptr;
 
   if (!srcData.CopyInto(mapped)) {
     NS_WARNING("Failed to copy image data!");
     return false;
   }
 
   if (TextureRequiresLocking(aTexture->GetFlags())) {
@@ -1804,25 +1816,29 @@ MappedYCbCrChannelData::CopyInto(MappedY
     return true;
   }
 
   for (int32_t i = 0; i < size.height; ++i) {
     if (aDst.skip == 0 && skip == 0) {
       // fast-ish path
       memcpy(aDst.data + i * aDst.stride,
              data + i * stride,
-             size.width);
+             size.width * bytesPerPixel);
     } else {
       // slow path
       uint8_t* src = data + i * stride;
       uint8_t* dst = aDst.data + i * aDst.stride;
       for (int32_t j = 0; j < size.width; ++j) {
-        *dst = *src;
-        src += 1 + skip;
-        dst += 1 + aDst.skip;
+        for (uint32_t k = 0; k < bytesPerPixel; ++k) {
+          *dst = *src;
+          src += 1;
+          dst += 1;
+        }
+        src += skip;
+        dst += aDst.skip;
       }
     }
   }
   return true;
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -134,16 +134,17 @@ struct MappedTextureData
 };
 
 struct MappedYCbCrChannelData
 {
   uint8_t* data;
   gfx::IntSize size;
   int32_t stride;
   int32_t skip;
+  uint32_t bytesPerPixel;
 
   bool CopyInto(MappedYCbCrChannelData& aDst);
 };
 
 struct MappedYCbCrTextureData {
   MappedYCbCrChannelData y;
   MappedYCbCrChannelData cb;
   MappedYCbCrChannelData cr;
@@ -342,19 +343,22 @@ public:
                     BackendSelector aSelector,
                     TextureFlags aTextureFlags,
                     TextureAllocationFlags aAllocFlags);
 
   // Creates and allocates a TextureClient supporting the YCbCr format.
   static already_AddRefed<TextureClient>
   CreateForYCbCr(KnowsCompositor* aAllocator,
                  gfx::IntSize aYSize,
+                 uint32_t aYStride,
                  gfx::IntSize aCbCrSize,
+                 uint32_t aCbCrStride,
                  StereoMode aStereoMode,
                  YUVColorSpace aYUVColorSpace,
+                 uint32_t aBitDepth,
                  TextureFlags aTextureFlags);
 
   // Creates and allocates a TextureClient (can be accessed through raw
   // pointers).
   static already_AddRefed<TextureClient>
   CreateForRawBufferAccess(KnowsCompositor* aAllocator,
                            gfx::SurfaceFormat aFormat,
                            gfx::IntSize aSize,
@@ -364,16 +368,17 @@ public:
 
   // Creates and allocates a TextureClient (can beaccessed through raw
   // pointers) with a certain buffer size. It's unfortunate that we need this.
   // providing format and sizes could let us do more optimization.
   static already_AddRefed<TextureClient>
   CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
                                size_t aSize,
                                YUVColorSpace aYUVColorSpace,
+                               uint32_t aBitDepth,
                                TextureFlags aTextureFlags);
 
   // Creates and allocates a TextureClient of the same type.
   already_AddRefed<TextureClient>
   CreateSimilar(LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
                 TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const;
 
--- a/gfx/layers/client/TextureClientRecycleAllocator.cpp
+++ b/gfx/layers/client/TextureClientRecycleAllocator.cpp
@@ -103,30 +103,34 @@ YCbCrTextureClientAllocationHelper::IsCo
 
   BufferTextureData* bufferData = aTextureClient->GetInternalData()->AsBufferTextureData();
   if (!bufferData ||
       aTextureClient->GetSize() != mData.mYSize ||
       bufferData->GetCbCrSize().isNothing() ||
       bufferData->GetCbCrSize().ref() != mData.mCbCrSize ||
       bufferData->GetYUVColorSpace().isNothing() ||
       bufferData->GetYUVColorSpace().ref() != mData.mYUVColorSpace ||
+      bufferData->GetBitDepth().isNothing() ||
+      bufferData->GetBitDepth().ref() != mData.mBitDepth ||
       bufferData->GetStereoMode().isNothing() ||
       bufferData->GetStereoMode().ref() != mData.mStereoMode) {
     return false;
   }
   return true;
 }
 
 already_AddRefed<TextureClient>
 YCbCrTextureClientAllocationHelper::Allocate(KnowsCompositor* aAllocator)
 {
   return TextureClient::CreateForYCbCr(aAllocator,
-                                       mData.mYSize, mData.mCbCrSize,
+                                       mData.mYSize, mData.mYStride,
+                                       mData.mCbCrSize, mData.mCbCrStride,
                                        mData.mStereoMode,
                                        mData.mYUVColorSpace,
+                                       mData.mBitDepth,
                                        mTextureFlags);
 }
 
 TextureClientRecycleAllocator::TextureClientRecycleAllocator(KnowsCompositor* aAllocator)
   : mSurfaceAllocator(aAllocator)
   , mMaxPooledSize(kMaxPooledSized)
   , mLock("TextureClientRecycleAllocatorImp.mLock")
   , mIsDestroyed(false)
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -441,17 +441,17 @@ TextureSource::~TextureSource()
 }
 
 const char*
 TextureSource::Name() const
 {
   MOZ_CRASH("GFX: TextureSource without class name");
   return "TextureSource";
 }
-  
+
 BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc,
                                      TextureFlags aFlags)
 : TextureHost(aFlags)
 , mUpdateSerial(1)
 , mLocked(false)
 , mNeedsFullUpdate(false)
 {
   mDescriptor = aDesc;
@@ -875,16 +875,26 @@ BufferTextureHost::GetYUVColorSpace() co
 {
   if (mFormat == gfx::SurfaceFormat::YUV) {
     const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
     return desc.yUVColorSpace();
   }
   return YUVColorSpace::UNKNOWN;
 }
 
+uint32_t
+BufferTextureHost::GetBitDepth() const
+{
+  if (mFormat == gfx::SurfaceFormat::YUV) {
+    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+    return desc.bitDepth();
+  }
+  return 8;
+}
+
 bool
 BufferTextureHost::UploadIfNeeded()
 {
   return MaybeUpload(!mNeedsFullUpdate ? &mMaybeUpdatedRegion : nullptr);
 }
 
 bool
 BufferTextureHost::MaybeUpload(nsIntRegion *aRegion)
@@ -981,29 +991,29 @@ BufferTextureHost::Upload(nsIntRegion *a
       MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling());
       srcY = mFirstSource;
       srcU = mFirstSource->GetNextSibling()->AsDataTextureSource();
       srcV = mFirstSource->GetNextSibling()->GetNextSibling()->AsDataTextureSource();
     }
 
     RefPtr<gfx::DataSourceSurface> tempY =
       gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetYChannel(buf, desc),
-                                                    desc.ySize().width,
+                                                    desc.yStride(),
                                                     desc.ySize(),
-                                                    gfx::SurfaceFormat::A8);
+                                                    SurfaceFormatForAlphaBitDepth(desc.bitDepth()));
     RefPtr<gfx::DataSourceSurface> tempCb =
       gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCbChannel(buf, desc),
-                                                    desc.cbCrSize().width,
+                                                    desc.cbCrStride(),
                                                     desc.cbCrSize(),
-                                                    gfx::SurfaceFormat::A8);
+                                                    SurfaceFormatForAlphaBitDepth(desc.bitDepth()));
     RefPtr<gfx::DataSourceSurface> tempCr =
       gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCrChannel(buf, desc),
-                                                    desc.cbCrSize().width,
+                                                    desc.cbCrStride(),
                                                     desc.cbCrSize(),
-                                                    gfx::SurfaceFormat::A8);
+                                                    SurfaceFormatForAlphaBitDepth(desc.bitDepth()));
     // We don't support partial updates for Y U V textures
     NS_ASSERTION(!aRegion, "Unsupported partial updates for YCbCr textures");
     if (!tempY ||
         !tempCb ||
         !tempCr ||
         !srcY->Update(tempY) ||
         !srcU->Update(tempCb) ||
         !srcV->Update(tempCr)) {
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -434,16 +434,21 @@ public:
    * Return the format used for reading the texture.
    * Apple's YCBCR_422 is R8G8B8X8.
    */
   virtual gfx::SurfaceFormat GetReadFormat() const { return GetFormat(); }
 
   virtual YUVColorSpace GetYUVColorSpace() const { return YUVColorSpace::UNKNOWN; }
 
   /**
+   * Return the bit depth of the image. Used with YUV textures.
+   */
+  virtual uint32_t GetBitDepth() const { return 8; }
+
+  /**
    * Called during the transaction. The TextureSource may or may not be composited.
    *
    * Note that this is called outside of lock/unlock.
    */
   virtual void PrepareTextureSource(CompositableTextureSourceRef& aTexture) {}
 
   /**
    * Called at composition time, just before compositing the TextureSource composited.
@@ -727,16 +732,18 @@ public:
    *
    * If the shared format is YCbCr and the compositor does not support it,
    * GetFormat will be RGB32 (even though mFormat is SurfaceFormat::YUV).
    */
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual YUVColorSpace GetYUVColorSpace() const override;
 
+  virtual uint32_t GetBitDepth() const override;
+
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
 
   virtual bool HasIntermediateBuffer() const override { return mHasIntermediateBuffer; }
 
   virtual BufferTextureHost* AsBufferTextureHost() override { return this; }
 
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -95,22 +95,25 @@ struct SurfaceDescriptorGPUVideo {
 struct RGBDescriptor {
   IntSize size;
   SurfaceFormat format;
   bool hasIntermediateBuffer;
 };
 
 struct YCbCrDescriptor {
   IntSize ySize;
+  uint32_t yStride;
   IntSize cbCrSize;
+  uint32_t cbCrStride;
   uint32_t yOffset;
   uint32_t cbOffset;
   uint32_t crOffset;
   StereoMode stereoMode;
   YUVColorSpace yUVColorSpace;
+  uint32_t bitDepth;
   bool hasIntermediateBuffer;
 };
 
 union BufferDescriptor {
   RGBDescriptor;
   YCbCrDescriptor;
 };
 
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -108,23 +108,31 @@ SharedPlanarYCbCrImage::AdoptData(const 
   mOrigin = gfx::IntPoint(aData.mPicX, aData.mPicY);
 
   uint8_t *base = GetBuffer();
   uint32_t yOffset = aData.mYChannel - base;
   uint32_t cbOffset = aData.mCbChannel - base;
   uint32_t crOffset = aData.mCrChannel - base;
 
   auto fwd = mCompositable->GetForwarder();
-  bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(gfx::SurfaceFormat::YUV,
-                                                            fwd->GetCompositorBackendType());
+  bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(
+    gfx::SurfaceFormat::YUV, fwd->GetCompositorBackendType());
 
-  static_cast<BufferTextureData*>(mTextureClient->GetInternalData())->SetDesciptor(
-    YCbCrDescriptor(aData.mYSize, aData.mCbCrSize, yOffset, cbOffset, crOffset,
-                    aData.mStereoMode, aData.mYUVColorSpace, hasIntermediateBuffer)
-  );
+  static_cast<BufferTextureData*>(mTextureClient->GetInternalData())
+    ->SetDesciptor(YCbCrDescriptor(aData.mYSize,
+                                   aData.mYStride,
+                                   aData.mCbCrSize,
+                                   aData.mCbCrStride,
+                                   yOffset,
+                                   cbOffset,
+                                   crOffset,
+                                   aData.mStereoMode,
+                                   aData.mYUVColorSpace,
+                                   aData.mBitDepth,
+                                   hasIntermediateBuffer));
 
   return true;
 }
 
 bool
 SharedPlanarYCbCrImage::IsValid() {
   return mTextureClient && mTextureClient->IsValid();
 }
@@ -170,28 +178,30 @@ SharedPlanarYCbCrImage::Allocate(PlanarY
   mData.mCrChannel = aData.mCrChannel;
   mData.mYSize = aData.mYSize;
   mData.mCbCrSize = aData.mCbCrSize;
   mData.mPicX = aData.mPicX;
   mData.mPicY = aData.mPicY;
   mData.mPicSize = aData.mPicSize;
   mData.mStereoMode = aData.mStereoMode;
   mData.mYUVColorSpace = aData.mYUVColorSpace;
+  mData.mBitDepth = aData.mBitDepth;
   // those members are not always equal to aData's, due to potentially different
   // packing.
   mData.mYSkip = 0;
   mData.mCbSkip = 0;
   mData.mCrSkip = 0;
-  mData.mYStride = mData.mYSize.width;
-  mData.mCbCrStride = mData.mCbCrSize.width;
+  mData.mYStride = aData.mYStride;
+  mData.mCbCrStride = aData.mCbCrStride;
 
   // do not set mBuffer like in PlanarYCbCrImage because the later
   // will try to manage this memory without knowing it belongs to a
   // shmem.
-  mBufferSize = ImageDataSerializer::ComputeYCbCrBufferSize(mData.mYSize, mData.mCbCrSize);
+  mBufferSize = ImageDataSerializer::ComputeYCbCrBufferSize(
+    mData.mYSize, mData.mYStride, mData.mCbCrSize, mData.mCbCrStride);
   mSize = mData.mPicSize;
   mOrigin = gfx::IntPoint(aData.mPicX, aData.mPicY);
 
   mTextureClient->Unlock();
 
   return mBufferSize > 0;
 }
 
--- a/gfx/tests/gtest/TestTextures.cpp
+++ b/gfx/tests/gtest/TestTextures.cpp
@@ -257,16 +257,17 @@ TEST(Layers, TextureYCbCrSerialization) 
   clientData.mCrChannel = crSurface->Data();
   clientData.mYSize = ySurface->GetSize();
   clientData.mPicSize = ySurface->GetSize();
   clientData.mCbCrSize = cbSurface->GetSize();
   clientData.mYStride = ySurface->Stride();
   clientData.mCbCrStride = cbSurface->Stride();
   clientData.mStereoMode = StereoMode::MONO;
   clientData.mYUVColorSpace = YUVColorSpace::BT601;
+  clientData.mBitDepth = 8;
   clientData.mYSkip = 0;
   clientData.mCbSkip = 0;
   clientData.mCrSkip = 0;
   clientData.mCrSkip = 0;
   clientData.mPicX = 0;
   clientData.mPicX = 0;
 
   uint32_t namespaceId = 1;
@@ -285,16 +286,16 @@ TEST(Layers, TextureYCbCrSerialization) 
     retry--;
   }
 
   // Skip this testing if IPDL connection is not ready
   if (!retry && !imageBridge->IPCOpen()) {
     return;
   }
 
-  RefPtr<TextureClient> client = TextureClient::CreateForYCbCr(imageBridge, clientData.mYSize, clientData.mCbCrSize,
+  RefPtr<TextureClient> client = TextureClient::CreateForYCbCr(imageBridge, clientData.mYSize, clientData.mYStride, clientData.mCbCrSize, clientData.mCbCrStride,
                                                                StereoMode::MONO, YUVColorSpace::BT601,
-                                                               TextureFlags::DEALLOCATE_CLIENT);
+                                                               8, TextureFlags::DEALLOCATE_CLIENT);
 
   TestTextureClientYCbCr(client, clientData);
 
   // XXX - Test more texture client types.
 }
--- a/gfx/tests/gtest/TextureHelper.h
+++ b/gfx/tests/gtest/TextureHelper.h
@@ -57,19 +57,24 @@ CreateYCbCrTextureClientWithBackend(Laye
   clientData.mCbSkip = 0;
   clientData.mCrSkip = 0;
   clientData.mCrSkip = 0;
   clientData.mPicX = 0;
   clientData.mPicX = 0;
 
   // Create YCbCrTexture for basice backend.
   if (aLayersBackend == LayersBackend::LAYERS_BASIC) {
-    return TextureClient::CreateForYCbCr(nullptr, clientData.mYSize,
-                                         clientData.mCbCrSize, StereoMode::MONO,
+    return TextureClient::CreateForYCbCr(nullptr,
+                                         clientData.mYSize,
+                                         clientData.mYStride,
+                                         clientData.mCbCrSize,
+                                         clientData.mCbCrStride,
+                                         StereoMode::MONO,
                                          YUVColorSpace::BT601,
+                                         8,
                                          TextureFlags::DEALLOCATE_CLIENT);
   }
 
 #ifdef XP_WIN
   RefPtr<ID3D11Device> device = DeviceManagerDx::Get()->GetContentDevice();
 
   if (device && aLayersBackend == LayersBackend::LAYERS_D3D11) {
     // Create YCbCrD3D11TextureData