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