mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
f2d4007ad9
This allows us to achieve detachment for software-decoded NV12 video on M1 Macs. Differential Revision: https://phabricator.services.mozilla.com/D128914
524 lines
20 KiB
C++
524 lines
20 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "MacIOSurface.h"
|
|
#include <OpenGL/gl.h>
|
|
#include <OpenGL/CGLIOSurface.h>
|
|
#include <QuartzCore/QuartzCore.h>
|
|
#include "GLConsts.h"
|
|
#include "GLContextCGL.h"
|
|
#include "nsPrintfCString.h"
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "mozilla/gfx/Logging.h"
|
|
#include "mozilla/StaticPrefs_gfx.h"
|
|
|
|
using namespace mozilla;
|
|
|
|
MacIOSurface::MacIOSurface(CFTypeRefPtr<IOSurfaceRef> aIOSurfaceRef,
|
|
bool aHasAlpha, gfx::YUVColorSpace aColorSpace)
|
|
: mIOSurfaceRef(std::move(aIOSurfaceRef)),
|
|
mHasAlpha(aHasAlpha),
|
|
mColorSpace(aColorSpace) {
|
|
IncrementUseCount();
|
|
}
|
|
|
|
MacIOSurface::~MacIOSurface() {
|
|
MOZ_RELEASE_ASSERT(!IsLocked(), "Destroying locked surface");
|
|
DecrementUseCount();
|
|
}
|
|
|
|
void AddDictionaryInt(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
|
|
const void* aType, uint32_t aValue) {
|
|
auto cfValue = CFTypeRefPtr<CFNumberRef>::WrapUnderCreateRule(
|
|
::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aValue));
|
|
::CFDictionaryAddValue(aDict.get(), aType, cfValue.get());
|
|
}
|
|
|
|
void SetSizeProperties(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
|
|
int aWidth, int aHeight, int aBytesPerPixel) {
|
|
AddDictionaryInt(aDict, kIOSurfaceWidth, aWidth);
|
|
AddDictionaryInt(aDict, kIOSurfaceHeight, aHeight);
|
|
::CFDictionaryAddValue(aDict.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
|
|
AddDictionaryInt(aDict, kIOSurfaceBytesPerElement, aBytesPerPixel);
|
|
|
|
size_t bytesPerRow =
|
|
IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, aWidth * aBytesPerPixel);
|
|
AddDictionaryInt(aDict, kIOSurfaceBytesPerRow, bytesPerRow);
|
|
|
|
// Add a SIMD register worth of extra bytes to the end of the allocation for
|
|
// SWGL.
|
|
size_t totalBytes =
|
|
IOSurfaceAlignProperty(kIOSurfaceAllocSize, aHeight * bytesPerRow + 16);
|
|
AddDictionaryInt(aDict, kIOSurfaceAllocSize, totalBytes);
|
|
}
|
|
|
|
/* static */
|
|
already_AddRefed<MacIOSurface> MacIOSurface::CreateIOSurface(int aWidth,
|
|
int aHeight,
|
|
bool aHasAlpha) {
|
|
auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
|
|
::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
|
|
&kCFTypeDictionaryKeyCallBacks,
|
|
&kCFTypeDictionaryValueCallBacks));
|
|
if (!props) return nullptr;
|
|
|
|
MOZ_ASSERT((size_t)aWidth <= GetMaxWidth());
|
|
MOZ_ASSERT((size_t)aHeight <= GetMaxHeight());
|
|
|
|
int32_t bytesPerElem = 4;
|
|
SetSizeProperties(props, aWidth, aHeight, bytesPerElem);
|
|
|
|
AddDictionaryInt(props, kIOSurfacePixelFormat,
|
|
(uint32_t)kCVPixelFormatType_32BGRA);
|
|
|
|
CFTypeRefPtr<IOSurfaceRef> surfaceRef =
|
|
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
|
|
::IOSurfaceCreate(props.get()));
|
|
|
|
if (StaticPrefs::gfx_color_management_native_srgb()) {
|
|
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
|
|
kCGColorSpaceSRGB);
|
|
}
|
|
|
|
if (!surfaceRef) {
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<MacIOSurface> ioSurface =
|
|
new MacIOSurface(std::move(surfaceRef), aHasAlpha);
|
|
|
|
return ioSurface.forget();
|
|
}
|
|
|
|
size_t CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
|
|
const gfx::IntSize& aSize, size_t aOffset,
|
|
size_t aBytesPerPixel) {
|
|
size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfacePlaneBytesPerRow,
|
|
aSize.width * aBytesPerPixel);
|
|
// Add a SIMD register worth of extra bytes to the end of the allocation for
|
|
// SWGL.
|
|
size_t totalBytes = IOSurfaceAlignProperty(kIOSurfacePlaneSize,
|
|
aSize.height * bytesPerRow + 16);
|
|
|
|
aDict = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
|
|
::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
|
|
&kCFTypeDictionaryKeyCallBacks,
|
|
&kCFTypeDictionaryValueCallBacks));
|
|
|
|
AddDictionaryInt(aDict, kIOSurfacePlaneWidth, aSize.width);
|
|
AddDictionaryInt(aDict, kIOSurfacePlaneHeight, aSize.height);
|
|
AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerRow, bytesPerRow);
|
|
AddDictionaryInt(aDict, kIOSurfacePlaneOffset, aOffset);
|
|
AddDictionaryInt(aDict, kIOSurfacePlaneSize, totalBytes);
|
|
AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerElement, aBytesPerPixel);
|
|
|
|
return totalBytes;
|
|
}
|
|
|
|
/* static */
|
|
already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12Surface(
|
|
const IntSize& aYSize, const IntSize& aCbCrSize, YUVColorSpace aColorSpace,
|
|
ColorRange aColorRange) {
|
|
MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
|
|
aColorSpace == YUVColorSpace::BT709);
|
|
MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
|
|
aColorRange == ColorRange::FULL);
|
|
|
|
auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
|
|
::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
|
|
&kCFTypeDictionaryKeyCallBacks,
|
|
&kCFTypeDictionaryValueCallBacks));
|
|
if (!props) return nullptr;
|
|
|
|
MOZ_ASSERT((size_t)aYSize.width <= GetMaxWidth());
|
|
MOZ_ASSERT((size_t)aYSize.height <= GetMaxHeight());
|
|
|
|
AddDictionaryInt(props, kIOSurfaceWidth, aYSize.width);
|
|
AddDictionaryInt(props, kIOSurfaceHeight, aYSize.height);
|
|
::CFDictionaryAddValue(props.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
|
|
|
|
if (aColorRange == ColorRange::LIMITED) {
|
|
AddDictionaryInt(props, kIOSurfacePixelFormat,
|
|
(uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
|
|
} else {
|
|
AddDictionaryInt(props, kIOSurfacePixelFormat,
|
|
(uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
|
|
}
|
|
|
|
CFTypeRefPtr<CFMutableDictionaryRef> planeProps[2];
|
|
size_t yPlaneBytes = CreatePlaneDictionary(planeProps[0], aYSize, 0, 1);
|
|
size_t cbCrOffset =
|
|
IOSurfaceAlignProperty(kIOSurfacePlaneOffset, yPlaneBytes);
|
|
size_t cbCrPlaneBytes =
|
|
CreatePlaneDictionary(planeProps[1], aCbCrSize, cbCrOffset, 2);
|
|
size_t totalBytes =
|
|
IOSurfaceAlignProperty(kIOSurfaceAllocSize, cbCrOffset + cbCrPlaneBytes);
|
|
|
|
AddDictionaryInt(props, kIOSurfaceAllocSize, totalBytes);
|
|
|
|
auto array = CFTypeRefPtr<CFArrayRef>::WrapUnderCreateRule(
|
|
CFArrayCreate(kCFAllocatorDefault, (const void**)planeProps, 2,
|
|
&kCFTypeArrayCallBacks));
|
|
::CFDictionaryAddValue(props.get(), kIOSurfacePlaneInfo, array.get());
|
|
|
|
CFTypeRefPtr<IOSurfaceRef> surfaceRef =
|
|
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
|
|
::IOSurfaceCreate(props.get()));
|
|
|
|
if (!surfaceRef) {
|
|
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"));
|
|
}
|
|
// 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(
|
|
CGColorSpaceCopyICCProfile(colorSpace.get()));
|
|
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
|
|
colorData.get());
|
|
|
|
RefPtr<MacIOSurface> ioSurface =
|
|
new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
|
|
|
|
return ioSurface.forget();
|
|
}
|
|
|
|
/* static */
|
|
already_AddRefed<MacIOSurface> MacIOSurface::CreateYUV422Surface(
|
|
const IntSize& aSize, YUVColorSpace aColorSpace, ColorRange aColorRange) {
|
|
MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
|
|
aColorSpace == YUVColorSpace::BT709);
|
|
MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
|
|
aColorRange == ColorRange::FULL);
|
|
|
|
auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
|
|
::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
|
|
&kCFTypeDictionaryKeyCallBacks,
|
|
&kCFTypeDictionaryValueCallBacks));
|
|
if (!props) return nullptr;
|
|
|
|
MOZ_ASSERT((size_t)aSize.width <= GetMaxWidth());
|
|
MOZ_ASSERT((size_t)aSize.height <= GetMaxHeight());
|
|
|
|
SetSizeProperties(props, aSize.width, aSize.height, 2);
|
|
|
|
if (aColorRange == ColorRange::LIMITED) {
|
|
AddDictionaryInt(props, kIOSurfacePixelFormat,
|
|
(uint32_t)kCVPixelFormatType_422YpCbCr8_yuvs);
|
|
} else {
|
|
AddDictionaryInt(props, kIOSurfacePixelFormat,
|
|
(uint32_t)kCVPixelFormatType_422YpCbCr8FullRange);
|
|
}
|
|
|
|
CFTypeRefPtr<IOSurfaceRef> surfaceRef =
|
|
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
|
|
::IOSurfaceCreate(props.get()));
|
|
|
|
if (!surfaceRef) {
|
|
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"));
|
|
}
|
|
// 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(
|
|
CGColorSpaceCopyICCProfile(colorSpace.get()));
|
|
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
|
|
colorData.get());
|
|
|
|
RefPtr<MacIOSurface> ioSurface =
|
|
new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
|
|
|
|
return ioSurface.forget();
|
|
}
|
|
|
|
/* static */
|
|
already_AddRefed<MacIOSurface> MacIOSurface::LookupSurface(
|
|
IOSurfaceID aIOSurfaceID, bool aHasAlpha, gfx::YUVColorSpace aColorSpace) {
|
|
CFTypeRefPtr<IOSurfaceRef> surfaceRef =
|
|
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
|
|
::IOSurfaceLookup(aIOSurfaceID));
|
|
if (!surfaceRef) return nullptr;
|
|
|
|
RefPtr<MacIOSurface> ioSurface =
|
|
new MacIOSurface(std::move(surfaceRef), aHasAlpha, aColorSpace);
|
|
|
|
return ioSurface.forget();
|
|
}
|
|
|
|
IOSurfaceID MacIOSurface::GetIOSurfaceID() const {
|
|
return ::IOSurfaceGetID(mIOSurfaceRef.get());
|
|
}
|
|
|
|
void* MacIOSurface::GetBaseAddress() const {
|
|
return ::IOSurfaceGetBaseAddress(mIOSurfaceRef.get());
|
|
}
|
|
|
|
void* MacIOSurface::GetBaseAddressOfPlane(size_t aPlaneIndex) const {
|
|
return ::IOSurfaceGetBaseAddressOfPlane(mIOSurfaceRef.get(), aPlaneIndex);
|
|
}
|
|
|
|
size_t MacIOSurface::GetWidth(size_t plane) const {
|
|
return GetDevicePixelWidth(plane);
|
|
}
|
|
|
|
size_t MacIOSurface::GetHeight(size_t plane) const {
|
|
return GetDevicePixelHeight(plane);
|
|
}
|
|
|
|
size_t MacIOSurface::GetPlaneCount() const {
|
|
return ::IOSurfaceGetPlaneCount(mIOSurfaceRef.get());
|
|
}
|
|
|
|
/*static*/
|
|
size_t MacIOSurface::GetMaxWidth() {
|
|
return ::IOSurfaceGetPropertyMaximum(kIOSurfaceWidth);
|
|
}
|
|
|
|
/*static*/
|
|
size_t MacIOSurface::GetMaxHeight() {
|
|
return ::IOSurfaceGetPropertyMaximum(kIOSurfaceHeight);
|
|
}
|
|
|
|
size_t MacIOSurface::GetDevicePixelWidth(size_t plane) const {
|
|
return ::IOSurfaceGetWidthOfPlane(mIOSurfaceRef.get(), plane);
|
|
}
|
|
|
|
size_t MacIOSurface::GetDevicePixelHeight(size_t plane) const {
|
|
return ::IOSurfaceGetHeightOfPlane(mIOSurfaceRef.get(), plane);
|
|
}
|
|
|
|
size_t MacIOSurface::GetBytesPerRow(size_t plane) const {
|
|
return ::IOSurfaceGetBytesPerRowOfPlane(mIOSurfaceRef.get(), plane);
|
|
}
|
|
|
|
size_t MacIOSurface::GetAllocSize() const {
|
|
return ::IOSurfaceGetAllocSize(mIOSurfaceRef.get());
|
|
}
|
|
|
|
OSType MacIOSurface::GetPixelFormat() const {
|
|
return ::IOSurfaceGetPixelFormat(mIOSurfaceRef.get());
|
|
}
|
|
|
|
void MacIOSurface::IncrementUseCount() {
|
|
::IOSurfaceIncrementUseCount(mIOSurfaceRef.get());
|
|
}
|
|
|
|
void MacIOSurface::DecrementUseCount() {
|
|
::IOSurfaceDecrementUseCount(mIOSurfaceRef.get());
|
|
}
|
|
|
|
void MacIOSurface::Lock(bool aReadOnly) {
|
|
MOZ_RELEASE_ASSERT(!mIsLocked, "double MacIOSurface lock");
|
|
::IOSurfaceLock(mIOSurfaceRef.get(), aReadOnly ? kIOSurfaceLockReadOnly : 0,
|
|
nullptr);
|
|
mIsLocked = true;
|
|
}
|
|
|
|
void MacIOSurface::Unlock(bool aReadOnly) {
|
|
MOZ_RELEASE_ASSERT(mIsLocked, "MacIOSurface unlock without being locked");
|
|
::IOSurfaceUnlock(mIOSurfaceRef.get(), aReadOnly ? kIOSurfaceLockReadOnly : 0,
|
|
nullptr);
|
|
mIsLocked = false;
|
|
}
|
|
|
|
using mozilla::gfx::IntSize;
|
|
using mozilla::gfx::SourceSurface;
|
|
using mozilla::gfx::SurfaceFormat;
|
|
|
|
static void MacIOSurfaceBufferDeallocator(void* aClosure) {
|
|
MOZ_ASSERT(aClosure);
|
|
|
|
delete[] static_cast<unsigned char*>(aClosure);
|
|
}
|
|
|
|
already_AddRefed<SourceSurface> MacIOSurface::GetAsSurface() {
|
|
Lock();
|
|
size_t bytesPerRow = GetBytesPerRow();
|
|
size_t ioWidth = GetDevicePixelWidth();
|
|
size_t ioHeight = GetDevicePixelHeight();
|
|
|
|
unsigned char* ioData = (unsigned char*)GetBaseAddress();
|
|
auto* dataCpy =
|
|
new unsigned char[bytesPerRow * ioHeight / sizeof(unsigned char)];
|
|
for (size_t i = 0; i < ioHeight; i++) {
|
|
memcpy(dataCpy + i * bytesPerRow, ioData + i * bytesPerRow, ioWidth * 4);
|
|
}
|
|
|
|
Unlock();
|
|
|
|
SurfaceFormat format = HasAlpha() ? mozilla::gfx::SurfaceFormat::B8G8R8A8
|
|
: mozilla::gfx::SurfaceFormat::B8G8R8X8;
|
|
|
|
RefPtr<mozilla::gfx::DataSourceSurface> surf =
|
|
mozilla::gfx::Factory::CreateWrappingDataSourceSurface(
|
|
dataCpy, bytesPerRow, IntSize(ioWidth, ioHeight), format,
|
|
&MacIOSurfaceBufferDeallocator, static_cast<void*>(dataCpy));
|
|
|
|
return surf.forget();
|
|
}
|
|
|
|
already_AddRefed<mozilla::gfx::DrawTarget> MacIOSurface::GetAsDrawTargetLocked(
|
|
mozilla::gfx::BackendType aBackendType) {
|
|
MOZ_RELEASE_ASSERT(
|
|
IsLocked(),
|
|
"Only call GetAsDrawTargetLocked while the surface is locked.");
|
|
|
|
size_t bytesPerRow = GetBytesPerRow();
|
|
size_t ioWidth = GetDevicePixelWidth();
|
|
size_t ioHeight = GetDevicePixelHeight();
|
|
unsigned char* ioData = (unsigned char*)GetBaseAddress();
|
|
SurfaceFormat format = GetFormat();
|
|
return mozilla::gfx::Factory::CreateDrawTargetForData(
|
|
aBackendType, ioData, IntSize(ioWidth, ioHeight), bytesPerRow, format);
|
|
}
|
|
|
|
SurfaceFormat MacIOSurface::GetFormat() const {
|
|
switch (GetPixelFormat()) {
|
|
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
|
|
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
|
|
return SurfaceFormat::NV12;
|
|
case kCVPixelFormatType_422YpCbCr8_yuvs:
|
|
case kCVPixelFormatType_422YpCbCr8FullRange:
|
|
return SurfaceFormat::YUV422;
|
|
case kCVPixelFormatType_32BGRA:
|
|
return HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
|
|
default:
|
|
MOZ_ASSERT_UNREACHABLE("Unknown format");
|
|
return SurfaceFormat::B8G8R8A8;
|
|
}
|
|
}
|
|
|
|
SurfaceFormat MacIOSurface::GetReadFormat() const {
|
|
SurfaceFormat format = GetFormat();
|
|
if (format == SurfaceFormat::YUV422) {
|
|
return SurfaceFormat::R8G8B8X8;
|
|
}
|
|
return format;
|
|
}
|
|
|
|
CGLError MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx, GLenum target,
|
|
GLenum internalFormat,
|
|
GLsizei width, GLsizei height,
|
|
GLenum format, GLenum type,
|
|
GLuint plane) const {
|
|
return ::CGLTexImageIOSurface2D(ctx, target, internalFormat, width, height,
|
|
format, type, mIOSurfaceRef.get(), plane);
|
|
}
|
|
|
|
CGLError MacIOSurface::CGLTexImageIOSurface2D(
|
|
mozilla::gl::GLContext* aGL, CGLContextObj ctx, size_t plane,
|
|
mozilla::gfx::SurfaceFormat* aOutReadFormat) {
|
|
MOZ_ASSERT(plane >= 0);
|
|
bool isCompatibilityProfile = aGL->IsCompatibilityProfile();
|
|
OSType pixelFormat = GetPixelFormat();
|
|
|
|
GLenum internalFormat;
|
|
GLenum format;
|
|
GLenum type;
|
|
if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
|
|
pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
|
|
MOZ_ASSERT(GetPlaneCount() == 2);
|
|
MOZ_ASSERT(plane < 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 (plane == 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_BYTE;
|
|
if (aOutReadFormat) {
|
|
*aOutReadFormat = mozilla::gfx::SurfaceFormat::NV12;
|
|
}
|
|
} else if (pixelFormat == kCVPixelFormatType_422YpCbCr8_yuvs ||
|
|
pixelFormat == kCVPixelFormatType_422YpCbCr8FullRange) {
|
|
MOZ_ASSERT(plane == 0);
|
|
// The YCBCR_422_APPLE ext is only available in compatibility profile. So,
|
|
// we should use RGB_422_APPLE for core profile. The difference between
|
|
// YCBCR_422_APPLE and RGB_422_APPLE is that the YCBCR_422_APPLE converts
|
|
// the YCbCr value to RGB with REC 601 conversion. But the RGB_422_APPLE
|
|
// doesn't contain color conversion. You should do the color conversion by
|
|
// yourself for RGB_422_APPLE.
|
|
//
|
|
// https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_ycbcr_422.txt
|
|
// https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
|
|
if (isCompatibilityProfile) {
|
|
format = LOCAL_GL_YCBCR_422_APPLE;
|
|
if (aOutReadFormat) {
|
|
*aOutReadFormat = mozilla::gfx::SurfaceFormat::R8G8B8X8;
|
|
}
|
|
} else {
|
|
format = LOCAL_GL_RGB_422_APPLE;
|
|
if (aOutReadFormat) {
|
|
*aOutReadFormat = mozilla::gfx::SurfaceFormat::YUV422;
|
|
}
|
|
}
|
|
internalFormat = LOCAL_GL_RGB;
|
|
type = LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE;
|
|
} else {
|
|
MOZ_ASSERT(plane == 0);
|
|
|
|
internalFormat = HasAlpha() ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
|
|
format = LOCAL_GL_BGRA;
|
|
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
|
|
if (aOutReadFormat) {
|
|
*aOutReadFormat = HasAlpha() ? mozilla::gfx::SurfaceFormat::R8G8B8A8
|
|
: mozilla::gfx::SurfaceFormat::R8G8B8X8;
|
|
}
|
|
}
|
|
|
|
auto err =
|
|
CGLTexImageIOSurface2D(ctx, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
|
internalFormat, GetDevicePixelWidth(plane),
|
|
GetDevicePixelHeight(plane), format, type, plane);
|
|
if (err) {
|
|
const auto formatChars = (const char*)&pixelFormat;
|
|
const char formatStr[] = {formatChars[3], formatChars[2], formatChars[1],
|
|
formatChars[0], 0};
|
|
const nsPrintfCString errStr(
|
|
"CGLTexImageIOSurface2D(context, target, 0x%04x,"
|
|
" %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i",
|
|
internalFormat, uint32_t(GetDevicePixelWidth(plane)),
|
|
uint32_t(GetDevicePixelHeight(plane)), format, type,
|
|
(unsigned int)plane, err);
|
|
gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr
|
|
<< ")";
|
|
}
|
|
return err;
|
|
}
|