• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrContextPriv.h"
11 #include "GrRenderTargetContextPriv.h"
12 #include "GrResourceProvider.h"
13 
14 #include "SkCanvas.h"
15 #include "SkColorSpace_Base.h"
16 #include "SkGpuDevice.h"
17 #include "SkImage_Base.h"
18 #include "SkImage_Gpu.h"
19 #include "SkImagePriv.h"
20 #include "SkSurface_Base.h"
21 
22 #if SK_SUPPORT_GPU
23 
SkSurface_Gpu(sk_sp<SkGpuDevice> device)24 SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
25     : INHERITED(device->width(), device->height(), &device->surfaceProps())
26     , fDevice(std::move(device)) {
27     SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
28 }
29 
~SkSurface_Gpu()30 SkSurface_Gpu::~SkSurface_Gpu() {
31 }
32 
prepare_rt_for_external_access(SkSurface_Gpu * surface,SkSurface::BackendHandleAccess access)33 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
34                                                       SkSurface::BackendHandleAccess access) {
35     switch (access) {
36         case SkSurface::kFlushRead_BackendHandleAccess:
37             break;
38         case SkSurface::kFlushWrite_BackendHandleAccess:
39         case SkSurface::kDiscardWrite_BackendHandleAccess:
40             // for now we don't special-case on Discard, but we may in the future.
41             surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
42             break;
43     }
44 
45     // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
46     surface->getDevice()->flush();
47     GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
48     return rtc->accessRenderTarget();
49 }
50 
onGetTextureHandle(BackendHandleAccess access)51 GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) {
52     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
53     if (!rt) {
54         return 0;
55     }
56     GrTexture* texture = rt->asTexture();
57     if (texture) {
58         return texture->getTextureHandle();
59     }
60     return 0;
61 }
62 
onGetRenderTargetHandle(GrBackendObject * obj,BackendHandleAccess access)63 bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
64     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
65     if (!rt) {
66         return false;
67     }
68     *obj = rt->getRenderTargetHandle();
69     return true;
70 }
71 
onNewCanvas()72 SkCanvas* SkSurface_Gpu::onNewCanvas() {
73     SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
74     flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag);
75 
76     return new SkCanvas(fDevice.get(), flags);
77 }
78 
onNewSurface(const SkImageInfo & info)79 sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
80     int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples();
81     GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
82     // TODO: Make caller specify this (change virtual signature of onNewSurface).
83     static const SkBudgeted kBudgeted = SkBudgeted::kNo;
84     return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
85                                        origin, &this->props());
86 }
87 
onNewImageSnapshot()88 sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot() {
89     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
90     if (!rtc) {
91         return nullptr;
92     }
93 
94     GrContext* ctx = fDevice->context();
95 
96     if (!rtc->asSurfaceProxy()) {
97         return nullptr;
98     }
99 
100     SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
101 
102     sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
103     // If the original render target is a buffer originally created by the client, then we don't
104     // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
105     // copy-on-write.
106     if (!srcProxy || rtc->priv().refsWrappedObjects()) {
107         // MDB TODO: replace this with GrSurfaceProxy::Copy?
108         GrSurfaceDesc desc = rtc->desc();
109         desc.fFlags = desc.fFlags & ~kRenderTarget_GrSurfaceFlag;
110 
111         sk_sp<GrSurfaceContext> copyCtx = ctx->contextPriv().makeDeferredSurfaceContext(
112                                                                 desc,
113                                                                 SkBackingFit::kExact,
114                                                                 budgeted);
115         if (!copyCtx) {
116             return nullptr;
117         }
118 
119         if (!copyCtx->copy(rtc->asSurfaceProxy())) {
120             return nullptr;
121         }
122 
123         srcProxy = copyCtx->asTextureProxyRef();
124     }
125 
126     const SkImageInfo info = fDevice->imageInfo();
127     sk_sp<SkImage> image;
128     if (srcProxy) {
129         // The renderTargetContext coming out of SkGpuDevice should always be exact and the
130         // above copy creates a kExact surfaceContext.
131         SkASSERT(srcProxy->priv().isExact());
132         image = sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
133                                         info.alphaType(), std::move(srcProxy),
134                                         info.refColorSpace(), budgeted);
135     }
136     return image;
137 }
138 
139 // Create a new render target and, if necessary, copy the contents of the old
140 // render target into it. Note that this flushes the SkGpuDevice but
141 // doesn't force an OpenGL flush.
onCopyOnWrite(ContentChangeMode mode)142 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
143     GrRenderTarget* rt = fDevice->accessRenderTargetContext()->accessRenderTarget();
144     if (!rt) {
145         return;
146     }
147     // are we sharing our render target with the image? Note this call should never create a new
148     // image because onCopyOnWrite is only called when there is a cached image.
149     sk_sp<SkImage> image(this->refCachedImage());
150     SkASSERT(image);
151     // MDB TODO: this is unfortunate. The snapping of an Image_Gpu from a surface currently
152     // funnels down to a GrTexture. Once Image_Gpus are proxy-backed we should be able to
153     // compare proxy uniqueIDs.
154     if (rt->asTexture()->getTextureHandle() == image->getTextureHandle(false)) {
155         fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
156     } else if (kDiscard_ContentChangeMode == mode) {
157         this->SkSurface_Gpu::onDiscard();
158     }
159 }
160 
onDiscard()161 void SkSurface_Gpu::onDiscard() {
162     fDevice->accessRenderTargetContext()->discard();
163 }
164 
onPrepareForExternalIO()165 void SkSurface_Gpu::onPrepareForExternalIO() {
166     fDevice->flush();
167 }
168 
169 ///////////////////////////////////////////////////////////////////////////////
170 
Valid(const SkImageInfo & info)171 bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
172     switch (info.colorType()) {
173         case kRGBA_F16_SkColorType:
174             return !info.colorSpace() || info.colorSpace()->gammaIsLinear();
175         case kRGBA_8888_SkColorType:
176         case kBGRA_8888_SkColorType:
177             return !info.colorSpace() || info.colorSpace()->gammaCloseToSRGB();
178         default:
179             return !info.colorSpace();
180     }
181 }
182 
Valid(GrContext * context,GrPixelConfig config,SkColorSpace * colorSpace)183 bool SkSurface_Gpu::Valid(GrContext* context, GrPixelConfig config, SkColorSpace* colorSpace) {
184     switch (config) {
185         case kRGBA_half_GrPixelConfig:
186             return !colorSpace || colorSpace->gammaIsLinear();
187         case kSRGBA_8888_GrPixelConfig:
188         case kSBGRA_8888_GrPixelConfig:
189             return context->caps()->srgbSupport() && colorSpace && colorSpace->gammaCloseToSRGB();
190         case kRGBA_8888_GrPixelConfig:
191         case kBGRA_8888_GrPixelConfig:
192             // If we don't have sRGB support, we may get here with a color space. It still needs
193             // to be sRGB-like (so that the application will work correctly on sRGB devices.)
194             return !colorSpace ||
195                 (colorSpace->gammaCloseToSRGB() && !context->caps()->srgbSupport());
196         default:
197             return !colorSpace;
198     }
199 }
200 
MakeRenderTarget(GrContext * ctx,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props)201 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
202                                              const SkImageInfo& info, int sampleCount,
203                                              GrSurfaceOrigin origin, const SkSurfaceProps* props) {
204     if (!SkSurface_Gpu::Valid(info)) {
205         return nullptr;
206     }
207 
208     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
209             ctx, budgeted, info, sampleCount, origin, props, SkGpuDevice::kClear_InitContents));
210     if (!device) {
211         return nullptr;
212     }
213     return sk_make_sp<SkSurface_Gpu>(std::move(device));
214 }
215 
MakeFromBackendTexture(GrContext * context,const GrBackendTextureDesc & desc,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)216 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context,
217                                                    const GrBackendTextureDesc& desc,
218                                                    sk_sp<SkColorSpace> colorSpace,
219                                                    const SkSurfaceProps* props) {
220     if (!context) {
221         return nullptr;
222     }
223     if (!SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag)) {
224         return nullptr;
225     }
226     if (!SkSurface_Gpu::Valid(context, desc.fConfig, colorSpace.get())) {
227         return nullptr;
228     }
229 
230     sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
231                                                                     desc,
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), desc.fWidth, desc.fHeight,
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     if (!SkSurface_Gpu::Valid(context, desc.fConfig, colorSpace.get())) {
254         return nullptr;
255     }
256 
257     sk_sp<GrRenderTargetContext> rtc(
258         context->contextPriv().makeBackendRenderTargetRenderTargetContext(desc,
259                                                                           std::move(colorSpace),
260                                                                           props));
261     if (!rtc) {
262         return nullptr;
263     }
264 
265     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), desc.fWidth, desc.fHeight,
266                                                 SkGpuDevice::kUninit_InitContents));
267     if (!device) {
268         return nullptr;
269     }
270 
271     return sk_make_sp<SkSurface_Gpu>(std::move(device));
272 }
273 
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTextureDesc & desc,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)274 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
275                                                                  const GrBackendTextureDesc& desc,
276                                                                  sk_sp<SkColorSpace> colorSpace,
277                                                                  const SkSurfaceProps* props) {
278     if (!context) {
279         return nullptr;
280     }
281     if (!SkSurface_Gpu::Valid(context, desc.fConfig, colorSpace.get())) {
282         return nullptr;
283     }
284 
285     sk_sp<GrRenderTargetContext> rtc(
286         context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
287                                                                               desc,
288                                                                               std::move(colorSpace),
289                                                                               props));
290     if (!rtc) {
291         return nullptr;
292     }
293 
294     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), desc.fWidth, desc.fHeight,
295                                                 SkGpuDevice::kUninit_InitContents));
296     if (!device) {
297         return nullptr;
298     }
299     return sk_make_sp<SkSurface_Gpu>(std::move(device));
300 }
301 
302 #endif
303