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