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