|
@@ -0,0 +1,1158 @@
|
|
|
|
+# HG changeset patch
|
|
|
|
+# User Jean-Yves Avenard <jyavenard@mozilla.com>
|
|
|
|
+# Date 1506695876 -7200
|
|
|
|
+# Node ID b55e89b5df041a28c7bf34d6896224a7e2d94929
|
|
|
|
+# Parent 84bcd57f2404a4fc48a42b36e5f553c8dec001ff
|
|
|
|
+Bug 1215089 - P7: Add support for 10/12 bits YUV surface with basic compositor. r=mattwoodrow
|
|
|
|
+
|
|
|
|
+MozReview-Commit-ID: Ej4MbvHnSk9
|
|
|
|
+
|
|
|
|
+diff --git a/gfx/2d/Tools.h b/gfx/2d/Tools.h
|
|
|
|
+--- a/gfx/2d/Tools.h
|
|
|
|
++++ b/gfx/2d/Tools.h
|
|
|
|
+@@ -88,30 +88,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:
|
|
|
|
+diff --git a/gfx/2d/Types.h b/gfx/2d/Types.h
|
|
|
|
+--- a/gfx/2d/Types.h
|
|
|
|
++++ b/gfx/2d/Types.h
|
|
|
|
+@@ -53,16 +53,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,
|
|
|
|
+diff --git a/gfx/layers/BufferTexture.cpp b/gfx/layers/BufferTexture.cpp
|
|
|
|
+--- a/gfx/layers/BufferTexture.cpp
|
|
|
|
++++ b/gfx/layers/BufferTexture.cpp
|
|
|
|
+@@ -155,67 +155,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;
|
|
|
|
+@@ -250,16 +266,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
|
|
|
|
+@@ -328,27 +350,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)
|
|
|
|
+ {
|
|
|
|
+diff --git a/gfx/layers/BufferTexture.h b/gfx/layers/BufferTexture.h
|
|
|
|
+--- a/gfx/layers/BufferTexture.h
|
|
|
|
++++ b/gfx/layers/BufferTexture.h
|
|
|
|
+@@ -26,27 +26,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;
|
|
|
|
+
|
|
|
|
+@@ -63,16 +67,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,
|
|
|
|
+diff --git a/gfx/layers/Effects.h b/gfx/layers/Effects.h
|
|
|
|
+--- a/gfx/layers/Effects.h
|
|
|
|
++++ b/gfx/layers/Effects.h
|
|
|
|
+@@ -157,24 +157,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)
|
|
|
|
+ {}
|
|
|
|
+
|
|
|
|
+@@ -266,17 +268,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();
|
|
|
|
+ }
|
|
|
|
+diff --git a/gfx/layers/ImageDataSerializer.cpp b/gfx/layers/ImageDataSerializer.cpp
|
|
|
|
+--- a/gfx/layers/ImageDataSerializer.cpp
|
|
|
|
++++ b/gfx/layers/ImageDataSerializer.cpp
|
|
|
|
+@@ -67,28 +67,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(const gfx::IntSize& aYSize, const gfx::IntSize& aCbCrSize,
|
|
|
|
+ uint32_t aYOffset, uint32_t aCbOffset, uint32_t aCrOffset)
|
|
|
|
+ {
|
|
|
|
+ MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
|
|
|
|
+
|
|
|
|
+ int32_t yStride = aYSize.width;
|
|
|
|
+ int32_t cbCrStride = aCbCrSize.width;
|
|
|
|
+@@ -168,37 +162,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();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+@@ -211,19 +215,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;
|
|
|
|
+@@ -240,24 +241,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();
|
|
|
|
+@@ -268,30 +270,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
|
|
|
|
+diff --git a/gfx/layers/ImageDataSerializer.h b/gfx/layers/ImageDataSerializer.h
|
|
|
|
+--- a/gfx/layers/ImageDataSerializer.h
|
|
|
|
++++ b/gfx/layers/ImageDataSerializer.h
|
|
|
|
+@@ -40,18 +40,16 @@ 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(const gfx::IntSize& aYSize,
|
|
|
|
+ const gfx::IntSize& aCbCrSize,
|
|
|
|
+ uint32_t aYOffset,
|
|
|
|
+ uint32_t aCbOffset,
|
|
|
|
+ uint32_t aCrOffset);
|
|
|
|
+ uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize);
|
|
|
|
+
|
|
|
|
+ void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
|
|
|
|
+ int32_t cbCrStride, int32_t cbCrHeight,
|
|
|
|
+@@ -60,16 +58,19 @@ void ComputeYCbCrOffsets(int32_t yStride
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp
|
|
|
|
+--- a/gfx/layers/client/ImageClient.cpp
|
|
|
|
++++ b/gfx/layers/client/ImageClient.cpp
|
|
|
|
+@@ -97,18 +97,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;
|
|
|
|
+diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp
|
|
|
|
+--- a/gfx/layers/client/TextureClient.cpp
|
|
|
|
++++ b/gfx/layers/client/TextureClient.cpp
|
|
|
|
+@@ -1253,82 +1253,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,
|
|
|
|
+@@ -1754,24 +1762,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())) {
|
|
|
|
+@@ -1806,25 +1818,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
|
|
|
|
+diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h
|
|
|
|
+--- a/gfx/layers/client/TextureClient.h
|
|
|
|
++++ b/gfx/layers/client/TextureClient.h
|
|
|
|
+@@ -135,16 +135,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;
|
|
|
|
+@@ -343,19 +344,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,
|
|
|
|
+@@ -365,16 +369,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;
|
|
|
|
+
|
|
|
|
+diff --git a/gfx/layers/client/TextureClientRecycleAllocator.cpp b/gfx/layers/client/TextureClientRecycleAllocator.cpp
|
|
|
|
+--- a/gfx/layers/client/TextureClientRecycleAllocator.cpp
|
|
|
|
++++ b/gfx/layers/client/TextureClientRecycleAllocator.cpp
|
|
|
|
+@@ -104,30 +104,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)
|
|
|
|
+diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp
|
|
|
|
+--- a/gfx/layers/composite/TextureHost.cpp
|
|
|
|
++++ b/gfx/layers/composite/TextureHost.cpp
|
|
|
|
+@@ -485,17 +485,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;
|
|
|
|
+@@ -934,16 +934,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)
|
|
|
|
+@@ -1039,29 +1049,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)) {
|
|
|
|
+diff --git a/gfx/layers/composite/TextureHost.h b/gfx/layers/composite/TextureHost.h
|
|
|
|
+--- a/gfx/layers/composite/TextureHost.h
|
|
|
|
++++ b/gfx/layers/composite/TextureHost.h
|
|
|
|
+@@ -435,16 +435,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.
|
|
|
|
+@@ -731,16 +736,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; }
|
|
|
|
+
|
|
|
|
+diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh
|
|
|
|
+--- 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;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+diff --git a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
|
|
|
|
+--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
|
|
|
|
++++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
|
|
|
|
+@@ -117,23 +117,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();
|
|
|
|
+ }
|
|
|
|
+@@ -179,28 +187,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;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+diff --git a/gfx/tests/gtest/TestTextures.cpp b/gfx/tests/gtest/TestTextures.cpp
|
|
|
|
+--- a/gfx/tests/gtest/TestTextures.cpp
|
|
|
|
++++ b/gfx/tests/gtest/TestTextures.cpp
|
|
|
|
+@@ -261,16 +261,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;
|
|
|
|
+@@ -289,16 +290,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.
|
|
|
|
+ }
|
|
|
|
+diff --git a/gfx/tests/gtest/TextureHelper.h b/gfx/tests/gtest/TextureHelper.h
|
|
|
|
+--- 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
|