• 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/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/GrBackendSurface.h"
20 #include "include/gpu/GrContextThreadSafeProxy.h"
21 #include "include/gpu/GrDirectContext.h"
22 #include "include/gpu/GrRecordingContext.h"
23 #include "include/gpu/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/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, true)) {
508         return false;
509     }
510 
511     sk_sp<SkColorSpace> colorSpace = fDevice->imageInfo().refColorSpace();
512 
513     SkASSERT(sampleCnt > 0);
514     sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
515             backendTexture,
516             sampleCnt,
517             kBorrow_GrWrapOwnership,
518             GrWrapCacheable::kNo,
519             std::move(releaseHelper)));
520     if (!proxy) {
521         return false;
522     }
523 
524     return fDevice->replaceBackingProxy(mode,
525                                         sk_ref_sp(proxy->asRenderTargetProxy()),
526                                         grColorType,
527                                         std::move(colorSpace),
528                                         origin,
529                                         this->props());
530 }
531 
validate_backend_render_target(const GrCaps * caps,const GrBackendRenderTarget & rt,GrColorType grCT)532 bool validate_backend_render_target(const GrCaps* caps,
533                                     const GrBackendRenderTarget& rt,
534                                     GrColorType grCT) {
535     if (!caps->areColorTypeAndFormatCompatible(grCT, rt.getBackendFormat())) {
536         return false;
537     }
538 
539     if (!caps->isFormatAsColorTypeRenderable(grCT, rt.getBackendFormat(), rt.sampleCnt())) {
540         return false;
541     }
542 
543     // We require the stencil bits to be either 0, 8, or 16.
544     int stencilBits = rt.stencilBits();
545     if (stencilBits != 0 && stencilBits != 8 && stencilBits != 16) {
546         return false;
547     }
548 
549     return true;
550 }
551 
552 namespace SkSurfaces {
RenderTarget(GrRecordingContext * rContext,const GrSurfaceCharacterization & c,skgpu::Budgeted budgeted)553 sk_sp<SkSurface> RenderTarget(GrRecordingContext* rContext,
554                               const GrSurfaceCharacterization& c,
555                               skgpu::Budgeted budgeted) {
556     if (!rContext || !c.isValid()) {
557         return nullptr;
558     }
559 
560     if (c.usesGLFBO0()) {
561         // If we are making the surface we will never use FBO0.
562         return nullptr;
563     }
564 
565     if (c.vulkanSecondaryCBCompatible()) {
566         return nullptr;
567     }
568 
569     auto device = rContext->priv().createDevice(budgeted,
570                                                 c.imageInfo(),
571                                                 SkBackingFit::kExact,
572                                                 c.sampleCount(),
573                                                 skgpu::Mipmapped(c.isMipMapped()),
574                                                 c.isProtected(),
575                                                 c.origin(),
576                                                 c.surfaceProps(),
577                                                 skgpu::ganesh::Device::InitContents::kClear);
578     if (!device) {
579         return nullptr;
580     }
581 
582     sk_sp<SkSurface> result = sk_make_sp<SkSurface_Ganesh>(std::move(device));
583 #ifdef SK_DEBUG
584     if (result) {
585         SkASSERT(result->isCompatible(c));
586     }
587 #endif
588 
589     return result;
590 }
591 
RenderTarget(GrRecordingContext * rContext,skgpu::Budgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips,bool isProtected)592 sk_sp<SkSurface> RenderTarget(GrRecordingContext* rContext,
593                               skgpu::Budgeted budgeted,
594                               const SkImageInfo& info,
595                               int sampleCount,
596                               GrSurfaceOrigin origin,
597                               const SkSurfaceProps* props,
598                               bool shouldCreateWithMips,
599                               bool isProtected) {
600     if (!rContext) {
601         return nullptr;
602     }
603     sampleCount = std::max(1, sampleCount);
604     skgpu::Mipmapped mipmapped =
605             shouldCreateWithMips ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
606 
607     if (!rContext->priv().caps()->mipmapSupport()) {
608         mipmapped = skgpu::Mipmapped::kNo;
609     }
610 
611     auto device = rContext->priv().createDevice(budgeted,
612                                                 info,
613                                                 SkBackingFit::kExact,
614                                                 sampleCount,
615                                                 mipmapped,
616                                                 GrProtected(isProtected),
617                                                 origin,
618                                                 SkSurfacePropsCopyOrDefault(props),
619                                                 skgpu::ganesh::Device::InitContents::kClear);
620     if (!device) {
621         return nullptr;
622     }
623     return sk_make_sp<SkSurface_Ganesh>(std::move(device));
624 }
625 
WrapBackendTexture(GrRecordingContext * rContext,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)626 sk_sp<SkSurface> WrapBackendTexture(GrRecordingContext* rContext,
627                                     const GrBackendTexture& tex,
628                                     GrSurfaceOrigin origin,
629                                     int sampleCnt,
630                                     SkColorType colorType,
631                                     sk_sp<SkColorSpace> colorSpace,
632                                     const SkSurfaceProps* props,
633                                     TextureReleaseProc textureReleaseProc,
634                                     ReleaseContext releaseContext) {
635     auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
636 
637     if (!rContext) {
638         RENDERENGINE_ABORTF("%s failed due to a null context ", __func__);
639         return nullptr;
640     }
641     sampleCnt = std::max(1, sampleCnt);
642 
643     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
644     if (grColorType == GrColorType::kUnknown) {
645         RENDERENGINE_ABORTF("%s failed due to an unsupported colorType %d", __func__, colorType);
646         return nullptr;
647     }
648 
649     if (!validate_backend_texture(rContext->priv().caps(), tex, sampleCnt, grColorType, true)) {
650         return nullptr;
651     }
652 
653     sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
654             tex,
655             sampleCnt,
656             kBorrow_GrWrapOwnership,
657             GrWrapCacheable::kNo,
658             std::move(releaseHelper)));
659     if (!proxy) {
660         // TODO(scroggo,kjlubick) inline this into Android's AutoBackendTexture.cpp so we
661         // don't have a sometimes-dependency on the GL backend.
662 #ifdef SK_IN_RENDERENGINE
663         GrGLTextureInfo textureInfo;
664         bool retrievedTextureInfo = GrBackendTextures::GetGLTextureInfo(tex, &textureInfo);
665         RENDERENGINE_ABORTF(
666                 "%s failed to wrap the texture into a renderable target "
667                 "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i texType: %i"
668                 "\n\t\tGrGLTextureInfo: success: %i fTarget: %u fFormat: %u"
669                 "\n\tmaxRenderTargetSize: %d",
670                 __func__,
671                 tex.width(),
672                 tex.height(),
673                 tex.hasMipmaps(),
674                 tex.isProtected(),
675                 static_cast<int>(tex.textureType()),
676                 retrievedTextureInfo,
677                 textureInfo.fTarget,
678                 textureInfo.fFormat,
679                 rContext->priv().caps()->maxRenderTargetSize());
680 #endif
681         return nullptr;
682     }
683 
684     auto device = rContext->priv().createDevice(grColorType,
685                                                 std::move(proxy),
686                                                 std::move(colorSpace),
687                                                 origin,
688                                                 SkSurfacePropsCopyOrDefault(props),
689                                                 skgpu::ganesh::Device::InitContents::kUninit);
690     if (!device) {
691         RENDERENGINE_ABORTF("%s failed to wrap the renderTarget into a surface", __func__);
692         return nullptr;
693     }
694 
695     return sk_make_sp<SkSurface_Ganesh>(std::move(device));
696 }
697 
WrapBackendRenderTarget(GrRecordingContext * rContext,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,RenderTargetReleaseProc relProc,ReleaseContext releaseContext)698 sk_sp<SkSurface> WrapBackendRenderTarget(GrRecordingContext* rContext,
699                                          const GrBackendRenderTarget& rt,
700                                          GrSurfaceOrigin origin,
701                                          SkColorType colorType,
702                                          sk_sp<SkColorSpace> colorSpace,
703                                          const SkSurfaceProps* props,
704                                          RenderTargetReleaseProc relProc,
705                                          ReleaseContext releaseContext) {
706     auto releaseHelper = skgpu::RefCntedCallback::Make(relProc, releaseContext);
707 
708     if (!rContext) {
709         return nullptr;
710     }
711 
712     GrColorType grColorType = SkColorTypeToGrColorType(colorType);
713     if (grColorType == GrColorType::kUnknown) {
714         return nullptr;
715     }
716 
717     if (!validate_backend_render_target(rContext->priv().caps(), rt, grColorType)) {
718         return nullptr;
719     }
720 
721     auto proxyProvider = rContext->priv().proxyProvider();
722     auto proxy = proxyProvider->wrapBackendRenderTarget(rt, std::move(releaseHelper));
723     if (!proxy) {
724         return nullptr;
725     }
726 
727     auto device = rContext->priv().createDevice(grColorType,
728                                                 std::move(proxy),
729                                                 std::move(colorSpace),
730                                                 origin,
731                                                 SkSurfacePropsCopyOrDefault(props),
732                                                 skgpu::ganesh::Device::InitContents::kUninit);
733     if (!device) {
734         return nullptr;
735     }
736 
737     return sk_make_sp<SkSurface_Ganesh>(std::move(device));
738 }
739 
GetBackendTexture(SkSurface * surface,BackendHandleAccess access)740 GrBackendTexture GetBackendTexture(SkSurface* surface, BackendHandleAccess access) {
741     if (surface == nullptr) {
742         return GrBackendTexture();
743     }
744     auto sb = asSB(surface);
745     if (!sb->isGaneshBacked()) {
746         return GrBackendTexture();
747     }
748     return static_cast<SkSurface_Ganesh*>(surface)->getBackendTexture(access);
749 }
750 
GetBackendRenderTarget(SkSurface * surface,BackendHandleAccess access)751 GrBackendRenderTarget GetBackendRenderTarget(SkSurface* surface, BackendHandleAccess access) {
752     if (surface == nullptr) {
753         return GrBackendRenderTarget();
754     }
755     auto sb = asSB(surface);
756     if (!sb->isGaneshBacked()) {
757         return GrBackendRenderTarget();
758     }
759     return static_cast<SkSurface_Ganesh*>(surface)->getBackendRenderTarget(access);
760 }
761 
ResolveMSAA(SkSurface * surface)762 void ResolveMSAA(SkSurface* surface) {
763     if (!surface) {
764         return;
765     }
766     auto sb = asSB(surface);
767     if (!sb->isGaneshBacked()) {
768         return;
769     }
770     auto gs = static_cast<SkSurface_Ganesh*>(surface);
771     gs->resolveMSAA();
772 }
773 
774 }  // namespace SkSurfaces
775 
776 namespace skgpu::ganesh {
Flush(SkSurface * surface)777 GrSemaphoresSubmitted Flush(SkSurface* surface) {
778     if (!surface) {
779         return GrSemaphoresSubmitted::kNo;
780     }
781     if (auto rContext = surface->recordingContext(); rContext != nullptr) {
782         return rContext->asDirectContext()->flush(surface, {});
783     }
784     return GrSemaphoresSubmitted::kNo;
785 }
786 
Flush(sk_sp<SkSurface> surface)787 GrSemaphoresSubmitted Flush(sk_sp<SkSurface> surface) {
788     if (!surface) {
789         return GrSemaphoresSubmitted::kNo;
790     }
791     if (auto rContext = surface->recordingContext(); rContext != nullptr) {
792         return rContext->asDirectContext()->flush(surface.get(), {});
793     }
794     return GrSemaphoresSubmitted::kNo;
795 }
796 
FlushAndSubmit(SkSurface * surface)797 void FlushAndSubmit(SkSurface* surface) {
798     if (!surface) {
799         return;
800     }
801     if (auto rContext = surface->recordingContext(); rContext != nullptr) {
802         rContext->asDirectContext()->flushAndSubmit(surface, GrSyncCpu::kNo);
803     }
804 }
805 
FlushAndSubmit(sk_sp<SkSurface> surface)806 void FlushAndSubmit(sk_sp<SkSurface> surface) {
807     if (!surface) {
808         return;
809     }
810     if (auto rContext = surface->recordingContext(); rContext != nullptr) {
811         rContext->asDirectContext()->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
812     }
813 }
814 
815 }  // namespace skgpu::ganesh
816