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