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