Bug 1906527 Part 3: Add YUV422P10 and NV16 formats. r=gfx-reviewers,ahale
YUV422P10 is needed to properly tag decoded YUV422P10 video. NV16 is needed to describe the macOS 10-bit YUV422 formats. Differential Revision: https://phabricator.services.mozilla.com/D217334
This commit is contained in:
@@ -322,10 +322,11 @@ Maybe<VideoPixelFormat> SurfaceFormatToVideoPixelFormat(
|
||||
return Some(VideoPixelFormat::RGBX);
|
||||
case gfx::SurfaceFormat::YUV420:
|
||||
return Some(VideoPixelFormat::I420);
|
||||
case gfx::SurfaceFormat::YUV422P10:
|
||||
return Some(VideoPixelFormat::I422P10);
|
||||
case gfx::SurfaceFormat::NV12:
|
||||
return Some(VideoPixelFormat::NV12);
|
||||
case gfx::SurfaceFormat::YUY2:
|
||||
return Some(VideoPixelFormat::I422);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -126,9 +126,58 @@ size_t CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
// Helper function to set common color IOSurface properties.
|
||||
void SetIOSurfaceCommonProperties(
|
||||
CFTypeRefPtr<IOSurfaceRef> surfaceRef,
|
||||
MacIOSurface::YUVColorSpace aColorSpace,
|
||||
MacIOSurface::TransferFunction aTransferFunction) {
|
||||
// Setup the correct YCbCr conversion matrix, color primaries, and transfer
|
||||
// functions on the IOSurface, in case we pass this directly to CoreAnimation.
|
||||
// For keys and values, we'd like to use values specified by the API, but
|
||||
// those are only defined for CVImageBuffers. Luckily, when an image buffer is
|
||||
// converted into an IOSurface, the keys are transformed but the values are
|
||||
// the same. Since we are creating the IOSurface directly, we use hard-coded
|
||||
// keys derived from inspecting the extracted IOSurfaces in the copying case,
|
||||
// but we use the API-defined values from CVImageBuffer.
|
||||
if (aColorSpace == MacIOSurface::YUVColorSpace::BT601) {
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
|
||||
kCVImageBufferYCbCrMatrix_ITU_R_601_4);
|
||||
} else if (aColorSpace == MacIOSurface::YUVColorSpace::BT709) {
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
|
||||
kCVImageBufferYCbCrMatrix_ITU_R_709_2);
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorPrimaries"),
|
||||
kCVImageBufferColorPrimaries_ITU_R_709_2);
|
||||
} else {
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
|
||||
kCVImageBufferYCbCrMatrix_ITU_R_2020);
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorPrimaries"),
|
||||
kCVImageBufferColorPrimaries_ITU_R_2020);
|
||||
}
|
||||
|
||||
// Transfer function is applied independently from the colorSpace.
|
||||
IOSurfaceSetValue(
|
||||
surfaceRef.get(), CFSTR("IOSurfaceTransferFunction"),
|
||||
gfxMacUtils::CFStringForTransferFunction(aTransferFunction));
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// Override the color space to be the same as the main display, so that
|
||||
// CoreAnimation won't try to do any color correction (from the IOSurface
|
||||
// space, to the display). In the future we may want to try specifying this
|
||||
// correctly, but probably only once we do the same for videos drawn through
|
||||
// our gfx code.
|
||||
auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
|
||||
CGDisplayCopyColorSpace(CGMainDisplayID()));
|
||||
auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
|
||||
CGColorSpaceCopyICCData(colorSpace.get()));
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
|
||||
colorData.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12OrP010Surface(
|
||||
const IntSize& aYSize, const IntSize& aCbCrSize, YUVColorSpace aColorSpace,
|
||||
already_AddRefed<MacIOSurface> MacIOSurface::CreateBiPlanarSurface(
|
||||
const IntSize& aYSize, const IntSize& aCbCrSize,
|
||||
ChromaSubsampling aChromaSubsampling, YUVColorSpace aColorSpace,
|
||||
TransferFunction aTransferFunction, ColorRange aColorRange,
|
||||
ColorDepth aColorDepth) {
|
||||
MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
|
||||
@@ -152,27 +201,43 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12OrP010Surface(
|
||||
AddDictionaryInt(props, kIOSurfaceHeight, aYSize.height);
|
||||
::CFDictionaryAddValue(props.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
|
||||
|
||||
if (aColorRange == ColorRange::LIMITED) {
|
||||
if (aChromaSubsampling == ChromaSubsampling::HALF_WIDTH_AND_HEIGHT) {
|
||||
// 4:2:0 subsampling.
|
||||
if (aColorDepth == ColorDepth::COLOR_8) {
|
||||
if (aColorRange == ColorRange::LIMITED) {
|
||||
AddDictionaryInt(
|
||||
props, kIOSurfacePixelFormat,
|
||||
(uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
|
||||
} else {
|
||||
AddDictionaryInt(
|
||||
props, kIOSurfacePixelFormat,
|
||||
(uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange);
|
||||
(uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
|
||||
}
|
||||
} else {
|
||||
if (aColorDepth == ColorDepth::COLOR_8) {
|
||||
if (aColorRange == ColorRange::LIMITED) {
|
||||
AddDictionaryInt(
|
||||
props, kIOSurfacePixelFormat,
|
||||
(uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
|
||||
(uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange);
|
||||
} else {
|
||||
AddDictionaryInt(
|
||||
props, kIOSurfacePixelFormat,
|
||||
(uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarFullRange);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 4:2:2 subsampling. We can only handle 10-bit color.
|
||||
MOZ_ASSERT(aColorDepth == ColorDepth::COLOR_10,
|
||||
"macOS bi-planar 4:2:2 formats must be 10-bit color.");
|
||||
if (aColorRange == ColorRange::LIMITED) {
|
||||
AddDictionaryInt(
|
||||
props, kIOSurfacePixelFormat,
|
||||
(uint32_t)kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange);
|
||||
} else {
|
||||
AddDictionaryInt(
|
||||
props, kIOSurfacePixelFormat,
|
||||
(uint32_t)kCVPixelFormatType_422YpCbCr10BiPlanarFullRange);
|
||||
}
|
||||
}
|
||||
|
||||
size_t bytesPerPixel = (aColorDepth == ColorDepth::COLOR_8) ? 1 : 2;
|
||||
|
||||
@@ -201,47 +266,7 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12OrP010Surface(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Setup the correct YCbCr conversion matrix, color primaries, and transfer
|
||||
// functions on the IOSurface, in case we pass this directly to CoreAnimation.
|
||||
// For keys and values, we'd like to use values specified by the API, but
|
||||
// those are only defined for CVImageBuffers. Luckily, when an image buffer is
|
||||
// converted into an IOSurface, the keys are transformed but the values are
|
||||
// the same. Since we are creating the IOSurface directly, we use hard-coded
|
||||
// keys derived from inspecting the extracted IOSurfaces in the copying case,
|
||||
// but we use the API-defined values from CVImageBuffer.
|
||||
if (aColorSpace == YUVColorSpace::BT601) {
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
|
||||
kCVImageBufferYCbCrMatrix_ITU_R_601_4);
|
||||
} else if (aColorSpace == YUVColorSpace::BT709) {
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
|
||||
kCVImageBufferYCbCrMatrix_ITU_R_709_2);
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorPrimaries"),
|
||||
kCVImageBufferColorPrimaries_ITU_R_709_2);
|
||||
} else {
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
|
||||
kCVImageBufferYCbCrMatrix_ITU_R_2020);
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorPrimaries"),
|
||||
kCVImageBufferColorPrimaries_ITU_R_2020);
|
||||
}
|
||||
|
||||
// Transfer function is applied independently from the colorSpace.
|
||||
IOSurfaceSetValue(
|
||||
surfaceRef.get(), CFSTR("IOSurfaceTransferFunction"),
|
||||
gfxMacUtils::CFStringForTransferFunction(aTransferFunction));
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// Override the color space to be the same as the main display, so that
|
||||
// CoreAnimation won't try to do any color correction (from the IOSurface
|
||||
// space, to the display). In the future we may want to try specifying this
|
||||
// correctly, but probably only once we do the same for videos drawn through
|
||||
// our gfx code.
|
||||
auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
|
||||
CGDisplayCopyColorSpace(CGMainDisplayID()));
|
||||
auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
|
||||
CGColorSpaceCopyICCData(colorSpace.get()));
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
|
||||
colorData.get());
|
||||
#endif
|
||||
SetIOSurfaceCommonProperties(surfaceRef, aColorSpace, aTransferFunction);
|
||||
|
||||
RefPtr<MacIOSurface> ioSurface =
|
||||
new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
|
||||
@@ -250,8 +275,9 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12OrP010Surface(
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<MacIOSurface> MacIOSurface::CreateYUY2Surface(
|
||||
const IntSize& aSize, YUVColorSpace aColorSpace, ColorRange aColorRange) {
|
||||
already_AddRefed<MacIOSurface> MacIOSurface::CreateSinglePlanarSurface(
|
||||
const IntSize& aSize, YUVColorSpace aColorSpace,
|
||||
TransferFunction aTransferFunction, ColorRange aColorRange) {
|
||||
MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
|
||||
aColorSpace == YUVColorSpace::BT709);
|
||||
MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
|
||||
@@ -284,29 +310,7 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateYUY2Surface(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Setup the correct YCbCr conversion matrix on the IOSurface, in case we pass
|
||||
// this directly to CoreAnimation.
|
||||
if (aColorSpace == YUVColorSpace::BT601) {
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
|
||||
CFSTR("ITU_R_601_4"));
|
||||
} else {
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
|
||||
CFSTR("ITU_R_709_2"));
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// Override the color space to be the same as the main display, so that
|
||||
// CoreAnimation won't try to do any color correction (from the IOSurface
|
||||
// space, to the display). In the future we may want to try specifying this
|
||||
// correctly, but probably only once we do the same for videos drawn through
|
||||
// our gfx code.
|
||||
auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
|
||||
CGDisplayCopyColorSpace(CGMainDisplayID()));
|
||||
auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
|
||||
CGColorSpaceCopyICCData(colorSpace.get()));
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
|
||||
colorData.get());
|
||||
#endif
|
||||
SetIOSurfaceCommonProperties(surfaceRef, aColorSpace, aTransferFunction);
|
||||
|
||||
RefPtr<MacIOSurface> ioSurface =
|
||||
new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
|
||||
@@ -467,6 +471,9 @@ SurfaceFormat MacIOSurface::GetFormat() const {
|
||||
case kCVPixelFormatType_422YpCbCr8_yuvs:
|
||||
case kCVPixelFormatType_422YpCbCr8FullRange:
|
||||
return SurfaceFormat::YUY2;
|
||||
case kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange:
|
||||
case kCVPixelFormatType_422YpCbCr10BiPlanarFullRange:
|
||||
return SurfaceFormat::NV16;
|
||||
case kCVPixelFormatType_32BGRA:
|
||||
return HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
|
||||
default:
|
||||
@@ -487,6 +494,8 @@ ColorDepth MacIOSurface::GetColorDepth() const {
|
||||
switch (GetPixelFormat()) {
|
||||
case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
|
||||
case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
|
||||
case kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange:
|
||||
case kCVPixelFormatType_422YpCbCr10BiPlanarFullRange:
|
||||
return ColorDepth::COLOR_10;
|
||||
default:
|
||||
return ColorDepth::COLOR_8;
|
||||
@@ -541,6 +550,25 @@ bool MacIOSurface::BindTexImage(mozilla::gl::GLContext* aGL, size_t aPlane,
|
||||
if (aOutReadFormat) {
|
||||
*aOutReadFormat = mozilla::gfx::SurfaceFormat::P010;
|
||||
}
|
||||
} else if (pixelFormat == kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange ||
|
||||
pixelFormat == kCVPixelFormatType_422YpCbCr10BiPlanarFullRange) {
|
||||
MOZ_ASSERT(GetPlaneCount() == 2);
|
||||
MOZ_ASSERT(aPlane < 2);
|
||||
|
||||
// The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated
|
||||
// format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile.
|
||||
// https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats
|
||||
if (aPlane == 0) {
|
||||
internalFormat = format =
|
||||
(isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE) : (LOCAL_GL_RED);
|
||||
} else {
|
||||
internalFormat = format =
|
||||
(isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE_ALPHA) : (LOCAL_GL_RG);
|
||||
}
|
||||
type = LOCAL_GL_UNSIGNED_SHORT;
|
||||
if (aOutReadFormat) {
|
||||
*aOutReadFormat = mozilla::gfx::SurfaceFormat::NV16;
|
||||
}
|
||||
} else if (pixelFormat == kCVPixelFormatType_422YpCbCr8_yuvs ||
|
||||
pixelFormat == kCVPixelFormatType_422YpCbCr8FullRange) {
|
||||
MOZ_ASSERT(aPlane == 0);
|
||||
|
||||
@@ -48,6 +48,7 @@ class MacIOSurface final
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
typedef mozilla::gfx::BackendType BackendType;
|
||||
typedef mozilla::gfx::IntSize IntSize;
|
||||
typedef mozilla::gfx::ChromaSubsampling ChromaSubsampling;
|
||||
typedef mozilla::gfx::YUVColorSpace YUVColorSpace;
|
||||
typedef mozilla::gfx::ColorSpace2 ColorSpace2;
|
||||
typedef mozilla::gfx::TransferFunction TransferFunction;
|
||||
@@ -60,12 +61,14 @@ class MacIOSurface final
|
||||
|
||||
static already_AddRefed<MacIOSurface> CreateIOSurface(int aWidth, int aHeight,
|
||||
bool aHasAlpha = true);
|
||||
static already_AddRefed<MacIOSurface> CreateNV12OrP010Surface(
|
||||
static already_AddRefed<MacIOSurface> CreateBiPlanarSurface(
|
||||
const IntSize& aYSize, const IntSize& aCbCrSize,
|
||||
YUVColorSpace aColorSpace, TransferFunction aTransferFunction,
|
||||
ColorRange aColorRange, ColorDepth aColorDepth);
|
||||
static already_AddRefed<MacIOSurface> CreateYUY2Surface(
|
||||
const IntSize& aSize, YUVColorSpace aColorSpace, ColorRange aColorRange);
|
||||
ChromaSubsampling aChromaSubsampling, YUVColorSpace aColorSpace,
|
||||
TransferFunction aTransferFunction, ColorRange aColorRange,
|
||||
ColorDepth aColorDepth);
|
||||
static already_AddRefed<MacIOSurface> CreateSinglePlanarSurface(
|
||||
const IntSize& aSize, YUVColorSpace aColorSpace,
|
||||
TransferFunction aTransferFunction, ColorRange aColorRange);
|
||||
static void ReleaseIOSurface(MacIOSurface* aIOSurface);
|
||||
static already_AddRefed<MacIOSurface> LookupSurface(
|
||||
IOSurfaceID aSurfaceID, bool aHasAlpha = true,
|
||||
@@ -115,7 +118,9 @@ class MacIOSurface final
|
||||
bool IsFullRange() const {
|
||||
OSType format = GetPixelFormat();
|
||||
return (format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
|
||||
format == kCVPixelFormatType_420YpCbCr10BiPlanarFullRange);
|
||||
format == kCVPixelFormatType_420YpCbCr10BiPlanarFullRange ||
|
||||
format == kCVPixelFormatType_422YpCbCr10BiPlanarFullRange ||
|
||||
format == kCVPixelFormatType_422YpCbCr8FullRange);
|
||||
}
|
||||
mozilla::gfx::ColorRange GetColorRange() const {
|
||||
if (IsFullRange()) return mozilla::gfx::ColorRange::FULL;
|
||||
|
||||
@@ -56,9 +56,11 @@ std::ostream& operator<<(std::ostream& aOut, const SurfaceFormat& aFormat) {
|
||||
Emit(SurfaceFormat::R8G8);
|
||||
Emit(SurfaceFormat::R16G16);
|
||||
Emit(SurfaceFormat::YUV420);
|
||||
Emit(SurfaceFormat::YUV422P10);
|
||||
Emit(SurfaceFormat::NV12);
|
||||
Emit(SurfaceFormat::P016);
|
||||
Emit(SurfaceFormat::P010);
|
||||
Emit(SurfaceFormat::NV16);
|
||||
Emit(SurfaceFormat::YUY2);
|
||||
Emit(SurfaceFormat::HSV);
|
||||
Emit(SurfaceFormat::Lab);
|
||||
|
||||
@@ -74,6 +74,9 @@ enum class SurfaceFormat : int8_t {
|
||||
|
||||
// These ones are their own special cases.
|
||||
YUV420, // Sometimes called YU12. 3 planes of 8 bit Y, then Cb, then Cr.
|
||||
// 4:2:0 chroma subsampling.
|
||||
YUV422P10, // 3 planes like YUV420, but with 4:2:2 chroma subampling and
|
||||
// 16 bit plane values where the 6 least significant bits are 0.
|
||||
NV12, // 2 planes. YUV 4:2:0 image with a plane of 8 bit Y samples
|
||||
// followed by an interleaved U/V plane containing 8 bit 2x2
|
||||
// subsampled colour difference samples.
|
||||
@@ -81,6 +84,9 @@ enum class SurfaceFormat : int8_t {
|
||||
P010, // Identical to P016 but the 6 least significant bits are 0.
|
||||
// With DXGI in theory entirely compatible, however practice has
|
||||
// shown that it's not the case.
|
||||
NV16, // Similar to NV12, but with 4:2:2 chroma subsampling. Technically
|
||||
// 8 bit, but we only use it for 10 bit, and it's really only here
|
||||
// to support the macOS bi-planar 422 formats.
|
||||
YUY2, // Sometimes called YUYV. Single plane / packed YUV 4:2:2 8 bit
|
||||
// samples interleaved as Y`0 Cb Y`1 Cr. Since 4 pixels require
|
||||
// 64 bits, this can also be considered a 16bpp format, but each
|
||||
@@ -152,9 +158,11 @@ inline std::optional<SurfaceFormatInfo> Info(const SurfaceFormat aFormat) {
|
||||
break;
|
||||
|
||||
case SurfaceFormat::YUV420:
|
||||
case SurfaceFormat::YUV422P10:
|
||||
case SurfaceFormat::NV12:
|
||||
case SurfaceFormat::P016:
|
||||
case SurfaceFormat::P010:
|
||||
case SurfaceFormat::NV16:
|
||||
case SurfaceFormat::YUY2:
|
||||
info.hasColor = true;
|
||||
info.hasAlpha = false;
|
||||
@@ -207,9 +215,11 @@ inline std::optional<SurfaceFormatInfo> Info(const SurfaceFormat aFormat) {
|
||||
break;
|
||||
|
||||
case SurfaceFormat::YUV420:
|
||||
case SurfaceFormat::YUV422P10:
|
||||
case SurfaceFormat::NV12:
|
||||
case SurfaceFormat::P016:
|
||||
case SurfaceFormat::P010:
|
||||
case SurfaceFormat::NV16:
|
||||
case SurfaceFormat::YUY2:
|
||||
case SurfaceFormat::UNKNOWN:
|
||||
break; // No bytesPerPixel per se.
|
||||
|
||||
@@ -88,8 +88,8 @@ bool MacIOSurfaceImage::SetData(ImageContainer* aContainer,
|
||||
auto ySize = aData.YDataSize();
|
||||
auto cbcrSize = aData.CbCrDataSize();
|
||||
RefPtr<MacIOSurface> surf = allocator->Allocate(
|
||||
ySize, cbcrSize, aData.mYUVColorSpace, aData.mTransferFunction,
|
||||
aData.mColorRange, aData.mColorDepth);
|
||||
ySize, cbcrSize, aData.mChromaSubsampling, aData.mYUVColorSpace,
|
||||
aData.mTransferFunction, aData.mColorRange, aData.mColorDepth);
|
||||
|
||||
surf->Lock(false);
|
||||
|
||||
@@ -194,6 +194,51 @@ bool MacIOSurfaceImage::SetData(ImageContainer* aContainer,
|
||||
(uint16_t*)(aData.mCrChannel + aData.mCbCrStride * i);
|
||||
uint16_t* rowDst = dst + stride * i;
|
||||
|
||||
for (const auto j : IntegerRange(cbcrSize.width)) {
|
||||
Unused << j;
|
||||
|
||||
*rowDst = safeShift10BitBy6(*rowCbSrc);
|
||||
rowDst++;
|
||||
rowCbSrc++;
|
||||
|
||||
*rowDst = safeShift10BitBy6(*rowCrSrc);
|
||||
rowDst++;
|
||||
rowCrSrc++;
|
||||
}
|
||||
}
|
||||
} else if (surf->GetFormat() == SurfaceFormat::NV16) {
|
||||
MOZ_ASSERT(aData.mColorDepth == ColorDepth::COLOR_10,
|
||||
"Currently NV16 only supports 10-bit color.");
|
||||
MOZ_ASSERT(ySize.height > 0);
|
||||
auto dst = reinterpret_cast<uint16_t*>(surf->GetBaseAddressOfPlane(0));
|
||||
size_t stride = surf->GetBytesPerRow(0) / 2;
|
||||
for (size_t i = 0; i < (size_t)ySize.height; i++) {
|
||||
auto rowSrc = reinterpret_cast<const uint16_t*>(aData.mYChannel +
|
||||
aData.mYStride * i);
|
||||
auto rowDst = dst + stride * i;
|
||||
|
||||
for (const auto j : IntegerRange(ySize.width)) {
|
||||
Unused << j;
|
||||
|
||||
*rowDst = safeShift10BitBy6(*rowSrc);
|
||||
rowDst++;
|
||||
rowSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy and interleave the Cb and Cr channels.
|
||||
MOZ_ASSERT(cbcrSize.height > 0);
|
||||
MOZ_ASSERT(cbcrSize.height == ySize.height,
|
||||
"4:2:2 CbCr should have same height as Y.");
|
||||
dst = (uint16_t*)surf->GetBaseAddressOfPlane(1);
|
||||
stride = surf->GetBytesPerRow(1) / 2;
|
||||
for (size_t i = 0; i < (size_t)cbcrSize.height; i++) {
|
||||
uint16_t* rowCbSrc =
|
||||
(uint16_t*)(aData.mCbChannel + aData.mCbCrStride * i);
|
||||
uint16_t* rowCrSrc =
|
||||
(uint16_t*)(aData.mCrChannel + aData.mCbCrStride * i);
|
||||
uint16_t* rowDst = dst + stride * i;
|
||||
|
||||
for (const auto j : IntegerRange(cbcrSize.width)) {
|
||||
Unused << j;
|
||||
|
||||
@@ -216,6 +261,7 @@ bool MacIOSurfaceImage::SetData(ImageContainer* aContainer,
|
||||
|
||||
already_AddRefed<MacIOSurface> MacIOSurfaceRecycleAllocator::Allocate(
|
||||
const gfx::IntSize aYSize, const gfx::IntSize& aCbCrSize,
|
||||
gfx::ChromaSubsampling aChromaSubsampling,
|
||||
gfx::YUVColorSpace aYUVColorSpace, gfx::TransferFunction aTransferFunction,
|
||||
gfx::ColorRange aColorRange, gfx::ColorDepth aColorDepth) {
|
||||
nsTArray<CFTypeRefPtr<IOSurfaceRef>> surfaces = std::move(mSurfaces);
|
||||
@@ -238,13 +284,23 @@ already_AddRefed<MacIOSurface> MacIOSurfaceRecycleAllocator::Allocate(
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
if (StaticPrefs::layers_iosurfaceimage_use_nv12_AtStartup()) {
|
||||
result = MacIOSurface::CreateNV12OrP010Surface(
|
||||
aYSize, aCbCrSize, aYUVColorSpace, aTransferFunction, aColorRange,
|
||||
aColorDepth);
|
||||
// Time to decide if we are creating a single planar or bi-planar surface.
|
||||
// We limit ourselves to macOS's single planar and bi-planar formats for
|
||||
// simplicity reasons, possibly gaining some small memory or performance
|
||||
// benefit relative to the tri-planar formats. We try and use as few
|
||||
// planes as possible.
|
||||
// 4:2:0 formats are always bi-planar, because there is no 4:2:0 single
|
||||
// planar format.
|
||||
// 4:2:2 formats with 8 bit color are single planar, otherwise bi-planar.
|
||||
|
||||
if (aChromaSubsampling == gfx::ChromaSubsampling::HALF_WIDTH &&
|
||||
aColorDepth == gfx::ColorDepth::COLOR_8) {
|
||||
result = MacIOSurface::CreateSinglePlanarSurface(
|
||||
aYSize, aYUVColorSpace, aTransferFunction, aColorRange);
|
||||
} else {
|
||||
result =
|
||||
MacIOSurface::CreateYUY2Surface(aYSize, aYUVColorSpace, aColorRange);
|
||||
result = MacIOSurface::CreateBiPlanarSurface(
|
||||
aYSize, aCbCrSize, aChromaSubsampling, aYUVColorSpace,
|
||||
aTransferFunction, aColorRange, aColorDepth);
|
||||
}
|
||||
|
||||
if (mSurfaces.Length() <
|
||||
|
||||
@@ -62,6 +62,7 @@ class MacIOSurfaceRecycleAllocator {
|
||||
|
||||
already_AddRefed<MacIOSurface> Allocate(
|
||||
const gfx::IntSize aYSize, const gfx::IntSize& aCbCrSize,
|
||||
gfx::ChromaSubsampling aChromaSubsampling,
|
||||
gfx::YUVColorSpace aYUVColorSpace,
|
||||
gfx::TransferFunction aTransferFunction, gfx::ColorRange aColorRange,
|
||||
gfx::ColorDepth aColorDepth);
|
||||
|
||||
@@ -97,7 +97,8 @@ uint32_t MacIOSurfaceTextureHostOGL::NumSubTextures() {
|
||||
return 1;
|
||||
}
|
||||
case gfx::SurfaceFormat::NV12:
|
||||
case gfx::SurfaceFormat::P010: {
|
||||
case gfx::SurfaceFormat::P010:
|
||||
case gfx::SurfaceFormat::NV16: {
|
||||
return 2;
|
||||
}
|
||||
default: {
|
||||
@@ -173,6 +174,21 @@ void MacIOSurfaceTextureHostOGL::PushResourceUpdates(
|
||||
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
|
||||
break;
|
||||
}
|
||||
case gfx::SurfaceFormat::NV16: {
|
||||
MOZ_ASSERT(aImageKeys.length() == 2);
|
||||
MOZ_ASSERT(mSurface->GetPlaneCount() == 2);
|
||||
wr::ImageDescriptor descriptor0(
|
||||
gfx::IntSize(mSurface->GetDevicePixelWidth(0),
|
||||
mSurface->GetDevicePixelHeight(0)),
|
||||
gfx::SurfaceFormat::A16);
|
||||
wr::ImageDescriptor descriptor1(
|
||||
gfx::IntSize(mSurface->GetDevicePixelWidth(1),
|
||||
mSurface->GetDevicePixelHeight(1)),
|
||||
gfx::SurfaceFormat::R16G16);
|
||||
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
|
||||
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||
}
|
||||
@@ -231,6 +247,16 @@ void MacIOSurfaceTextureHostOGL::PushDisplayItems(
|
||||
/* aSupportsExternalCompositing */ true);
|
||||
break;
|
||||
}
|
||||
case gfx::SurfaceFormat::NV16: {
|
||||
MOZ_ASSERT(aImageKeys.length() == 2);
|
||||
MOZ_ASSERT(mSurface->GetPlaneCount() == 2);
|
||||
aBuilder.PushNV16Image(
|
||||
aBounds, aClip, true, aImageKeys[0], aImageKeys[1],
|
||||
wr::ColorDepth::Color10, wr::ToWrYuvColorSpace(GetYUVColorSpace()),
|
||||
wr::ToWrColorRange(GetColorRange()), aFilter, preferCompositorSurface,
|
||||
/* aSupportsExternalCompositing */ true);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
||||
}
|
||||
|
||||
@@ -1555,6 +1555,20 @@ void DisplayListBuilder::PushP010Image(
|
||||
aSupportsExternalCompositing);
|
||||
}
|
||||
|
||||
void DisplayListBuilder::PushNV16Image(
|
||||
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
|
||||
wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
|
||||
wr::WrYuvColorSpace aColorSpace, wr::WrColorRange aColorRange,
|
||||
wr::ImageRendering aRendering, bool aPreferCompositorSurface,
|
||||
bool aSupportsExternalCompositing) {
|
||||
wr_dp_push_yuv_NV16_image(
|
||||
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
||||
&mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, aColorDepth,
|
||||
aColorSpace, aColorRange, aRendering, aPreferCompositorSurface,
|
||||
aSupportsExternalCompositing);
|
||||
}
|
||||
|
||||
void DisplayListBuilder::PushYCbCrInterleavedImage(
|
||||
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
|
||||
|
||||
@@ -712,6 +712,14 @@ class DisplayListBuilder final {
|
||||
bool aPreferCompositorSurface = false,
|
||||
bool aSupportsExternalCompositing = false);
|
||||
|
||||
void PushNV16Image(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
|
||||
wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
|
||||
wr::WrYuvColorSpace aColorSpace,
|
||||
wr::WrColorRange aColorRange, wr::ImageRendering aFilter,
|
||||
bool aPreferCompositorSurface = false,
|
||||
bool aSupportsExternalCompositing = false);
|
||||
|
||||
void PushYCbCrInterleavedImage(
|
||||
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
|
||||
|
||||
@@ -3369,6 +3369,49 @@ pub extern "C" fn wr_dp_push_yuv_P010_image(
|
||||
);
|
||||
}
|
||||
|
||||
/// Push a 2 planar NV16 image.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_push_yuv_NV16_image(
|
||||
state: &mut WrState,
|
||||
bounds: LayoutRect,
|
||||
clip: LayoutRect,
|
||||
is_backface_visible: bool,
|
||||
parent: &WrSpaceAndClipChain,
|
||||
image_key_0: WrImageKey,
|
||||
image_key_1: WrImageKey,
|
||||
color_depth: WrColorDepth,
|
||||
color_space: WrYuvColorSpace,
|
||||
color_range: WrColorRange,
|
||||
image_rendering: ImageRendering,
|
||||
prefer_compositor_surface: bool,
|
||||
supports_external_compositing: bool,
|
||||
) {
|
||||
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
|
||||
|
||||
let space_and_clip = parent.to_webrender(state.pipeline_id);
|
||||
|
||||
let prim_info = CommonItemProperties {
|
||||
clip_rect: clip,
|
||||
clip_chain_id: space_and_clip.clip_chain_id,
|
||||
spatial_id: space_and_clip.spatial_id,
|
||||
flags: prim_flags2(
|
||||
is_backface_visible,
|
||||
prefer_compositor_surface,
|
||||
supports_external_compositing,
|
||||
),
|
||||
};
|
||||
|
||||
state.frame_builder.dl_builder.push_yuv_image(
|
||||
&prim_info,
|
||||
bounds,
|
||||
YuvData::NV16(image_key_0, image_key_1),
|
||||
color_depth,
|
||||
color_space,
|
||||
color_range,
|
||||
image_rendering,
|
||||
);
|
||||
}
|
||||
|
||||
/// Push a yuv interleaved image.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_push_yuv_interleaved_image(
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
|
||||
#define YUV_FORMAT_NV12 0
|
||||
#define YUV_FORMAT_P010 1
|
||||
#define YUV_FORMAT_PLANAR 2
|
||||
#define YUV_FORMAT_INTERLEAVED 3
|
||||
#define YUV_FORMAT_NV16 2
|
||||
#define YUV_FORMAT_PLANAR 3
|
||||
#define YUV_FORMAT_INTERLEAVED 4
|
||||
|
||||
//#define YUV_PRECISION mediump
|
||||
#define YUV_PRECISION highp
|
||||
@@ -200,6 +201,7 @@ vec4 sample_yuv(
|
||||
|
||||
case YUV_FORMAT_NV12:
|
||||
case YUV_FORMAT_P010:
|
||||
case YUV_FORMAT_NV16:
|
||||
{
|
||||
vec2 uv_y = clamp(in_uv_y, uv_bounds_y.xy, uv_bounds_y.zw);
|
||||
vec2 uv_uv = clamp(in_uv_u, uv_bounds_u.xy, uv_bounds_u.zw);
|
||||
|
||||
@@ -3613,6 +3613,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
let yuv_key = match yuv_data {
|
||||
YuvData::NV12(plane_0, plane_1) => [plane_0, plane_1, ImageKey::DUMMY],
|
||||
YuvData::P010(plane_0, plane_1) => [plane_0, plane_1, ImageKey::DUMMY],
|
||||
YuvData::NV16(plane_0, plane_1) => [plane_0, plane_1, ImageKey::DUMMY],
|
||||
YuvData::PlanarYCbCr(plane_0, plane_1, plane_2) => [plane_0, plane_1, plane_2],
|
||||
YuvData::InterleavedYCbCr(plane_0) => [plane_0, ImageKey::DUMMY, ImageKey::DUMMY],
|
||||
};
|
||||
|
||||
@@ -1928,6 +1928,7 @@ impl YuvColorSpace {
|
||||
pub enum YuvData {
|
||||
NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
|
||||
P010(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
|
||||
NV16(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
|
||||
PlanarYCbCr(ImageKey, ImageKey, ImageKey), // (Y channel, Cb channel, Cr Channel)
|
||||
InterleavedYCbCr(ImageKey), // (YCbCr interleaved channel)
|
||||
}
|
||||
@@ -1937,6 +1938,7 @@ impl YuvData {
|
||||
match *self {
|
||||
YuvData::NV12(..) => YuvFormat::NV12,
|
||||
YuvData::P010(..) => YuvFormat::P010,
|
||||
YuvData::NV16(..) => YuvFormat::NV16,
|
||||
YuvData::PlanarYCbCr(..) => YuvFormat::PlanarYCbCr,
|
||||
YuvData::InterleavedYCbCr(..) => YuvFormat::InterleavedYCbCr,
|
||||
}
|
||||
@@ -1945,16 +1947,18 @@ impl YuvData {
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum YuvFormat {
|
||||
// These enum values need to be kept in sync with yuv.glsl.
|
||||
NV12 = 0,
|
||||
P010 = 1,
|
||||
PlanarYCbCr = 2,
|
||||
InterleavedYCbCr = 3,
|
||||
NV16 = 2,
|
||||
PlanarYCbCr = 3,
|
||||
InterleavedYCbCr = 4,
|
||||
}
|
||||
|
||||
impl YuvFormat {
|
||||
pub fn get_plane_num(self) -> usize {
|
||||
match self {
|
||||
YuvFormat::NV12 | YuvFormat::P010 => 2,
|
||||
YuvFormat::NV12 | YuvFormat::P010 | YuvFormat::NV16 => 2,
|
||||
YuvFormat::PlanarYCbCr => 3,
|
||||
YuvFormat::InterleavedYCbCr => 1,
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
skip_on(android,device) fuzzy(1,331264) == tile-repeat-prim-or-decompose.yaml tile-repeat-prim-or-decompose-ref.yaml
|
||||
platform(linux,mac) options(allow-mipmaps) == downscale.yaml downscale.png
|
||||
skip_on(android,device) fuzzy-if(platform(swgl),1,20) == segments.yaml segments.png
|
||||
platform(linux,mac) fuzzy(1,6105) == yuv.yaml yuv.png
|
||||
platform(linux,mac) fuzzy(1,6105) fuzzy-if(platform(swgl),1,205000) == yuv-clip.yaml yuv.png
|
||||
platform(linux,mac) fuzzy(1,6108) == yuv.yaml yuv.png
|
||||
platform(linux,mac) fuzzy(1,6108) fuzzy-if(platform(swgl),1,205000) == yuv-clip.yaml yuv.png
|
||||
skip_on(android,device) == tiled-clip-chain.yaml tiled-clip-chain-ref.yaml
|
||||
skip_on(android,device) == tiled-complex-clip.yaml tiled-complex-clip-ref.yaml
|
||||
platform(linux,mac) == texture-rect.yaml texture-rect-ref.yaml
|
||||
|
||||
@@ -1235,6 +1235,15 @@ impl YamlFrameReader {
|
||||
|
||||
YuvData::P010(y_key, uv_key)
|
||||
}
|
||||
"nv16" => {
|
||||
let y_path = rsrc_path(&item["src-y"], &self.aux_dir);
|
||||
let (y_key, _) = self.add_or_get_image(&y_path, None, item, wrench);
|
||||
|
||||
let uv_path = rsrc_path(&item["src-uv"], &self.aux_dir);
|
||||
let (uv_key, _) = self.add_or_get_image(&uv_path, None, item, wrench);
|
||||
|
||||
YuvData::NV16(y_key, uv_key)
|
||||
}
|
||||
"interleaved" => {
|
||||
let yuv_path = rsrc_path(&item["src"], &self.aux_dir);
|
||||
let (yuv_key, _) = self.add_or_get_image(&yuv_path, None, item, wrench);
|
||||
|
||||
Reference in New Issue
Block a user