|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 // vim:set ts=2 sts=2 sw=2 et cin: |
|
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 <QuartzCore/QuartzCore.h> |
|
10 #include <dlfcn.h> |
|
11 #include "mozilla/RefPtr.h" |
|
12 #include "mozilla/Assertions.h" |
|
13 |
|
14 using namespace mozilla; |
|
15 // IOSurface signatures |
|
16 #define IOSURFACE_FRAMEWORK_PATH \ |
|
17 "/System/Library/Frameworks/IOSurface.framework/IOSurface" |
|
18 #define OPENGL_FRAMEWORK_PATH \ |
|
19 "/System/Library/Frameworks/OpenGL.framework/OpenGL" |
|
20 #define COREGRAPHICS_FRAMEWORK_PATH \ |
|
21 "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/CoreGraphics" |
|
22 |
|
23 |
|
24 |
|
25 #define GET_CONST(const_name) \ |
|
26 ((CFStringRef*) dlsym(sIOSurfaceFramework, const_name)) |
|
27 #define GET_IOSYM(dest,sym_name) \ |
|
28 (typeof(dest)) dlsym(sIOSurfaceFramework, sym_name) |
|
29 #define GET_CGLSYM(dest,sym_name) \ |
|
30 (typeof(dest)) dlsym(sOpenGLFramework, sym_name) |
|
31 #define GET_CGSYM(dest,sym_name) \ |
|
32 (typeof(dest)) dlsym(sCoreGraphicsFramework, sym_name) |
|
33 |
|
34 MacIOSurfaceLib::LibraryUnloader MacIOSurfaceLib::sLibraryUnloader; |
|
35 bool MacIOSurfaceLib::isLoaded = false; |
|
36 void* MacIOSurfaceLib::sIOSurfaceFramework; |
|
37 void* MacIOSurfaceLib::sOpenGLFramework; |
|
38 void* MacIOSurfaceLib::sCoreGraphicsFramework; |
|
39 IOSurfaceCreateFunc MacIOSurfaceLib::sCreate; |
|
40 IOSurfaceGetIDFunc MacIOSurfaceLib::sGetID; |
|
41 IOSurfaceLookupFunc MacIOSurfaceLib::sLookup; |
|
42 IOSurfaceGetBaseAddressFunc MacIOSurfaceLib::sGetBaseAddress; |
|
43 IOSurfaceGetWidthFunc MacIOSurfaceLib::sWidth; |
|
44 IOSurfaceGetHeightFunc MacIOSurfaceLib::sHeight; |
|
45 IOSurfaceGetBytesPerRowFunc MacIOSurfaceLib::sBytesPerRow; |
|
46 IOSurfaceLockFunc MacIOSurfaceLib::sLock; |
|
47 IOSurfaceUnlockFunc MacIOSurfaceLib::sUnlock; |
|
48 CGLTexImageIOSurface2DFunc MacIOSurfaceLib::sTexImage; |
|
49 IOSurfaceContextCreateFunc MacIOSurfaceLib::sIOSurfaceContextCreate; |
|
50 IOSurfaceContextCreateImageFunc MacIOSurfaceLib::sIOSurfaceContextCreateImage; |
|
51 IOSurfaceContextGetSurfaceFunc MacIOSurfaceLib::sIOSurfaceContextGetSurface; |
|
52 unsigned int (*MacIOSurfaceLib::sCGContextGetTypePtr) (CGContextRef) = nullptr; |
|
53 |
|
54 CFStringRef MacIOSurfaceLib::kPropWidth; |
|
55 CFStringRef MacIOSurfaceLib::kPropHeight; |
|
56 CFStringRef MacIOSurfaceLib::kPropBytesPerElem; |
|
57 CFStringRef MacIOSurfaceLib::kPropBytesPerRow; |
|
58 CFStringRef MacIOSurfaceLib::kPropIsGlobal; |
|
59 |
|
60 bool MacIOSurfaceLib::isInit() { |
|
61 // Guard against trying to reload the library |
|
62 // if it is not available. |
|
63 if (!isLoaded) |
|
64 LoadLibrary(); |
|
65 MOZ_ASSERT(sIOSurfaceFramework); |
|
66 return sIOSurfaceFramework; |
|
67 } |
|
68 |
|
69 IOSurfacePtr MacIOSurfaceLib::IOSurfaceCreate(CFDictionaryRef properties) { |
|
70 return sCreate(properties); |
|
71 } |
|
72 |
|
73 IOSurfacePtr MacIOSurfaceLib::IOSurfaceLookup(IOSurfaceID aIOSurfaceID) { |
|
74 return sLookup(aIOSurfaceID); |
|
75 } |
|
76 |
|
77 IOSurfaceID MacIOSurfaceLib::IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr) { |
|
78 return sGetID(aIOSurfacePtr); |
|
79 } |
|
80 |
|
81 void* MacIOSurfaceLib::IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr) { |
|
82 return sGetBaseAddress(aIOSurfacePtr); |
|
83 } |
|
84 |
|
85 size_t MacIOSurfaceLib::IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr) { |
|
86 return sWidth(aIOSurfacePtr); |
|
87 } |
|
88 |
|
89 size_t MacIOSurfaceLib::IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr) { |
|
90 return sHeight(aIOSurfacePtr); |
|
91 } |
|
92 |
|
93 size_t MacIOSurfaceLib::IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr) { |
|
94 return sBytesPerRow(aIOSurfacePtr); |
|
95 } |
|
96 |
|
97 IOReturn MacIOSurfaceLib::IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, |
|
98 uint32_t options, uint32_t *seed) { |
|
99 return sLock(aIOSurfacePtr, options, seed); |
|
100 } |
|
101 |
|
102 IOReturn MacIOSurfaceLib::IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, |
|
103 uint32_t options, uint32_t *seed) { |
|
104 return sUnlock(aIOSurfacePtr, options, seed); |
|
105 } |
|
106 |
|
107 CGLError MacIOSurfaceLib::CGLTexImageIOSurface2D(CGLContextObj ctxt, |
|
108 GLenum target, GLenum internalFormat, |
|
109 GLsizei width, GLsizei height, |
|
110 GLenum format, GLenum type, |
|
111 IOSurfacePtr ioSurface, GLuint plane) { |
|
112 return sTexImage(ctxt, target, internalFormat, width, height, |
|
113 format, type, ioSurface, plane); |
|
114 } |
|
115 |
|
116 CGContextRef MacIOSurfaceLib::IOSurfaceContextCreate(IOSurfacePtr aIOSurfacePtr, |
|
117 unsigned aWidth, unsigned aHeight, |
|
118 unsigned aBitsPerComponent, unsigned aBytes, |
|
119 CGColorSpaceRef aColorSpace, CGBitmapInfo bitmapInfo) { |
|
120 if (!sIOSurfaceContextCreate) |
|
121 return nullptr; |
|
122 return sIOSurfaceContextCreate(aIOSurfacePtr, aWidth, aHeight, aBitsPerComponent, aBytes, aColorSpace, bitmapInfo); |
|
123 } |
|
124 |
|
125 CGImageRef MacIOSurfaceLib::IOSurfaceContextCreateImage(CGContextRef aContext) { |
|
126 if (!sIOSurfaceContextCreateImage) |
|
127 return nullptr; |
|
128 return sIOSurfaceContextCreateImage(aContext); |
|
129 } |
|
130 |
|
131 IOSurfacePtr MacIOSurfaceLib::IOSurfaceContextGetSurface(CGContextRef aContext) { |
|
132 if (!sIOSurfaceContextGetSurface) |
|
133 return nullptr; |
|
134 return sIOSurfaceContextGetSurface(aContext); |
|
135 } |
|
136 |
|
137 CFStringRef MacIOSurfaceLib::GetIOConst(const char* symbole) { |
|
138 CFStringRef *address = (CFStringRef*)dlsym(sIOSurfaceFramework, symbole); |
|
139 if (!address) |
|
140 return nullptr; |
|
141 |
|
142 return *address; |
|
143 } |
|
144 |
|
145 void MacIOSurfaceLib::LoadLibrary() { |
|
146 if (isLoaded) { |
|
147 return; |
|
148 } |
|
149 isLoaded = true; |
|
150 sIOSurfaceFramework = dlopen(IOSURFACE_FRAMEWORK_PATH, |
|
151 RTLD_LAZY | RTLD_LOCAL); |
|
152 sOpenGLFramework = dlopen(OPENGL_FRAMEWORK_PATH, |
|
153 RTLD_LAZY | RTLD_LOCAL); |
|
154 |
|
155 sCoreGraphicsFramework = dlopen(COREGRAPHICS_FRAMEWORK_PATH, |
|
156 RTLD_LAZY | RTLD_LOCAL); |
|
157 if (!sIOSurfaceFramework || !sOpenGLFramework || !sCoreGraphicsFramework) { |
|
158 if (sIOSurfaceFramework) |
|
159 dlclose(sIOSurfaceFramework); |
|
160 if (sOpenGLFramework) |
|
161 dlclose(sOpenGLFramework); |
|
162 if (sCoreGraphicsFramework) |
|
163 dlclose(sCoreGraphicsFramework); |
|
164 sIOSurfaceFramework = nullptr; |
|
165 sOpenGLFramework = nullptr; |
|
166 sCoreGraphicsFramework = nullptr; |
|
167 return; |
|
168 } |
|
169 |
|
170 kPropWidth = GetIOConst("kIOSurfaceWidth"); |
|
171 kPropHeight = GetIOConst("kIOSurfaceHeight"); |
|
172 kPropBytesPerElem = GetIOConst("kIOSurfaceBytesPerElement"); |
|
173 kPropBytesPerRow = GetIOConst("kIOSurfaceBytesPerRow"); |
|
174 kPropIsGlobal = GetIOConst("kIOSurfaceIsGlobal"); |
|
175 sCreate = GET_IOSYM(sCreate, "IOSurfaceCreate"); |
|
176 sGetID = GET_IOSYM(sGetID, "IOSurfaceGetID"); |
|
177 sWidth = GET_IOSYM(sWidth, "IOSurfaceGetWidth"); |
|
178 sHeight = GET_IOSYM(sHeight, "IOSurfaceGetHeight"); |
|
179 sBytesPerRow = GET_IOSYM(sBytesPerRow, "IOSurfaceGetBytesPerRow"); |
|
180 sLookup = GET_IOSYM(sLookup, "IOSurfaceLookup"); |
|
181 sLock = GET_IOSYM(sLock, "IOSurfaceLock"); |
|
182 sUnlock = GET_IOSYM(sUnlock, "IOSurfaceUnlock"); |
|
183 sGetBaseAddress = GET_IOSYM(sGetBaseAddress, "IOSurfaceGetBaseAddress"); |
|
184 sTexImage = GET_CGLSYM(sTexImage, "CGLTexImageIOSurface2D"); |
|
185 sCGContextGetTypePtr = (unsigned int (*)(CGContext*))dlsym(RTLD_DEFAULT, "CGContextGetType"); |
|
186 |
|
187 // Optional symbols |
|
188 sIOSurfaceContextCreate = GET_CGSYM(sIOSurfaceContextCreate, "CGIOSurfaceContextCreate"); |
|
189 sIOSurfaceContextCreateImage = GET_CGSYM(sIOSurfaceContextCreateImage, "CGIOSurfaceContextCreateImage"); |
|
190 sIOSurfaceContextGetSurface = GET_CGSYM(sIOSurfaceContextGetSurface, "CGIOSurfaceContextGetSurface"); |
|
191 |
|
192 if (!sCreate || !sGetID || !sLookup || !sTexImage || !sGetBaseAddress || |
|
193 !kPropWidth || !kPropHeight || !kPropBytesPerElem || !kPropIsGlobal || |
|
194 !sLock || !sUnlock || !sWidth || !sHeight || !kPropBytesPerRow || |
|
195 !sBytesPerRow) { |
|
196 CloseLibrary(); |
|
197 } |
|
198 } |
|
199 |
|
200 void MacIOSurfaceLib::CloseLibrary() { |
|
201 if (sIOSurfaceFramework) { |
|
202 dlclose(sIOSurfaceFramework); |
|
203 } |
|
204 if (sOpenGLFramework) { |
|
205 dlclose(sOpenGLFramework); |
|
206 } |
|
207 sIOSurfaceFramework = nullptr; |
|
208 sOpenGLFramework = nullptr; |
|
209 } |
|
210 |
|
211 MacIOSurface::~MacIOSurface() { |
|
212 CFRelease(mIOSurfacePtr); |
|
213 } |
|
214 |
|
215 TemporaryRef<MacIOSurface> MacIOSurface::CreateIOSurface(int aWidth, int aHeight, |
|
216 double aContentsScaleFactor, |
|
217 bool aHasAlpha) { |
|
218 if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) |
|
219 return nullptr; |
|
220 |
|
221 CFMutableDictionaryRef props = ::CFDictionaryCreateMutable( |
|
222 kCFAllocatorDefault, 4, |
|
223 &kCFTypeDictionaryKeyCallBacks, |
|
224 &kCFTypeDictionaryValueCallBacks); |
|
225 if (!props) |
|
226 return nullptr; |
|
227 |
|
228 int32_t bytesPerElem = 4; |
|
229 size_t intScaleFactor = ceil(aContentsScaleFactor); |
|
230 aWidth *= intScaleFactor; |
|
231 aHeight *= intScaleFactor; |
|
232 CFNumberRef cfWidth = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aWidth); |
|
233 CFNumberRef cfHeight = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aHeight); |
|
234 CFNumberRef cfBytesPerElem = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &bytesPerElem); |
|
235 ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropWidth, |
|
236 cfWidth); |
|
237 ::CFRelease(cfWidth); |
|
238 ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropHeight, |
|
239 cfHeight); |
|
240 ::CFRelease(cfHeight); |
|
241 ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropBytesPerElem, |
|
242 cfBytesPerElem); |
|
243 ::CFRelease(cfBytesPerElem); |
|
244 ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropIsGlobal, |
|
245 kCFBooleanTrue); |
|
246 |
|
247 IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceCreate(props); |
|
248 ::CFRelease(props); |
|
249 |
|
250 if (!surfaceRef) |
|
251 return nullptr; |
|
252 |
|
253 RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); |
|
254 if (!ioSurface) { |
|
255 ::CFRelease(surfaceRef); |
|
256 return nullptr; |
|
257 } |
|
258 |
|
259 return ioSurface.forget(); |
|
260 } |
|
261 |
|
262 TemporaryRef<MacIOSurface> MacIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID, |
|
263 double aContentsScaleFactor, |
|
264 bool aHasAlpha) { |
|
265 if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) |
|
266 return nullptr; |
|
267 |
|
268 IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceLookup(aIOSurfaceID); |
|
269 if (!surfaceRef) |
|
270 return nullptr; |
|
271 |
|
272 RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); |
|
273 if (!ioSurface) { |
|
274 ::CFRelease(surfaceRef); |
|
275 return nullptr; |
|
276 } |
|
277 return ioSurface.forget(); |
|
278 } |
|
279 |
|
280 IOSurfaceID MacIOSurface::GetIOSurfaceID() { |
|
281 return MacIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr); |
|
282 } |
|
283 |
|
284 void* MacIOSurface::GetBaseAddress() { |
|
285 return MacIOSurfaceLib::IOSurfaceGetBaseAddress(mIOSurfacePtr); |
|
286 } |
|
287 |
|
288 size_t MacIOSurface::GetWidth() { |
|
289 size_t intScaleFactor = ceil(mContentsScaleFactor); |
|
290 return GetDevicePixelWidth() / intScaleFactor; |
|
291 } |
|
292 |
|
293 size_t MacIOSurface::GetHeight() { |
|
294 size_t intScaleFactor = ceil(mContentsScaleFactor); |
|
295 return GetDevicePixelHeight() / intScaleFactor; |
|
296 } |
|
297 |
|
298 size_t MacIOSurface::GetDevicePixelWidth() { |
|
299 return MacIOSurfaceLib::IOSurfaceGetWidth(mIOSurfacePtr); |
|
300 } |
|
301 |
|
302 size_t MacIOSurface::GetDevicePixelHeight() { |
|
303 return MacIOSurfaceLib::IOSurfaceGetHeight(mIOSurfacePtr); |
|
304 } |
|
305 |
|
306 size_t MacIOSurface::GetBytesPerRow() { |
|
307 return MacIOSurfaceLib::IOSurfaceGetBytesPerRow(mIOSurfacePtr); |
|
308 } |
|
309 |
|
310 #define READ_ONLY 0x1 |
|
311 void MacIOSurface::Lock() { |
|
312 MacIOSurfaceLib::IOSurfaceLock(mIOSurfacePtr, READ_ONLY, nullptr); |
|
313 } |
|
314 |
|
315 void MacIOSurface::Unlock() { |
|
316 MacIOSurfaceLib::IOSurfaceUnlock(mIOSurfacePtr, READ_ONLY, nullptr); |
|
317 } |
|
318 |
|
319 #include "SourceSurfaceRawData.h" |
|
320 using mozilla::gfx::SourceSurface; |
|
321 using mozilla::gfx::SourceSurfaceRawData; |
|
322 using mozilla::gfx::IntSize; |
|
323 using mozilla::gfx::SurfaceFormat; |
|
324 |
|
325 TemporaryRef<SourceSurface> |
|
326 MacIOSurface::GetAsSurface() { |
|
327 Lock(); |
|
328 size_t bytesPerRow = GetBytesPerRow(); |
|
329 size_t ioWidth = GetDevicePixelWidth(); |
|
330 size_t ioHeight = GetDevicePixelHeight(); |
|
331 |
|
332 unsigned char* ioData = (unsigned char*)GetBaseAddress(); |
|
333 unsigned char* dataCpy = (unsigned char*)malloc(bytesPerRow*ioHeight); |
|
334 for (size_t i = 0; i < ioHeight; i++) { |
|
335 memcpy(dataCpy + i * bytesPerRow, |
|
336 ioData + i * bytesPerRow, ioWidth * 4); |
|
337 } |
|
338 |
|
339 Unlock(); |
|
340 |
|
341 SurfaceFormat format = HasAlpha() ? mozilla::gfx::SurfaceFormat::B8G8R8A8 : |
|
342 mozilla::gfx::SurfaceFormat::B8G8R8X8; |
|
343 |
|
344 RefPtr<SourceSurfaceRawData> surf = new SourceSurfaceRawData(); |
|
345 surf->InitWrappingData(dataCpy, IntSize(ioWidth, ioHeight), bytesPerRow, format, true); |
|
346 |
|
347 return surf.forget(); |
|
348 } |
|
349 |
|
350 CGLError |
|
351 MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx) |
|
352 { |
|
353 return MacIOSurfaceLib::CGLTexImageIOSurface2D(ctx, |
|
354 GL_TEXTURE_RECTANGLE_ARB, |
|
355 HasAlpha() ? GL_RGBA : GL_RGB, |
|
356 GetDevicePixelWidth(), |
|
357 GetDevicePixelHeight(), |
|
358 GL_BGRA, |
|
359 GL_UNSIGNED_INT_8_8_8_8_REV, |
|
360 mIOSurfacePtr, 0); |
|
361 } |
|
362 |
|
363 static |
|
364 CGColorSpaceRef CreateSystemColorSpace() { |
|
365 CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID()); |
|
366 if (!cspace) { |
|
367 cspace = ::CGColorSpaceCreateDeviceRGB(); |
|
368 } |
|
369 return cspace; |
|
370 } |
|
371 |
|
372 CGContextRef MacIOSurface::CreateIOSurfaceContext() { |
|
373 CGColorSpaceRef cspace = CreateSystemColorSpace(); |
|
374 CGContextRef ref = MacIOSurfaceLib::IOSurfaceContextCreate(mIOSurfacePtr, |
|
375 GetDevicePixelWidth(), |
|
376 GetDevicePixelHeight(), |
|
377 8, 32, cspace, 0x2002); |
|
378 ::CGColorSpaceRelease(cspace); |
|
379 return ref; |
|
380 } |
|
381 |
|
382 CGImageRef MacIOSurface::CreateImageFromIOSurfaceContext(CGContextRef aContext) { |
|
383 if (!MacIOSurfaceLib::isInit()) |
|
384 return nullptr; |
|
385 |
|
386 return MacIOSurfaceLib::IOSurfaceContextCreateImage(aContext); |
|
387 } |
|
388 |
|
389 TemporaryRef<MacIOSurface> MacIOSurface::IOSurfaceContextGetSurface(CGContextRef aContext, |
|
390 double aContentsScaleFactor, |
|
391 bool aHasAlpha) { |
|
392 if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) |
|
393 return nullptr; |
|
394 |
|
395 IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceContextGetSurface(aContext); |
|
396 if (!surfaceRef) |
|
397 return nullptr; |
|
398 |
|
399 // Retain the IOSurface because MacIOSurface will release it |
|
400 CFRetain(surfaceRef); |
|
401 |
|
402 RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); |
|
403 if (!ioSurface) { |
|
404 ::CFRelease(surfaceRef); |
|
405 return nullptr; |
|
406 } |
|
407 return ioSurface.forget(); |
|
408 } |
|
409 |
|
410 |
|
411 CGContextType GetContextType(CGContextRef ref) |
|
412 { |
|
413 if (!MacIOSurfaceLib::isInit() || !MacIOSurfaceLib::sCGContextGetTypePtr) |
|
414 return CG_CONTEXT_TYPE_UNKNOWN; |
|
415 |
|
416 unsigned int type = MacIOSurfaceLib::sCGContextGetTypePtr(ref); |
|
417 if (type == CG_CONTEXT_TYPE_BITMAP) { |
|
418 return CG_CONTEXT_TYPE_BITMAP; |
|
419 } else if (type == CG_CONTEXT_TYPE_IOSURFACE) { |
|
420 return CG_CONTEXT_TYPE_IOSURFACE; |
|
421 } else { |
|
422 return CG_CONTEXT_TYPE_UNKNOWN; |
|
423 } |
|
424 } |
|
425 |
|
426 |