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"
9 # include <OpenGL/gl.h>
10 # include <OpenGL/CGLIOSurface.h>
12 #include <QuartzCore/QuartzCore.h>
15 # include "GLContextCGL.h"
17 # include "GLContextEAGL.h"
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
)),
32 mColorSpace(aColorSpace
) {
36 MacIOSurface::~MacIOSurface() {
37 MOZ_RELEASE_ASSERT(!IsLocked(), "Destroying locked surface");
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
);
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
62 IOSurfaceAlignProperty(kIOSurfaceAllocSize
, aHeight
* bytesPerRow
+ 16);
63 AddDictionaryInt(aDict
, kIOSurfaceAllocSize
, totalBytes
);
67 already_AddRefed
<MacIOSurface
> MacIOSurface::CreateIOSurface(int aWidth
,
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"),
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
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
);
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
) {
158 props
, kIOSurfacePixelFormat
,
159 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
);
162 props
, kIOSurfacePixelFormat
,
163 (uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange
);
166 if (aColorDepth
== ColorDepth::COLOR_8
) {
168 props
, kIOSurfacePixelFormat
,
169 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
);
172 props
, kIOSurfacePixelFormat
,
173 (uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarFullRange
);
177 size_t bytesPerPixel
= (aColorDepth
== ColorDepth::COLOR_8
) ? 1 : 2;
179 CFTypeRefPtr
<CFMutableDictionaryRef
> planeProps
[2];
181 CreatePlaneDictionary(planeProps
[0], aYSize
, 0, bytesPerPixel
);
183 IOSurfaceAlignProperty(kIOSurfacePlaneOffset
, yPlaneBytes
);
184 size_t cbCrPlaneBytes
= CreatePlaneDictionary(planeProps
[1], aCbCrSize
,
185 cbCrOffset
, bytesPerPixel
* 2);
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()));
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
);
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.
229 surfaceRef
.get(), CFSTR("IOSurfaceTransferFunction"),
230 gfxMacUtils::CFStringForTransferFunction(aTransferFunction
));
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
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"),
246 RefPtr
<MacIOSurface
> ioSurface
=
247 new MacIOSurface(std::move(surfaceRef
), false, aColorSpace
);
249 return ioSurface
.forget();
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
);
275 AddDictionaryInt(props
, kIOSurfacePixelFormat
,
276 (uint32_t)kCVPixelFormatType_422YpCbCr8FullRange
);
279 CFTypeRefPtr
<IOSurfaceRef
> surfaceRef
=
280 CFTypeRefPtr
<IOSurfaceRef
>::WrapUnderCreateRule(
281 ::IOSurfaceCreate(props
.get()));
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"));
293 IOSurfaceSetValue(surfaceRef
.get(), CFSTR("IOSurfaceYCbCrMatrix"),
294 CFSTR("ITU_R_709_2"));
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
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"),
311 RefPtr
<MacIOSurface
> ioSurface
=
312 new MacIOSurface(std::move(surfaceRef
), false, aColorSpace
);
314 return ioSurface
.forget();
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());
356 size_t MacIOSurface::GetMaxWidth() {
357 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceWidth
);
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,
400 void MacIOSurface::Unlock(bool aReadOnly
) {
401 MOZ_RELEASE_ASSERT(mIsLocked
, "MacIOSurface unlock without being locked");
402 ::IOSurfaceUnlock(mIOSurfaceRef
.get(), aReadOnly
? kIOSurfaceLockReadOnly
: 0,
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() {
420 size_t bytesPerRow
= GetBytesPerRow();
421 size_t ioWidth
= GetDevicePixelWidth();
422 size_t ioHeight
= GetDevicePixelHeight();
424 unsigned char* ioData
= (unsigned char*)GetBaseAddress();
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);
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
) {
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
;
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
;
486 ColorDepth
MacIOSurface::GetColorDepth() const {
487 switch (GetPixelFormat()) {
488 case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange
:
489 case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange
:
490 return ColorDepth::COLOR_10
;
492 return ColorDepth::COLOR_8
;
496 bool MacIOSurface::BindTexImage(mozilla::gl::GLContext
* aGL
, size_t aPlane
,
497 mozilla::gfx::SurfaceFormat
* aOutReadFormat
) {
499 MOZ_ASSERT(aPlane
>= 0);
500 bool isCompatibilityProfile
= aGL
->IsCompatibilityProfile();
501 OSType pixelFormat
= GetPixelFormat();
503 GLenum internalFormat
;
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
515 internalFormat
= format
=
516 (isCompatibilityProfile
) ? (LOCAL_GL_LUMINANCE
) : (LOCAL_GL_RED
);
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
534 internalFormat
= format
=
535 (isCompatibilityProfile
) ? (LOCAL_GL_LUMINANCE
) : (LOCAL_GL_RED
);
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
;
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
;
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
);
589 const auto formatChars
= (const char*)&pixelFormat
;
590 const char formatStr
[] = {formatChars
[3], formatChars
[2], formatChars
[1],
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
602 MOZ_CRASH("unimplemented");
606 void MacIOSurface::SetColorSpace(const mozilla::gfx::ColorSpace2 cs
) const {
607 Maybe
<CFStringRef
> str
;
609 case gfx::ColorSpace2::UNKNOWN
:
611 case gfx::ColorSpace2::SRGB
:
612 str
= Some(kCGColorSpaceSRGB
);
614 case gfx::ColorSpace2::DISPLAY_P3
:
615 str
= Some(kCGColorSpaceDisplayP3
);
617 case gfx::ColorSpace2::BT601_525
: // Doesn't really have a better option.
618 case gfx::ColorSpace2::BT709
:
619 str
= Some(kCGColorSpaceITUR_709
);
621 case gfx::ColorSpace2::BT2020
:
622 str
= Some(kCGColorSpaceITUR_2020
);
626 IOSurfaceSetValue(mIOSurfaceRef
.get(), CFSTR("IOSurfaceColorSpace"), *str
);