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/CGLIOSurface.h>
10 #include <QuartzCore/QuartzCore.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
)),
26 mColorSpace(aColorSpace
) {
30 MacIOSurface::~MacIOSurface() {
31 MOZ_RELEASE_ASSERT(!IsLocked(), "Destroying locked surface");
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
);
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
56 IOSurfaceAlignProperty(kIOSurfaceAllocSize
, aHeight
* bytesPerRow
+ 16);
57 AddDictionaryInt(aDict
, kIOSurfaceAllocSize
, totalBytes
);
61 already_AddRefed
<MacIOSurface
> MacIOSurface::CreateIOSurface(int aWidth
,
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"),
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
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
);
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
) {
152 props
, kIOSurfacePixelFormat
,
153 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
);
156 props
, kIOSurfacePixelFormat
,
157 (uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange
);
160 if (aColorDepth
== ColorDepth::COLOR_8
) {
162 props
, kIOSurfacePixelFormat
,
163 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
);
166 props
, kIOSurfacePixelFormat
,
167 (uint32_t)kCVPixelFormatType_420YpCbCr10BiPlanarFullRange
);
171 size_t bytesPerPixel
= (aColorDepth
== ColorDepth::COLOR_8
) ? 1 : 2;
173 CFTypeRefPtr
<CFMutableDictionaryRef
> planeProps
[2];
175 CreatePlaneDictionary(planeProps
[0], aYSize
, 0, bytesPerPixel
);
177 IOSurfaceAlignProperty(kIOSurfacePlaneOffset
, yPlaneBytes
);
178 size_t cbCrPlaneBytes
= CreatePlaneDictionary(planeProps
[1], aCbCrSize
,
179 cbCrOffset
, bytesPerPixel
* 2);
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()));
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
);
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.
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
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"),
238 RefPtr
<MacIOSurface
> ioSurface
=
239 new MacIOSurface(std::move(surfaceRef
), false, aColorSpace
);
241 return ioSurface
.forget();
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
);
267 AddDictionaryInt(props
, kIOSurfacePixelFormat
,
268 (uint32_t)kCVPixelFormatType_422YpCbCr8FullRange
);
271 CFTypeRefPtr
<IOSurfaceRef
> surfaceRef
=
272 CFTypeRefPtr
<IOSurfaceRef
>::WrapUnderCreateRule(
273 ::IOSurfaceCreate(props
.get()));
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"));
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
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"),
300 RefPtr
<MacIOSurface
> ioSurface
=
301 new MacIOSurface(std::move(surfaceRef
), false, aColorSpace
);
303 return ioSurface
.forget();
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());
345 size_t MacIOSurface::GetMaxWidth() {
346 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceWidth
);
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,
389 void MacIOSurface::Unlock(bool aReadOnly
) {
390 MOZ_RELEASE_ASSERT(mIsLocked
, "MacIOSurface unlock without being locked");
391 ::IOSurfaceUnlock(mIOSurfaceRef
.get(), aReadOnly
? kIOSurfaceLockReadOnly
: 0,
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() {
409 size_t bytesPerRow
= GetBytesPerRow();
410 size_t ioWidth
= GetDevicePixelWidth();
411 size_t ioHeight
= GetDevicePixelHeight();
413 unsigned char* ioData
= (unsigned char*)GetBaseAddress();
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);
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
) {
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
;
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
;
475 ColorDepth
MacIOSurface::GetColorDepth() const {
476 switch (GetPixelFormat()) {
477 case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange
:
478 case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange
:
479 return ColorDepth::COLOR_10
;
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
;
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
513 internalFormat
= format
=
514 (isCompatibilityProfile
) ? (LOCAL_GL_LUMINANCE
) : (LOCAL_GL_RED
);
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
532 internalFormat
= format
=
533 (isCompatibilityProfile
) ? (LOCAL_GL_LUMINANCE
) : (LOCAL_GL_RED
);
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
;
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
;
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
;
580 CGLTexImageIOSurface2D(ctx
, LOCAL_GL_TEXTURE_RECTANGLE_ARB
,
581 internalFormat
, GetDevicePixelWidth(plane
),
582 GetDevicePixelHeight(plane
), format
, type
, plane
);
584 const auto formatChars
= (const char*)&pixelFormat
;
585 const char formatStr
[] = {formatChars
[3], formatChars
[2], formatChars
[1],
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
599 void MacIOSurface::SetColorSpace(const mozilla::gfx::ColorSpace2 cs
) const {
600 Maybe
<CFStringRef
> str
;
602 case gfx::ColorSpace2::UNKNOWN
:
604 case gfx::ColorSpace2::SRGB
:
605 str
= Some(kCGColorSpaceSRGB
);
607 case gfx::ColorSpace2::DISPLAY_P3
:
608 str
= Some(kCGColorSpaceDisplayP3
);
610 case gfx::ColorSpace2::BT601_525
: // Doesn't really have a better option.
611 case gfx::ColorSpace2::BT709
:
612 str
= Some(kCGColorSpaceITUR_709
);
614 case gfx::ColorSpace2::BT2020
:
615 str
= Some(kCGColorSpaceITUR_2020
);
619 IOSurfaceSetValue(mIOSurfaceRef
.get(), CFSTR("IOSurfaceColorSpace"), *str
);