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