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