Bug 1869043 add a main thread record of track audio outputs r=padenot
[gecko.git] / gfx / 2d / MacIOSurface.cpp
blob8c1c24bc10a3ca0d637c13e6111b8d7f3d3df9ac
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "MacIOSurface.h"
8 #include <OpenGL/gl.h>
9 #include <OpenGL/CGLIOSurface.h>
10 #include <QuartzCore/QuartzCore.h>
11 #include "GLConsts.h"
12 #include "GLContextCGL.h"
13 #include "gfxMacUtils.h"
14 #include "nsPrintfCString.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/RefPtr.h"
17 #include "mozilla/gfx/Logging.h"
18 #include "mozilla/StaticPrefs_gfx.h"
20 using namespace mozilla;
22 MacIOSurface::MacIOSurface(CFTypeRefPtr<IOSurfaceRef> aIOSurfaceRef,
23 bool aHasAlpha, gfx::YUVColorSpace aColorSpace)
24 : mIOSurfaceRef(std::move(aIOSurfaceRef)),
25 mHasAlpha(aHasAlpha),
26 mColorSpace(aColorSpace) {
27 IncrementUseCount();
30 MacIOSurface::~MacIOSurface() {
31 MOZ_RELEASE_ASSERT(!IsLocked(), "Destroying locked surface");
32 DecrementUseCount();
35 void AddDictionaryInt(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
36 const void* aType, uint32_t aValue) {
37 auto cfValue = CFTypeRefPtr<CFNumberRef>::WrapUnderCreateRule(
38 ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aValue));
39 ::CFDictionaryAddValue(aDict.get(), aType, cfValue.get());
42 void SetSizeProperties(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
43 int aWidth, int aHeight, int aBytesPerPixel) {
44 AddDictionaryInt(aDict, kIOSurfaceWidth, aWidth);
45 AddDictionaryInt(aDict, kIOSurfaceHeight, aHeight);
46 ::CFDictionaryAddValue(aDict.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
47 AddDictionaryInt(aDict, kIOSurfaceBytesPerElement, aBytesPerPixel);
49 size_t bytesPerRow =
50 IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, aWidth * aBytesPerPixel);
51 AddDictionaryInt(aDict, kIOSurfaceBytesPerRow, bytesPerRow);
53 // Add a SIMD register worth of extra bytes to the end of the allocation for
54 // SWGL.
55 size_t totalBytes =
56 IOSurfaceAlignProperty(kIOSurfaceAllocSize, aHeight * bytesPerRow + 16);
57 AddDictionaryInt(aDict, kIOSurfaceAllocSize, totalBytes);
60 /* static */
61 already_AddRefed<MacIOSurface> MacIOSurface::CreateIOSurface(int aWidth,
62 int aHeight,
63 bool aHasAlpha) {
64 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
65 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
66 &kCFTypeDictionaryKeyCallBacks,
67 &kCFTypeDictionaryValueCallBacks));
68 if (!props) return nullptr;
70 MOZ_ASSERT((size_t)aWidth <= GetMaxWidth());
71 MOZ_ASSERT((size_t)aHeight <= GetMaxHeight());
73 int32_t bytesPerElem = 4;
74 SetSizeProperties(props, aWidth, aHeight, bytesPerElem);
76 AddDictionaryInt(props, kIOSurfacePixelFormat,
77 (uint32_t)kCVPixelFormatType_32BGRA);
79 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
80 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
81 ::IOSurfaceCreate(props.get()));
83 if (StaticPrefs::gfx_color_management_native_srgb()) {
84 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
85 kCGColorSpaceSRGB);
88 if (!surfaceRef) {
89 return nullptr;
92 RefPtr<MacIOSurface> ioSurface =
93 new MacIOSurface(std::move(surfaceRef), aHasAlpha);
95 return ioSurface.forget();
98 size_t CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
99 const gfx::IntSize& aSize, size_t aOffset,
100 size_t aBytesPerPixel) {
101 size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfacePlaneBytesPerRow,
102 aSize.width * aBytesPerPixel);
103 // Add a SIMD register worth of extra bytes to the end of the allocation for
104 // SWGL.
105 size_t totalBytes = IOSurfaceAlignProperty(kIOSurfacePlaneSize,
106 aSize.height * bytesPerRow + 16);
108 aDict = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
109 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
110 &kCFTypeDictionaryKeyCallBacks,
111 &kCFTypeDictionaryValueCallBacks));
113 AddDictionaryInt(aDict, kIOSurfacePlaneWidth, aSize.width);
114 AddDictionaryInt(aDict, kIOSurfacePlaneHeight, aSize.height);
115 AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerRow, bytesPerRow);
116 AddDictionaryInt(aDict, kIOSurfacePlaneOffset, aOffset);
117 AddDictionaryInt(aDict, kIOSurfacePlaneSize, totalBytes);
118 AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerElement, aBytesPerPixel);
120 return totalBytes;
123 /* static */
124 already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12OrP010Surface(
125 const IntSize& aYSize, const IntSize& aCbCrSize, YUVColorSpace aColorSpace,
126 TransferFunction aTransferFunction, ColorRange aColorRange,
127 ColorDepth aColorDepth) {
128 MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
129 aColorSpace == YUVColorSpace::BT709 ||
130 aColorSpace == YUVColorSpace::BT2020);
131 MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
132 aColorRange == ColorRange::FULL);
133 MOZ_ASSERT(aColorDepth == ColorDepth::COLOR_8 ||
134 aColorDepth == ColorDepth::COLOR_10);
136 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
137 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
138 &kCFTypeDictionaryKeyCallBacks,
139 &kCFTypeDictionaryValueCallBacks));
140 if (!props) return nullptr;
142 MOZ_ASSERT((size_t)aYSize.width <= GetMaxWidth());
143 MOZ_ASSERT((size_t)aYSize.height <= GetMaxHeight());
145 AddDictionaryInt(props, kIOSurfaceWidth, aYSize.width);
146 AddDictionaryInt(props, kIOSurfaceHeight, aYSize.height);
147 ::CFDictionaryAddValue(props.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
149 if (aColorRange == ColorRange::LIMITED) {
150 if (aColorDepth == ColorDepth::COLOR_8) {
151 AddDictionaryInt(
152 props, kIOSurfacePixelFormat,
153 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
154 } else {
155 AddDictionaryInt(
156 props, kIOSurfacePixelFormat,
157 (uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange);
159 } else {
160 if (aColorDepth == ColorDepth::COLOR_8) {
161 AddDictionaryInt(
162 props, kIOSurfacePixelFormat,
163 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
164 } else {
165 AddDictionaryInt(
166 props, kIOSurfacePixelFormat,
167 (uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarFullRange);
171 size_t bytesPerPixel = (aColorDepth == ColorDepth::COLOR_8) ? 1 : 2;
173 CFTypeRefPtr<CFMutableDictionaryRef> planeProps[2];
174 size_t yPlaneBytes =
175 CreatePlaneDictionary(planeProps[0], aYSize, 0, bytesPerPixel);
176 size_t cbCrOffset =
177 IOSurfaceAlignProperty(kIOSurfacePlaneOffset, yPlaneBytes);
178 size_t cbCrPlaneBytes = CreatePlaneDictionary(planeProps[1], aCbCrSize,
179 cbCrOffset, bytesPerPixel * 2);
180 size_t totalBytes =
181 IOSurfaceAlignProperty(kIOSurfaceAllocSize, cbCrOffset + cbCrPlaneBytes);
183 AddDictionaryInt(props, kIOSurfaceAllocSize, totalBytes);
185 auto array = CFTypeRefPtr<CFArrayRef>::WrapUnderCreateRule(
186 CFArrayCreate(kCFAllocatorDefault, (const void**)planeProps, 2,
187 &kCFTypeArrayCallBacks));
188 ::CFDictionaryAddValue(props.get(), kIOSurfacePlaneInfo, array.get());
190 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
191 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
192 ::IOSurfaceCreate(props.get()));
194 if (!surfaceRef) {
195 return nullptr;
198 // Setup the correct YCbCr conversion matrix, color primaries, and transfer
199 // functions on the IOSurface, in case we pass this directly to CoreAnimation.
200 // For keys and values, we'd like to use values specified by the API, but
201 // those are only defined for CVImageBuffers. Luckily, when an image buffer is
202 // converted into an IOSurface, the keys are transformed but the values are
203 // the same. Since we are creating the IOSurface directly, we use hard-coded
204 // keys derived from inspecting the extracted IOSurfaces in the copying case,
205 // but we use the API-defined values from CVImageBuffer.
206 if (aColorSpace == YUVColorSpace::BT601) {
207 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
208 kCVImageBufferYCbCrMatrix_ITU_R_601_4);
209 } else if (aColorSpace == YUVColorSpace::BT709) {
210 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
211 kCVImageBufferYCbCrMatrix_ITU_R_709_2);
212 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorPrimaries"),
213 kCVImageBufferColorPrimaries_ITU_R_709_2);
214 } else {
215 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
216 kCVImageBufferYCbCrMatrix_ITU_R_2020);
217 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorPrimaries"),
218 kCVImageBufferColorPrimaries_ITU_R_2020);
221 // Transfer function is applied independently from the colorSpace.
222 IOSurfaceSetValue(
223 surfaceRef.get(), CFSTR("IOSurfaceTransferFunction"),
224 gfxMacUtils::CFStringForTransferFunction(aTransferFunction));
226 // Override the color space to be the same as the main display, so that
227 // CoreAnimation won't try to do any color correction (from the IOSurface
228 // space, to the display). In the future we may want to try specifying this
229 // correctly, but probably only once we do the same for videos drawn through
230 // our gfx code.
231 auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
232 CGDisplayCopyColorSpace(CGMainDisplayID()));
233 auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
234 CGColorSpaceCopyICCData(colorSpace.get()));
235 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
236 colorData.get());
238 RefPtr<MacIOSurface> ioSurface =
239 new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
241 return ioSurface.forget();
244 /* static */
245 already_AddRefed<MacIOSurface> MacIOSurface::CreateYUV422Surface(
246 const IntSize& aSize, YUVColorSpace aColorSpace, ColorRange aColorRange) {
247 MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
248 aColorSpace == YUVColorSpace::BT709);
249 MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
250 aColorRange == ColorRange::FULL);
252 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
253 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
254 &kCFTypeDictionaryKeyCallBacks,
255 &kCFTypeDictionaryValueCallBacks));
256 if (!props) return nullptr;
258 MOZ_ASSERT((size_t)aSize.width <= GetMaxWidth());
259 MOZ_ASSERT((size_t)aSize.height <= GetMaxHeight());
261 SetSizeProperties(props, aSize.width, aSize.height, 2);
263 if (aColorRange == ColorRange::LIMITED) {
264 AddDictionaryInt(props, kIOSurfacePixelFormat,
265 (uint32_t)kCVPixelFormatType_422YpCbCr8_yuvs);
266 } else {
267 AddDictionaryInt(props, kIOSurfacePixelFormat,
268 (uint32_t)kCVPixelFormatType_422YpCbCr8FullRange);
271 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
272 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
273 ::IOSurfaceCreate(props.get()));
275 if (!surfaceRef) {
276 return nullptr;
279 // Setup the correct YCbCr conversion matrix on the IOSurface, in case we pass
280 // this directly to CoreAnimation.
281 if (aColorSpace == YUVColorSpace::BT601) {
282 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
283 CFSTR("ITU_R_601_4"));
284 } else {
285 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
286 CFSTR("ITU_R_709_2"));
288 // Override the color space to be the same as the main display, so that
289 // CoreAnimation won't try to do any color correction (from the IOSurface
290 // space, to the display). In the future we may want to try specifying this
291 // correctly, but probably only once we do the same for videos drawn through
292 // our gfx code.
293 auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
294 CGDisplayCopyColorSpace(CGMainDisplayID()));
295 auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
296 CGColorSpaceCopyICCData(colorSpace.get()));
297 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
298 colorData.get());
300 RefPtr<MacIOSurface> ioSurface =
301 new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
303 return ioSurface.forget();
306 /* static */
307 already_AddRefed<MacIOSurface> MacIOSurface::LookupSurface(
308 IOSurfaceID aIOSurfaceID, bool aHasAlpha, gfx::YUVColorSpace aColorSpace) {
309 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
310 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
311 ::IOSurfaceLookup(aIOSurfaceID));
312 if (!surfaceRef) return nullptr;
314 RefPtr<MacIOSurface> ioSurface =
315 new MacIOSurface(std::move(surfaceRef), aHasAlpha, aColorSpace);
317 return ioSurface.forget();
320 IOSurfaceID MacIOSurface::GetIOSurfaceID() const {
321 return ::IOSurfaceGetID(mIOSurfaceRef.get());
324 void* MacIOSurface::GetBaseAddress() const {
325 return ::IOSurfaceGetBaseAddress(mIOSurfaceRef.get());
328 void* MacIOSurface::GetBaseAddressOfPlane(size_t aPlaneIndex) const {
329 return ::IOSurfaceGetBaseAddressOfPlane(mIOSurfaceRef.get(), aPlaneIndex);
332 size_t MacIOSurface::GetWidth(size_t plane) const {
333 return GetDevicePixelWidth(plane);
336 size_t MacIOSurface::GetHeight(size_t plane) const {
337 return GetDevicePixelHeight(plane);
340 size_t MacIOSurface::GetPlaneCount() const {
341 return ::IOSurfaceGetPlaneCount(mIOSurfaceRef.get());
344 /*static*/
345 size_t MacIOSurface::GetMaxWidth() {
346 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceWidth);
349 /*static*/
350 size_t MacIOSurface::GetMaxHeight() {
351 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceHeight);
354 size_t MacIOSurface::GetDevicePixelWidth(size_t plane) const {
355 return ::IOSurfaceGetWidthOfPlane(mIOSurfaceRef.get(), plane);
358 size_t MacIOSurface::GetDevicePixelHeight(size_t plane) const {
359 return ::IOSurfaceGetHeightOfPlane(mIOSurfaceRef.get(), plane);
362 size_t MacIOSurface::GetBytesPerRow(size_t plane) const {
363 return ::IOSurfaceGetBytesPerRowOfPlane(mIOSurfaceRef.get(), plane);
366 size_t MacIOSurface::GetAllocSize() const {
367 return ::IOSurfaceGetAllocSize(mIOSurfaceRef.get());
370 OSType MacIOSurface::GetPixelFormat() const {
371 return ::IOSurfaceGetPixelFormat(mIOSurfaceRef.get());
374 void MacIOSurface::IncrementUseCount() {
375 ::IOSurfaceIncrementUseCount(mIOSurfaceRef.get());
378 void MacIOSurface::DecrementUseCount() {
379 ::IOSurfaceDecrementUseCount(mIOSurfaceRef.get());
382 void MacIOSurface::Lock(bool aReadOnly) {
383 MOZ_RELEASE_ASSERT(!mIsLocked, "double MacIOSurface lock");
384 ::IOSurfaceLock(mIOSurfaceRef.get(), aReadOnly ? kIOSurfaceLockReadOnly : 0,
385 nullptr);
386 mIsLocked = true;
389 void MacIOSurface::Unlock(bool aReadOnly) {
390 MOZ_RELEASE_ASSERT(mIsLocked, "MacIOSurface unlock without being locked");
391 ::IOSurfaceUnlock(mIOSurfaceRef.get(), aReadOnly ? kIOSurfaceLockReadOnly : 0,
392 nullptr);
393 mIsLocked = false;
396 using mozilla::gfx::ColorDepth;
397 using mozilla::gfx::IntSize;
398 using mozilla::gfx::SourceSurface;
399 using mozilla::gfx::SurfaceFormat;
401 static void MacIOSurfaceBufferDeallocator(void* aClosure) {
402 MOZ_ASSERT(aClosure);
404 delete[] static_cast<unsigned char*>(aClosure);
407 already_AddRefed<SourceSurface> MacIOSurface::GetAsSurface() {
408 Lock();
409 size_t bytesPerRow = GetBytesPerRow();
410 size_t ioWidth = GetDevicePixelWidth();
411 size_t ioHeight = GetDevicePixelHeight();
413 unsigned char* ioData = (unsigned char*)GetBaseAddress();
414 auto* dataCpy =
415 new unsigned char[bytesPerRow * ioHeight / sizeof(unsigned char)];
416 for (size_t i = 0; i < ioHeight; i++) {
417 memcpy(dataCpy + i * bytesPerRow, ioData + i * bytesPerRow, ioWidth * 4);
420 Unlock();
422 SurfaceFormat format = HasAlpha() ? mozilla::gfx::SurfaceFormat::B8G8R8A8
423 : mozilla::gfx::SurfaceFormat::B8G8R8X8;
425 RefPtr<mozilla::gfx::DataSourceSurface> surf =
426 mozilla::gfx::Factory::CreateWrappingDataSourceSurface(
427 dataCpy, bytesPerRow, IntSize(ioWidth, ioHeight), format,
428 &MacIOSurfaceBufferDeallocator, static_cast<void*>(dataCpy));
430 return surf.forget();
433 already_AddRefed<mozilla::gfx::DrawTarget> MacIOSurface::GetAsDrawTargetLocked(
434 mozilla::gfx::BackendType aBackendType) {
435 MOZ_RELEASE_ASSERT(
436 IsLocked(),
437 "Only call GetAsDrawTargetLocked while the surface is locked.");
439 size_t bytesPerRow = GetBytesPerRow();
440 size_t ioWidth = GetDevicePixelWidth();
441 size_t ioHeight = GetDevicePixelHeight();
442 unsigned char* ioData = (unsigned char*)GetBaseAddress();
443 SurfaceFormat format = GetFormat();
444 return mozilla::gfx::Factory::CreateDrawTargetForData(
445 aBackendType, ioData, IntSize(ioWidth, ioHeight), bytesPerRow, format);
448 SurfaceFormat MacIOSurface::GetFormat() const {
449 switch (GetPixelFormat()) {
450 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
451 case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
452 return SurfaceFormat::NV12;
453 case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
454 case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
455 return SurfaceFormat::P010;
456 case kCVPixelFormatType_422YpCbCr8_yuvs:
457 case kCVPixelFormatType_422YpCbCr8FullRange:
458 return SurfaceFormat::YUV422;
459 case kCVPixelFormatType_32BGRA:
460 return HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
461 default:
462 MOZ_ASSERT_UNREACHABLE("Unknown format");
463 return SurfaceFormat::B8G8R8A8;
467 SurfaceFormat MacIOSurface::GetReadFormat() const {
468 SurfaceFormat format = GetFormat();
469 if (format == SurfaceFormat::YUV422) {
470 return SurfaceFormat::R8G8B8X8;
472 return format;
475 ColorDepth MacIOSurface::GetColorDepth() const {
476 switch (GetPixelFormat()) {
477 case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
478 case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
479 return ColorDepth::COLOR_10;
480 default:
481 return ColorDepth::COLOR_8;
485 CGLError MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx, GLenum target,
486 GLenum internalFormat,
487 GLsizei width, GLsizei height,
488 GLenum format, GLenum type,
489 GLuint plane) const {
490 return ::CGLTexImageIOSurface2D(ctx, target, internalFormat, width, height,
491 format, type, mIOSurfaceRef.get(), plane);
494 CGLError MacIOSurface::CGLTexImageIOSurface2D(
495 mozilla::gl::GLContext* aGL, CGLContextObj ctx, size_t plane,
496 mozilla::gfx::SurfaceFormat* aOutReadFormat) {
497 MOZ_ASSERT(plane >= 0);
498 bool isCompatibilityProfile = aGL->IsCompatibilityProfile();
499 OSType pixelFormat = GetPixelFormat();
501 GLenum internalFormat;
502 GLenum format;
503 GLenum type;
504 if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
505 pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
506 MOZ_ASSERT(GetPlaneCount() == 2);
507 MOZ_ASSERT(plane < 2);
509 // The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated
510 // format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile.
511 // https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats
512 if (plane == 0) {
513 internalFormat = format =
514 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE) : (LOCAL_GL_RED);
515 } else {
516 internalFormat = format =
517 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE_ALPHA) : (LOCAL_GL_RG);
519 type = LOCAL_GL_UNSIGNED_BYTE;
520 if (aOutReadFormat) {
521 *aOutReadFormat = mozilla::gfx::SurfaceFormat::NV12;
523 } else if (pixelFormat == kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange ||
524 pixelFormat == kCVPixelFormatType_420YpCbCr10BiPlanarFullRange) {
525 MOZ_ASSERT(GetPlaneCount() == 2);
526 MOZ_ASSERT(plane < 2);
528 // The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated
529 // format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile.
530 // https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats
531 if (plane == 0) {
532 internalFormat = format =
533 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE) : (LOCAL_GL_RED);
534 } else {
535 internalFormat = format =
536 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE_ALPHA) : (LOCAL_GL_RG);
538 type = LOCAL_GL_UNSIGNED_SHORT;
539 if (aOutReadFormat) {
540 *aOutReadFormat = mozilla::gfx::SurfaceFormat::P010;
542 } else if (pixelFormat == kCVPixelFormatType_422YpCbCr8_yuvs ||
543 pixelFormat == kCVPixelFormatType_422YpCbCr8FullRange) {
544 MOZ_ASSERT(plane == 0);
545 // The YCBCR_422_APPLE ext is only available in compatibility profile. So,
546 // we should use RGB_422_APPLE for core profile. The difference between
547 // YCBCR_422_APPLE and RGB_422_APPLE is that the YCBCR_422_APPLE converts
548 // the YCbCr value to RGB with REC 601 conversion. But the RGB_422_APPLE
549 // doesn't contain color conversion. You should do the color conversion by
550 // yourself for RGB_422_APPLE.
552 // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_ycbcr_422.txt
553 // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
554 if (isCompatibilityProfile) {
555 format = LOCAL_GL_YCBCR_422_APPLE;
556 if (aOutReadFormat) {
557 *aOutReadFormat = mozilla::gfx::SurfaceFormat::R8G8B8X8;
559 } else {
560 format = LOCAL_GL_RGB_422_APPLE;
561 if (aOutReadFormat) {
562 *aOutReadFormat = mozilla::gfx::SurfaceFormat::YUV422;
565 internalFormat = LOCAL_GL_RGB;
566 type = LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE;
567 } else {
568 MOZ_ASSERT(plane == 0);
570 internalFormat = HasAlpha() ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
571 format = LOCAL_GL_BGRA;
572 type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
573 if (aOutReadFormat) {
574 *aOutReadFormat = HasAlpha() ? mozilla::gfx::SurfaceFormat::R8G8B8A8
575 : mozilla::gfx::SurfaceFormat::R8G8B8X8;
579 auto err =
580 CGLTexImageIOSurface2D(ctx, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
581 internalFormat, GetDevicePixelWidth(plane),
582 GetDevicePixelHeight(plane), format, type, plane);
583 if (err) {
584 const auto formatChars = (const char*)&pixelFormat;
585 const char formatStr[] = {formatChars[3], formatChars[2], formatChars[1],
586 formatChars[0], 0};
587 const nsPrintfCString errStr(
588 "CGLTexImageIOSurface2D(context, target, 0x%04x,"
589 " %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i",
590 internalFormat, uint32_t(GetDevicePixelWidth(plane)),
591 uint32_t(GetDevicePixelHeight(plane)), format, type,
592 (unsigned int)plane, err);
593 gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr
594 << ")";
596 return err;
599 void MacIOSurface::SetColorSpace(const mozilla::gfx::ColorSpace2 cs) const {
600 Maybe<CFStringRef> str;
601 switch (cs) {
602 case gfx::ColorSpace2::UNKNOWN:
603 break;
604 case gfx::ColorSpace2::SRGB:
605 str = Some(kCGColorSpaceSRGB);
606 break;
607 case gfx::ColorSpace2::DISPLAY_P3:
608 str = Some(kCGColorSpaceDisplayP3);
609 break;
610 case gfx::ColorSpace2::BT601_525: // Doesn't really have a better option.
611 case gfx::ColorSpace2::BT709:
612 str = Some(kCGColorSpaceITUR_709);
613 break;
614 case gfx::ColorSpace2::BT2020:
615 str = Some(kCGColorSpaceITUR_2020);
616 break;
618 if (str) {
619 IOSurfaceSetValue(mIOSurfaceRef.get(), CFSTR("IOSurfaceColorSpace"), *str);