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->colorInfo().colorType(),
108                                         rtc->mipMapped(), *subset, 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->colorInfo().colorType(),
116                                         rtc->mipMapped(), 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,
136                                                 const SkIRect& srcRect,
137                                                 RescaleGamma rescaleGamma,
138                                                 SkFilterQuality rescaleQuality,
139                                                 ReadPixelsCallback callback,
140                                                 ReadPixelsContext context) {
141     auto* rtc = this->fDevice->accessRenderTargetContext();
142     rtc->asyncRescaleAndReadPixels(info, srcRect, rescaleGamma, rescaleQuality, callback, context);
143 }
144 
onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallback callback,ReadPixelsContext context)145 void SkSurface_Gpu::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
146                                                       sk_sp<SkColorSpace> dstColorSpace,
147                                                       const SkIRect& srcRect,
148                                                       const SkISize& dstSize,
149                                                       RescaleGamma rescaleGamma,
150                                                       SkFilterQuality rescaleQuality,
151                                                       ReadPixelsCallback callback,
152                                                       ReadPixelsContext context) {
153     auto* rtc = this->fDevice->accessRenderTargetContext();
154     rtc->asyncRescaleAndReadPixelsYUV420(yuvColorSpace,
155                                          std::move(dstColorSpace),
156                                          srcRect,
157                                          dstSize,
158                                          rescaleGamma,
159                                          rescaleQuality,
160                                          callback,
161                                          context);
162 }
163 
164 // Create a new render target and, if necessary, copy the contents of the old
165 // render target into it. Note that this flushes the SkGpuDevice but
166 // doesn't force an OpenGL flush.
onCopyOnWrite(ContentChangeMode mode)167 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
168     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
169 
170     // are we sharing our backing proxy with the image? Note this call should never create a new
171     // image because onCopyOnWrite is only called when there is a cached image.
172     sk_sp<SkImage> image(this->refCachedImage());
173     SkASSERT(image);
174 
175     GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
176     SkASSERT(imageProxy);
177 
178     if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
179         fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
180     } else if (kDiscard_ContentChangeMode == mode) {
181         this->SkSurface_Gpu::onDiscard();
182     }
183 }
184 
onDiscard()185 void SkSurface_Gpu::onDiscard() {
186     fDevice->accessRenderTargetContext()->discard();
187 }
188 
onFlush(BackendSurfaceAccess access,const GrFlushInfo & info)189 GrSemaphoresSubmitted SkSurface_Gpu::onFlush(BackendSurfaceAccess access,
190                                              const GrFlushInfo& info) {
191     return fDevice->flush(access, info);
192 }
193 
onWait(int numSemaphores,const GrBackendSemaphore * waitSemaphores)194 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
195     return fDevice->wait(numSemaphores, waitSemaphores);
196 }
197 
onCharacterize(SkSurfaceCharacterization * characterization) const198 bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* characterization) const {
199     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
200     GrContext* ctx = fDevice->context();
201 
202     size_t maxResourceBytes = ctx->getResourceCacheLimit();
203 
204     bool mipmapped = rtc->asTextureProxy() ? GrMipMapped::kYes == rtc->asTextureProxy()->mipMapped()
205                                            : false;
206 
207     SkColorType ct = GrColorTypeToSkColorType(rtc->colorInfo().colorType());
208     if (ct == kUnknown_SkColorType) {
209         return false;
210     }
211 
212     bool usesGLFBO0 = rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0();
213     // We should never get in the situation where we have a texture render target that is also
214     // backend by FBO 0.
215     SkASSERT(!usesGLFBO0 || !SkToBool(rtc->asTextureProxy()));
216 
217     SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType,
218                                        rtc->colorInfo().refColorSpace());
219 
220     GrBackendFormat format = rtc->asSurfaceProxy()->backendFormat();
221 
222     characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, format,
223                           rtc->origin(), rtc->numSamples(),
224                           SkSurfaceCharacterization::Textureable(SkToBool(rtc->asTextureProxy())),
225                           SkSurfaceCharacterization::MipMapped(mipmapped),
226                           SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0),
227                           SkSurfaceCharacterization::VulkanSecondaryCBCompatible(false),
228                           GrProtected(rtc->asRenderTargetProxy()->isProtected()),
229                           this->props());
230     return true;
231 }
232 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint)233 void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
234     // If the dst is also GPU we try to not force a new image snapshot (by calling the base class
235     // onDraw) since that may not always perform the copy-on-write optimization.
236     auto tryDraw = [&] {
237         SkASSERT(fDevice->context()->priv().asDirectContext());
238         GrContext* context = fDevice->context();
239         GrContext* canvasContext = canvas->getGrContext();
240         if (!canvasContext) {
241             return false;
242         }
243         if (!canvasContext->priv().asDirectContext() ||
244             canvasContext->priv().contextID() != context->priv().contextID()) {
245             return false;
246         }
247         GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
248         if (!rtc) {
249             return false;
250         }
251         sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
252         if (!srcProxy) {
253             return false;
254         }
255         // Possibly we could skip making an image here if SkGpuDevice exposed a lower level way
256         // of drawing a texture proxy.
257         const SkImageInfo info = fDevice->imageInfo();
258         sk_sp<SkImage> image;
259         image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, info.alphaType(),
260                                         std::move(srcProxy), info.refColorSpace());
261         canvas->drawImage(image, x, y, paint);
262         return true;
263     };
264     if (!tryDraw()) {
265         INHERITED::onDraw(canvas, x, y, paint);
266     }
267 }
268 
onIsCompatible(const SkSurfaceCharacterization & characterization) const269 bool SkSurface_Gpu::onIsCompatible(const SkSurfaceCharacterization& characterization) const {
270     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
271     GrContext* ctx = fDevice->context();
272 
273     if (!characterization.isValid()) {
274         return false;
275     }
276 
277     if (characterization.vulkanSecondaryCBCompatible()) {
278         return false;
279     }
280 
281     // As long as the current state if the context allows for greater or equal resources,
282     // we allow the DDL to be replayed.
283     // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
284     size_t maxResourceBytes = ctx->getResourceCacheLimit();
285 
286     if (characterization.isTextureable()) {
287         if (!rtc->asTextureProxy()) {
288             // If the characterization was textureable we require the replay dest to also be
289             // textureable. If the characterized surface wasn't textureable we allow the replay
290             // dest to be textureable.
291             return false;
292         }
293 
294         if (characterization.isMipMapped() &&
295             GrMipMapped::kNo == rtc->asTextureProxy()->mipMapped()) {
296             // Fail if the DDL's surface was mipmapped but the replay surface is not.
297             // Allow drawing to proceed if the DDL was not mipmapped but the replay surface is.
298             return false;
299         }
300     }
301 
302     if (characterization.usesGLFBO0() != rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0()) {
303         return false;
304     }
305 
306     SkColorType rtcColorType = GrColorTypeToSkColorType(rtc->colorInfo().colorType());
307     if (rtcColorType == kUnknown_SkColorType) {
308         return false;
309     }
310 
311     GrProtected isProtected = GrProtected(rtc->asSurfaceProxy()->isProtected());
312 
313     return characterization.contextInfo() && characterization.contextInfo()->priv().matches(ctx) &&
314            characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
315            characterization.origin() == rtc->origin() &&
316            characterization.backendFormat() == rtc->asSurfaceProxy()->backendFormat() &&
317            characterization.width() == rtc->width() && characterization.height() == rtc->height() &&
318            characterization.colorType() == rtcColorType &&
319            characterization.sampleCount() == rtc->numSamples() &&
320            SkColorSpace::Equals(characterization.colorSpace(), rtc->colorInfo().colorSpace()) &&
321            characterization.isProtected() == isProtected &&
322            characterization.surfaceProps() == rtc->surfaceProps();
323 }
324 
onDraw(const SkDeferredDisplayList * ddl)325 bool SkSurface_Gpu::onDraw(const SkDeferredDisplayList* ddl) {
326     if (!ddl || !this->isCompatible(ddl->characterization())) {
327         return false;
328     }
329 
330     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
331     GrContext* ctx = fDevice->context();
332 
333     ctx->priv().copyRenderTasksFromDDL(ddl, rtc->asRenderTargetProxy());
334     return true;
335 }
336 
337 
338 ///////////////////////////////////////////////////////////////////////////////
339 
MakeRenderTarget(GrRecordingContext * context,const SkSurfaceCharacterization & c,SkBudgeted budgeted)340 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* context,
341                                              const SkSurfaceCharacterization& c,
342                                              SkBudgeted budgeted) {
343     if (!context || !c.isValid()) {
344         return nullptr;
345     }
346 
347     if (c.usesGLFBO0()) {
348         // If we are making the surface we will never use FBO0.
349         return nullptr;
350     }
351 
352     if (c.vulkanSecondaryCBCompatible()) {
353         return nullptr;
354     }
355 
356     GrColorType grColorType = SkColorTypeToGrColorType(c.colorType());
357 
358     auto rtc = context->priv().makeDeferredRenderTargetContext(SkBackingFit::kExact,
359                                                                c.width(),
360                                                                c.height(),
361                                                                grColorType,
362                                                                c.refColorSpace(),
363                                                                c.sampleCount(),
364                                                                GrMipMapped(c.isMipMapped()),
365                                                                c.origin(),
366                                                                &c.surfaceProps(),
367                                                                budgeted,
368                                                                c.isProtected());
369     if (!rtc) {
370         return nullptr;
371     }
372 
373     // CONTEXT TODO: remove this use of 'backdoor' to create an SkGpuDevice
374     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context->priv().backdoor(), std::move(rtc),
375                                                 SkGpuDevice::kClear_InitContents));
376     if (!device) {
377         return nullptr;
378     }
379 
380     sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
381 #ifdef SK_DEBUG
382     if (result) {
383         SkASSERT(result->isCompatible(c));
384     }
385 #endif
386 
387     return result;
388 }
389 
validate_backend_texture(const GrCaps * caps,const GrBackendTexture & tex,int sampleCnt,GrColorType grCT,bool texturable)390 static bool validate_backend_texture(const GrCaps* caps, const GrBackendTexture& tex,
391                                      int sampleCnt, GrColorType grCT,
392                                      bool texturable) {
393     if (!tex.isValid()) {
394         return false;
395     }
396 
397     GrBackendFormat backendFormat = tex.getBackendFormat();
398     if (!backendFormat.isValid()) {
399         return false;
400     }
401 
402     if (!caps->areColorTypeAndFormatCompatible(grCT, backendFormat)) {
403         return false;
404     }
405 
406     if (!caps->isFormatAsColorTypeRenderable(grCT, backendFormat, sampleCnt)) {
407         return false;
408     }
409 
410     if (texturable && !caps->isFormatTexturable(backendFormat)) {
411         return false;
412     }
413 
414     return true;
415 }
416 
MakeFromBackendTexture(GrContext * context,const SkSurfaceCharacterization & c,const GrBackendTexture & backendTexture,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)417 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context,
418                                                    const SkSurfaceCharacterization& c,
419                                                    const GrBackendTexture& backendTexture,
420                                                    TextureReleaseProc textureReleaseProc,
421                                                    ReleaseContext releaseContext) {
422     if (!context || !c.isValid()) {
423         return nullptr;
424     }
425 
426     if (c.usesGLFBO0()) {
427         // If we are making the surface we will never use FBO0.
428         return nullptr;
429     }
430 
431     if (!c.isCompatible(backendTexture)) {
432         return nullptr;
433     }
434 
435     GrColorType grCT = SkColorTypeAndFormatToGrColorType(context->priv().caps(), c.colorType(),
436                                                          backendTexture.getBackendFormat());
437     if (grCT == GrColorType::kUnknown) {
438         return nullptr;
439     }
440 
441     if (!validate_backend_texture(context->priv().caps(), backendTexture,
442                                   c.sampleCount(), grCT, true)) {
443         return nullptr;
444     }
445 
446     auto rtc = context->priv().makeBackendTextureRenderTargetContext(
447             backendTexture, c.origin(), c.sampleCount(), grCT, c.refColorSpace(), &c.surfaceProps(),
448             textureReleaseProc, releaseContext);
449     if (!rtc) {
450         return nullptr;
451     }
452 
453     auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
454     if (!device) {
455         return nullptr;
456     }
457 
458     sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
459 #ifdef SK_DEBUG
460     if (result) {
461         SkASSERT(result->isCompatible(c));
462     }
463 #endif
464 
465     return result;
466 }
467 
MakeRenderTarget(GrContext * ctx,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips)468 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
469                                              const SkImageInfo& info, int sampleCount,
470                                              GrSurfaceOrigin origin, const SkSurfaceProps* props,
471                                              bool shouldCreateWithMips) {
472     if (!ctx) {
473         return nullptr;
474     }
475     sampleCount = SkTMax(1, sampleCount);
476     GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
477 
478     if (!ctx->priv().caps()->mipMapSupport()) {
479         mipMapped = GrMipMapped::kNo;
480     }
481 
482     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
483             ctx, budgeted, info, sampleCount, origin, props, mipMapped,
484             SkGpuDevice::kClear_InitContents));
485     if (!device) {
486         return nullptr;
487     }
488     return sk_make_sp<SkSurface_Gpu>(std::move(device));
489 }
490 
MakeWrappedRenderTarget(GrContext * context,std::unique_ptr<GrRenderTargetContext> rtc)491 sk_sp<SkSurface> SkSurface_Gpu::MakeWrappedRenderTarget(
492         GrContext* context, std::unique_ptr<GrRenderTargetContext> rtc) {
493     if (!context) {
494         return nullptr;
495     }
496 
497     auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
498     if (!device) {
499         return nullptr;
500     }
501 
502     return sk_make_sp<SkSurface_Gpu>(std::move(device));
503 }
504 
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)505 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
506                                                    GrSurfaceOrigin origin, int sampleCnt,
507                                                    SkColorType colorType,
508                                                    sk_sp<SkColorSpace> colorSpace,
509                                                    const SkSurfaceProps* props,
510                                                    SkSurface::TextureReleaseProc textureReleaseProc,
511                                                    SkSurface::ReleaseContext releaseContext) {
512     if (!context) {
513         return nullptr;
514     }
515     sampleCnt = SkTMax(1, sampleCnt);
516 
517     GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
518                                                                 tex.getBackendFormat());
519     if (grColorType == GrColorType::kUnknown) {
520         return nullptr;
521     }
522 
523     if (!validate_backend_texture(context->priv().caps(), tex, sampleCnt, grColorType, true)) {
524         return nullptr;
525     }
526 
527     auto rtc = context->priv().makeBackendTextureRenderTargetContext(
528             tex, origin, sampleCnt, grColorType, std::move(colorSpace), props, textureReleaseProc,
529             releaseContext);
530     if (!rtc) {
531         return nullptr;
532     }
533 
534     auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
535     if (!device) {
536         return nullptr;
537     }
538     return sk_make_sp<SkSurface_Gpu>(std::move(device));
539 }
540 
onReplaceBackendTexture(const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,TextureReleaseProc releaseProc,ReleaseContext releaseContext)541 bool SkSurface_Gpu::onReplaceBackendTexture(const GrBackendTexture& backendTexture,
542                                             GrSurfaceOrigin origin, TextureReleaseProc releaseProc,
543                                             ReleaseContext releaseContext) {
544     auto context = this->fDevice->context();
545     if (context->abandoned()) {
546         return false;
547     }
548     if (!backendTexture.isValid()) {
549         return false;
550     }
551     if (backendTexture.width() != this->width() || backendTexture.height() != this->height()) {
552         return false;
553     }
554     auto* oldRTC = fDevice->accessRenderTargetContext();
555     auto oldProxy = sk_ref_sp(oldRTC->asTextureProxy());
556     if (!oldProxy) {
557         return false;
558     }
559     auto* oldTexture = oldProxy->peekTexture();
560     if (!oldTexture) {
561         return false;
562     }
563     if (!oldTexture->resourcePriv().refsWrappedObjects()) {
564         return false;
565     }
566     if (oldTexture->backendFormat() != backendTexture.getBackendFormat()) {
567         return false;
568     }
569     if (oldTexture->getBackendTexture().isSameTexture(backendTexture)) {
570         return false;
571     }
572     SkASSERT(oldTexture->asRenderTarget());
573     int sampleCnt = oldTexture->asRenderTarget()->numSamples();
574     GrColorType grColorType = SkColorTypeToGrColorType(this->getCanvas()->imageInfo().colorType());
575     auto colorSpace = sk_ref_sp(oldRTC->colorInfo().colorSpace());
576     if (!validate_backend_texture(context->priv().caps(), backendTexture,
577                                   sampleCnt, grColorType, true)) {
578         return false;
579     }
580     auto rtc =
581             context->priv().makeBackendTextureRenderTargetContext(backendTexture,
582                                                                   origin,
583                                                                   sampleCnt,
584                                                                   oldRTC->colorInfo().colorType(),
585                                                                   std::move(colorSpace),
586                                                                   &this->props(),
587                                                                   releaseProc,
588                                                                   releaseContext);
589     if (!rtc) {
590         return false;
591     }
592     fDevice->replaceRenderTargetContext(std::move(rtc), true);
593     return true;
594 }
595 
validate_backend_render_target(const GrCaps * caps,const GrBackendRenderTarget & rt,GrColorType grCT)596 bool validate_backend_render_target(const GrCaps* caps, const GrBackendRenderTarget& rt,
597                                     GrColorType grCT) {
598     if (!caps->areColorTypeAndFormatCompatible(grCT, rt.getBackendFormat())) {
599         return false;
600     }
601 
602     if (!caps->isFormatAsColorTypeRenderable(grCT, rt.getBackendFormat(), rt.sampleCnt())) {
603         return false;
604     }
605     return true;
606 }
607 
MakeFromBackendRenderTarget(GrContext * context,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,SkSurface::RenderTargetReleaseProc relProc,SkSurface::ReleaseContext releaseContext)608 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
609                                                         const GrBackendRenderTarget& rt,
610                                                         GrSurfaceOrigin origin,
611                                                         SkColorType colorType,
612                                                         sk_sp<SkColorSpace> colorSpace,
613                                                         const SkSurfaceProps* props,
614                                                         SkSurface::RenderTargetReleaseProc relProc,
615                                                         SkSurface::ReleaseContext releaseContext) {
616     if (!context) {
617         return nullptr;
618     }
619 
620     GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
621                                                                 rt.getBackendFormat());
622     if (grColorType == GrColorType::kUnknown) {
623         return nullptr;
624     }
625 
626     if (!validate_backend_render_target(context->priv().caps(), rt, grColorType)) {
627         return nullptr;
628     }
629 
630     auto rtc = context->priv().makeBackendRenderTargetRenderTargetContext(
631             rt, origin, grColorType, std::move(colorSpace), props, relProc, releaseContext);
632     if (!rtc) {
633         return nullptr;
634     }
635 
636     auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
637     if (!device) {
638         return nullptr;
639     }
640 
641     return sk_make_sp<SkSurface_Gpu>(std::move(device));
642 }
643 
MakeFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props)644 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
645                                                                  const GrBackendTexture& tex,
646                                                                  GrSurfaceOrigin origin,
647                                                                  int sampleCnt,
648                                                                  SkColorType colorType,
649                                                                  sk_sp<SkColorSpace> colorSpace,
650                                                                  const SkSurfaceProps* props) {
651     if (!context) {
652         return nullptr;
653     }
654 
655     sampleCnt = SkTMax(1, sampleCnt);
656     GrColorType grColorType = SkColorTypeAndFormatToGrColorType(context->priv().caps(), colorType,
657                                                                 tex.getBackendFormat());
658     if (grColorType == GrColorType::kUnknown) {
659         return nullptr;
660     }
661     if (!validate_backend_texture(context->priv().caps(), tex, sampleCnt, grColorType, false)) {
662         return nullptr;
663     }
664 
665     auto rtc = context->priv().makeBackendTextureAsRenderTargetRenderTargetContext(
666             tex, origin, sampleCnt, grColorType, std::move(colorSpace), props);
667     if (!rtc) {
668         return nullptr;
669     }
670 
671     auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents);
672     if (!device) {
673         return nullptr;
674     }
675     return sk_make_sp<SkSurface_Gpu>(std::move(device));
676 }
677 
678 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(GrContext * context,AHardwareBuffer * hardwareBuffer,GrSurfaceOrigin origin,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps)679 sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrContext* context,
680                                                     AHardwareBuffer* hardwareBuffer,
681                                                     GrSurfaceOrigin origin,
682                                                     sk_sp<SkColorSpace> colorSpace,
683                                                     const SkSurfaceProps* surfaceProps) {
684     AHardwareBuffer_Desc bufferDesc;
685     AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
686 
687     if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT)) {
688         return nullptr;
689     }
690 
691     bool isTextureable = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE);
692     bool isProtectedContent = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
693 
694     // We currently don't support protected content
695     if (isProtectedContent) {
696         SkDebugf("We currently don't support protected content on android\n");
697         return nullptr;
698     }
699 
700     GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(context,
701                                                                              hardwareBuffer,
702                                                                              bufferDesc.format,
703                                                                              true);
704     if (!backendFormat.isValid()) {
705         return nullptr;
706     }
707 
708     if (isTextureable) {
709         GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
710         GrAHardwareBufferUtils::UpdateImageProc updateImageProc = nullptr;
711         GrAHardwareBufferUtils::TexImageCtx deleteImageCtx = nullptr;
712 
713         GrBackendTexture backendTexture =
714                 GrAHardwareBufferUtils::MakeBackendTexture(context, hardwareBuffer,
715                                                            bufferDesc.width, bufferDesc.height,
716                                                            &deleteImageProc, &updateImageProc,
717                                                            &deleteImageCtx, isProtectedContent,
718                                                            backendFormat, true);
719         if (!backendTexture.isValid()) {
720             return nullptr;
721         }
722 
723         SkColorType colorType =
724                 GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
725 
726         sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, backendTexture,
727                 origin, 0, colorType, std::move(colorSpace), surfaceProps, deleteImageProc,
728                 deleteImageCtx);
729 
730         if (!surface) {
731             SkASSERT(deleteImageProc);
732             deleteImageProc(deleteImageCtx);
733         }
734         return surface;
735     } else {
736         return nullptr;
737     }
738 }
739 #endif
740 
741 #endif
742