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