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