michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: // vim:set ts=2 sts=2 sw=2 et cin: michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "MacIOSurface.h" michael@0: #include michael@0: #include michael@0: #include michael@0: #include "mozilla/RefPtr.h" michael@0: #include "mozilla/Assertions.h" michael@0: michael@0: using namespace mozilla; michael@0: // IOSurface signatures michael@0: #define IOSURFACE_FRAMEWORK_PATH \ michael@0: "/System/Library/Frameworks/IOSurface.framework/IOSurface" michael@0: #define OPENGL_FRAMEWORK_PATH \ michael@0: "/System/Library/Frameworks/OpenGL.framework/OpenGL" michael@0: #define COREGRAPHICS_FRAMEWORK_PATH \ michael@0: "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/CoreGraphics" michael@0: michael@0: michael@0: michael@0: #define GET_CONST(const_name) \ michael@0: ((CFStringRef*) dlsym(sIOSurfaceFramework, const_name)) michael@0: #define GET_IOSYM(dest,sym_name) \ michael@0: (typeof(dest)) dlsym(sIOSurfaceFramework, sym_name) michael@0: #define GET_CGLSYM(dest,sym_name) \ michael@0: (typeof(dest)) dlsym(sOpenGLFramework, sym_name) michael@0: #define GET_CGSYM(dest,sym_name) \ michael@0: (typeof(dest)) dlsym(sCoreGraphicsFramework, sym_name) michael@0: michael@0: MacIOSurfaceLib::LibraryUnloader MacIOSurfaceLib::sLibraryUnloader; michael@0: bool MacIOSurfaceLib::isLoaded = false; michael@0: void* MacIOSurfaceLib::sIOSurfaceFramework; michael@0: void* MacIOSurfaceLib::sOpenGLFramework; michael@0: void* MacIOSurfaceLib::sCoreGraphicsFramework; michael@0: IOSurfaceCreateFunc MacIOSurfaceLib::sCreate; michael@0: IOSurfaceGetIDFunc MacIOSurfaceLib::sGetID; michael@0: IOSurfaceLookupFunc MacIOSurfaceLib::sLookup; michael@0: IOSurfaceGetBaseAddressFunc MacIOSurfaceLib::sGetBaseAddress; michael@0: IOSurfaceGetWidthFunc MacIOSurfaceLib::sWidth; michael@0: IOSurfaceGetHeightFunc MacIOSurfaceLib::sHeight; michael@0: IOSurfaceGetBytesPerRowFunc MacIOSurfaceLib::sBytesPerRow; michael@0: IOSurfaceLockFunc MacIOSurfaceLib::sLock; michael@0: IOSurfaceUnlockFunc MacIOSurfaceLib::sUnlock; michael@0: CGLTexImageIOSurface2DFunc MacIOSurfaceLib::sTexImage; michael@0: IOSurfaceContextCreateFunc MacIOSurfaceLib::sIOSurfaceContextCreate; michael@0: IOSurfaceContextCreateImageFunc MacIOSurfaceLib::sIOSurfaceContextCreateImage; michael@0: IOSurfaceContextGetSurfaceFunc MacIOSurfaceLib::sIOSurfaceContextGetSurface; michael@0: unsigned int (*MacIOSurfaceLib::sCGContextGetTypePtr) (CGContextRef) = nullptr; michael@0: michael@0: CFStringRef MacIOSurfaceLib::kPropWidth; michael@0: CFStringRef MacIOSurfaceLib::kPropHeight; michael@0: CFStringRef MacIOSurfaceLib::kPropBytesPerElem; michael@0: CFStringRef MacIOSurfaceLib::kPropBytesPerRow; michael@0: CFStringRef MacIOSurfaceLib::kPropIsGlobal; michael@0: michael@0: bool MacIOSurfaceLib::isInit() { michael@0: // Guard against trying to reload the library michael@0: // if it is not available. michael@0: if (!isLoaded) michael@0: LoadLibrary(); michael@0: MOZ_ASSERT(sIOSurfaceFramework); michael@0: return sIOSurfaceFramework; michael@0: } michael@0: michael@0: IOSurfacePtr MacIOSurfaceLib::IOSurfaceCreate(CFDictionaryRef properties) { michael@0: return sCreate(properties); michael@0: } michael@0: michael@0: IOSurfacePtr MacIOSurfaceLib::IOSurfaceLookup(IOSurfaceID aIOSurfaceID) { michael@0: return sLookup(aIOSurfaceID); michael@0: } michael@0: michael@0: IOSurfaceID MacIOSurfaceLib::IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr) { michael@0: return sGetID(aIOSurfacePtr); michael@0: } michael@0: michael@0: void* MacIOSurfaceLib::IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr) { michael@0: return sGetBaseAddress(aIOSurfacePtr); michael@0: } michael@0: michael@0: size_t MacIOSurfaceLib::IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr) { michael@0: return sWidth(aIOSurfacePtr); michael@0: } michael@0: michael@0: size_t MacIOSurfaceLib::IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr) { michael@0: return sHeight(aIOSurfacePtr); michael@0: } michael@0: michael@0: size_t MacIOSurfaceLib::IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr) { michael@0: return sBytesPerRow(aIOSurfacePtr); michael@0: } michael@0: michael@0: IOReturn MacIOSurfaceLib::IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, michael@0: uint32_t options, uint32_t *seed) { michael@0: return sLock(aIOSurfacePtr, options, seed); michael@0: } michael@0: michael@0: IOReturn MacIOSurfaceLib::IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, michael@0: uint32_t options, uint32_t *seed) { michael@0: return sUnlock(aIOSurfacePtr, options, seed); michael@0: } michael@0: michael@0: CGLError MacIOSurfaceLib::CGLTexImageIOSurface2D(CGLContextObj ctxt, michael@0: GLenum target, GLenum internalFormat, michael@0: GLsizei width, GLsizei height, michael@0: GLenum format, GLenum type, michael@0: IOSurfacePtr ioSurface, GLuint plane) { michael@0: return sTexImage(ctxt, target, internalFormat, width, height, michael@0: format, type, ioSurface, plane); michael@0: } michael@0: michael@0: CGContextRef MacIOSurfaceLib::IOSurfaceContextCreate(IOSurfacePtr aIOSurfacePtr, michael@0: unsigned aWidth, unsigned aHeight, michael@0: unsigned aBitsPerComponent, unsigned aBytes, michael@0: CGColorSpaceRef aColorSpace, CGBitmapInfo bitmapInfo) { michael@0: if (!sIOSurfaceContextCreate) michael@0: return nullptr; michael@0: return sIOSurfaceContextCreate(aIOSurfacePtr, aWidth, aHeight, aBitsPerComponent, aBytes, aColorSpace, bitmapInfo); michael@0: } michael@0: michael@0: CGImageRef MacIOSurfaceLib::IOSurfaceContextCreateImage(CGContextRef aContext) { michael@0: if (!sIOSurfaceContextCreateImage) michael@0: return nullptr; michael@0: return sIOSurfaceContextCreateImage(aContext); michael@0: } michael@0: michael@0: IOSurfacePtr MacIOSurfaceLib::IOSurfaceContextGetSurface(CGContextRef aContext) { michael@0: if (!sIOSurfaceContextGetSurface) michael@0: return nullptr; michael@0: return sIOSurfaceContextGetSurface(aContext); michael@0: } michael@0: michael@0: CFStringRef MacIOSurfaceLib::GetIOConst(const char* symbole) { michael@0: CFStringRef *address = (CFStringRef*)dlsym(sIOSurfaceFramework, symbole); michael@0: if (!address) michael@0: return nullptr; michael@0: michael@0: return *address; michael@0: } michael@0: michael@0: void MacIOSurfaceLib::LoadLibrary() { michael@0: if (isLoaded) { michael@0: return; michael@0: } michael@0: isLoaded = true; michael@0: sIOSurfaceFramework = dlopen(IOSURFACE_FRAMEWORK_PATH, michael@0: RTLD_LAZY | RTLD_LOCAL); michael@0: sOpenGLFramework = dlopen(OPENGL_FRAMEWORK_PATH, michael@0: RTLD_LAZY | RTLD_LOCAL); michael@0: michael@0: sCoreGraphicsFramework = dlopen(COREGRAPHICS_FRAMEWORK_PATH, michael@0: RTLD_LAZY | RTLD_LOCAL); michael@0: if (!sIOSurfaceFramework || !sOpenGLFramework || !sCoreGraphicsFramework) { michael@0: if (sIOSurfaceFramework) michael@0: dlclose(sIOSurfaceFramework); michael@0: if (sOpenGLFramework) michael@0: dlclose(sOpenGLFramework); michael@0: if (sCoreGraphicsFramework) michael@0: dlclose(sCoreGraphicsFramework); michael@0: sIOSurfaceFramework = nullptr; michael@0: sOpenGLFramework = nullptr; michael@0: sCoreGraphicsFramework = nullptr; michael@0: return; michael@0: } michael@0: michael@0: kPropWidth = GetIOConst("kIOSurfaceWidth"); michael@0: kPropHeight = GetIOConst("kIOSurfaceHeight"); michael@0: kPropBytesPerElem = GetIOConst("kIOSurfaceBytesPerElement"); michael@0: kPropBytesPerRow = GetIOConst("kIOSurfaceBytesPerRow"); michael@0: kPropIsGlobal = GetIOConst("kIOSurfaceIsGlobal"); michael@0: sCreate = GET_IOSYM(sCreate, "IOSurfaceCreate"); michael@0: sGetID = GET_IOSYM(sGetID, "IOSurfaceGetID"); michael@0: sWidth = GET_IOSYM(sWidth, "IOSurfaceGetWidth"); michael@0: sHeight = GET_IOSYM(sHeight, "IOSurfaceGetHeight"); michael@0: sBytesPerRow = GET_IOSYM(sBytesPerRow, "IOSurfaceGetBytesPerRow"); michael@0: sLookup = GET_IOSYM(sLookup, "IOSurfaceLookup"); michael@0: sLock = GET_IOSYM(sLock, "IOSurfaceLock"); michael@0: sUnlock = GET_IOSYM(sUnlock, "IOSurfaceUnlock"); michael@0: sGetBaseAddress = GET_IOSYM(sGetBaseAddress, "IOSurfaceGetBaseAddress"); michael@0: sTexImage = GET_CGLSYM(sTexImage, "CGLTexImageIOSurface2D"); michael@0: sCGContextGetTypePtr = (unsigned int (*)(CGContext*))dlsym(RTLD_DEFAULT, "CGContextGetType"); michael@0: michael@0: // Optional symbols michael@0: sIOSurfaceContextCreate = GET_CGSYM(sIOSurfaceContextCreate, "CGIOSurfaceContextCreate"); michael@0: sIOSurfaceContextCreateImage = GET_CGSYM(sIOSurfaceContextCreateImage, "CGIOSurfaceContextCreateImage"); michael@0: sIOSurfaceContextGetSurface = GET_CGSYM(sIOSurfaceContextGetSurface, "CGIOSurfaceContextGetSurface"); michael@0: michael@0: if (!sCreate || !sGetID || !sLookup || !sTexImage || !sGetBaseAddress || michael@0: !kPropWidth || !kPropHeight || !kPropBytesPerElem || !kPropIsGlobal || michael@0: !sLock || !sUnlock || !sWidth || !sHeight || !kPropBytesPerRow || michael@0: !sBytesPerRow) { michael@0: CloseLibrary(); michael@0: } michael@0: } michael@0: michael@0: void MacIOSurfaceLib::CloseLibrary() { michael@0: if (sIOSurfaceFramework) { michael@0: dlclose(sIOSurfaceFramework); michael@0: } michael@0: if (sOpenGLFramework) { michael@0: dlclose(sOpenGLFramework); michael@0: } michael@0: sIOSurfaceFramework = nullptr; michael@0: sOpenGLFramework = nullptr; michael@0: } michael@0: michael@0: MacIOSurface::~MacIOSurface() { michael@0: CFRelease(mIOSurfacePtr); michael@0: } michael@0: michael@0: TemporaryRef MacIOSurface::CreateIOSurface(int aWidth, int aHeight, michael@0: double aContentsScaleFactor, michael@0: bool aHasAlpha) { michael@0: if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) michael@0: return nullptr; michael@0: michael@0: CFMutableDictionaryRef props = ::CFDictionaryCreateMutable( michael@0: kCFAllocatorDefault, 4, michael@0: &kCFTypeDictionaryKeyCallBacks, michael@0: &kCFTypeDictionaryValueCallBacks); michael@0: if (!props) michael@0: return nullptr; michael@0: michael@0: int32_t bytesPerElem = 4; michael@0: size_t intScaleFactor = ceil(aContentsScaleFactor); michael@0: aWidth *= intScaleFactor; michael@0: aHeight *= intScaleFactor; michael@0: CFNumberRef cfWidth = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aWidth); michael@0: CFNumberRef cfHeight = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aHeight); michael@0: CFNumberRef cfBytesPerElem = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &bytesPerElem); michael@0: ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropWidth, michael@0: cfWidth); michael@0: ::CFRelease(cfWidth); michael@0: ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropHeight, michael@0: cfHeight); michael@0: ::CFRelease(cfHeight); michael@0: ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropBytesPerElem, michael@0: cfBytesPerElem); michael@0: ::CFRelease(cfBytesPerElem); michael@0: ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropIsGlobal, michael@0: kCFBooleanTrue); michael@0: michael@0: IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceCreate(props); michael@0: ::CFRelease(props); michael@0: michael@0: if (!surfaceRef) michael@0: return nullptr; michael@0: michael@0: RefPtr ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); michael@0: if (!ioSurface) { michael@0: ::CFRelease(surfaceRef); michael@0: return nullptr; michael@0: } michael@0: michael@0: return ioSurface.forget(); michael@0: } michael@0: michael@0: TemporaryRef MacIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID, michael@0: double aContentsScaleFactor, michael@0: bool aHasAlpha) { michael@0: if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) michael@0: return nullptr; michael@0: michael@0: IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceLookup(aIOSurfaceID); michael@0: if (!surfaceRef) michael@0: return nullptr; michael@0: michael@0: RefPtr ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); michael@0: if (!ioSurface) { michael@0: ::CFRelease(surfaceRef); michael@0: return nullptr; michael@0: } michael@0: return ioSurface.forget(); michael@0: } michael@0: michael@0: IOSurfaceID MacIOSurface::GetIOSurfaceID() { michael@0: return MacIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr); michael@0: } michael@0: michael@0: void* MacIOSurface::GetBaseAddress() { michael@0: return MacIOSurfaceLib::IOSurfaceGetBaseAddress(mIOSurfacePtr); michael@0: } michael@0: michael@0: size_t MacIOSurface::GetWidth() { michael@0: size_t intScaleFactor = ceil(mContentsScaleFactor); michael@0: return GetDevicePixelWidth() / intScaleFactor; michael@0: } michael@0: michael@0: size_t MacIOSurface::GetHeight() { michael@0: size_t intScaleFactor = ceil(mContentsScaleFactor); michael@0: return GetDevicePixelHeight() / intScaleFactor; michael@0: } michael@0: michael@0: size_t MacIOSurface::GetDevicePixelWidth() { michael@0: return MacIOSurfaceLib::IOSurfaceGetWidth(mIOSurfacePtr); michael@0: } michael@0: michael@0: size_t MacIOSurface::GetDevicePixelHeight() { michael@0: return MacIOSurfaceLib::IOSurfaceGetHeight(mIOSurfacePtr); michael@0: } michael@0: michael@0: size_t MacIOSurface::GetBytesPerRow() { michael@0: return MacIOSurfaceLib::IOSurfaceGetBytesPerRow(mIOSurfacePtr); michael@0: } michael@0: michael@0: #define READ_ONLY 0x1 michael@0: void MacIOSurface::Lock() { michael@0: MacIOSurfaceLib::IOSurfaceLock(mIOSurfacePtr, READ_ONLY, nullptr); michael@0: } michael@0: michael@0: void MacIOSurface::Unlock() { michael@0: MacIOSurfaceLib::IOSurfaceUnlock(mIOSurfacePtr, READ_ONLY, nullptr); michael@0: } michael@0: michael@0: #include "SourceSurfaceRawData.h" michael@0: using mozilla::gfx::SourceSurface; michael@0: using mozilla::gfx::SourceSurfaceRawData; michael@0: using mozilla::gfx::IntSize; michael@0: using mozilla::gfx::SurfaceFormat; michael@0: michael@0: TemporaryRef michael@0: MacIOSurface::GetAsSurface() { michael@0: Lock(); michael@0: size_t bytesPerRow = GetBytesPerRow(); michael@0: size_t ioWidth = GetDevicePixelWidth(); michael@0: size_t ioHeight = GetDevicePixelHeight(); michael@0: michael@0: unsigned char* ioData = (unsigned char*)GetBaseAddress(); michael@0: unsigned char* dataCpy = (unsigned char*)malloc(bytesPerRow*ioHeight); michael@0: for (size_t i = 0; i < ioHeight; i++) { michael@0: memcpy(dataCpy + i * bytesPerRow, michael@0: ioData + i * bytesPerRow, ioWidth * 4); michael@0: } michael@0: michael@0: Unlock(); michael@0: michael@0: SurfaceFormat format = HasAlpha() ? mozilla::gfx::SurfaceFormat::B8G8R8A8 : michael@0: mozilla::gfx::SurfaceFormat::B8G8R8X8; michael@0: michael@0: RefPtr surf = new SourceSurfaceRawData(); michael@0: surf->InitWrappingData(dataCpy, IntSize(ioWidth, ioHeight), bytesPerRow, format, true); michael@0: michael@0: return surf.forget(); michael@0: } michael@0: michael@0: CGLError michael@0: MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx) michael@0: { michael@0: return MacIOSurfaceLib::CGLTexImageIOSurface2D(ctx, michael@0: GL_TEXTURE_RECTANGLE_ARB, michael@0: HasAlpha() ? GL_RGBA : GL_RGB, michael@0: GetDevicePixelWidth(), michael@0: GetDevicePixelHeight(), michael@0: GL_BGRA, michael@0: GL_UNSIGNED_INT_8_8_8_8_REV, michael@0: mIOSurfacePtr, 0); michael@0: } michael@0: michael@0: static michael@0: CGColorSpaceRef CreateSystemColorSpace() { michael@0: CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID()); michael@0: if (!cspace) { michael@0: cspace = ::CGColorSpaceCreateDeviceRGB(); michael@0: } michael@0: return cspace; michael@0: } michael@0: michael@0: CGContextRef MacIOSurface::CreateIOSurfaceContext() { michael@0: CGColorSpaceRef cspace = CreateSystemColorSpace(); michael@0: CGContextRef ref = MacIOSurfaceLib::IOSurfaceContextCreate(mIOSurfacePtr, michael@0: GetDevicePixelWidth(), michael@0: GetDevicePixelHeight(), michael@0: 8, 32, cspace, 0x2002); michael@0: ::CGColorSpaceRelease(cspace); michael@0: return ref; michael@0: } michael@0: michael@0: CGImageRef MacIOSurface::CreateImageFromIOSurfaceContext(CGContextRef aContext) { michael@0: if (!MacIOSurfaceLib::isInit()) michael@0: return nullptr; michael@0: michael@0: return MacIOSurfaceLib::IOSurfaceContextCreateImage(aContext); michael@0: } michael@0: michael@0: TemporaryRef MacIOSurface::IOSurfaceContextGetSurface(CGContextRef aContext, michael@0: double aContentsScaleFactor, michael@0: bool aHasAlpha) { michael@0: if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) michael@0: return nullptr; michael@0: michael@0: IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceContextGetSurface(aContext); michael@0: if (!surfaceRef) michael@0: return nullptr; michael@0: michael@0: // Retain the IOSurface because MacIOSurface will release it michael@0: CFRetain(surfaceRef); michael@0: michael@0: RefPtr ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); michael@0: if (!ioSurface) { michael@0: ::CFRelease(surfaceRef); michael@0: return nullptr; michael@0: } michael@0: return ioSurface.forget(); michael@0: } michael@0: michael@0: michael@0: CGContextType GetContextType(CGContextRef ref) michael@0: { michael@0: if (!MacIOSurfaceLib::isInit() || !MacIOSurfaceLib::sCGContextGetTypePtr) michael@0: return CG_CONTEXT_TYPE_UNKNOWN; michael@0: michael@0: unsigned int type = MacIOSurfaceLib::sCGContextGetTypePtr(ref); michael@0: if (type == CG_CONTEXT_TYPE_BITMAP) { michael@0: return CG_CONTEXT_TYPE_BITMAP; michael@0: } else if (type == CG_CONTEXT_TYPE_IOSURFACE) { michael@0: return CG_CONTEXT_TYPE_IOSURFACE; michael@0: } else { michael@0: return CG_CONTEXT_TYPE_UNKNOWN; michael@0: } michael@0: } michael@0: michael@0: