1 /*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkSurface_Gpu.h"
9
10 #include "GrBackendSurface.h"
11 #include "GrContextPriv.h"
12 #include "GrRenderTargetContextPriv.h"
13 #include "GrTexture.h"
14
15 #include "SkCanvas.h"
16 #include "SkColorSpace_Base.h"
17 #include "SkGpuDevice.h"
18 #include "SkImage_Base.h"
19 #include "SkImage_Gpu.h"
20 #include "SkImagePriv.h"
21 #include "SkSurface_Base.h"
22
23 #if SK_SUPPORT_GPU
24
SkSurface_Gpu(sk_sp<SkGpuDevice> device)25 SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
26 : INHERITED(device->width(), device->height(), &device->surfaceProps())
27 , fDevice(std::move(device)) {
28 SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
29 }
30
~SkSurface_Gpu()31 SkSurface_Gpu::~SkSurface_Gpu() {
32 }
33
prepare_rt_for_external_access(SkSurface_Gpu * surface,SkSurface::BackendHandleAccess access)34 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
35 SkSurface::BackendHandleAccess access) {
36 switch (access) {
37 case SkSurface::kFlushRead_BackendHandleAccess:
38 break;
39 case SkSurface::kFlushWrite_BackendHandleAccess:
40 case SkSurface::kDiscardWrite_BackendHandleAccess:
41 // for now we don't special-case on Discard, but we may in the future.
42 surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
43 break;
44 }
45
46 // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
47 surface->getDevice()->flush();
48 GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
49 return rtc->accessRenderTarget();
50 }
51
onGetTextureHandle(BackendHandleAccess access)52 GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) {
53 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
54 if (!rt) {
55 return 0;
56 }
57 GrTexture* texture = rt->asTexture();
58 if (texture) {
59 return texture->getTextureHandle();
60 }
61 return 0;
62 }
63
onGetRenderTargetHandle(GrBackendObject * obj,BackendHandleAccess access)64 bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
65 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
66 if (!rt) {
67 return false;
68 }
69 *obj = rt->getRenderTargetHandle();
70 return true;
71 }
72
onNewCanvas()73 SkCanvas* SkSurface_Gpu::onNewCanvas() {
74 SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
75 flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag);
76
77 return new SkCanvas(fDevice.get(), flags);
78 }
79
onNewSurface(const SkImageInfo & info)80 sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
81 int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples();
82 GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
83 // TODO: Make caller specify this (change virtual signature of onNewSurface).
84 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
85 return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
86 origin, &this->props());
87 }
88
onNewImageSnapshot()89 sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot() {
90 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
91 if (!rtc) {
92 return nullptr;
93 }
94
95 GrContext* ctx = fDevice->context();
96
97 if (!rtc->asSurfaceProxy()) {
98 return nullptr;
99 }
100
101 SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
102
103 sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
104 // If the original render target is a buffer originally created by the client, then we don't
105 // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
106 // copy-on-write.
107 if (!srcProxy || rtc->priv().refsWrappedObjects()) {
108 SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
109
110 srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), budgeted);
111 }
112
113 const SkImageInfo info = fDevice->imageInfo();
114 sk_sp<SkImage> image;
115 if (srcProxy) {
116 // The renderTargetContext coming out of SkGpuDevice should always be exact and the
117 // above copy creates a kExact surfaceContext.
118 SkASSERT(srcProxy->priv().isExact());
119 image = sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
120 info.alphaType(), std::move(srcProxy),
121 info.refColorSpace(), budgeted);
122 }
123 return image;
124 }
125
126 // Create a new render target and, if necessary, copy the contents of the old
127 // render target into it. Note that this flushes the SkGpuDevice but
128 // doesn't force an OpenGL flush.
onCopyOnWrite(ContentChangeMode mode)129 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
130 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
131
132 // are we sharing our backing proxy with the image? Note this call should never create a new
133 // image because onCopyOnWrite is only called when there is a cached image.
134 sk_sp<SkImage> image(this->refCachedImage());
135 SkASSERT(image);
136
137 GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
138 SkASSERT(imageProxy);
139
140 if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
141 fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
142 } else if (kDiscard_ContentChangeMode == mode) {
143 this->SkSurface_Gpu::onDiscard();
144 }
145 }
146
onDiscard()147 void SkSurface_Gpu::onDiscard() {
148 fDevice->accessRenderTargetContext()->discard();
149 }
150
onFlush(int numSemaphores,GrBackendSemaphore * signalSemaphores)151 bool SkSurface_Gpu::onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
152 return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
153 }
154
onWait(int numSemaphores,const GrBackendSemaphore * waitSemaphores)155 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
156 return fDevice->wait(numSemaphores, waitSemaphores);
157 }
158
159 ///////////////////////////////////////////////////////////////////////////////
160
Valid(const SkImageInfo & info)161 bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
162 switch (info.colorType()) {
163 case kRGBA_F16_SkColorType:
164 return info.colorSpace() && info.colorSpace()->gammaIsLinear();
165 case kRGBA_8888_SkColorType:
166 case kBGRA_8888_SkColorType:
167 return !info.colorSpace() || info.colorSpace()->gammaCloseToSRGB();
168 default:
169 return !info.colorSpace();
170 }
171 }
172
Valid(GrContext * context,GrPixelConfig config,SkColorSpace * colorSpace)173 bool SkSurface_Gpu::Valid(GrContext* context, GrPixelConfig config, SkColorSpace* colorSpace) {
174 switch (config) {
175 case kRGBA_half_GrPixelConfig:
176 return colorSpace && colorSpace->gammaIsLinear();
177 case kSRGBA_8888_GrPixelConfig:
178 case kSBGRA_8888_GrPixelConfig:
179 return context->caps()->srgbSupport() && colorSpace && colorSpace->gammaCloseToSRGB();
180 case kRGBA_8888_GrPixelConfig:
181 case kBGRA_8888_GrPixelConfig:
182 // If we don't have sRGB support, we may get here with a color space. It still needs
183 // to be sRGB-like (so that the application will work correctly on sRGB devices.)
184 return !colorSpace ||
185 (colorSpace->gammaCloseToSRGB() && !context->caps()->srgbSupport());
186 default:
187 return !colorSpace;
188 }
189 }
190
MakeRenderTarget(GrContext * ctx,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props)191 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
192 const SkImageInfo& info, int sampleCount,
193 GrSurfaceOrigin origin, const SkSurfaceProps* props) {
194 if (!SkSurface_Gpu::Valid(info)) {
195 return nullptr;
196 }
197
198 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
199 ctx, budgeted, info, sampleCount, origin, props, SkGpuDevice::kClear_InitContents));
200 if (!device) {
201 return nullptr;
202 }
203 return sk_make_sp<SkSurface_Gpu>(std::move(device));
204 }
205
MakeFromBackendTexture(GrContext * context,const GrBackendTextureDesc & desc,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)206 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context,
207 const GrBackendTextureDesc& desc,
208 sk_sp<SkColorSpace> colorSpace,
209 const SkSurfaceProps* props) {
210 if (!context) {
211 return nullptr;
212 }
213 GrBackendTexture tex(desc, context->contextPriv().getBackend());
214 return MakeFromBackendTexture(context, tex, desc.fOrigin, desc.fSampleCnt, colorSpace, props);
215 }
216
MakeFromBackendTexture(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)217 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
218 GrSurfaceOrigin origin, int sampleCnt,
219 sk_sp<SkColorSpace> colorSpace,
220 const SkSurfaceProps* props) {
221 if (!context) {
222 return nullptr;
223 }
224 if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
225 return nullptr;
226 }
227
228 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
229 tex,
230 origin,
231 sampleCnt,
232 std::move(colorSpace),
233 props));
234 if (!rtc) {
235 return nullptr;
236 }
237
238 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
239 SkGpuDevice::kUninit_InitContents));
240 if (!device) {
241 return nullptr;
242 }
243 return sk_make_sp<SkSurface_Gpu>(std::move(device));
244 }
245
MakeFromBackendRenderTarget(GrContext * context,const GrBackendRenderTargetDesc & desc,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)246 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
247 const GrBackendRenderTargetDesc& desc,
248 sk_sp<SkColorSpace> colorSpace,
249 const SkSurfaceProps* props) {
250 if (!context) {
251 return nullptr;
252 }
253
254 GrBackendRenderTarget backendRT(desc, context->contextPriv().getBackend());
255 return MakeFromBackendRenderTarget(context, backendRT, desc.fOrigin,
256 std::move(colorSpace), props);
257
258 }
259
MakeFromBackendRenderTarget(GrContext * context,const GrBackendRenderTarget & backendRT,GrSurfaceOrigin origin,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)260 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
261 const GrBackendRenderTarget& backendRT,
262 GrSurfaceOrigin origin,
263 sk_sp<SkColorSpace> colorSpace,
264 const SkSurfaceProps* props) {
265 if (!context) {
266 return nullptr;
267 }
268 if (!SkSurface_Gpu::Valid(context, backendRT.config(), colorSpace.get())) {
269 return nullptr;
270 }
271
272 sk_sp<GrRenderTargetContext> rtc(
273 context->contextPriv().makeBackendRenderTargetRenderTargetContext(backendRT,
274 origin,
275 std::move(colorSpace),
276 props));
277 if (!rtc) {
278 return nullptr;
279 }
280
281 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc),
282 backendRT.width(), backendRT.height(),
283 SkGpuDevice::kUninit_InitContents));
284 if (!device) {
285 return nullptr;
286 }
287
288 return sk_make_sp<SkSurface_Gpu>(std::move(device));
289 }
290
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTextureDesc & desc,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)291 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
292 const GrBackendTextureDesc& desc,
293 sk_sp<SkColorSpace> colorSpace,
294 const SkSurfaceProps* props) {
295 if (!context) {
296 return nullptr;
297 }
298 GrBackendTexture tex(desc, context->contextPriv().getBackend());
299 return MakeFromBackendTextureAsRenderTarget(context, tex, desc.fOrigin, desc.fSampleCnt,
300 std::move(colorSpace), props);
301 }
302
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)303 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
304 const GrBackendTexture& tex,
305 GrSurfaceOrigin origin,
306 int sampleCnt,
307 sk_sp<SkColorSpace> colorSpace,
308 const SkSurfaceProps* props) {
309 if (!context) {
310 return nullptr;
311 }
312 if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
313 return nullptr;
314 }
315
316 sk_sp<GrRenderTargetContext> rtc(
317 context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
318 tex,
319 origin,
320 sampleCnt,
321 std::move(colorSpace),
322 props));
323 if (!rtc) {
324 return nullptr;
325 }
326
327 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
328 SkGpuDevice::kUninit_InitContents));
329 if (!device) {
330 return nullptr;
331 }
332 return sk_make_sp<SkSurface_Gpu>(std::move(device));
333 }
334
335 #endif
336