• 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 "include/core/SkCanvas.h"
9 #include "include/core/SkSurfaceCharacterization.h"
10 #include "include/gpu/GrBackendSurface.h"
11 #include "include/gpu/GrTexture.h"
12 #include "include/private/GrRecordingContext.h"
13 #include "include/private/SkDeferredDisplayList.h"
14 #include "src/core/SkImagePriv.h"
15 #include "src/gpu/GrAHardwareBufferUtils.h"
16 #include "src/gpu/GrCaps.h"
17 #include "src/gpu/GrContextPriv.h"
18 #include "src/gpu/GrContextThreadSafeProxyPriv.h"
19 #include "src/gpu/GrRecordingContextPriv.h"
20 #include "src/gpu/GrRenderTarget.h"
21 #include "src/gpu/GrRenderTargetContextPriv.h"
22 #include "src/gpu/GrRenderTargetProxyPriv.h"
23 #include "src/gpu/SkGpuDevice.h"
24 #include "src/image/SkImage_Base.h"
25 #include "src/image/SkImage_Gpu.h"
26 #include "src/image/SkSurface_Base.h"
27 #include "src/image/SkSurface_Gpu.h"
28 
29 #if SK_SUPPORT_GPU
30 
SkSurface_Gpu(sk_sp<SkGpuDevice> device)31 SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
32     : INHERITED(device->width(), device->height(), &device->surfaceProps())
33     , fDevice(std::move(device)) {
34     SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
35 }
36 
~SkSurface_Gpu()37 SkSurface_Gpu::~SkSurface_Gpu() {
38 }
39 
prepare_rt_for_external_access(SkSurface_Gpu * surface,SkSurface::BackendHandleAccess access)40 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
41                                                       SkSurface::BackendHandleAccess access) {
42     switch (access) {
43         case SkSurface::kFlushRead_BackendHandleAccess:
44             break;
45         case SkSurface::kFlushWrite_BackendHandleAccess:
46         case SkSurface::kDiscardWrite_BackendHandleAccess:
47             // for now we don't special-case on Discard, but we may in the future.
48             surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
49             break;
50     }
51 
52     // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
53     surface->getDevice()->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
54     GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
55     return rtc->accessRenderTarget();
56 }
57 
onGetBackendTexture(BackendHandleAccess access)58 GrBackendTexture SkSurface_Gpu::onGetBackendTexture(BackendHandleAccess access) {
59     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
60     if (!rt) {
61         return GrBackendTexture(); // invalid
62     }
63     GrTexture* texture = rt->asTexture();
64     if (texture) {
65         return texture->getBackendTexture();
66     }
67     return GrBackendTexture(); // invalid
68 }
69 
onGetBackendRenderTarget(BackendHandleAccess access)70 GrBackendRenderTarget SkSurface_Gpu::onGetBackendRenderTarget(BackendHandleAccess access) {
71     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
72     if (!rt) {
73         return GrBackendRenderTarget(); // invalid
74     }
75 
76     return rt->getBackendRenderTarget();
77 }
78 
onNewCanvas()79 SkCanvas* SkSurface_Gpu::onNewCanvas() { return new SkCanvas(fDevice); }
80 
onNewSurface(const SkImageInfo & info)81 sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
82     int sampleCount = fDevice->accessRenderTargetContext()->numSamples();
83     GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
84     // TODO: Make caller specify this (change virtual signature of onNewSurface).
85     static const SkBudgeted kBudgeted = SkBudgeted::kNo;
86     return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
87                                        origin, &this->props());
88 }
89 
onNewImageSnapshot(const SkIRect * subset)90 sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot(const SkIRect* subset) {
91     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
92     if (!rtc) {
93         return nullptr;
94     }
95 
96     GrContext* ctx = fDevice->context();
97 
98     if (!rtc->asSurfaceProxy()) {
99         return nullptr;
100     }
101 
102     SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
103 
104     sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
105 
106     if (subset) {
107         srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), *subset,
108                                         SkBackingFit::kExact, budgeted);
109     } else if (!srcProxy || rtc->priv().refsWrappedObjects()) {
110         // If the original render target is a buffer originally created by the client, then we don't
111         // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
112         // copy-on-write.
113         SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
114 
115         srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(),
116                                         SkBackingFit::kExact, budgeted);
117     }
118 
119     const SkImageInfo info = fDevice->imageInfo();
120     sk_sp<SkImage> image;
121     if (srcProxy) {
122         // The renderTargetContext coming out of SkGpuDevice should always be exact and the
123         // above copy creates a kExact surfaceContext.
124         SkASSERT(srcProxy->priv().isExact());
125         image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, info.alphaType(),
126                                         std::move(srcProxy), info.refColorSpace());
127     }
128     return image;
129 }
130 
onWritePixels(const SkPixmap & src,int x,int y)131 void SkSurface_Gpu::onWritePixels(const SkPixmap& src, int x, int y) {
132     fDevice->writePixels(src, x, y);
133 }
134 
onAsyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallback callback,ReadPixelsContext context)135 void SkSurface_Gpu::onAsyncRescaleAndReadPixels(const SkImageInfo& info, const SkIRect& srcRect,
136                                                 RescaleGamma rescaleGamma,
137                                                 SkFilterQuality rescaleQuality,
138                                                 ReadPixelsCallback callback,
139                                                 ReadPixelsContext context) {
140     auto* rtc = this->fDevice->accessRenderTargetContext();
141     rtc->asyncRescaleAndReadPixels(info, srcRect, rescaleGamma, rescaleQuality, callback, context);
142 }
143 
onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,int dstW,int dstH,RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallbackYUV420 callback,ReadPixelsContext context)144 void SkSurface_Gpu::onAsyncRescaleAndReadPixelsYUV420(
145         SkYUVColorSpace yuvColorSpace, sk_sp<SkColorSpace> dstColorSpace, const SkIRect& srcRect,
146         int dstW, int dstH, RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality,
147         ReadPixelsCallbackYUV420 callback, ReadPixelsContext context) {
148     auto* rtc = this->fDevice->accessRenderTargetContext();
149     rtc->asyncRescaleAndReadPixelsYUV420(yuvColorSpace, std::move(dstColorSpace), srcRect, dstW,
150                                          dstH, rescaleGamma, rescaleQuality, callback, context);
151 }
152 
153 // Create a new render target and, if necessary, copy the contents of the old
154 // render target into it. Note that this flushes the SkGpuDevice but
155 // doesn't force an OpenGL flush.
onCopyOnWrite(ContentChangeMode mode)156 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
157     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
158 
159     // are we sharing our backing proxy with the image? Note this call should never create a new
160     // image because onCopyOnWrite is only called when there is a cached image.
161     sk_sp<SkImage> image(this->refCachedImage());
162     SkASSERT(image);
163 
164     GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
165     SkASSERT(imageProxy);
166 
167     if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
168         fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
169     } else if (kDiscard_ContentChangeMode == mode) {
170         this->SkSurface_Gpu::onDiscard();
171     }
172 }
173 
onDiscard()174 void SkSurface_Gpu::onDiscard() {
175     fDevice->accessRenderTargetContext()->discard();
176 }
177 
onFlush(BackendSurfaceAccess access,const GrFlushInfo & info)178 GrSemaphoresSubmitted SkSurface_Gpu::onFlush(BackendSurfaceAccess access,
179                                              const GrFlushInfo& info) {
180     return fDevice->flush(access, info);
181 }
182 
onWait(int numSemaphores,const GrBackendSemaphore * waitSemaphores)183 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
184     return fDevice->wait(numSemaphores, waitSemaphores);
185 }
186 
onCharacterize(SkSurfaceCharacterization * characterization) const187 bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* characterization) const {
188     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
189     GrContext* ctx = fDevice->context();
190 
191     int maxResourceCount;
192     size_t maxResourceBytes;
193     ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
194 
195     bool mipmapped = rtc->asTextureProxy() ? GrMipMapped::kYes == rtc->asTextureProxy()->mipMapped()
196                                            : false;
197 
198     SkColorType ct = GrColorTypeToSkColorType(rtc->colorSpaceInfo().colorType());
199     if (ct == kUnknown_SkColorType) {
200         return false;
201     }
202 
203     bool usesGLFBO0 = rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0();
204     // We should never get in the situation where we have a texture render target that is also
205     // backend by FBO 0.
206     SkASSERT(!usesGLFBO0 || !SkToBool(rtc->asTextureProxy()));
207 
208     SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType,
209                                        rtc->colorSpaceInfo().refColorSpace());
210 
211     GrBackendFormat format = rtc->asSurfaceProxy()->backendFormat();
212 
213     characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, format,
214                           rtc->origin(), rtc->numSamples(),
215                           SkSurfaceCharacterization::Textureable(SkToBool(rtc->asTextureProxy())),
216                           SkSurfaceCharacterization::MipMapped(mipmapped),
217                           SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0),
218                           SkSurfaceCharacterization::VulkanSecondaryCBCompatible(false),
219                           GrProtected(rtc->asRenderTargetProxy()->isProtected()),
220                           this->props());
221     return true;
222 }
223 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint)224 void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
225     // If the dst is also GPU we try to not force a new image snapshot (by calling the base class
226     // onDraw) since that may not always perform the copy-on-write optimization.
227     auto tryDraw = [&] {
228         SkASSERT(fDevice->context()->priv().asDirectContext());
229         GrContext* context = fDevice->context();
230         GrContext* canvasContext = canvas->getGrContext();
231         if (!canvasContext) {
232             return false;
233         }
234         if (!canvasContext->priv().asDirectContext() ||
235             canvasContext->priv().contextID() != context->priv().contextID()) {
236             return false;
237         }
238         GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
239         if (!rtc) {
240             return false;
241         }
242         sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
243         if (!srcProxy) {
244             return false;
245         }
246         // Possibly we could skip making an image here if SkGpuDevice exposed a lower level way
247         // of drawing a texture proxy.
248         const SkImageInfo info = fDevice->imageInfo();
249         sk_sp<SkImage> image;
250         image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, info.alphaType(),
251                                         std::move(srcProxy), info.refColorSpace());
252         canvas->drawImage(image, x, y, paint);
253         return true;
254     };
255     if (!tryDraw()) {
256         INHERITED::onDraw(canvas, x, y, paint);
257     }
258 }
259 
onIsCompatible(const SkSurfaceCharacterization & characterization) const260 bool SkSurface_Gpu::onIsCompatible(const SkSurfaceCharacterization& characterization) const {
261     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
262     GrContext* ctx = fDevice->context();
263 
264     if (!characterization.isValid()) {
265         return false;
266     }
267 
268     if (characterization.vulkanSecondaryCBCompatible()) {
269         return false;
270     }
271 
272     // As long as the current state if the context allows for greater or equal resources,
273     // we allow the DDL to be replayed.
274     // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
275     int maxResourceCount;
276     size_t maxResourceBytes;
277     ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
278 
279     if (characterization.isTextureable()) {
280         if (!rtc->asTextureProxy()) {
281             // If the characterization was textureable we require the replay dest to also be
282             // textureable. If the characterized surface wasn't textureable we allow the replay
283             // dest to be textureable.
284             return false;
285         }
286 
287         if (characterization.isMipMapped() &&
288             GrMipMapped::kNo == rtc->asTextureProxy()->mipMapped()) {
289             // Fail if the DDL's surface was mipmapped but the replay surface is not.
290             // Allow drawing to proceed if the DDL was not mipmapped but the replay surface is.
291             return false;
292         }
293     }
294 
295     if (characterization.usesGLFBO0() != rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0()) {
296         return false;
297     }
298 
299     SkColorType rtcColorType = GrColorTypeToSkColorType(rtc->colorSpaceInfo().colorType());
300     if (rtcColorType == kUnknown_SkColorType) {
301         return false;
302     }
303 
304     GrProtected isProtected = GrProtected(rtc->asSurfaceProxy()->isProtected());
305 
306     return characterization.contextInfo() && characterization.contextInfo()->priv().matches(ctx) &&
307            characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
308            characterization.origin() == rtc->origin() &&
309            characterization.backendFormat() == rtc->asSurfaceProxy()->backendFormat() &&
310            characterization.width() == rtc->width() &&
311            characterization.height() == rtc->height() &&
312            characterization.colorType() == rtcColorType &&
313            characterization.sampleCount() == rtc->numSamples() &&
314            SkColorSpace::Equals(characterization.colorSpace(),
315                                 rtc->colorSpaceInfo().colorSpace()) &&
316            characterization.isProtected() == isProtected &&
317            characterization.surfaceProps() == rtc->surfaceProps();
318 }
319 
onDraw(const SkDeferredDisplayList * ddl)320 bool SkSurface_Gpu::onDraw(const SkDeferredDisplayList* ddl) {
321     if (!ddl || !this->isCompatible(ddl->characterization())) {
322         return false;
323     }
324 
325     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
326     GrContext* ctx = fDevice->context();
327 
328     ctx->priv().copyRenderTasksFromDDL(ddl, rtc->asRenderTargetProxy());
329     return true;
330 }
331 
332 
333 ///////////////////////////////////////////////////////////////////////////////
334 
Valid(const GrCaps * caps,const GrBackendFormat & format)335 bool SkSurface_Gpu::Valid(const GrCaps* caps, const GrBackendFormat& format) {
336     if (caps->isFormatSRGB(format)) {
337         return caps->srgbSupport();
338     }
339 
340     return true;
341 }
342 
MakeRenderTarget(GrRecordingContext * context,const SkSurfaceCharacterization & c,SkBudgeted budgeted)343 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* context,
344                                              const SkSurfaceCharacterization& c,
345                                              SkBudgeted budgeted) {
346     if (!context || !c.isValid()) {
347         return nullptr;
348     }
349 
350     const GrCaps* caps = context->priv().caps();
351 
352     if (c.usesGLFBO0()) {
353         // If we are making the surface we will never use FBO0.
354         return nullptr;
355     }
356 
357     if (c.vulkanSecondaryCBCompatible()) {
358         return nullptr;
359     }
360 
361     if (!SkSurface_Gpu::Valid(caps, c.backendFormat())) {
362         return nullptr;
363     }
364 
365     GrColorType grColorType = SkColorTypeToGrColorType(c.colorType());
366 
367     sk_sp<GrRenderTargetContext> rtc(context->priv().makeDeferredRenderTargetContext(
368             SkBackingFit::kExact,
369             c.width(),
370             c.height(),
371             grColorType,
372             c.refColorSpace(),
373             c.sampleCount(),
374             GrMipMapped(c.isMipMapped()),
375             c.origin(),
376             &c.surfaceProps(),
377             budgeted,
378             c.isProtected()));
379     if (!rtc) {
380         return nullptr;
381     }
382 
383     // CONTEXT TODO: remove this use of 'backdoor' to create an SkGpuDevice
384     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context->priv().backdoor(), std::move(rtc),
385                                                 c.width(), c.height(),
386                                                 SkGpuDevice::kClear_InitContents));
387     if (!device) {
388         return nullptr;
389     }
390 
391     sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
392 #ifdef SK_DEBUG
393     if (result) {
394         SkASSERT(result->isCompatible(c));
395     }
396 #endif
397 
398     return result;
399 }
400 
validate_backend_texture(const GrCaps * caps,const GrBackendTexture & tex,int sampleCnt,GrColorType grCT,bool texturable)401 static bool validate_backend_texture(const GrCaps* caps, const GrBackendTexture& tex,
402                                      int sampleCnt, GrColorType grCT,
403                                      bool texturable) {
404     if (!tex.isValid()) {
405         return false;
406     }
407 
408     GrBackendFormat backendFormat = tex.getBackendFormat();
409     if (!backendFormat.isValid()) {
410         return false;
411     }
412 
413     if (!caps->areColorTypeAndFormatCompatible(grCT, backendFormat)) {
414         return false;
415     }
416 
417     if (!caps->isFormatAsColorTypeRenderable(grCT, backendFormat, sampleCnt)) {
418         return false;
419     }
420 
421     if (texturable && !caps->isFormatTexturable(backendFormat)) {
422         return false;
423     }
424 
425     if (!SkSurface_Gpu::Valid(caps, backendFormat)) {
426         return false;
427     }
428 
429     return true;
430 }
431 
MakeFromBackendTexture(GrContext * context,const SkSurfaceCharacterization & c,const GrBackendTexture & backendTexture,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)432 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context,
433                                                    const SkSurfaceCharacterization& c,
434                                                    const GrBackendTexture& backendTexture,
435                                                    TextureReleaseProc textureReleaseProc,
436                                                    ReleaseContext releaseContext) {
437     if (!context || !c.isValid()) {
438         return nullptr;
439     }
440 
441     if (c.usesGLFBO0()) {
442         // If we are making the surface we will never use FBO0.
443         return nullptr;
444     }
445 
446     if (!c.isCompatible(backendTexture)) {
447         return nullptr;
448     }
449 
450     GrColorType grCT = SkColorTypeAndFormatToGrColorType(context->priv().caps(), c.colorType(),
451                                                          backendTexture.getBackendFormat());
452     if (grCT == GrColorType::kUnknown) {
453         return nullptr;
454     }
455 
456     if (!validate_backend_texture(context->priv().caps(), backendTexture,
457                                   c.sampleCount(), grCT, true)) {
458         return nullptr;
459     }
460 
461     sk_sp<GrRenderTargetContext> rtc(context->priv().makeBackendTextureRenderTargetContext(
462                 backendTexture, c.origin(), c.sampleCount(), grCT,
463                 c.refColorSpace(), &c.surfaceProps(), textureReleaseProc, releaseContext));
464     if (!rtc) {
465         return nullptr;
466     }
467 
468     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc),
469                                                 backendTexture.width(), backendTexture.height(),
470                                                 SkGpuDevice::kUninit_InitContents));
471     if (!device) {
472         return nullptr;
473     }
474 
475     sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
476 #ifdef SK_DEBUG
477     if (result) {
478         SkASSERT(result->isCompatible(c));
479     }
480 #endif
481 
482     return result;
483 }
484 
MakeRenderTarget(GrContext * ctx,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips)485 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
486                                              const SkImageInfo& info, int sampleCount,
487                                              GrSurfaceOrigin origin, const SkSurfaceProps* props,
488                                              bool shouldCreateWithMips) {
489     if (!ctx) {
490         return nullptr;
491     }
492     sampleCount = SkTMax(1, sampleCount);
493     GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
494 
495     if (!ctx->priv().caps()->mipMapSupport()) {
496         mipMapped = GrMipMapped::kNo;
497     }
498 
499     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
500             ctx, budgeted, info, sampleCount, origin, props, mipMapped,
501             SkGpuDevice::kClear_InitContents));
502     if (!device) {
503         return nullptr;
504     }
505     return sk_make_sp<SkSurface_Gpu>(std::move(device));
506 }
507 
MakeWrappedRenderTarget(GrContext * context,sk_sp<GrRenderTargetContext> rtc)508 sk_sp<SkSurface> SkSurface_Gpu::MakeWrappedRenderTarget(GrContext* context,
509                                                         sk_sp<GrRenderTargetContext> rtc) {
510     if (!context) {
511         return nullptr;
512     }
513 
514     int w = rtc->width();
515     int h = rtc->height();
516     sk_sp<SkGpuDevice> device(
517             SkGpuDevice::Make(context, std::move(rtc), w, h, SkGpuDevice::kUninit_InitContents));
518     if (!device) {
519         return nullptr;
520     }
521 
522     return sk_make_sp<SkSurface_Gpu>(std::move(device));
523 }
524 
MakeFromBackendTexture(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,SkSurface::TextureReleaseProc textureReleaseProc,SkSurface::ReleaseContext releaseContext)525 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
526                                                    GrSurfaceOrigin origin, int sampleCnt,
527                                                    SkColorType colorType,
528                                                    sk_sp<SkColorSpace> colorSpace,
529                                                    const SkSurfaceProps* props,
530                                                    SkSurface::TextureReleaseProc textureReleaseProc,
531                                                    SkSurface::ReleaseContext releaseContext) {
532     if (!context) {
533         return nullptr;
534     }
535     sampleCnt = SkTMax(1, sampleCnt);
536 
537     GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
538                                                                 tex.getBackendFormat());
539     if (grColorType == GrColorType::kUnknown) {
540         return nullptr;
541     }
542 
543     if (!validate_backend_texture(context->priv().caps(), tex, sampleCnt, grColorType, true)) {
544         return nullptr;
545     }
546 
547     sk_sp<GrRenderTargetContext> rtc(context->priv().makeBackendTextureRenderTargetContext(
548             tex, origin, sampleCnt, grColorType, std::move(colorSpace), props,
549             textureReleaseProc, releaseContext));
550     if (!rtc) {
551         return nullptr;
552     }
553 
554     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
555                                                 SkGpuDevice::kUninit_InitContents));
556     if (!device) {
557         return nullptr;
558     }
559     return sk_make_sp<SkSurface_Gpu>(std::move(device));
560 }
561 
onReplaceBackendTexture(const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,TextureReleaseProc releaseProc,ReleaseContext releaseContext)562 bool SkSurface_Gpu::onReplaceBackendTexture(const GrBackendTexture& backendTexture,
563                                             GrSurfaceOrigin origin, TextureReleaseProc releaseProc,
564                                             ReleaseContext releaseContext) {
565     auto context = this->fDevice->context();
566     if (context->abandoned()) {
567         return false;
568     }
569     if (!backendTexture.isValid()) {
570         return false;
571     }
572     if (backendTexture.width() != this->width() || backendTexture.height() != this->height()) {
573         return false;
574     }
575     auto* oldRTC = fDevice->accessRenderTargetContext();
576     auto oldProxy = sk_ref_sp(oldRTC->asTextureProxy());
577     if (!oldProxy) {
578         return false;
579     }
580     auto* oldTexture = oldProxy->peekTexture();
581     if (!oldTexture) {
582         return false;
583     }
584     if (!oldTexture->resourcePriv().refsWrappedObjects()) {
585         return false;
586     }
587     if (oldTexture->backendFormat() != backendTexture.getBackendFormat()) {
588         return false;
589     }
590     if (oldTexture->getBackendTexture().isSameTexture(backendTexture)) {
591         return false;
592     }
593     SkASSERT(oldTexture->asRenderTarget());
594     int sampleCnt = oldTexture->asRenderTarget()->numSamples();
595     GrColorType grColorType = SkColorTypeToGrColorType(this->getCanvas()->imageInfo().colorType());
596     auto colorSpace = sk_ref_sp(oldRTC->colorSpaceInfo().colorSpace());
597     if (!validate_backend_texture(context->priv().caps(), backendTexture,
598                                   sampleCnt, grColorType, true)) {
599         return false;
600     }
601     sk_sp<GrRenderTargetContext> rtc(context->priv().makeBackendTextureRenderTargetContext(
602             backendTexture,
603             origin,
604             sampleCnt,
605             oldRTC->colorSpaceInfo().colorType(),
606             std::move(colorSpace),
607             &this->props(),
608             releaseProc,
609             releaseContext));
610     if (!rtc) {
611         return false;
612     }
613     fDevice->replaceRenderTargetContext(std::move(rtc), true);
614     return true;
615 }
616 
validate_backend_render_target(const GrCaps * caps,const GrBackendRenderTarget & rt,GrColorType grCT)617 bool validate_backend_render_target(const GrCaps* caps, const GrBackendRenderTarget& rt,
618                                     GrColorType grCT) {
619     if (!caps->areColorTypeAndFormatCompatible(grCT, rt.getBackendFormat())) {
620         return false;
621     }
622 
623     if (!caps->isFormatAsColorTypeRenderable(grCT, rt.getBackendFormat(), rt.sampleCnt())) {
624         return false;
625     }
626     if (!SkSurface_Gpu::Valid(caps, rt.getBackendFormat())) {
627         return false;
628     }
629 
630     return true;
631 }
632 
MakeFromBackendRenderTarget(GrContext * context,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,SkSurface::RenderTargetReleaseProc relProc,SkSurface::ReleaseContext releaseContext)633 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
634                                                         const GrBackendRenderTarget& rt,
635                                                         GrSurfaceOrigin origin,
636                                                         SkColorType colorType,
637                                                         sk_sp<SkColorSpace> colorSpace,
638                                                         const SkSurfaceProps* props,
639                                                         SkSurface::RenderTargetReleaseProc relProc,
640                                                         SkSurface::ReleaseContext releaseContext) {
641     if (!context) {
642         return nullptr;
643     }
644 
645     GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
646                                                                 rt.getBackendFormat());
647     if (grColorType == GrColorType::kUnknown) {
648         return nullptr;
649     }
650 
651     if (!validate_backend_render_target(context->priv().caps(), rt, grColorType)) {
652         return nullptr;
653     }
654 
655     sk_sp<GrRenderTargetContext> rtc(context->priv().makeBackendRenderTargetRenderTargetContext(
656             rt, origin, grColorType, std::move(colorSpace), props, relProc, releaseContext));
657     if (!rtc) {
658         return nullptr;
659     }
660 
661     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), rt.width(), rt.height(),
662                                                 SkGpuDevice::kUninit_InitContents));
663     if (!device) {
664         return nullptr;
665     }
666 
667     return sk_make_sp<SkSurface_Gpu>(std::move(device));
668 }
669 
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)670 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
671                                                                  const GrBackendTexture& tex,
672                                                                  GrSurfaceOrigin origin,
673                                                                  int sampleCnt,
674                                                                  SkColorType colorType,
675                                                                  sk_sp<SkColorSpace> colorSpace,
676                                                                  const SkSurfaceProps* props) {
677     if (!context) {
678         return nullptr;
679     }
680 
681     sampleCnt = SkTMax(1, sampleCnt);
682     GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
683                                                                 tex.getBackendFormat());
684     if (grColorType == GrColorType::kUnknown) {
685         return nullptr;
686     }
687     if (!validate_backend_texture(context->priv().caps(), tex, sampleCnt, grColorType, false)) {
688         return nullptr;
689     }
690 
691     sk_sp<GrRenderTargetContext> rtc(
692             context->priv().makeBackendTextureAsRenderTargetRenderTargetContext(
693                     tex,
694                     origin,
695                     sampleCnt,
696                     grColorType,
697                     std::move(colorSpace),
698                     props));
699     if (!rtc) {
700         return nullptr;
701     }
702 
703     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
704                                                 SkGpuDevice::kUninit_InitContents));
705     if (!device) {
706         return nullptr;
707     }
708     return sk_make_sp<SkSurface_Gpu>(std::move(device));
709 }
710 
711 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(GrContext * context,AHardwareBuffer * hardwareBuffer,GrSurfaceOrigin origin,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps)712 sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrContext* context,
713                                                     AHardwareBuffer* hardwareBuffer,
714                                                     GrSurfaceOrigin origin,
715                                                     sk_sp<SkColorSpace> colorSpace,
716                                                     const SkSurfaceProps* surfaceProps) {
717     AHardwareBuffer_Desc bufferDesc;
718     AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
719 
720     if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT)) {
721         return nullptr;
722     }
723 
724     bool isTextureable = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE);
725     bool isProtectedContent = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
726 
727     // We currently don't support protected content
728     if (isProtectedContent) {
729         SkDebugf("We currently don't support protected content on android\n");
730         return nullptr;
731     }
732 
733     GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(context,
734                                                                              hardwareBuffer,
735                                                                              bufferDesc.format,
736                                                                              true);
737     if (!backendFormat.isValid()) {
738         return nullptr;
739     }
740 
741     if (isTextureable) {
742         GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
743         GrAHardwareBufferUtils::UpdateImageProc updateImageProc = nullptr;
744         GrAHardwareBufferUtils::TexImageCtx deleteImageCtx = nullptr;
745 
746         GrBackendTexture backendTexture =
747                 GrAHardwareBufferUtils::MakeBackendTexture(context, hardwareBuffer,
748                                                            bufferDesc.width, bufferDesc.height,
749                                                            &deleteImageProc, &updateImageProc,
750                                                            &deleteImageCtx, isProtectedContent,
751                                                            backendFormat, true);
752         if (!backendTexture.isValid()) {
753             return nullptr;
754         }
755 
756         SkColorType colorType =
757                 GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
758 
759         sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, backendTexture,
760                 origin, 0, colorType, std::move(colorSpace), surfaceProps, deleteImageProc,
761                 deleteImageCtx);
762 
763         if (!surface) {
764             SkASSERT(deleteImageProc);
765             deleteImageProc(deleteImageCtx);
766         }
767         return surface;
768     } else {
769         return nullptr;
770     }
771 }
772 #endif
773 
774 #endif
775