Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / platform / graphics / cocoa / IOSurface.mm
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "IOSurface.h"
28
29 #if USE(IOSURFACE)
30
31 #import "GraphicsContextCG.h"
32 #import "IOSurfacePool.h"
33 #import "IOSurfaceSPI.h"
34 #import "ImageBuffer.h"
35 #import "ImageBufferDataCG.h"
36 #import "MachSendRight.h"
37 #import <wtf/Assertions.h>
38
39 extern "C" {
40 CGContextRef CGIOSurfaceContextCreate(IOSurfaceRef, size_t, size_t, size_t, size_t, CGColorSpaceRef, CGBitmapInfo);
41 CGImageRef CGIOSurfaceContextCreateImage(CGContextRef);
42 CGImageRef CGIOSurfaceContextCreateImageReference(CGContextRef);
43 }
44
45 using namespace WebCore;
46
47 inline std::unique_ptr<IOSurface> IOSurface::surfaceFromPool(IntSize size, IntSize contextSize, ColorSpace colorSpace, Format pixelFormat)
48 {
49     auto cachedSurface = IOSurfacePool::sharedPool().takeSurface(size, colorSpace, pixelFormat);
50     if (!cachedSurface)
51         return nullptr;
52
53     cachedSurface->setContextSize(contextSize);
54     return cachedSurface;
55 }
56
57 std::unique_ptr<IOSurface> IOSurface::create(IntSize size, ColorSpace colorSpace, Format pixelFormat)
58 {
59     if (auto cachedSurface = surfaceFromPool(size, size, colorSpace, pixelFormat))
60         return cachedSurface;
61
62     return std::unique_ptr<IOSurface>(new IOSurface(size, colorSpace, pixelFormat));
63 }
64
65 std::unique_ptr<IOSurface> IOSurface::create(IntSize size, IntSize contextSize, ColorSpace colorSpace, Format pixelFormat)
66 {
67     if (auto cachedSurface = surfaceFromPool(size, contextSize, colorSpace, pixelFormat))
68         return cachedSurface;
69     return std::unique_ptr<IOSurface>(new IOSurface(size, contextSize, colorSpace, pixelFormat));
70 }
71
72 std::unique_ptr<IOSurface> IOSurface::createFromSendRight(const MachSendRight& sendRight, ColorSpace colorSpace)
73 {
74     auto surface = adoptCF(IOSurfaceLookupFromMachPort(sendRight.sendRight()));
75     return IOSurface::createFromSurface(surface.get(), colorSpace);
76 }
77
78 std::unique_ptr<IOSurface> IOSurface::createFromSurface(IOSurfaceRef surface, ColorSpace colorSpace)
79 {
80     return std::unique_ptr<IOSurface>(new IOSurface(surface, colorSpace));
81 }
82
83 std::unique_ptr<IOSurface> IOSurface::createFromImage(CGImageRef image)
84 {
85     if (!image)
86         return nullptr;
87
88     size_t width = CGImageGetWidth(image);
89     size_t height = CGImageGetHeight(image);
90
91     auto surface = IOSurface::create(IntSize(width, height), ColorSpaceSRGB);
92     auto surfaceContext = surface->ensurePlatformContext();
93     CGContextDrawImage(surfaceContext, CGRectMake(0, 0, width, height), image);
94     CGContextFlush(surfaceContext);
95
96     return surface;
97 }
98
99 void IOSurface::moveToPool(std::unique_ptr<IOSurface>&& surface)
100 {
101     IOSurfacePool::sharedPool().addSurface(WTFMove(surface));
102 }
103
104 std::unique_ptr<IOSurface> IOSurface::createFromImageBuffer(std::unique_ptr<ImageBuffer> imageBuffer)
105 {
106     return WTFMove(imageBuffer->m_data.surface);
107 }
108
109 IOSurface::IOSurface(IntSize size, ColorSpace colorSpace, Format format)
110     : m_colorSpace(colorSpace)
111     , m_size(size)
112     , m_contextSize(size)
113 {
114     unsigned pixelFormat;
115     unsigned bytesPerPixel;
116     unsigned bytesPerElement;
117
118     int width = size.width();
119     int height = size.height();
120
121     NSDictionary *options;
122     
123     if (format == Format::RGB10A8) {
124         pixelFormat = 'b3a8';
125         
126         // RGB plane (10-10-10)
127         bytesPerPixel = 4;
128         bytesPerElement = 4;
129
130         size_t rgbPlaneBytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerElement);
131         size_t rgbPlaneTotalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * rgbPlaneBytesPerRow);
132
133         // Alpha plane (8)
134         bytesPerElement = 1;
135         size_t alphaPlaneBytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerElement);
136         size_t alphaPlaneTotalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * alphaPlaneBytesPerRow);
137         
138         m_totalBytes = rgbPlaneTotalBytes + alphaPlaneTotalBytes;
139
140         NSArray *planeInfo = @[
141             @{
142                 (id)kIOSurfacePlaneWidth: @(width),
143                 (id)kIOSurfacePlaneHeight: @(height),
144                 (id)kIOSurfacePlaneBytesPerRow: @(rgbPlaneBytesPerRow),
145                 (id)kIOSurfacePlaneOffset: @(0),
146                 (id)kIOSurfacePlaneSize: @(rgbPlaneTotalBytes)
147             },
148             @{
149                 (id)kIOSurfacePlaneWidth: @(width),
150                 (id)kIOSurfacePlaneHeight: @(height),
151                 (id)kIOSurfacePlaneBytesPerRow: @(alphaPlaneBytesPerRow),
152                 (id)kIOSurfacePlaneOffset: @(rgbPlaneTotalBytes),
153                 (id)kIOSurfacePlaneSize: @(alphaPlaneTotalBytes)
154             }
155         ];
156
157         options = @{
158             (id)kIOSurfaceWidth: @(width),
159             (id)kIOSurfaceHeight: @(height),
160             (id)kIOSurfacePixelFormat: @(pixelFormat),
161             (id)kIOSurfaceAllocSize: @(m_totalBytes),
162 #if PLATFORM(IOS)
163             (id)kIOSurfaceCacheMode: @(kIOMapWriteCombineCache),
164 #endif
165             (id)kIOSurfacePlaneInfo: planeInfo,
166         };
167     } else {
168         unsigned elementWidth;
169
170         switch (format) {
171         case Format::RGBA:
172             pixelFormat = 'BGRA';
173             bytesPerPixel = 4;
174             bytesPerElement = 4;
175             elementWidth = 1;
176             break;
177         case Format::YUV422:
178             pixelFormat = 'yuvf';
179             bytesPerPixel = 2;
180             bytesPerElement = 4;
181             elementWidth = 2;
182             break;
183         case Format::RGB10:
184             pixelFormat = 'w30r';
185             bytesPerPixel = 4;
186             bytesPerElement = 4;
187             elementWidth = 1;
188             break;
189         case Format::RGB10A8:
190             ASSERT_NOT_REACHED();
191             pixelFormat = 'b3a8';
192             bytesPerPixel = 1;
193             bytesPerElement = 1;
194             elementWidth = 1;
195             break;
196         }
197
198         size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerPixel);
199         ASSERT(bytesPerRow);
200
201         m_totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * bytesPerRow);
202         ASSERT(m_totalBytes);
203
204         options = @{
205             (id)kIOSurfaceWidth: @(width),
206             (id)kIOSurfaceHeight: @(height),
207             (id)kIOSurfacePixelFormat: @(pixelFormat),
208             (id)kIOSurfaceBytesPerElement: @(bytesPerElement),
209             (id)kIOSurfaceBytesPerRow: @(bytesPerRow),
210             (id)kIOSurfaceAllocSize: @(m_totalBytes),
211 #if PLATFORM(IOS)
212             (id)kIOSurfaceCacheMode: @(kIOMapWriteCombineCache),
213 #endif
214             (id)kIOSurfaceElementWidth: @(elementWidth),
215             (id)kIOSurfaceElementHeight: @(1)
216         };
217     }
218     
219     m_surface = adoptCF(IOSurfaceCreate((CFDictionaryRef)options));
220     if (!m_surface)
221         NSLog(@"Surface creation failed for options %@", options);
222 }
223
224 IOSurface::IOSurface(IntSize size, IntSize contextSize, ColorSpace colorSpace, Format pixelFormat)
225     : IOSurface(size, colorSpace, pixelFormat)
226 {
227     ASSERT(contextSize.width() <= size.width());
228     ASSERT(contextSize.height() <= size.height());
229     m_contextSize = contextSize;
230 }
231
232 IOSurface::IOSurface(IOSurfaceRef surface, ColorSpace colorSpace)
233     : m_colorSpace(colorSpace)
234     , m_surface(surface)
235 {
236     m_size = IntSize(IOSurfaceGetWidth(surface), IOSurfaceGetHeight(surface));
237     m_totalBytes = IOSurfaceGetAllocSize(surface);
238 }
239
240 IntSize IOSurface::maximumSize()
241 {
242     return IntSize(IOSurfaceGetPropertyMaximum(kIOSurfaceWidth), IOSurfaceGetPropertyMaximum(kIOSurfaceHeight));
243 }
244
245 MachSendRight IOSurface::createSendRight() const
246 {
247     return MachSendRight::adopt(IOSurfaceCreateMachPort(m_surface.get()));
248 }
249
250 RetainPtr<CGImageRef> IOSurface::createImage()
251 {
252     return adoptCF(CGIOSurfaceContextCreateImage(ensurePlatformContext()));
253 }
254
255 RetainPtr<CGImageRef> IOSurface::sinkIntoImage(std::unique_ptr<IOSurface> surface)
256 {
257 #if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
258     return adoptCF(CGIOSurfaceContextCreateImageReference(surface->ensurePlatformContext()));
259 #else
260     return surface->createImage();
261 #endif
262 }
263
264 void IOSurface::setContextSize(IntSize contextSize)
265 {
266     if (contextSize == m_contextSize)
267         return;
268
269     // Release the graphics context and update the context size. Next time the graphics context is
270     // accessed, we will construct it again with the right size.
271     releaseGraphicsContext();
272     m_contextSize = contextSize;
273 }
274
275 CGContextRef IOSurface::ensurePlatformContext()
276 {
277     if (m_cgContext)
278         return m_cgContext.get();
279
280     CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
281
282     size_t bitsPerComponent = 8;
283     size_t bitsPerPixel = 32;
284     
285     switch (format()) {
286     case Format::RGBA:
287         break;
288     case Format::RGB10:
289         bitsPerComponent = 10;
290         bitsPerPixel = 32;
291         break;
292     case Format::RGB10A8:
293         // FIXME: This doesn't take the two-plane format into account.
294         bitsPerComponent = 10;
295         bitsPerPixel = 32;
296         break;
297     case Format::YUV422:
298         ASSERT_NOT_REACHED();
299         break;
300     }
301     
302     m_cgContext = adoptCF(CGIOSurfaceContextCreate(m_surface.get(), m_contextSize.width(), m_contextSize.height(), bitsPerComponent, bitsPerPixel, cachedCGColorSpace(m_colorSpace), bitmapInfo));
303
304     return m_cgContext.get();
305 }
306
307 GraphicsContext& IOSurface::ensureGraphicsContext()
308 {
309     if (m_graphicsContext)
310         return *m_graphicsContext;
311
312     m_graphicsContext = std::make_unique<GraphicsContext>(ensurePlatformContext());
313     m_graphicsContext->setIsAcceleratedContext(true);
314
315     return *m_graphicsContext;
316 }
317
318 IOSurface::SurfaceState IOSurface::state() const
319 {
320     uint32_t previousState = 0;
321     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), kIOSurfacePurgeableKeepCurrent, &previousState);
322     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
323     return previousState == kIOSurfacePurgeableEmpty ? IOSurface::SurfaceState::Empty : IOSurface::SurfaceState::Valid;
324 }
325
326 bool IOSurface::isVolatile() const
327 {
328     uint32_t previousState = 0;
329     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), kIOSurfacePurgeableKeepCurrent, &previousState);
330     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
331     return previousState != kIOSurfacePurgeableNonVolatile;
332 }
333
334 IOSurface::SurfaceState IOSurface::setIsVolatile(bool isVolatile)
335 {
336     uint32_t previousState = 0;
337     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), isVolatile ? kIOSurfacePurgeableVolatile : kIOSurfacePurgeableNonVolatile, &previousState);
338     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
339
340     if (previousState == kIOSurfacePurgeableEmpty)
341         return IOSurface::SurfaceState::Empty;
342
343     return IOSurface::SurfaceState::Valid;
344 }
345
346 IOSurface::Format IOSurface::format() const
347 {
348     unsigned pixelFormat = IOSurfaceGetPixelFormat(m_surface.get());
349     if (pixelFormat == 'BGRA')
350         return Format::RGBA;
351
352     if (pixelFormat == 'w30r')
353         return Format::RGB10;
354
355     if (pixelFormat == 'b3a8')
356         return Format::RGB10A8;
357
358     if (pixelFormat == 'yuvf')
359         return Format::YUV422;
360
361     ASSERT_NOT_REACHED();
362     return Format::RGBA;
363 }
364
365 bool IOSurface::isInUse() const
366 {
367     return IOSurfaceIsInUse(m_surface.get());
368 }
369
370 void IOSurface::releaseGraphicsContext()
371 {
372     m_graphicsContext = nullptr;
373     m_cgContext = nullptr;
374 }
375
376 #if PLATFORM(IOS)
377 WEBCORE_EXPORT void IOSurface::copyToSurface(IOSurface& destSurface)
378 {
379     if (destSurface.format() != format()) {
380         WTFLogAlways("Trying to copy IOSurface to another surface with a different format");
381         return;
382     }
383
384     if (destSurface.size() != size()) {
385         WTFLogAlways("Trying to copy IOSurface to another surface with a different size");
386         return;
387     }
388
389     static IOSurfaceAcceleratorRef accelerator;
390     if (!accelerator)
391         IOSurfaceAcceleratorCreate(nullptr, nullptr, &accelerator);
392
393     IOReturn ret = IOSurfaceAcceleratorTransformSurface(accelerator, m_surface.get(), destSurface.surface(), nullptr, nullptr, nullptr, nullptr, nullptr);
394     if (ret)
395         WTFLogAlways("IOSurfaceAcceleratorTransformSurface %p to %p failed with error %d", m_surface.get(), destSurface.surface(), ret);
396 }
397
398 void IOSurface::convertToFormat(std::unique_ptr<WebCore::IOSurface>&& inSurface, Format format, std::function<void(std::unique_ptr<WebCore::IOSurface>)> callback)
399 {
400     static IOSurfaceAcceleratorRef accelerator;
401     if (!accelerator) {
402         IOSurfaceAcceleratorCreate(nullptr, nullptr, &accelerator);
403
404         auto runLoopSource = IOSurfaceAcceleratorGetRunLoopSource(accelerator);
405         CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopDefaultMode);
406     }
407
408     if (inSurface->format() == format) {
409         callback(WTFMove(inSurface));
410         return;
411     }
412
413     auto destinationSurface = IOSurface::create(inSurface->size(), inSurface->colorSpace(), format);
414     IOSurfaceRef destinationIOSurfaceRef = destinationSurface->surface();
415
416     IOSurfaceAcceleratorCompletion completion;
417     completion.completionRefCon = new std::function<void(std::unique_ptr<IOSurface>)> (WTFMove(callback));
418     completion.completionRefCon2 = destinationSurface.release();
419     completion.completionCallback = [](void *completionRefCon, IOReturn, void * completionRefCon2) {
420         auto* callback = static_cast<std::function<void(std::unique_ptr<WebCore::IOSurface>)>*>(completionRefCon);
421         auto destinationSurface = std::unique_ptr<IOSurface>(static_cast<IOSurface*>(completionRefCon2));
422         
423         (*callback)(WTFMove(destinationSurface));
424         delete callback;
425     };
426
427     IOReturn ret = IOSurfaceAcceleratorTransformSurface(accelerator, inSurface->surface(), destinationIOSurfaceRef, nullptr, nullptr, &completion, nullptr, nullptr);
428     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
429 }
430 #endif // PLATFORM(IOS)
431
432 #endif // USE(IOSURFACE)