• 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 "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