• 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         return GrSemaphoresSubmitted::kNo;
223     }
224 
225     GrRenderTargetProxy* rtp = fDevice->targetProxy();
226 
227     return dContext->priv().flushSurface(rtp, access, info, newState);
228 }
229 
onWait(int numSemaphores,const GrBackendSemaphore * waitSemaphores,bool deleteSemaphoresAfterWait)230 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores,
231                            bool deleteSemaphoresAfterWait) {
232     return fDevice->wait(numSemaphores, waitSemaphores, deleteSemaphoresAfterWait);
233 }
234 
onCharacterize(SkSurfaceCharacterization * characterization) const235 bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* characterization) const {
236     auto direct = fDevice->recordingContext()->asDirectContext();
237     if (!direct) {
238         return false;
239     }
240 
241     SkImageInfo ii = fDevice->imageInfo();
242     if (ii.colorType() == kUnknown_SkColorType) {
243         return false;
244     }
245 
246     GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView();
247     size_t maxResourceBytes = direct->getResourceCacheLimit();
248 
249     bool mipmapped = readSurfaceView.asTextureProxy()
250                             ? GrMipmapped::kYes == readSurfaceView.asTextureProxy()->mipmapped()
251                             : false;
252 
253     bool usesGLFBO0 = readSurfaceView.asRenderTargetProxy()->glRTFBOIDIs0();
254     // We should never get in the situation where we have a texture render target that is also
255     // backend by FBO 0.
256     SkASSERT(!usesGLFBO0 || !SkToBool(readSurfaceView.asTextureProxy()));
257 
258     bool vkRTSupportsInputAttachment =
259                             readSurfaceView.asRenderTargetProxy()->supportsVkInputAttachment();
260 
261     GrBackendFormat format = readSurfaceView.proxy()->backendFormat();
262     int numSamples = readSurfaceView.asRenderTargetProxy()->numSamples();
263     GrProtected isProtected = readSurfaceView.asRenderTargetProxy()->isProtected();
264 
265     characterization->set(
266             direct->threadSafeProxy(),
267             maxResourceBytes,
268             ii,
269             format,
270             readSurfaceView.origin(),
271             numSamples,
272             SkSurfaceCharacterization::Textureable(SkToBool(readSurfaceView.asTextureProxy())),
273             SkSurfaceCharacterization::MipMapped(mipmapped),
274             SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0),
275             SkSurfaceCharacterization::VkRTSupportsInputAttachment(vkRTSupportsInputAttachment),
276             SkSurfaceCharacterization::VulkanSecondaryCBCompatible(false),
277             isProtected,
278             this->props());
279     return true;
280 }
281 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)282 void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
283                            const SkSamplingOptions& sampling, const SkPaint* paint) {
284     // If the dst is also GPU we try to not force a new image snapshot (by calling the base class
285     // onDraw) since that may not always perform the copy-on-write optimization.
286     auto tryDraw = [&] {
287         auto surfaceContext = fDevice->recordingContext();
288         auto canvasContext = GrAsDirectContext(canvas->recordingContext());
289         if (!canvasContext) {
290             return false;
291         }
292         if (canvasContext->priv().contextID() != surfaceContext->priv().contextID()) {
293             return false;
294         }
295         GrSurfaceProxyView srcView = fDevice->readSurfaceView();
296         if (!srcView.asTextureProxyRef()) {
297             return false;
298         }
299         // Possibly we could skip making an image here if SkGpuDevice exposed a lower level way
300         // of drawing a texture proxy.
301         const SkImageInfo info = fDevice->imageInfo();
302         sk_sp<SkImage> image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(canvasContext),
303                                                        kNeedNewImageUniqueID,
304                                                        std::move(srcView),
305                                                        info.colorInfo());
306         canvas->drawImage(image.get(), x, y, sampling, paint);
307         return true;
308     };
309     if (!tryDraw()) {
310         INHERITED::onDraw(canvas, x, y, sampling, paint);
311     }
312 }
313 
onIsCompatible(const SkSurfaceCharacterization & characterization) const314 bool SkSurface_Gpu::onIsCompatible(const SkSurfaceCharacterization& characterization) const {
315     auto direct = fDevice->recordingContext()->asDirectContext();
316     if (!direct) {
317         return false;
318     }
319 
320     if (!characterization.isValid()) {
321         return false;
322     }
323 
324     if (characterization.vulkanSecondaryCBCompatible()) {
325         return false;
326     }
327 
328     SkImageInfo ii = fDevice->imageInfo();
329     if (ii.colorType() == kUnknown_SkColorType) {
330         return false;
331     }
332 
333     GrSurfaceProxyView targetView = fDevice->readSurfaceView();
334     // As long as the current state if the context allows for greater or equal resources,
335     // we allow the DDL to be replayed.
336     // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
337     size_t maxResourceBytes = direct->getResourceCacheLimit();
338 
339     if (characterization.isTextureable()) {
340         if (!targetView.asTextureProxy()) {
341             // If the characterization was textureable we require the replay dest to also be
342             // textureable. If the characterized surface wasn't textureable we allow the replay
343             // dest to be textureable.
344             return false;
345         }
346 
347         if (characterization.isMipMapped() &&
348             GrMipmapped::kNo == targetView.asTextureProxy()->mipmapped()) {
349             // Fail if the DDL's surface was mipmapped but the replay surface is not.
350             // Allow drawing to proceed if the DDL was not mipmapped but the replay surface is.
351             return false;
352         }
353     }
354 
355     if (characterization.usesGLFBO0() != targetView.asRenderTargetProxy()->glRTFBOIDIs0()) {
356         // FBO0-ness effects how MSAA and window rectangles work. If the characterization was
357         // tagged as FBO0 it would never have been allowed to use window rectangles. If MSAA
358         // was also never used then a DDL recorded with this characterization should be replayable
359         // on a non-FBO0 surface.
360         if (!characterization.usesGLFBO0() || characterization.sampleCount() > 1) {
361             return false;
362         }
363     }
364 
365     GrBackendFormat format = targetView.asRenderTargetProxy()->backendFormat();
366     int numSamples = targetView.asRenderTargetProxy()->numSamples();
367     GrProtected isProtected = targetView.proxy()->isProtected();
368 
369     return characterization.contextInfo() &&
370            characterization.contextInfo()->priv().matches(direct) &&
371            characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
372            characterization.origin() == targetView.origin() &&
373            characterization.backendFormat() == format &&
374            characterization.width() == ii.width() &&
375            characterization.height() == ii.height() &&
376            characterization.colorType() == ii.colorType() &&
377            characterization.sampleCount() == numSamples &&
378            SkColorSpace::Equals(characterization.colorSpace(), ii.colorInfo().colorSpace()) &&
379            characterization.isProtected() == isProtected &&
380            characterization.surfaceProps() == fDevice->surfaceProps();
381 }
382 
onDraw(sk_sp<const SkDeferredDisplayList> ddl,SkIPoint offset)383 bool SkSurface_Gpu::onDraw(sk_sp<const SkDeferredDisplayList> ddl, SkIPoint offset) {
384     if (!ddl || !this->isCompatible(ddl->characterization())) {
385         return false;
386     }
387 
388     auto direct = fDevice->recordingContext()->asDirectContext();
389     if (!direct) {
390         return false;
391     }
392 
393     GrSurfaceProxyView view = fDevice->readSurfaceView();
394 
395     direct->priv().createDDLTask(std::move(ddl), view.asRenderTargetProxyRef(), offset);
396     return true;
397 }
398 
399 ///////////////////////////////////////////////////////////////////////////////
400 
MakeRenderTarget(GrRecordingContext * rContext,const SkSurfaceCharacterization & c,SkBudgeted budgeted)401 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* rContext,
402                                              const SkSurfaceCharacterization& c,
403                                              SkBudgeted budgeted) {
404     if (!rContext || !c.isValid()) {
405         return nullptr;
406     }
407 
408     if (c.usesGLFBO0()) {
409         // If we are making the surface we will never use FBO0.
410         return nullptr;
411     }
412 
413     if (c.vulkanSecondaryCBCompatible()) {
414         return nullptr;
415     }
416 
417     auto device = rContext->priv().createDevice(budgeted, c.imageInfo(), SkBackingFit::kExact,
418                                                 c.sampleCount(), GrMipmapped(c.isMipMapped()),
419                                                 c.isProtected(), c.origin(), c.surfaceProps(),
420                                                 skgpu::BaseDevice::InitContents::kClear);
421     if (!device) {
422         return nullptr;
423     }
424 
425     sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
426 #ifdef SK_DEBUG
427     if (result) {
428         SkASSERT(result->isCompatible(c));
429     }
430 #endif
431 
432     return result;
433 }
434 
validate_backend_texture(const GrCaps * caps,const GrBackendTexture & tex,int sampleCnt,GrColorType grCT,bool texturable)435 static bool validate_backend_texture(const GrCaps* caps, const GrBackendTexture& tex,
436                                      int sampleCnt, GrColorType grCT,
437                                      bool texturable) {
438     if (!tex.isValid()) {
439         return false;
440     }
441 
442     GrBackendFormat backendFormat = tex.getBackendFormat();
443     if (!backendFormat.isValid()) {
444         return false;
445     }
446 
447     if (!caps->areColorTypeAndFormatCompatible(grCT, backendFormat)) {
448         return false;
449     }
450 
451     if (!caps->isFormatAsColorTypeRenderable(grCT, backendFormat, sampleCnt)) {
452         return false;
453     }
454 
455     if (texturable && !caps->isFormatTexturable(backendFormat, tex.textureType())) {
456         return false;
457     }
458 
459     return true;
460 }
461 
MakeRenderTarget(GrRecordingContext * rContext,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips)462 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* rContext, SkBudgeted budgeted,
463                                              const SkImageInfo& info, int sampleCount,
464                                              GrSurfaceOrigin origin, const SkSurfaceProps* props,
465                                              bool shouldCreateWithMips) {
466     if (!rContext) {
467         return nullptr;
468     }
469     sampleCount = std::max(1, sampleCount);
470     GrMipmapped mipMapped = shouldCreateWithMips ? GrMipmapped::kYes : GrMipmapped::kNo;
471 
472     if (!rContext->priv().caps()->mipmapSupport()) {
473         mipMapped = GrMipmapped::kNo;
474     }
475 
476     auto device = rContext->priv().createDevice(budgeted, info, SkBackingFit::kExact,
477                                                 sampleCount, mipMapped, GrProtected::kNo, origin,
478                                                 SkSurfacePropsCopyOrDefault(props),
479                                                 skgpu::BaseDevice::InitContents::kClear);
480     if (!device) {
481         return nullptr;
482     }
483     return sk_make_sp<SkSurface_Gpu>(std::move(device));
484 }
485 
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)486 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrRecordingContext* rContext,
487                                                    const GrBackendTexture& tex,
488                                                    GrSurfaceOrigin origin,
489                                                    int sampleCnt,
490                                                    SkColorType colorType,
491                                                    sk_sp<SkColorSpace> colorSpace,
492                                                    const SkSurfaceProps* props,
493                                                    SkSurface::TextureReleaseProc textureReleaseProc,
494                                                    SkSurface::ReleaseContext releaseContext) {
495     auto releaseHelper = GrRefCntedCallback::Make(textureReleaseProc, releaseContext);
496 
497     if (!rContext) {
498         return nullptr;
499     }
500     sampleCnt = std::max(1, sampleCnt);
501 
502     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
503     if (grColorType == GrColorType::kUnknown) {
504         return nullptr;
505     }
506 
507     if (!validate_backend_texture(rContext->priv().caps(), tex, sampleCnt, grColorType, true)) {
508         return nullptr;
509     }
510 
511     sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
512             tex, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
513             std::move(releaseHelper)));
514     if (!proxy) {
515         return nullptr;
516     }
517 
518     auto device = rContext->priv().createDevice(grColorType, std::move(proxy),
519                                                 std::move(colorSpace), origin,
520                                                 SkSurfacePropsCopyOrDefault(props),
521                                                 skgpu::BaseDevice::InitContents::kUninit);
522     if (!device) {
523         return nullptr;
524     }
525 
526     return sk_make_sp<SkSurface_Gpu>(std::move(device));
527 }
528 
onReplaceBackendTexture(const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,ContentChangeMode mode,TextureReleaseProc releaseProc,ReleaseContext releaseContext)529 bool SkSurface_Gpu::onReplaceBackendTexture(const GrBackendTexture& backendTexture,
530                                             GrSurfaceOrigin origin,
531                                             ContentChangeMode mode,
532                                             TextureReleaseProc releaseProc,
533                                             ReleaseContext releaseContext) {
534     auto releaseHelper = GrRefCntedCallback::Make(releaseProc, releaseContext);
535 
536     auto rContext = fDevice->recordingContext();
537     if (rContext->abandoned()) {
538         return false;
539     }
540     if (!backendTexture.isValid()) {
541         return false;
542     }
543     if (backendTexture.width() != this->width() || backendTexture.height() != this->height()) {
544         return false;
545     }
546     auto* oldRTP = fDevice->targetProxy();
547     auto oldProxy = sk_ref_sp(oldRTP->asTextureProxy());
548     if (!oldProxy) {
549         return false;
550     }
551     auto* oldTexture = oldProxy->peekTexture();
552     if (!oldTexture) {
553         return false;
554     }
555     if (!oldTexture->resourcePriv().refsWrappedObjects()) {
556         return false;
557     }
558     if (oldTexture->backendFormat() != backendTexture.getBackendFormat()) {
559         return false;
560     }
561     if (oldTexture->getBackendTexture().isSameTexture(backendTexture)) {
562         return false;
563     }
564     SkASSERT(oldTexture->asRenderTarget());
565     int sampleCnt = oldTexture->asRenderTarget()->numSamples();
566     GrColorType grColorType = SkColorTypeToGrColorType(this->getCanvas()->imageInfo().colorType());
567     if (!validate_backend_texture(rContext->priv().caps(), backendTexture,
568                                   sampleCnt, grColorType, true)) {
569         return false;
570     }
571 
572     sk_sp<SkColorSpace> colorSpace = fDevice->imageInfo().refColorSpace();
573 
574     SkASSERT(sampleCnt > 0);
575     sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
576             backendTexture, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
577             std::move(releaseHelper)));
578     if (!proxy) {
579         return false;
580     }
581 
582     return fDevice->replaceBackingProxy(mode, sk_ref_sp(proxy->asRenderTargetProxy()), grColorType,
583                                         std::move(colorSpace), origin, this->props());
584 }
585 
validate_backend_render_target(const GrCaps * caps,const GrBackendRenderTarget & rt,GrColorType grCT)586 bool validate_backend_render_target(const GrCaps* caps, const GrBackendRenderTarget& rt,
587                                     GrColorType grCT) {
588     if (!caps->areColorTypeAndFormatCompatible(grCT, rt.getBackendFormat())) {
589         return false;
590     }
591 
592     if (!caps->isFormatAsColorTypeRenderable(grCT, rt.getBackendFormat(), rt.sampleCnt())) {
593         return false;
594     }
595 
596     // We require the stencil bits to be either 0, 8, or 16.
597     int stencilBits = rt.stencilBits();
598     if (stencilBits != 0 && stencilBits != 8 && stencilBits != 16) {
599         return false;
600     }
601 
602     return true;
603 }
604 
MakeFromBackendRenderTarget(GrRecordingContext * rContext,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,SkSurface::RenderTargetReleaseProc relProc,SkSurface::ReleaseContext releaseContext)605 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrRecordingContext* rContext,
606                                                         const GrBackendRenderTarget& rt,
607                                                         GrSurfaceOrigin origin,
608                                                         SkColorType colorType,
609                                                         sk_sp<SkColorSpace> colorSpace,
610                                                         const SkSurfaceProps* props,
611                                                         SkSurface::RenderTargetReleaseProc relProc,
612                                                         SkSurface::ReleaseContext releaseContext) {
613     auto releaseHelper = GrRefCntedCallback::Make(relProc, releaseContext);
614 
615     if (!rContext) {
616         return nullptr;
617     }
618 
619     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
620     if (grColorType == GrColorType::kUnknown) {
621         return nullptr;
622     }
623 
624     if (!validate_backend_render_target(rContext->priv().caps(), rt, grColorType)) {
625         return nullptr;
626     }
627 
628     auto proxyProvider = rContext->priv().proxyProvider();
629     auto proxy = proxyProvider->wrapBackendRenderTarget(rt, std::move(releaseHelper));
630     if (!proxy) {
631         return nullptr;
632     }
633 
634     auto device = rContext->priv().createDevice(grColorType, std::move(proxy),
635                                                 std::move(colorSpace), origin,
636                                                 SkSurfacePropsCopyOrDefault(props),
637                                                 skgpu::BaseDevice::InitContents::kUninit);
638     if (!device) {
639         return nullptr;
640     }
641 
642     return sk_make_sp<SkSurface_Gpu>(std::move(device));
643 }
644 
645 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,GrSurfaceOrigin origin,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps)646 sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrDirectContext* dContext,
647                                                     AHardwareBuffer* hardwareBuffer,
648                                                     GrSurfaceOrigin origin,
649                                                     sk_sp<SkColorSpace> colorSpace,
650                                                     const SkSurfaceProps* surfaceProps) {
651     AHardwareBuffer_Desc bufferDesc;
652     AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
653 
654     if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT)) {
655         return nullptr;
656     }
657 
658     bool isTextureable = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE);
659 
660     GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(dContext,
661                                                                              hardwareBuffer,
662                                                                              bufferDesc.format,
663                                                                              true);
664     if (!backendFormat.isValid()) {
665         return nullptr;
666     }
667 
668     if (isTextureable) {
669         GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
670         GrAHardwareBufferUtils::UpdateImageProc updateImageProc = nullptr;
671         GrAHardwareBufferUtils::TexImageCtx deleteImageCtx = nullptr;
672 
673         bool isProtectedContent =
674                 SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
675 
676         GrBackendTexture backendTexture =
677                 GrAHardwareBufferUtils::MakeBackendTexture(dContext, hardwareBuffer,
678                                                            bufferDesc.width, bufferDesc.height,
679                                                            &deleteImageProc, &updateImageProc,
680                                                            &deleteImageCtx, isProtectedContent,
681                                                            backendFormat, true);
682         if (!backendTexture.isValid()) {
683             return nullptr;
684         }
685 
686         SkColorType colorType =
687                 GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
688 
689         sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(dContext, backendTexture,
690                 origin, 0, colorType, std::move(colorSpace), surfaceProps, deleteImageProc,
691                 deleteImageCtx);
692 
693         if (!surface) {
694             SkASSERT(deleteImageProc);
695             deleteImageProc(deleteImageCtx);
696         }
697 
698         return surface;
699     } else {
700         return nullptr;
701     }
702 }
703 #endif
704 
flushAndSubmit(bool syncCpu)705 void SkSurface::flushAndSubmit(bool syncCpu) {
706     this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
707 
708     auto direct = GrAsDirectContext(this->recordingContext());
709     if (direct) {
710         direct->submit(syncCpu);
711     }
712 }
713 
714 #endif
715