Bug 1703443 - pt 6. Move RunNextCollectorTimer() into CCGCScheduler r=smaug
[gecko.git] / gfx / 2d / MacIOSurface.cpp
blob208e4bf46707e187ed4e3e537962603ec00f47d0
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 "nsPrintfCString.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/gfx/Logging.h"
17 #include "mozilla/StaticPrefs_gfx.h"
19 using namespace mozilla;
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();
29 MacIOSurface::~MacIOSurface() {
30 MOZ_RELEASE_ASSERT(!IsLocked(), "Destroying locked surface");
31 DecrementUseCount();
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());
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);
48 size_t bytesPerRow =
49 IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, aWidth * aBytesPerPixel);
50 AddDictionaryInt(aDict, kIOSurfaceBytesPerRow, bytesPerRow);
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);
59 /* static */
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;
69 MOZ_ASSERT((size_t)aWidth <= GetMaxWidth());
70 MOZ_ASSERT((size_t)aHeight <= GetMaxHeight());
72 int32_t bytesPerElem = 4;
73 SetSizeProperties(props, aWidth, aHeight, bytesPerElem);
75 AddDictionaryInt(props, kIOSurfacePixelFormat,
76 (uint32_t)kCVPixelFormatType_32BGRA);
78 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
79 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
80 ::IOSurfaceCreate(props.get()));
82 if (StaticPrefs::gfx_color_management_native_srgb()) {
83 IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
84 kCGColorSpaceSRGB);
87 if (!surfaceRef) {
88 return nullptr;
91 RefPtr<MacIOSurface> ioSurface =
92 new MacIOSurface(std::move(surfaceRef), aHasAlpha);
94 return ioSurface.forget();
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);
107 aDict = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
108 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
109 &kCFTypeDictionaryKeyCallBacks,
110 &kCFTypeDictionaryValueCallBacks));
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);
119 return totalBytes;
122 /* static */
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);
131 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
132 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
133 &kCFTypeDictionaryKeyCallBacks,
134 &kCFTypeDictionaryValueCallBacks));
135 if (!props) return nullptr;
137 MOZ_ASSERT((size_t)aYSize.width <= GetMaxWidth());
138 MOZ_ASSERT((size_t)aYSize.height <= GetMaxHeight());
140 AddDictionaryInt(props, kIOSurfaceWidth, aYSize.width);
141 AddDictionaryInt(props, kIOSurfaceHeight, aYSize.height);
142 ::CFDictionaryAddValue(props.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
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);
152 CFTypeRefPtr<CFMutableDictionaryRef> planeProps[2];
153 size_t planeTotalBytes = CreatePlaneDictionary(planeProps[0], aYSize, 0, 1);
154 planeTotalBytes +=
155 CreatePlaneDictionary(planeProps[1], aCbCrSize, planeTotalBytes, 2);
157 AddDictionaryInt(props, kIOSurfaceAllocSize, planeTotalBytes);
159 auto array = CFTypeRefPtr<CFArrayRef>::WrapUnderCreateRule(
160 CFArrayCreate(kCFAllocatorDefault, (const void**)planeProps, 2,
161 &kCFTypeArrayCallBacks));
162 ::CFDictionaryAddValue(props.get(), kIOSurfacePlaneInfo, array.get());
164 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
165 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
166 ::IOSurfaceCreate(props.get()));
168 if (!surfaceRef) {
169 return nullptr;
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"));
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());
193 RefPtr<MacIOSurface> ioSurface =
194 new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
196 return ioSurface.forget();
199 /* static */
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);
207 auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
208 ::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
209 &kCFTypeDictionaryKeyCallBacks,
210 &kCFTypeDictionaryValueCallBacks));
211 if (!props) return nullptr;
213 MOZ_ASSERT((size_t)aSize.width <= GetMaxWidth());
214 MOZ_ASSERT((size_t)aSize.height <= GetMaxHeight());
216 SetSizeProperties(props, aSize.width, aSize.height, 2);
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);
226 CFTypeRefPtr<IOSurfaceRef> surfaceRef =
227 CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
228 ::IOSurfaceCreate(props.get()));
230 if (!surfaceRef) {
231 return nullptr;
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"));
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());
255 RefPtr<MacIOSurface> ioSurface =
256 new MacIOSurface(std::move(surfaceRef), false, aColorSpace);
258 return ioSurface.forget();
261 /* static */
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;
269 RefPtr<MacIOSurface> ioSurface =
270 new MacIOSurface(std::move(surfaceRef), aHasAlpha, aColorSpace);
272 return ioSurface.forget();
275 IOSurfaceID MacIOSurface::GetIOSurfaceID() const {
276 return ::IOSurfaceGetID(mIOSurfaceRef.get());
279 void* MacIOSurface::GetBaseAddress() const {
280 return ::IOSurfaceGetBaseAddress(mIOSurfaceRef.get());
283 void* MacIOSurface::GetBaseAddressOfPlane(size_t aPlaneIndex) const {
284 return ::IOSurfaceGetBaseAddressOfPlane(mIOSurfaceRef.get(), aPlaneIndex);
287 size_t MacIOSurface::GetWidth(size_t plane) const {
288 return GetDevicePixelWidth(plane);
291 size_t MacIOSurface::GetHeight(size_t plane) const {
292 return GetDevicePixelHeight(plane);
295 size_t MacIOSurface::GetPlaneCount() const {
296 return ::IOSurfaceGetPlaneCount(mIOSurfaceRef.get());
299 /*static*/
300 size_t MacIOSurface::GetMaxWidth() {
301 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceWidth);
304 /*static*/
305 size_t MacIOSurface::GetMaxHeight() {
306 return ::IOSurfaceGetPropertyMaximum(kIOSurfaceHeight);
309 size_t MacIOSurface::GetDevicePixelWidth(size_t plane) const {
310 return ::IOSurfaceGetWidthOfPlane(mIOSurfaceRef.get(), plane);
313 size_t MacIOSurface::GetDevicePixelHeight(size_t plane) const {
314 return ::IOSurfaceGetHeightOfPlane(mIOSurfaceRef.get(), plane);
317 size_t MacIOSurface::GetBytesPerRow(size_t plane) const {
318 return ::IOSurfaceGetBytesPerRowOfPlane(mIOSurfaceRef.get(), plane);
321 size_t MacIOSurface::GetAllocSize() const {
322 return ::IOSurfaceGetAllocSize(mIOSurfaceRef.get());
325 OSType MacIOSurface::GetPixelFormat() const {
326 return ::IOSurfaceGetPixelFormat(mIOSurfaceRef.get());
329 void MacIOSurface::IncrementUseCount() {
330 ::IOSurfaceIncrementUseCount(mIOSurfaceRef.get());
333 void MacIOSurface::DecrementUseCount() {
334 ::IOSurfaceDecrementUseCount(mIOSurfaceRef.get());
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;
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;
351 using mozilla::gfx::IntSize;
352 using mozilla::gfx::SourceSurface;
353 using mozilla::gfx::SurfaceFormat;
355 static void MacIOSurfaceBufferDeallocator(void* aClosure) {
356 MOZ_ASSERT(aClosure);
358 delete[] static_cast<unsigned char*>(aClosure);
361 already_AddRefed<SourceSurface> MacIOSurface::GetAsSurface() {
362 Lock();
363 size_t bytesPerRow = GetBytesPerRow();
364 size_t ioWidth = GetDevicePixelWidth();
365 size_t ioHeight = GetDevicePixelHeight();
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);
374 Unlock();
376 SurfaceFormat format = HasAlpha() ? mozilla::gfx::SurfaceFormat::B8G8R8A8
377 : mozilla::gfx::SurfaceFormat::B8G8R8X8;
379 RefPtr<mozilla::gfx::DataSourceSurface> surf =
380 mozilla::gfx::Factory::CreateWrappingDataSourceSurface(
381 dataCpy, bytesPerRow, IntSize(ioWidth, ioHeight), format,
382 &MacIOSurfaceBufferDeallocator, static_cast<void*>(dataCpy));
384 return surf.forget();
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.");
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);
402 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;
418 SurfaceFormat MacIOSurface::GetReadFormat() const {
419 SurfaceFormat format = GetFormat();
420 if (format == SurfaceFormat::YUV422) {
421 return SurfaceFormat::R8G8B8X8;
423 return format;
426 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);
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();
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);
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);
460 type = LOCAL_GL_UNSIGNED_BYTE;
461 if (aOutReadFormat) {
462 *aOutReadFormat = mozilla::gfx::SurfaceFormat::NV12;
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.
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;
481 } else {
482 format = LOCAL_GL_RGB_422_APPLE;
483 if (aOutReadFormat) {
484 *aOutReadFormat = mozilla::gfx::SurfaceFormat::YUV422;
487 internalFormat = LOCAL_GL_RGB;
488 type = LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE;
489 } else {
490 MOZ_ASSERT(plane == 0);
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;
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 << ")";
518 return err;