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