no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / gfx / 2d / MacIOSurface.cpp
blob1701731d61d5671cbf43d870793c0f16d7bf1465
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 #ifdef XP_MACOSX
9 # include <OpenGL/gl.h>
10 # include <OpenGL/CGLIOSurface.h>
11 #endif
12 #include <QuartzCore/QuartzCore.h>
13 #include "GLConsts.h"
14 #ifdef XP_MACOSX
15 # include "GLContextCGL.h"
16 #else
17 # include "GLContextEAGL.h"
18 #endif
19 #include "gfxMacUtils.h"
20 #include "nsPrintfCString.h"
21 #include "mozilla/Assertions.h"
22 #include "mozilla/RefPtr.h"
23 #include "mozilla/gfx/Logging.h"
24 #include "mozilla/StaticPrefs_gfx.h"
26 using namespace mozilla;
28 MacIOSurface::MacIOSurface(CFTypeRefPtr<IOSurfaceRef> aIOSurfaceRef,
29 bool aHasAlpha, gfx::YUVColorSpace aColorSpace)
30 : mIOSurfaceRef(std::move(aIOSurfaceRef)),
31 mHasAlpha(aHasAlpha),
32 mColorSpace(aColorSpace) {
33 IncrementUseCount();
36 MacIOSurface::~MacIOSurface() {
37 MOZ_RELEASE_ASSERT(!IsLocked(), "Destroying locked surface");
38 DecrementUseCount();
41 void AddDictionaryInt(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
42 const void* aType, uint32_t aValue) {
43 auto cfValue = CFTypeRefPtr<CFNumberRef>::WrapUnderCreateRule(
44 ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aValue));
45 ::CFDictionaryAddValue(aDict.get(), aType, cfValue.get());
48 void SetSizeProperties(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
49 int aWidth, int aHeight, int aBytesPerPixel) {
50 AddDictionaryInt(aDict, kIOSurfaceWidth, aWidth);
51 AddDictionaryInt(aDict, kIOSurfaceHeight, aHeight);
52 ::CFDictionaryAddValue(aDict.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
53 AddDictionaryInt(aDict, kIOSurfaceBytesPerElement, aBytesPerPixel);
55 size_t bytesPerRow =
56 IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, aWidth * aBytesPerPixel);
57 AddDictionaryInt(aDict, kIOSurfaceBytesPerRow, bytesPerRow);
59 // Add a SIMD register worth of extra bytes to the end of the allocation for
60 // SWGL.
61 size_t totalBytes =
62 IOSurfaceAlignProperty(kIOSurfaceAllocSize, aHeight * bytesPerRow + 16);
63 AddDictionaryInt(aDict, kIOSurfaceAllocSize, totalBytes);
66 /* static */
67 already_AddRefed<MacIOSurface> MacIOSurface::CreateIOSurface(int aWidth,
68 int aHeight,
69 bool aHasAlpha) {
70 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
71 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
72 &kCFTypeDictionaryKeyCallBacks,
73 &kCFTypeDictionaryValueCallBacks));
74 if (!props) return nullptr;
76 MOZ_ASSERT((size_t)aWidth <= GetMaxWidth());
77 MOZ_ASSERT((size_t)aHeight <= GetMaxHeight());
79 int32_t bytesPerElem = 4;
80 SetSizeProperties(props, aWidth, aHeight, bytesPerElem);
82 AddDictionaryInt(props, kIOSurfacePixelFormat,
83 (uint32_t)kCVPixelFormatType_32BGRA);
85 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
86 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
87 ::IOSurfaceCreate(props.get()));
89 if (StaticPrefs::gfx_color_management_native_srgb()) {
90 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
91 kCGColorSpaceSRGB);
94 if (!surfaceRef) {
95 return nullptr;
98 RefPtr<MacIOSurface> ioSurface =
99 new MacIOSurface(std::move(surfaceRef), aHasAlpha);
101 return ioSurface.forget();
104 size_t CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
105 const gfx::IntSize& aSize, size_t aOffset,
106 size_t aBytesPerPixel) {
107 size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfacePlaneBytesPerRow,
108 aSize.width * aBytesPerPixel);
109 // Add a SIMD register worth of extra bytes to the end of the allocation for
110 // SWGL.
111 size_t totalBytes = IOSurfaceAlignProperty(kIOSurfacePlaneSize,
112 aSize.height * bytesPerRow + 16);
114 aDict = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
115 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
116 &kCFTypeDictionaryKeyCallBacks,
117 &kCFTypeDictionaryValueCallBacks));
119 AddDictionaryInt(aDict, kIOSurfacePlaneWidth, aSize.width);
120 AddDictionaryInt(aDict, kIOSurfacePlaneHeight, aSize.height);
121 AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerRow, bytesPerRow);
122 AddDictionaryInt(aDict, kIOSurfacePlaneOffset, aOffset);
123 AddDictionaryInt(aDict, kIOSurfacePlaneSize, totalBytes);
124 AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerElement, aBytesPerPixel);
126 return totalBytes;
129 /* static */
130 already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12OrP010Surface(
131 const IntSize& aYSize, const IntSize& aCbCrSize, YUVColorSpace aColorSpace,
132 TransferFunction aTransferFunction, ColorRange aColorRange,
133 ColorDepth aColorDepth) {
134 MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
135 aColorSpace == YUVColorSpace::BT709 ||
136 aColorSpace == YUVColorSpace::BT2020);
137 MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
138 aColorRange == ColorRange::FULL);
139 MOZ_ASSERT(aColorDepth == ColorDepth::COLOR_8 ||
140 aColorDepth == ColorDepth::COLOR_10);
142 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
143 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
144 &kCFTypeDictionaryKeyCallBacks,
145 &kCFTypeDictionaryValueCallBacks));
146 if (!props) return nullptr;
148 MOZ_ASSERT((size_t)aYSize.width <= GetMaxWidth());
149 MOZ_ASSERT((size_t)aYSize.height <= GetMaxHeight());
151 AddDictionaryInt(props, kIOSurfaceWidth, aYSize.width);
152 AddDictionaryInt(props, kIOSurfaceHeight, aYSize.height);
153 ::CFDictionaryAddValue(props.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
155 if (aColorRange == ColorRange::LIMITED) {
156 if (aColorDepth == ColorDepth::COLOR_8) {
157 AddDictionaryInt(
158 props, kIOSurfacePixelFormat,
159 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
160 } else {
161 AddDictionaryInt(
162 props, kIOSurfacePixelFormat,
163 (uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange);
165 } else {
166 if (aColorDepth == ColorDepth::COLOR_8) {
167 AddDictionaryInt(
168 props, kIOSurfacePixelFormat,
169 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
170 } else {
171 AddDictionaryInt(
172 props, kIOSurfacePixelFormat,
173 (uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarFullRange);
177 size_t bytesPerPixel = (aColorDepth == ColorDepth::COLOR_8) ? 1 : 2;
179 CFTypeRefPtr<CFMutableDictionaryRef> planeProps[2];
180 size_t yPlaneBytes =
181 CreatePlaneDictionary(planeProps[0], aYSize, 0, bytesPerPixel);
182 size_t cbCrOffset =
183 IOSurfaceAlignProperty(kIOSurfacePlaneOffset, yPlaneBytes);
184 size_t cbCrPlaneBytes = CreatePlaneDictionary(planeProps[1], aCbCrSize,
185 cbCrOffset, bytesPerPixel * 2);
186 size_t totalBytes =
187 IOSurfaceAlignProperty(kIOSurfaceAllocSize, cbCrOffset + cbCrPlaneBytes);
189 AddDictionaryInt(props, kIOSurfaceAllocSize, totalBytes);
191 auto array = CFTypeRefPtr<CFArrayRef>::WrapUnderCreateRule(
192 CFArrayCreate(kCFAllocatorDefault, (const void**)planeProps, 2,
193 &kCFTypeArrayCallBacks));
194 ::CFDictionaryAddValue(props.get(), kIOSurfacePlaneInfo, array.get());
196 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
197 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
198 ::IOSurfaceCreate(props.get()));
200 if (!surfaceRef) {
201 return nullptr;
204 // Setup the correct YCbCr conversion matrix, color primaries, and transfer
205 // functions on the IOSurface, in case we pass this directly to CoreAnimation.
206 // For keys and values, we'd like to use values specified by the API, but
207 // those are only defined for CVImageBuffers. Luckily, when an image buffer is
208 // converted into an IOSurface, the keys are transformed but the values are
209 // the same. Since we are creating the IOSurface directly, we use hard-coded
210 // keys derived from inspecting the extracted IOSurfaces in the copying case,
211 // but we use the API-defined values from CVImageBuffer.
212 if (aColorSpace == YUVColorSpace::BT601) {
213 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
214 kCVImageBufferYCbCrMatrix_ITU_R_601_4);
215 } else if (aColorSpace == YUVColorSpace::BT709) {
216 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
217 kCVImageBufferYCbCrMatrix_ITU_R_709_2);
218 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorPrimaries"),
219 kCVImageBufferColorPrimaries_ITU_R_709_2);
220 } else {
221 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
222 kCVImageBufferYCbCrMatrix_ITU_R_2020);
223 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorPrimaries"),
224 kCVImageBufferColorPrimaries_ITU_R_2020);
227 // Transfer function is applied independently from the colorSpace.
228 IOSurfaceSetValue(
229 surfaceRef.get(), CFSTR("IOSurfaceTransferFunction"),
230 gfxMacUtils::CFStringForTransferFunction(aTransferFunction));
232 #ifdef XP_MACOSX
233 // Override the color space to be the same as the main display, so that
234 // CoreAnimation won't try to do any color correction (from the IOSurface
235 // space, to the display). In the future we may want to try specifying this
236 // correctly, but probably only once we do the same for videos drawn through
237 // our gfx code.
238 auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
239 CGDisplayCopyColorSpace(CGMainDisplayID()));
240 auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
241 CGColorSpaceCopyICCData(colorSpace.get()));
242 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
243 colorData.get());
244 #endif
246 RefPtr<MacIOSurface> ioSurface =
247 new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
249 return ioSurface.forget();
252 /* static */
253 already_AddRefed<MacIOSurface> MacIOSurface::CreateYUV422Surface(
254 const IntSize& aSize, YUVColorSpace aColorSpace, ColorRange aColorRange) {
255 MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
256 aColorSpace == YUVColorSpace::BT709);
257 MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
258 aColorRange == ColorRange::FULL);
260 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
261 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
262 &kCFTypeDictionaryKeyCallBacks,
263 &kCFTypeDictionaryValueCallBacks));
264 if (!props) return nullptr;
266 MOZ_ASSERT((size_t)aSize.width <= GetMaxWidth());
267 MOZ_ASSERT((size_t)aSize.height <= GetMaxHeight());
269 SetSizeProperties(props, aSize.width, aSize.height, 2);
271 if (aColorRange == ColorRange::LIMITED) {
272 AddDictionaryInt(props, kIOSurfacePixelFormat,
273 (uint32_t)kCVPixelFormatType_422YpCbCr8_yuvs);
274 } else {
275 AddDictionaryInt(props, kIOSurfacePixelFormat,
276 (uint32_t)kCVPixelFormatType_422YpCbCr8FullRange);
279 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
280 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
281 ::IOSurfaceCreate(props.get()));
283 if (!surfaceRef) {
284 return nullptr;
287 // Setup the correct YCbCr conversion matrix on the IOSurface, in case we pass
288 // this directly to CoreAnimation.
289 if (aColorSpace == YUVColorSpace::BT601) {
290 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
291 CFSTR("ITU_R_601_4"));
292 } else {
293 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
294 CFSTR("ITU_R_709_2"));
297 #ifdef XP_MACOSX
298 // Override the color space to be the same as the main display, so that
299 // CoreAnimation won't try to do any color correction (from the IOSurface
300 // space, to the display). In the future we may want to try specifying this
301 // correctly, but probably only once we do the same for videos drawn through
302 // our gfx code.
303 auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
304 CGDisplayCopyColorSpace(CGMainDisplayID()));
305 auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
306 CGColorSpaceCopyICCData(colorSpace.get()));
307 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
308 colorData.get());
309 #endif
311 RefPtr<MacIOSurface> ioSurface =
312 new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
314 return ioSurface.forget();
317 /* static */
318 already_AddRefed<MacIOSurface> MacIOSurface::LookupSurface(
319 IOSurfaceID aIOSurfaceID, bool aHasAlpha, gfx::YUVColorSpace aColorSpace) {
320 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
321 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
322 ::IOSurfaceLookup(aIOSurfaceID));
323 if (!surfaceRef) return nullptr;
325 RefPtr<MacIOSurface> ioSurface =
326 new MacIOSurface(std::move(surfaceRef), aHasAlpha, aColorSpace);
328 return ioSurface.forget();
331 IOSurfaceID MacIOSurface::GetIOSurfaceID() const {
332 return ::IOSurfaceGetID(mIOSurfaceRef.get());
335 void* MacIOSurface::GetBaseAddress() const {
336 return ::IOSurfaceGetBaseAddress(mIOSurfaceRef.get());
339 void* MacIOSurface::GetBaseAddressOfPlane(size_t aPlaneIndex) const {
340 return ::IOSurfaceGetBaseAddressOfPlane(mIOSurfaceRef.get(), aPlaneIndex);
343 size_t MacIOSurface::GetWidth(size_t plane) const {
344 return GetDevicePixelWidth(plane);
347 size_t MacIOSurface::GetHeight(size_t plane) const {
348 return GetDevicePixelHeight(plane);
351 size_t MacIOSurface::GetPlaneCount() const {
352 return ::IOSurfaceGetPlaneCount(mIOSurfaceRef.get());
355 /*static*/
356 size_t MacIOSurface::GetMaxWidth() {
357 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceWidth);
360 /*static*/
361 size_t MacIOSurface::GetMaxHeight() {
362 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceHeight);
365 size_t MacIOSurface::GetDevicePixelWidth(size_t plane) const {
366 return ::IOSurfaceGetWidthOfPlane(mIOSurfaceRef.get(), plane);
369 size_t MacIOSurface::GetDevicePixelHeight(size_t plane) const {
370 return ::IOSurfaceGetHeightOfPlane(mIOSurfaceRef.get(), plane);
373 size_t MacIOSurface::GetBytesPerRow(size_t plane) const {
374 return ::IOSurfaceGetBytesPerRowOfPlane(mIOSurfaceRef.get(), plane);
377 size_t MacIOSurface::GetAllocSize() const {
378 return ::IOSurfaceGetAllocSize(mIOSurfaceRef.get());
381 OSType MacIOSurface::GetPixelFormat() const {
382 return ::IOSurfaceGetPixelFormat(mIOSurfaceRef.get());
385 void MacIOSurface::IncrementUseCount() {
386 ::IOSurfaceIncrementUseCount(mIOSurfaceRef.get());
389 void MacIOSurface::DecrementUseCount() {
390 ::IOSurfaceDecrementUseCount(mIOSurfaceRef.get());
393 void MacIOSurface::Lock(bool aReadOnly) {
394 MOZ_RELEASE_ASSERT(!mIsLocked, "double MacIOSurface lock");
395 ::IOSurfaceLock(mIOSurfaceRef.get(), aReadOnly ? kIOSurfaceLockReadOnly : 0,
396 nullptr);
397 mIsLocked = true;
400 void MacIOSurface::Unlock(bool aReadOnly) {
401 MOZ_RELEASE_ASSERT(mIsLocked, "MacIOSurface unlock without being locked");
402 ::IOSurfaceUnlock(mIOSurfaceRef.get(), aReadOnly ? kIOSurfaceLockReadOnly : 0,
403 nullptr);
404 mIsLocked = false;
407 using mozilla::gfx::ColorDepth;
408 using mozilla::gfx::IntSize;
409 using mozilla::gfx::SourceSurface;
410 using mozilla::gfx::SurfaceFormat;
412 static void MacIOSurfaceBufferDeallocator(void* aClosure) {
413 MOZ_ASSERT(aClosure);
415 delete[] static_cast<unsigned char*>(aClosure);
418 already_AddRefed<SourceSurface> MacIOSurface::GetAsSurface() {
419 Lock();
420 size_t bytesPerRow = GetBytesPerRow();
421 size_t ioWidth = GetDevicePixelWidth();
422 size_t ioHeight = GetDevicePixelHeight();
424 unsigned char* ioData = (unsigned char*)GetBaseAddress();
425 auto* dataCpy =
426 new unsigned char[bytesPerRow * ioHeight / sizeof(unsigned char)];
427 for (size_t i = 0; i < ioHeight; i++) {
428 memcpy(dataCpy + i * bytesPerRow, ioData + i * bytesPerRow, ioWidth * 4);
431 Unlock();
433 SurfaceFormat format = HasAlpha() ? mozilla::gfx::SurfaceFormat::B8G8R8A8
434 : mozilla::gfx::SurfaceFormat::B8G8R8X8;
436 RefPtr<mozilla::gfx::DataSourceSurface> surf =
437 mozilla::gfx::Factory::CreateWrappingDataSourceSurface(
438 dataCpy, bytesPerRow, IntSize(ioWidth, ioHeight), format,
439 &MacIOSurfaceBufferDeallocator, static_cast<void*>(dataCpy));
441 return surf.forget();
444 already_AddRefed<mozilla::gfx::DrawTarget> MacIOSurface::GetAsDrawTargetLocked(
445 mozilla::gfx::BackendType aBackendType) {
446 MOZ_RELEASE_ASSERT(
447 IsLocked(),
448 "Only call GetAsDrawTargetLocked while the surface is locked.");
450 size_t bytesPerRow = GetBytesPerRow();
451 size_t ioWidth = GetDevicePixelWidth();
452 size_t ioHeight = GetDevicePixelHeight();
453 unsigned char* ioData = (unsigned char*)GetBaseAddress();
454 SurfaceFormat format = GetFormat();
455 return mozilla::gfx::Factory::CreateDrawTargetForData(
456 aBackendType, ioData, IntSize(ioWidth, ioHeight), bytesPerRow, format);
459 SurfaceFormat MacIOSurface::GetFormat() const {
460 switch (GetPixelFormat()) {
461 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
462 case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
463 return SurfaceFormat::NV12;
464 case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
465 case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
466 return SurfaceFormat::P010;
467 case kCVPixelFormatType_422YpCbCr8_yuvs:
468 case kCVPixelFormatType_422YpCbCr8FullRange:
469 return SurfaceFormat::YUV422;
470 case kCVPixelFormatType_32BGRA:
471 return HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
472 default:
473 MOZ_ASSERT_UNREACHABLE("Unknown format");
474 return SurfaceFormat::B8G8R8A8;
478 SurfaceFormat MacIOSurface::GetReadFormat() const {
479 SurfaceFormat format = GetFormat();
480 if (format == SurfaceFormat::YUV422) {
481 return SurfaceFormat::R8G8B8X8;
483 return format;
486 ColorDepth MacIOSurface::GetColorDepth() const {
487 switch (GetPixelFormat()) {
488 case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
489 case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
490 return ColorDepth::COLOR_10;
491 default:
492 return ColorDepth::COLOR_8;
496 bool MacIOSurface::BindTexImage(mozilla::gl::GLContext* aGL, size_t aPlane,
497 mozilla::gfx::SurfaceFormat* aOutReadFormat) {
498 #ifdef XP_MACOSX
499 MOZ_ASSERT(aPlane >= 0);
500 bool isCompatibilityProfile = aGL->IsCompatibilityProfile();
501 OSType pixelFormat = GetPixelFormat();
503 GLenum internalFormat;
504 GLenum format;
505 GLenum type;
506 if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
507 pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
508 MOZ_ASSERT(GetPlaneCount() == 2);
509 MOZ_ASSERT(aPlane < 2);
511 // The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated
512 // format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile.
513 // https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats
514 if (aPlane == 0) {
515 internalFormat = format =
516 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE) : (LOCAL_GL_RED);
517 } else {
518 internalFormat = format =
519 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE_ALPHA) : (LOCAL_GL_RG);
521 type = LOCAL_GL_UNSIGNED_BYTE;
522 if (aOutReadFormat) {
523 *aOutReadFormat = mozilla::gfx::SurfaceFormat::NV12;
525 } else if (pixelFormat == kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange ||
526 pixelFormat == kCVPixelFormatType_420YpCbCr10BiPlanarFullRange) {
527 MOZ_ASSERT(GetPlaneCount() == 2);
528 MOZ_ASSERT(aPlane < 2);
530 // The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated
531 // format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile.
532 // https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats
533 if (aPlane == 0) {
534 internalFormat = format =
535 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE) : (LOCAL_GL_RED);
536 } else {
537 internalFormat = format =
538 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE_ALPHA) : (LOCAL_GL_RG);
540 type = LOCAL_GL_UNSIGNED_SHORT;
541 if (aOutReadFormat) {
542 *aOutReadFormat = mozilla::gfx::SurfaceFormat::P010;
544 } else if (pixelFormat == kCVPixelFormatType_422YpCbCr8_yuvs ||
545 pixelFormat == kCVPixelFormatType_422YpCbCr8FullRange) {
546 MOZ_ASSERT(aPlane == 0);
547 // The YCBCR_422_APPLE ext is only available in compatibility profile. So,
548 // we should use RGB_422_APPLE for core profile. The difference between
549 // YCBCR_422_APPLE and RGB_422_APPLE is that the YCBCR_422_APPLE converts
550 // the YCbCr value to RGB with REC 601 conversion. But the RGB_422_APPLE
551 // doesn't contain color conversion. You should do the color conversion by
552 // yourself for RGB_422_APPLE.
554 // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_ycbcr_422.txt
555 // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
556 if (isCompatibilityProfile) {
557 format = LOCAL_GL_YCBCR_422_APPLE;
558 if (aOutReadFormat) {
559 *aOutReadFormat = mozilla::gfx::SurfaceFormat::R8G8B8X8;
561 } else {
562 format = LOCAL_GL_RGB_422_APPLE;
563 if (aOutReadFormat) {
564 *aOutReadFormat = mozilla::gfx::SurfaceFormat::YUV422;
567 internalFormat = LOCAL_GL_RGB;
568 type = LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE;
569 } else {
570 MOZ_ASSERT(aPlane == 0);
572 internalFormat = HasAlpha() ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
573 format = LOCAL_GL_BGRA;
574 type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
575 if (aOutReadFormat) {
576 *aOutReadFormat = HasAlpha() ? mozilla::gfx::SurfaceFormat::R8G8B8A8
577 : mozilla::gfx::SurfaceFormat::R8G8B8X8;
581 size_t width = GetDevicePixelWidth(aPlane);
582 size_t height = GetDevicePixelHeight(aPlane);
584 auto err = ::CGLTexImageIOSurface2D(
585 gl::GLContextCGL::Cast(aGL)->GetCGLContext(),
586 LOCAL_GL_TEXTURE_RECTANGLE_ARB, internalFormat, width, height, format,
587 type, mIOSurfaceRef.get(), aPlane);
588 if (err) {
589 const auto formatChars = (const char*)&pixelFormat;
590 const char formatStr[] = {formatChars[3], formatChars[2], formatChars[1],
591 formatChars[0], 0};
592 const nsPrintfCString errStr(
593 "CGLTexImageIOSurface2D(context, target, 0x%04x,"
594 " %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i",
595 internalFormat, uint32_t(width), uint32_t(height), format, type,
596 (unsigned int)aPlane, err);
597 gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr
598 << ")";
600 return !err;
601 #else
602 MOZ_CRASH("unimplemented");
603 #endif
606 void MacIOSurface::SetColorSpace(const mozilla::gfx::ColorSpace2 cs) const {
607 Maybe<CFStringRef> str;
608 switch (cs) {
609 case gfx::ColorSpace2::UNKNOWN:
610 break;
611 case gfx::ColorSpace2::SRGB:
612 str = Some(kCGColorSpaceSRGB);
613 break;
614 case gfx::ColorSpace2::DISPLAY_P3:
615 str = Some(kCGColorSpaceDisplayP3);
616 break;
617 case gfx::ColorSpace2::BT601_525: // Doesn't really have a better option.
618 case gfx::ColorSpace2::BT709:
619 str = Some(kCGColorSpaceITUR_709);
620 break;
621 case gfx::ColorSpace2::BT2020:
622 str = Some(kCGColorSpaceITUR_2020);
623 break;
625 if (str) {
626 IOSurfaceSetValue(mIOSurfaceRef.get(), CFSTR("IOSurfaceColorSpace"), *str);