a849d26ffac7acd2d02d78dd60e8467ef569e868
[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 "MachSendRight.h"
34 #import <IOSurface/IOSurface.h>
35 #import <wtf/Assertions.h>
36
37 #if __has_include(<IOSurface/IOSurfacePrivate.h>)
38 #import <IOSurface/IOSurfacePrivate.h>
39 #else
40 enum {
41     kIOSurfacePurgeableNonVolatile = 0,
42     kIOSurfacePurgeableVolatile = 1,
43     kIOSurfacePurgeableEmpty = 2,
44     kIOSurfacePurgeableKeepCurrent = 3,
45 };
46 #endif
47
48 extern "C" {
49 CGContextRef CGIOSurfaceContextCreate(IOSurfaceRef, size_t, size_t, size_t, size_t, CGColorSpaceRef, CGBitmapInfo);
50 CGImageRef CGIOSurfaceContextCreateImage(CGContextRef);
51 IOReturn IOSurfaceSetPurgeable(IOSurfaceRef, uint32_t, uint32_t *);
52 }
53
54 using namespace WebCore;
55
56 PassRefPtr<IOSurface> IOSurface::create(IntSize size, ColorSpace colorSpace)
57 {
58     if (RefPtr<IOSurface> cachedSurface = IOSurfacePool::sharedPool().takeSurface(size, colorSpace))
59         return cachedSurface.release();
60     return adoptRef(new IOSurface(size, colorSpace));
61 }
62
63 PassRefPtr<IOSurface> IOSurface::createFromSendRight(const MachSendRight& sendRight, ColorSpace colorSpace)
64 {
65     RetainPtr<IOSurfaceRef> surface = adoptCF(IOSurfaceLookupFromMachPort(sendRight.sendRight()));
66     return IOSurface::createFromSurface(surface.get(), colorSpace);
67 }
68
69 PassRefPtr<IOSurface> IOSurface::createFromSurface(IOSurfaceRef surface, ColorSpace colorSpace)
70 {
71     return adoptRef(new IOSurface(surface, colorSpace));
72 }
73
74 PassRefPtr<IOSurface> IOSurface::createFromImage(CGImageRef image)
75 {
76     if (!image)
77         return nullptr;
78
79     size_t width = CGImageGetWidth(image);
80     size_t height = CGImageGetHeight(image);
81
82     RefPtr<IOSurface> surface = IOSurface::create(IntSize(width, height), ColorSpaceDeviceRGB);
83     auto surfaceContext = surface->ensurePlatformContext();
84     CGContextDrawImage(surfaceContext, CGRectMake(0, 0, width, height), image);
85     CGContextFlush(surfaceContext);
86
87     return surface.release();
88 }
89
90 IOSurface::IOSurface(IntSize size, ColorSpace colorSpace)
91     : m_colorSpace(colorSpace)
92     , m_size(size)
93 {
94     unsigned pixelFormat = 'BGRA';
95     unsigned bytesPerElement = 4;
96     int width = size.width();
97     int height = size.height();
98
99     size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerElement);
100     ASSERT(bytesPerRow);
101
102     m_totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * bytesPerRow);
103     ASSERT(m_totalBytes);
104
105     NSDictionary *options = @{
106         (id)kIOSurfaceWidth: @(width),
107         (id)kIOSurfaceHeight: @(height),
108         (id)kIOSurfacePixelFormat: @(pixelFormat),
109         (id)kIOSurfaceBytesPerElement: @(bytesPerElement),
110         (id)kIOSurfaceBytesPerRow: @(bytesPerRow),
111         (id)kIOSurfaceAllocSize: @(m_totalBytes),
112 #if PLATFORM(IOS)
113         (id)kIOSurfaceCacheMode: @(kIOMapWriteCombineCache)
114 #endif
115     };
116
117     m_surface = adoptCF(IOSurfaceCreate((CFDictionaryRef)options));
118 }
119
120 IOSurface::IOSurface(IOSurfaceRef surface, ColorSpace colorSpace)
121     : m_colorSpace(colorSpace)
122     , m_surface(surface)
123 {
124     m_size = IntSize(IOSurfaceGetWidth(surface), IOSurfaceGetHeight(surface));
125     m_totalBytes = IOSurfaceGetAllocSize(surface);
126 }
127
128 IntSize IOSurface::maximumSize()
129 {
130     return IntSize(IOSurfaceGetPropertyMaximum(kIOSurfaceWidth), IOSurfaceGetPropertyMaximum(kIOSurfaceHeight));
131 }
132
133 MachSendRight IOSurface::createSendRight() const
134 {
135     return MachSendRight::adopt(IOSurfaceCreateMachPort(m_surface.get()));
136 }
137
138 RetainPtr<CGImageRef> IOSurface::createImage()
139 {
140     return adoptCF(CGIOSurfaceContextCreateImage(ensurePlatformContext()));
141 }
142
143 CGContextRef IOSurface::ensurePlatformContext()
144 {
145     if (m_cgContext)
146         return m_cgContext.get();
147
148     CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
149     size_t bitsPerComponent = 8;
150     size_t bitsPerPixel = 32;
151     m_cgContext = adoptCF(CGIOSurfaceContextCreate(m_surface.get(), m_size.width(), m_size.height(), bitsPerComponent, bitsPerPixel, cachedCGColorSpace(m_colorSpace), bitmapInfo));
152
153     return m_cgContext.get();
154 }
155
156 GraphicsContext& IOSurface::ensureGraphicsContext()
157 {
158     if (m_graphicsContext)
159         return *m_graphicsContext;
160
161     m_graphicsContext = adoptPtr(new GraphicsContext(ensurePlatformContext()));
162
163     return *m_graphicsContext;
164 }
165
166 IOSurface::SurfaceState IOSurface::state() const
167 {
168 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
169     uint32_t previousState = 0;
170     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), kIOSurfacePurgeableKeepCurrent, &previousState);
171     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
172     return previousState == kIOSurfacePurgeableEmpty ? IOSurface::SurfaceState::Empty : IOSurface::SurfaceState::Valid;
173 #else
174     return SurfaceState::Valid;
175 #endif
176 }
177
178 bool IOSurface::isVolatile() const
179 {
180 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
181     uint32_t previousState = 0;
182     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), kIOSurfacePurgeableKeepCurrent, &previousState);
183     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
184     return previousState != kIOSurfacePurgeableNonVolatile;
185 #else
186     return false;
187 #endif
188 }
189
190 IOSurface::SurfaceState IOSurface::setIsVolatile(bool isVolatile)
191 {
192 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
193     uint32_t previousState = 0;
194     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), isVolatile ? kIOSurfacePurgeableVolatile : kIOSurfacePurgeableNonVolatile, &previousState);
195     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
196
197     if (previousState == kIOSurfacePurgeableEmpty)
198         return IOSurface::SurfaceState::Empty;
199 #else
200     UNUSED_PARAM(isVolatile);
201 #endif
202
203     return IOSurface::SurfaceState::Valid;
204 }
205
206 bool IOSurface::isInUse() const
207 {
208     return IOSurfaceIsInUse(m_surface.get());
209 }
210
211 void IOSurface::releaseGraphicsContext()
212 {
213     m_graphicsContext = nullptr;
214     m_cgContext = nullptr;
215 }
216
217 #endif // USE(IOSURFACE)