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