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/. */
6
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 "nsPrintfCString.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/gfx/Logging.h"
17 #include "mozilla/StaticPrefs_gfx.h"
18
19 using namespace mozilla;
20
MacIOSurface(CFTypeRefPtr<IOSurfaceRef> aIOSurfaceRef,bool aHasAlpha,gfx::YUVColorSpace aColorSpace)21 MacIOSurface::MacIOSurface(CFTypeRefPtr<IOSurfaceRef> aIOSurfaceRef,
22 bool aHasAlpha, gfx::YUVColorSpace aColorSpace)
23 : mIOSurfaceRef(std::move(aIOSurfaceRef)),
24 mHasAlpha(aHasAlpha),
25 mColorSpace(aColorSpace) {
26 IncrementUseCount();
27 }
28
~MacIOSurface()29 MacIOSurface::~MacIOSurface() {
30 MOZ_RELEASE_ASSERT(!IsLocked(), "Destroying locked surface");
31 DecrementUseCount();
32 }
33
AddDictionaryInt(const CFTypeRefPtr<CFMutableDictionaryRef> & aDict,const void * aType,uint32_t aValue)34 void AddDictionaryInt(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
35 const void* aType, uint32_t aValue) {
36 auto cfValue = CFTypeRefPtr<CFNumberRef>::WrapUnderCreateRule(
37 ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aValue));
38 ::CFDictionaryAddValue(aDict.get(), aType, cfValue.get());
39 }
40
SetSizeProperties(const CFTypeRefPtr<CFMutableDictionaryRef> & aDict,int aWidth,int aHeight,int aBytesPerPixel)41 void SetSizeProperties(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
42 int aWidth, int aHeight, int aBytesPerPixel) {
43 AddDictionaryInt(aDict, kIOSurfaceWidth, aWidth);
44 AddDictionaryInt(aDict, kIOSurfaceHeight, aHeight);
45 ::CFDictionaryAddValue(aDict.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
46 AddDictionaryInt(aDict, kIOSurfaceBytesPerElement, aBytesPerPixel);
47
48 size_t bytesPerRow =
49 IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, aWidth * aBytesPerPixel);
50 AddDictionaryInt(aDict, kIOSurfaceBytesPerRow, bytesPerRow);
51
52 // Add a SIMD register worth of extra bytes to the end of the allocation for
53 // SWGL.
54 size_t totalBytes =
55 IOSurfaceAlignProperty(kIOSurfaceAllocSize, aHeight * bytesPerRow + 16);
56 AddDictionaryInt(aDict, kIOSurfaceAllocSize, totalBytes);
57 }
58
59 /* static */
CreateIOSurface(int aWidth,int aHeight,bool aHasAlpha)60 already_AddRefed<MacIOSurface> MacIOSurface::CreateIOSurface(int aWidth,
61 int aHeight,
62 bool aHasAlpha) {
63 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
64 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
65 &kCFTypeDictionaryKeyCallBacks,
66 &kCFTypeDictionaryValueCallBacks));
67 if (!props) return nullptr;
68
69 MOZ_ASSERT((size_t)aWidth <= GetMaxWidth());
70 MOZ_ASSERT((size_t)aHeight <= GetMaxHeight());
71
72 int32_t bytesPerElem = 4;
73 SetSizeProperties(props, aWidth, aHeight, bytesPerElem);
74
75 AddDictionaryInt(props, kIOSurfacePixelFormat,
76 (uint32_t)kCVPixelFormatType_32BGRA);
77
78 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
79 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
80 ::IOSurfaceCreate(props.get()));
81
82 if (StaticPrefs::gfx_color_management_native_srgb()) {
83 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
84 kCGColorSpaceSRGB);
85 }
86
87 if (!surfaceRef) {
88 return nullptr;
89 }
90
91 RefPtr<MacIOSurface> ioSurface =
92 new MacIOSurface(std::move(surfaceRef), aHasAlpha);
93
94 return ioSurface.forget();
95 }
96
CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef> & aDict,const gfx::IntSize & aSize,size_t aOffset,size_t aBytesPerPixel)97 size_t CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
98 const gfx::IntSize& aSize, size_t aOffset,
99 size_t aBytesPerPixel) {
100 size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow,
101 aSize.width * aBytesPerPixel);
102 // Add a SIMD register worth of extra bytes to the end of the allocation for
103 // SWGL.
104 size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize,
105 aSize.height * bytesPerRow + 16);
106
107 aDict = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
108 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
109 &kCFTypeDictionaryKeyCallBacks,
110 &kCFTypeDictionaryValueCallBacks));
111
112 AddDictionaryInt(aDict, kIOSurfacePlaneWidth, aSize.width);
113 AddDictionaryInt(aDict, kIOSurfacePlaneHeight, aSize.height);
114 AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerRow, bytesPerRow);
115 AddDictionaryInt(aDict, kIOSurfacePlaneOffset, aOffset);
116 AddDictionaryInt(aDict, kIOSurfacePlaneSize, totalBytes);
117 AddDictionaryInt(aDict, kIOSurfaceBytesPerElement, aBytesPerPixel);
118
119 return totalBytes;
120 }
121
122 /* static */
CreateNV12Surface(const IntSize & aYSize,const IntSize & aCbCrSize,YUVColorSpace aColorSpace,ColorRange aColorRange)123 already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12Surface(
124 const IntSize& aYSize, const IntSize& aCbCrSize, YUVColorSpace aColorSpace,
125 ColorRange aColorRange) {
126 MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
127 aColorSpace == YUVColorSpace::BT709);
128 MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
129 aColorRange == ColorRange::FULL);
130
131 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
132 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
133 &kCFTypeDictionaryKeyCallBacks,
134 &kCFTypeDictionaryValueCallBacks));
135 if (!props) return nullptr;
136
137 MOZ_ASSERT((size_t)aYSize.width <= GetMaxWidth());
138 MOZ_ASSERT((size_t)aYSize.height <= GetMaxHeight());
139
140 AddDictionaryInt(props, kIOSurfaceWidth, aYSize.width);
141 AddDictionaryInt(props, kIOSurfaceHeight, aYSize.height);
142 ::CFDictionaryAddValue(props.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
143
144 if (aColorRange == ColorRange::LIMITED) {
145 AddDictionaryInt(props, kIOSurfacePixelFormat,
146 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
147 } else {
148 AddDictionaryInt(props, kIOSurfacePixelFormat,
149 (uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
150 }
151
152 CFTypeRefPtr<CFMutableDictionaryRef> planeProps[2];
153 size_t planeTotalBytes = CreatePlaneDictionary(planeProps[0], aYSize, 0, 1);
154 planeTotalBytes +=
155 CreatePlaneDictionary(planeProps[1], aCbCrSize, planeTotalBytes, 2);
156
157 AddDictionaryInt(props, kIOSurfaceAllocSize, planeTotalBytes);
158
159 auto array = CFTypeRefPtr<CFArrayRef>::WrapUnderCreateRule(
160 CFArrayCreate(kCFAllocatorDefault, (const void**)planeProps, 2,
161 &kCFTypeArrayCallBacks));
162 ::CFDictionaryAddValue(props.get(), kIOSurfacePlaneInfo, array.get());
163
164 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
165 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
166 ::IOSurfaceCreate(props.get()));
167
168 if (!surfaceRef) {
169 return nullptr;
170 }
171
172 // Setup the correct YCbCr conversion matrix on the IOSurface, in case we pass
173 // this directly to CoreAnimation.
174 if (aColorSpace == YUVColorSpace::BT601) {
175 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
176 CFSTR("ITU_R_601_4"));
177 } else {
178 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
179 CFSTR("ITU_R_709_2"));
180 }
181 // Override the color space to be the same as the main display, so that
182 // CoreAnimation won't try to do any color correction (from the IOSurface
183 // space, to the display). In the future we may want to try specifying this
184 // correctly, but probably only once we do the same for videos drawn through
185 // our gfx code.
186 auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
187 CGDisplayCopyColorSpace(CGMainDisplayID()));
188 auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
189 CGColorSpaceCopyICCProfile(colorSpace.get()));
190 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
191 colorData.get());
192
193 RefPtr<MacIOSurface> ioSurface =
194 new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
195
196 return ioSurface.forget();
197 }
198
199 /* static */
CreateYUV422Surface(const IntSize & aSize,YUVColorSpace aColorSpace,ColorRange aColorRange)200 already_AddRefed<MacIOSurface> MacIOSurface::CreateYUV422Surface(
201 const IntSize& aSize, YUVColorSpace aColorSpace, ColorRange aColorRange) {
202 MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
203 aColorSpace == YUVColorSpace::BT709);
204 MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
205 aColorRange == ColorRange::FULL);
206
207 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
208 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
209 &kCFTypeDictionaryKeyCallBacks,
210 &kCFTypeDictionaryValueCallBacks));
211 if (!props) return nullptr;
212
213 MOZ_ASSERT((size_t)aSize.width <= GetMaxWidth());
214 MOZ_ASSERT((size_t)aSize.height <= GetMaxHeight());
215
216 SetSizeProperties(props, aSize.width, aSize.height, 2);
217
218 if (aColorRange == ColorRange::LIMITED) {
219 AddDictionaryInt(props, kIOSurfacePixelFormat,
220 (uint32_t)kCVPixelFormatType_422YpCbCr8_yuvs);
221 } else {
222 AddDictionaryInt(props, kIOSurfacePixelFormat,
223 (uint32_t)kCVPixelFormatType_422YpCbCr8FullRange);
224 }
225
226 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
227 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
228 ::IOSurfaceCreate(props.get()));
229
230 if (!surfaceRef) {
231 return nullptr;
232 }
233
234 // Setup the correct YCbCr conversion matrix on the IOSurface, in case we pass
235 // this directly to CoreAnimation.
236 if (aColorSpace == YUVColorSpace::BT601) {
237 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
238 CFSTR("ITU_R_601_4"));
239 } else {
240 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceYCbCrMatrix"),
241 CFSTR("ITU_R_709_2"));
242 }
243 // Override the color space to be the same as the main display, so that
244 // CoreAnimation won't try to do any color correction (from the IOSurface
245 // space, to the display). In the future we may want to try specifying this
246 // correctly, but probably only once we do the same for videos drawn through
247 // our gfx code.
248 auto colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
249 CGDisplayCopyColorSpace(CGMainDisplayID()));
250 auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
251 CGColorSpaceCopyICCProfile(colorSpace.get()));
252 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
253 colorData.get());
254
255 RefPtr<MacIOSurface> ioSurface =
256 new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
257
258 return ioSurface.forget();
259 }
260
261 /* static */
LookupSurface(IOSurfaceID aIOSurfaceID,bool aHasAlpha,gfx::YUVColorSpace aColorSpace)262 already_AddRefed<MacIOSurface> MacIOSurface::LookupSurface(
263 IOSurfaceID aIOSurfaceID, bool aHasAlpha, gfx::YUVColorSpace aColorSpace) {
264 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
265 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
266 ::IOSurfaceLookup(aIOSurfaceID));
267 if (!surfaceRef) return nullptr;
268
269 RefPtr<MacIOSurface> ioSurface =
270 new MacIOSurface(std::move(surfaceRef), aHasAlpha, aColorSpace);
271
272 return ioSurface.forget();
273 }
274
GetIOSurfaceID() const275 IOSurfaceID MacIOSurface::GetIOSurfaceID() const {
276 return ::IOSurfaceGetID(mIOSurfaceRef.get());
277 }
278
GetBaseAddress() const279 void* MacIOSurface::GetBaseAddress() const {
280 return ::IOSurfaceGetBaseAddress(mIOSurfaceRef.get());
281 }
282
GetBaseAddressOfPlane(size_t aPlaneIndex) const283 void* MacIOSurface::GetBaseAddressOfPlane(size_t aPlaneIndex) const {
284 return ::IOSurfaceGetBaseAddressOfPlane(mIOSurfaceRef.get(), aPlaneIndex);
285 }
286
GetWidth(size_t plane) const287 size_t MacIOSurface::GetWidth(size_t plane) const {
288 return GetDevicePixelWidth(plane);
289 }
290
GetHeight(size_t plane) const291 size_t MacIOSurface::GetHeight(size_t plane) const {
292 return GetDevicePixelHeight(plane);
293 }
294
GetPlaneCount() const295 size_t MacIOSurface::GetPlaneCount() const {
296 return ::IOSurfaceGetPlaneCount(mIOSurfaceRef.get());
297 }
298
299 /*static*/
GetMaxWidth()300 size_t MacIOSurface::GetMaxWidth() {
301 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceWidth);
302 }
303
304 /*static*/
GetMaxHeight()305 size_t MacIOSurface::GetMaxHeight() {
306 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceHeight);
307 }
308
GetDevicePixelWidth(size_t plane) const309 size_t MacIOSurface::GetDevicePixelWidth(size_t plane) const {
310 return ::IOSurfaceGetWidthOfPlane(mIOSurfaceRef.get(), plane);
311 }
312
GetDevicePixelHeight(size_t plane) const313 size_t MacIOSurface::GetDevicePixelHeight(size_t plane) const {
314 return ::IOSurfaceGetHeightOfPlane(mIOSurfaceRef.get(), plane);
315 }
316
GetBytesPerRow(size_t plane) const317 size_t MacIOSurface::GetBytesPerRow(size_t plane) const {
318 return ::IOSurfaceGetBytesPerRowOfPlane(mIOSurfaceRef.get(), plane);
319 }
320
GetAllocSize() const321 size_t MacIOSurface::GetAllocSize() const {
322 return ::IOSurfaceGetAllocSize(mIOSurfaceRef.get());
323 }
324
GetPixelFormat() const325 OSType MacIOSurface::GetPixelFormat() const {
326 return ::IOSurfaceGetPixelFormat(mIOSurfaceRef.get());
327 }
328
IncrementUseCount()329 void MacIOSurface::IncrementUseCount() {
330 ::IOSurfaceIncrementUseCount(mIOSurfaceRef.get());
331 }
332
DecrementUseCount()333 void MacIOSurface::DecrementUseCount() {
334 ::IOSurfaceDecrementUseCount(mIOSurfaceRef.get());
335 }
336
Lock(bool aReadOnly)337 void MacIOSurface::Lock(bool aReadOnly) {
338 MOZ_RELEASE_ASSERT(!mIsLocked, "double MacIOSurface lock");
339 ::IOSurfaceLock(mIOSurfaceRef.get(), aReadOnly ? kIOSurfaceLockReadOnly : 0,
340 nullptr);
341 mIsLocked = true;
342 }
343
Unlock(bool aReadOnly)344 void MacIOSurface::Unlock(bool aReadOnly) {
345 MOZ_RELEASE_ASSERT(mIsLocked, "MacIOSurface unlock without being locked");
346 ::IOSurfaceUnlock(mIOSurfaceRef.get(), aReadOnly ? kIOSurfaceLockReadOnly : 0,
347 nullptr);
348 mIsLocked = false;
349 }
350
351 using mozilla::gfx::IntSize;
352 using mozilla::gfx::SourceSurface;
353 using mozilla::gfx::SurfaceFormat;
354
MacIOSurfaceBufferDeallocator(void * aClosure)355 static void MacIOSurfaceBufferDeallocator(void* aClosure) {
356 MOZ_ASSERT(aClosure);
357
358 delete[] static_cast<unsigned char*>(aClosure);
359 }
360
GetAsSurface()361 already_AddRefed<SourceSurface> MacIOSurface::GetAsSurface() {
362 Lock();
363 size_t bytesPerRow = GetBytesPerRow();
364 size_t ioWidth = GetDevicePixelWidth();
365 size_t ioHeight = GetDevicePixelHeight();
366
367 unsigned char* ioData = (unsigned char*)GetBaseAddress();
368 auto* dataCpy =
369 new unsigned char[bytesPerRow * ioHeight / sizeof(unsigned char)];
370 for (size_t i = 0; i < ioHeight; i++) {
371 memcpy(dataCpy + i * bytesPerRow, ioData + i * bytesPerRow, ioWidth * 4);
372 }
373
374 Unlock();
375
376 SurfaceFormat format = HasAlpha() ? mozilla::gfx::SurfaceFormat::B8G8R8A8
377 : mozilla::gfx::SurfaceFormat::B8G8R8X8;
378
379 RefPtr<mozilla::gfx::DataSourceSurface> surf =
380 mozilla::gfx::Factory::CreateWrappingDataSourceSurface(
381 dataCpy, bytesPerRow, IntSize(ioWidth, ioHeight), format,
382 &MacIOSurfaceBufferDeallocator, static_cast<void*>(dataCpy));
383
384 return surf.forget();
385 }
386
GetAsDrawTargetLocked(mozilla::gfx::BackendType aBackendType)387 already_AddRefed<mozilla::gfx::DrawTarget> MacIOSurface::GetAsDrawTargetLocked(
388 mozilla::gfx::BackendType aBackendType) {
389 MOZ_RELEASE_ASSERT(
390 IsLocked(),
391 "Only call GetAsDrawTargetLocked while the surface is locked.");
392
393 size_t bytesPerRow = GetBytesPerRow();
394 size_t ioWidth = GetDevicePixelWidth();
395 size_t ioHeight = GetDevicePixelHeight();
396 unsigned char* ioData = (unsigned char*)GetBaseAddress();
397 SurfaceFormat format = GetFormat();
398 return mozilla::gfx::Factory::CreateDrawTargetForData(
399 aBackendType, ioData, IntSize(ioWidth, ioHeight), bytesPerRow, format);
400 }
401
GetFormat() const402 SurfaceFormat MacIOSurface::GetFormat() const {
403 switch (GetPixelFormat()) {
404 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
405 case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
406 return SurfaceFormat::NV12;
407 case kCVPixelFormatType_422YpCbCr8_yuvs:
408 case kCVPixelFormatType_422YpCbCr8FullRange:
409 return SurfaceFormat::YUV422;
410 case kCVPixelFormatType_32BGRA:
411 return HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
412 default:
413 MOZ_ASSERT_UNREACHABLE("Unknown format");
414 return SurfaceFormat::B8G8R8A8;
415 }
416 }
417
GetReadFormat() const418 SurfaceFormat MacIOSurface::GetReadFormat() const {
419 SurfaceFormat format = GetFormat();
420 if (format == SurfaceFormat::YUV422) {
421 return SurfaceFormat::R8G8B8X8;
422 }
423 return format;
424 }
425
CGLTexImageIOSurface2D(CGLContextObj ctx,GLenum target,GLenum internalFormat,GLsizei width,GLsizei height,GLenum format,GLenum type,GLuint plane) const426 CGLError MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx, GLenum target,
427 GLenum internalFormat,
428 GLsizei width, GLsizei height,
429 GLenum format, GLenum type,
430 GLuint plane) const {
431 return ::CGLTexImageIOSurface2D(ctx, target, internalFormat, width, height,
432 format, type, mIOSurfaceRef.get(), plane);
433 }
434
CGLTexImageIOSurface2D(mozilla::gl::GLContext * aGL,CGLContextObj ctx,size_t plane,mozilla::gfx::SurfaceFormat * aOutReadFormat)435 CGLError MacIOSurface::CGLTexImageIOSurface2D(
436 mozilla::gl::GLContext* aGL, CGLContextObj ctx, size_t plane,
437 mozilla::gfx::SurfaceFormat* aOutReadFormat) {
438 MOZ_ASSERT(plane >= 0);
439 bool isCompatibilityProfile = aGL->IsCompatibilityProfile();
440 OSType pixelFormat = GetPixelFormat();
441
442 GLenum internalFormat;
443 GLenum format;
444 GLenum type;
445 if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
446 pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
447 MOZ_ASSERT(GetPlaneCount() == 2);
448 MOZ_ASSERT(plane < 2);
449
450 // The LOCAL_GL_LUMINANCE and LOCAL_GL_LUMINANCE_ALPHA are the deprecated
451 // format. So, use LOCAL_GL_RED and LOCAL_GL_RB if we use core profile.
452 // https://www.khronos.org/opengl/wiki/Image_Format#Legacy_Image_Formats
453 if (plane == 0) {
454 internalFormat = format =
455 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE) : (LOCAL_GL_RED);
456 } else {
457 internalFormat = format =
458 (isCompatibilityProfile) ? (LOCAL_GL_LUMINANCE_ALPHA) : (LOCAL_GL_RG);
459 }
460 type = LOCAL_GL_UNSIGNED_BYTE;
461 if (aOutReadFormat) {
462 *aOutReadFormat = mozilla::gfx::SurfaceFormat::NV12;
463 }
464 } else if (pixelFormat == kCVPixelFormatType_422YpCbCr8_yuvs ||
465 pixelFormat == kCVPixelFormatType_422YpCbCr8FullRange) {
466 MOZ_ASSERT(plane == 0);
467 // The YCBCR_422_APPLE ext is only available in compatibility profile. So,
468 // we should use RGB_422_APPLE for core profile. The difference between
469 // YCBCR_422_APPLE and RGB_422_APPLE is that the YCBCR_422_APPLE converts
470 // the YCbCr value to RGB with REC 601 conversion. But the RGB_422_APPLE
471 // doesn't contain color conversion. You should do the color conversion by
472 // yourself for RGB_422_APPLE.
473 //
474 // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_ycbcr_422.txt
475 // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
476 if (isCompatibilityProfile) {
477 format = LOCAL_GL_YCBCR_422_APPLE;
478 if (aOutReadFormat) {
479 *aOutReadFormat = mozilla::gfx::SurfaceFormat::R8G8B8X8;
480 }
481 } else {
482 format = LOCAL_GL_RGB_422_APPLE;
483 if (aOutReadFormat) {
484 *aOutReadFormat = mozilla::gfx::SurfaceFormat::YUV422;
485 }
486 }
487 internalFormat = LOCAL_GL_RGB;
488 type = LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE;
489 } else {
490 MOZ_ASSERT(plane == 0);
491
492 internalFormat = HasAlpha() ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
493 format = LOCAL_GL_BGRA;
494 type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
495 if (aOutReadFormat) {
496 *aOutReadFormat = HasAlpha() ? mozilla::gfx::SurfaceFormat::R8G8B8A8
497 : mozilla::gfx::SurfaceFormat::R8G8B8X8;
498 }
499 }
500
501 auto err =
502 CGLTexImageIOSurface2D(ctx, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
503 internalFormat, GetDevicePixelWidth(plane),
504 GetDevicePixelHeight(plane), format, type, plane);
505 if (err) {
506 const auto formatChars = (const char*)&pixelFormat;
507 const char formatStr[] = {formatChars[3], formatChars[2], formatChars[1],
508 formatChars[0], 0};
509 const nsPrintfCString errStr(
510 "CGLTexImageIOSurface2D(context, target, 0x%04x,"
511 " %u, %u, 0x%04x, 0x%04x, iosurfPtr, %u) -> %i",
512 internalFormat, uint32_t(GetDevicePixelWidth(plane)),
513 uint32_t(GetDevicePixelHeight(plane)), format, type,
514 (unsigned int)plane, err);
515 gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr
516 << ")";
517 }
518 return err;
519 }
520