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