• 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 "GrRenderTarget.h"
13 #include "GrRenderTargetContextPriv.h"
14 #include "GrTexture.h"
15 
16 #include "SkCanvas.h"
17 #include "SkDeferredDisplayList.h"
18 #include "SkGpuDevice.h"
19 #include "SkImage_Base.h"
20 #include "SkImage_Gpu.h"
21 #include "SkImagePriv.h"
22 #include "SkSurface_Base.h"
23 #include "SkSurfaceCharacterization.h"
24 
25 #if SK_SUPPORT_GPU
26 
SkSurface_Gpu(sk_sp<SkGpuDevice> device)27 SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
28     : INHERITED(device->width(), device->height(), &device->surfaceProps())
29     , fDevice(std::move(device)) {
30     SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
31 }
32 
~SkSurface_Gpu()33 SkSurface_Gpu::~SkSurface_Gpu() {
34 }
35 
prepare_rt_for_external_access(SkSurface_Gpu * surface,SkSurface::BackendHandleAccess access)36 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
37                                                       SkSurface::BackendHandleAccess access) {
38     switch (access) {
39         case SkSurface::kFlushRead_BackendHandleAccess:
40             break;
41         case SkSurface::kFlushWrite_BackendHandleAccess:
42         case SkSurface::kDiscardWrite_BackendHandleAccess:
43             // for now we don't special-case on Discard, but we may in the future.
44             surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
45             break;
46     }
47 
48     // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
49     surface->getDevice()->flush();
50     GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
51     return rtc->accessRenderTarget();
52 }
53 
onGetTextureHandle(BackendHandleAccess access)54 GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) {
55     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
56     if (!rt) {
57         return 0;
58     }
59     GrTexture* texture = rt->asTexture();
60     if (texture) {
61         return texture->getTextureHandle();
62     }
63     return 0;
64 }
65 
onGetRenderTargetHandle(GrBackendObject * obj,BackendHandleAccess access)66 bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
67     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
68     if (!rt) {
69         return false;
70     }
71     *obj = rt->getRenderTargetHandle();
72     return true;
73 }
74 
onNewCanvas()75 SkCanvas* SkSurface_Gpu::onNewCanvas() {
76     SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
77     flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag);
78 
79     return new SkCanvas(fDevice.get(), flags);
80 }
81 
onNewSurface(const SkImageInfo & info)82 sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
83     int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples();
84     GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
85     // TODO: Make caller specify this (change virtual signature of onNewSurface).
86     static const SkBudgeted kBudgeted = SkBudgeted::kNo;
87     return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
88                                        origin, &this->props());
89 }
90 
onNewImageSnapshot()91 sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot() {
92     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
93     if (!rtc) {
94         return nullptr;
95     }
96 
97     GrContext* ctx = fDevice->context();
98 
99     if (!rtc->asSurfaceProxy()) {
100         return nullptr;
101     }
102 
103     SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
104 
105     sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
106     // If the original render target is a buffer originally created by the client, then we don't
107     // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
108     // copy-on-write.
109     if (!srcProxy || rtc->priv().refsWrappedObjects()) {
110         SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
111 
112         srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), budgeted);
113     }
114 
115     const SkImageInfo info = fDevice->imageInfo();
116     sk_sp<SkImage> image;
117     if (srcProxy) {
118         // The renderTargetContext coming out of SkGpuDevice should always be exact and the
119         // above copy creates a kExact surfaceContext.
120         SkASSERT(srcProxy->priv().isExact());
121         image = sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
122                                         info.alphaType(), std::move(srcProxy),
123                                         info.refColorSpace(), budgeted);
124     }
125     return image;
126 }
127 
128 // Create a new render target and, if necessary, copy the contents of the old
129 // render target into it. Note that this flushes the SkGpuDevice but
130 // doesn't force an OpenGL flush.
onCopyOnWrite(ContentChangeMode mode)131 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
132     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
133 
134     // are we sharing our backing proxy with the image? Note this call should never create a new
135     // image because onCopyOnWrite is only called when there is a cached image.
136     sk_sp<SkImage> image(this->refCachedImage());
137     SkASSERT(image);
138 
139     GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
140     SkASSERT(imageProxy);
141 
142     if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
143         fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
144     } else if (kDiscard_ContentChangeMode == mode) {
145         this->SkSurface_Gpu::onDiscard();
146     }
147 }
148 
onDiscard()149 void SkSurface_Gpu::onDiscard() {
150     fDevice->accessRenderTargetContext()->discard();
151 }
152 
onFlush(int numSemaphores,GrBackendSemaphore signalSemaphores[])153 GrSemaphoresSubmitted SkSurface_Gpu::onFlush(int numSemaphores,
154                                              GrBackendSemaphore signalSemaphores[]) {
155     return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
156 }
157 
onWait(int numSemaphores,const GrBackendSemaphore * waitSemaphores)158 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
159     return fDevice->wait(numSemaphores, waitSemaphores);
160 }
161 
onCharacterize(SkSurfaceCharacterization * data) const162 bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* data) const {
163     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
164     GrContext* ctx = fDevice->context();
165 
166     int maxResourceCount;
167     size_t maxResourceBytes;
168     ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
169 
170     data->set(ctx->threadSafeProxy(), maxResourceCount, maxResourceBytes,
171               rtc->origin(), rtc->width(), rtc->height(),
172               rtc->colorSpaceInfo().config(), rtc->fsaaType(), rtc->numStencilSamples(),
173               rtc->colorSpaceInfo().refColorSpace(), this->props());
174 
175     return true;
176 }
177 
isCompatible(const SkSurfaceCharacterization & data) const178 bool SkSurface_Gpu::isCompatible(const SkSurfaceCharacterization& data) const {
179     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
180     GrContext* ctx = fDevice->context();
181 
182     // As long as the current state if the context allows for greater or equal resources,
183     // we allow the DDL to be replayed.
184     int maxResourceCount;
185     size_t maxResourceBytes;
186     ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
187 
188     return data.contextInfo() && data.contextInfo()->matches(ctx) &&
189            data.cacheMaxResourceCount() <= maxResourceCount &&
190            data.cacheMaxResourceBytes() <= maxResourceBytes &&
191            data.origin() == rtc->origin() && data.width() == rtc->width() &&
192            data.height() == rtc->height() && data.config() == rtc->colorSpaceInfo().config() &&
193            data.fsaaType() == rtc->fsaaType() && data.stencilCount() == rtc->numStencilSamples() &&
194            SkColorSpace::Equals(data.colorSpace(), rtc->colorSpaceInfo().colorSpace()) &&
195            data.surfaceProps() == rtc->surfaceProps();
196 }
197 
onDraw(const SkDeferredDisplayList * ddl)198 bool SkSurface_Gpu::onDraw(const SkDeferredDisplayList* ddl) {
199     if (!this->isCompatible(ddl->characterization())) {
200         return false;
201     }
202 
203 #ifdef SK_RASTER_RECORDER_IMPLEMENTATION
204     // Ultimately need to pass opLists from the DeferredDisplayList on to the
205     // SkGpuDevice's renderTargetContext.
206     return ddl->draw(this);
207 #else
208     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
209     GrContext* ctx = fDevice->context();
210 
211     ctx->contextPriv().copyOpListsFromDDL(ddl, rtc->asRenderTargetProxy());
212     return true;
213 #endif
214 }
215 
216 
217 ///////////////////////////////////////////////////////////////////////////////
218 
Valid(const SkImageInfo & info)219 bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
220     switch (info.colorType()) {
221         case kRGBA_F16_SkColorType:
222             return (!info.colorSpace()) || info.colorSpace()->gammaIsLinear();
223         case kRGBA_8888_SkColorType:
224         case kBGRA_8888_SkColorType:
225             return !info.colorSpace() || info.colorSpace()->gammaCloseToSRGB();
226         default:
227             return !info.colorSpace();
228     }
229 }
230 
Valid(GrContext * context,GrPixelConfig config,SkColorSpace * colorSpace)231 bool SkSurface_Gpu::Valid(GrContext* context, GrPixelConfig config, SkColorSpace* colorSpace) {
232     switch (config) {
233         case kRGBA_half_GrPixelConfig:
234             return (!colorSpace) || colorSpace->gammaIsLinear();
235         case kSRGBA_8888_GrPixelConfig:
236         case kSBGRA_8888_GrPixelConfig:
237             return context->caps()->srgbSupport() && colorSpace && colorSpace->gammaCloseToSRGB();
238         case kRGBA_8888_GrPixelConfig:
239         case kBGRA_8888_GrPixelConfig:
240             // If we don't have sRGB support, we may get here with a color space. It still needs
241             // to be sRGB-like (so that the application will work correctly on sRGB devices.)
242             return !colorSpace ||
243                 (colorSpace->gammaCloseToSRGB() && !context->caps()->srgbSupport());
244         default:
245             return !colorSpace;
246     }
247 }
248 
MakeRenderTarget(GrContext * ctx,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips)249 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
250                                              const SkImageInfo& info, int sampleCount,
251                                              GrSurfaceOrigin origin, const SkSurfaceProps* props,
252                                              bool shouldCreateWithMips) {
253     if (!ctx) {
254         return nullptr;
255     }
256     if (!SkSurface_Gpu::Valid(info)) {
257         return nullptr;
258     }
259     sampleCount = SkTMax(1, sampleCount);
260     GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
261 
262     if (!ctx->caps()->mipMapSupport()) {
263         mipMapped = GrMipMapped::kNo;
264     }
265 
266     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
267             ctx, budgeted, info, sampleCount, origin, props, mipMapped,
268             SkGpuDevice::kClear_InitContents));
269     if (!device) {
270         return nullptr;
271     }
272     return sk_make_sp<SkSurface_Gpu>(std::move(device));
273 }
274 
MakeWrappedRenderTarget(GrContext * context,sk_sp<GrRenderTargetContext> rtc)275 sk_sp<SkSurface> SkSurface_Gpu::MakeWrappedRenderTarget(GrContext* context,
276                                                         sk_sp<GrRenderTargetContext> rtc) {
277     if (!context) {
278         return nullptr;
279     }
280 
281     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc),
282                                                 rtc->width(), rtc->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 
291 
MakeFromBackendTexture(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)292 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
293                                                    GrSurfaceOrigin origin, int sampleCnt,
294                                                    sk_sp<SkColorSpace> colorSpace,
295                                                    const SkSurfaceProps* props) {
296     if (!context) {
297         return nullptr;
298     }
299     if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
300         return nullptr;
301     }
302     sampleCnt = SkTMax(1, sampleCnt);
303 
304     sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
305                                                                     tex,
306                                                                     origin,
307                                                                     sampleCnt,
308                                                                     std::move(colorSpace),
309                                                                     props));
310     if (!rtc) {
311         return nullptr;
312     }
313 
314     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
315                                                 SkGpuDevice::kUninit_InitContents));
316     if (!device) {
317         return nullptr;
318     }
319     return sk_make_sp<SkSurface_Gpu>(std::move(device));
320 }
321 
validate_backend_texture(GrContext * ctx,const GrBackendTexture & tex,GrPixelConfig * config,int sampleCnt,SkColorType ct,sk_sp<SkColorSpace> cs,bool texturable)322 bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
323                               int sampleCnt, SkColorType ct, sk_sp<SkColorSpace> cs,
324                               bool texturable) {
325     // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
326     // create a fake image info here.
327     SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
328 
329     if (!SkSurface_Gpu::Valid(info)) {
330         return false;
331     }
332 
333     if (!ctx->caps()->validateBackendTexture(tex, ct, config)) {
334         return false;
335     }
336 
337     if (!ctx->caps()->isConfigRenderable(*config, sampleCnt > 1)) {
338         return false;
339     }
340 
341     if (ctx->caps()->getSampleCount(sampleCnt, *config) != sampleCnt) {
342         return false;
343     }
344 
345     if (texturable && !ctx->caps()->isConfigTexturable(*config)) {
346         return false;
347     }
348     return true;
349 }
350 
MakeFromBackendTexture(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)351 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
352                                                    GrSurfaceOrigin origin, int sampleCnt,
353                                                    SkColorType colorType,
354                                                    sk_sp<SkColorSpace> colorSpace,
355                                                    const SkSurfaceProps* props) {
356     if (!context) {
357         return nullptr;
358     }
359     sampleCnt = SkTMax(1, sampleCnt);
360     GrBackendTexture texCopy = tex;
361     if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
362                                   sampleCnt, colorType, colorSpace, true)) {
363         return nullptr;
364     }
365 
366     return MakeFromBackendTexture(context, texCopy, origin, sampleCnt, colorSpace, props);
367 }
368 
MakeFromBackendRenderTarget(GrContext * context,const GrBackendRenderTarget & backendRT,GrSurfaceOrigin origin,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)369 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
370                                                         const GrBackendRenderTarget& backendRT,
371                                                         GrSurfaceOrigin origin,
372                                                         sk_sp<SkColorSpace> colorSpace,
373                                                         const SkSurfaceProps* props) {
374     if (!context) {
375         return nullptr;
376     }
377     if (!SkSurface_Gpu::Valid(context, backendRT.config(), colorSpace.get())) {
378         return nullptr;
379     }
380 
381     sk_sp<GrRenderTargetContext> rtc(
382         context->contextPriv().makeBackendRenderTargetRenderTargetContext(backendRT,
383                                                                           origin,
384                                                                           std::move(colorSpace),
385                                                                           props));
386     if (!rtc) {
387         return nullptr;
388     }
389 
390     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc),
391                                                 backendRT.width(), backendRT.height(),
392                                                 SkGpuDevice::kUninit_InitContents));
393     if (!device) {
394         return nullptr;
395     }
396 
397     return sk_make_sp<SkSurface_Gpu>(std::move(device));
398 }
399 
validate_backend_render_target(GrContext * ctx,const GrBackendRenderTarget & rt,GrPixelConfig * config,SkColorType ct,sk_sp<SkColorSpace> cs)400 bool validate_backend_render_target(GrContext* ctx, const GrBackendRenderTarget& rt,
401                                     GrPixelConfig* config, SkColorType ct, sk_sp<SkColorSpace> cs) {
402     // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
403     // create a fake image info here.
404     SkImageInfo info = SkImageInfo::Make(1, 1, ct, kPremul_SkAlphaType, cs);
405 
406     if (!SkSurface_Gpu::Valid(info)) {
407         return false;
408     }
409 
410     if (!ctx->caps()->validateBackendRenderTarget(rt, ct, config)) {
411         return false;
412     }
413 
414     if (!ctx->caps()->isConfigRenderable(*config, false)) {
415         return false;
416     }
417 
418     return true;
419 }
420 
MakeFromBackendRenderTarget(GrContext * context,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)421 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
422                                                         const GrBackendRenderTarget& rt,
423                                                         GrSurfaceOrigin origin,
424                                                         SkColorType colorType,
425                                                         sk_sp<SkColorSpace> colorSpace,
426                                                         const SkSurfaceProps* props) {
427     if (!context) {
428         return nullptr;
429     }
430     GrBackendRenderTarget rtCopy = rt;
431     if (!validate_backend_render_target(context, rtCopy, &rtCopy.fConfig, colorType, colorSpace)) {
432         return nullptr;
433     }
434 
435     return MakeFromBackendRenderTarget(context, rtCopy, origin, colorSpace, props);
436 }
437 
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)438 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
439                                                                  const GrBackendTexture& tex,
440                                                                  GrSurfaceOrigin origin,
441                                                                  int sampleCnt,
442                                                                  sk_sp<SkColorSpace> colorSpace,
443                                                                  const SkSurfaceProps* props) {
444     if (!context) {
445         return nullptr;
446     }
447     if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
448         return nullptr;
449     }
450     sampleCnt = SkTMax(1, sampleCnt);
451 
452     sk_sp<GrRenderTargetContext> rtc(
453         context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
454                                                                               tex,
455                                                                               origin,
456                                                                               sampleCnt,
457                                                                               std::move(colorSpace),
458                                                                               props));
459     if (!rtc) {
460         return nullptr;
461     }
462 
463     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
464                                                 SkGpuDevice::kUninit_InitContents));
465     if (!device) {
466         return nullptr;
467     }
468     return sk_make_sp<SkSurface_Gpu>(std::move(device));
469 }
470 
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)471 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
472                                                                  const GrBackendTexture& tex,
473                                                                  GrSurfaceOrigin origin,
474                                                                  int sampleCnt,
475                                                                  SkColorType colorType,
476                                                                  sk_sp<SkColorSpace> colorSpace,
477                                                                  const SkSurfaceProps* props) {
478     if (!context) {
479         return nullptr;
480     }
481     sampleCnt = SkTMax(1, sampleCnt);
482     GrBackendTexture texCopy = tex;
483     if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
484                                   sampleCnt, colorType, colorSpace, false)) {
485         return nullptr;
486     }
487 
488     return MakeFromBackendTextureAsRenderTarget(context, texCopy, origin, sampleCnt, colorSpace,
489                                                 props);
490 }
491 
492 #endif
493