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
onFlush(BackendSurfaceAccess access,const GrFlushInfo & info,const GrBackendSurfaceMutableState * newState)210 GrSemaphoresSubmitted SkSurface_Gpu::onFlush(BackendSurfaceAccess access, const GrFlushInfo& info,
211 const GrBackendSurfaceMutableState* newState) {
212
213 auto dContext = fDevice->recordingContext()->asDirectContext();
214 if (!dContext) {
215 return GrSemaphoresSubmitted::kNo;
216 }
217
218 GrRenderTargetProxy* rtp = fDevice->targetProxy();
219
220 return dContext->priv().flushSurface(rtp, access, info, newState);
221 }
222
onWait(int numSemaphores,const GrBackendSemaphore * waitSemaphores,bool deleteSemaphoresAfterWait)223 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores,
224 bool deleteSemaphoresAfterWait) {
225 return fDevice->wait(numSemaphores, waitSemaphores, deleteSemaphoresAfterWait);
226 }
227
onCharacterize(SkSurfaceCharacterization * characterization) const228 bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* characterization) const {
229 auto direct = fDevice->recordingContext()->asDirectContext();
230 if (!direct) {
231 return false;
232 }
233
234 SkImageInfo ii = fDevice->imageInfo();
235 if (ii.colorType() == kUnknown_SkColorType) {
236 return false;
237 }
238
239 GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView();
240 size_t maxResourceBytes = direct->getResourceCacheLimit();
241
242 bool mipmapped = readSurfaceView.asTextureProxy()
243 ? GrMipmapped::kYes == readSurfaceView.asTextureProxy()->mipmapped()
244 : false;
245
246 bool usesGLFBO0 = readSurfaceView.asRenderTargetProxy()->glRTFBOIDIs0();
247 // We should never get in the situation where we have a texture render target that is also
248 // backend by FBO 0.
249 SkASSERT(!usesGLFBO0 || !SkToBool(readSurfaceView.asTextureProxy()));
250
251 bool vkRTSupportsInputAttachment =
252 readSurfaceView.asRenderTargetProxy()->supportsVkInputAttachment();
253
254 GrBackendFormat format = readSurfaceView.proxy()->backendFormat();
255 int numSamples = readSurfaceView.asRenderTargetProxy()->numSamples();
256 GrProtected isProtected = readSurfaceView.asRenderTargetProxy()->isProtected();
257
258 characterization->set(
259 direct->threadSafeProxy(),
260 maxResourceBytes,
261 ii,
262 format,
263 readSurfaceView.origin(),
264 numSamples,
265 SkSurfaceCharacterization::Textureable(SkToBool(readSurfaceView.asTextureProxy())),
266 SkSurfaceCharacterization::MipMapped(mipmapped),
267 SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0),
268 SkSurfaceCharacterization::VkRTSupportsInputAttachment(vkRTSupportsInputAttachment),
269 SkSurfaceCharacterization::VulkanSecondaryCBCompatible(false),
270 isProtected,
271 this->props());
272 return true;
273 }
274
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)275 void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
276 const SkSamplingOptions& sampling, const SkPaint* paint) {
277 // If the dst is also GPU we try to not force a new image snapshot (by calling the base class
278 // onDraw) since that may not always perform the copy-on-write optimization.
279 auto tryDraw = [&] {
280 auto surfaceContext = fDevice->recordingContext();
281 auto canvasContext = GrAsDirectContext(canvas->recordingContext());
282 if (!canvasContext) {
283 return false;
284 }
285 if (canvasContext->priv().contextID() != surfaceContext->priv().contextID()) {
286 return false;
287 }
288 GrSurfaceProxyView srcView = fDevice->readSurfaceView();
289 if (!srcView.asTextureProxyRef()) {
290 return false;
291 }
292 // Possibly we could skip making an image here if SkGpuDevice exposed a lower level way
293 // of drawing a texture proxy.
294 const SkImageInfo info = fDevice->imageInfo();
295 sk_sp<SkImage> image = sk_make_sp<SkImage_Gpu>(sk_ref_sp(canvasContext),
296 kNeedNewImageUniqueID,
297 std::move(srcView),
298 info.colorInfo());
299 canvas->drawImage(image.get(), x, y, sampling, paint);
300 return true;
301 };
302 if (!tryDraw()) {
303 INHERITED::onDraw(canvas, x, y, sampling, paint);
304 }
305 }
306
onIsCompatible(const SkSurfaceCharacterization & characterization) const307 bool SkSurface_Gpu::onIsCompatible(const SkSurfaceCharacterization& characterization) const {
308 auto direct = fDevice->recordingContext()->asDirectContext();
309 if (!direct) {
310 return false;
311 }
312
313 if (!characterization.isValid()) {
314 return false;
315 }
316
317 if (characterization.vulkanSecondaryCBCompatible()) {
318 return false;
319 }
320
321 SkImageInfo ii = fDevice->imageInfo();
322 if (ii.colorType() == kUnknown_SkColorType) {
323 return false;
324 }
325
326 GrSurfaceProxyView targetView = fDevice->readSurfaceView();
327 // As long as the current state if the context allows for greater or equal resources,
328 // we allow the DDL to be replayed.
329 // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
330 size_t maxResourceBytes = direct->getResourceCacheLimit();
331
332 if (characterization.isTextureable()) {
333 if (!targetView.asTextureProxy()) {
334 // If the characterization was textureable we require the replay dest to also be
335 // textureable. If the characterized surface wasn't textureable we allow the replay
336 // dest to be textureable.
337 return false;
338 }
339
340 if (characterization.isMipMapped() &&
341 GrMipmapped::kNo == targetView.asTextureProxy()->mipmapped()) {
342 // Fail if the DDL's surface was mipmapped but the replay surface is not.
343 // Allow drawing to proceed if the DDL was not mipmapped but the replay surface is.
344 return false;
345 }
346 }
347
348 if (characterization.usesGLFBO0() != targetView.asRenderTargetProxy()->glRTFBOIDIs0()) {
349 // FBO0-ness effects how MSAA and window rectangles work. If the characterization was
350 // tagged as FBO0 it would never have been allowed to use window rectangles. If MSAA
351 // was also never used then a DDL recorded with this characterization should be replayable
352 // on a non-FBO0 surface.
353 if (!characterization.usesGLFBO0() || characterization.sampleCount() > 1) {
354 return false;
355 }
356 }
357
358 GrBackendFormat format = targetView.asRenderTargetProxy()->backendFormat();
359 int numSamples = targetView.asRenderTargetProxy()->numSamples();
360 GrProtected isProtected = targetView.proxy()->isProtected();
361
362 return characterization.contextInfo() &&
363 characterization.contextInfo()->priv().matches(direct) &&
364 characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
365 characterization.origin() == targetView.origin() &&
366 characterization.backendFormat() == format &&
367 characterization.width() == ii.width() &&
368 characterization.height() == ii.height() &&
369 characterization.colorType() == ii.colorType() &&
370 characterization.sampleCount() == numSamples &&
371 SkColorSpace::Equals(characterization.colorSpace(), ii.colorInfo().colorSpace()) &&
372 characterization.isProtected() == isProtected &&
373 characterization.surfaceProps() == fDevice->surfaceProps();
374 }
375
onDraw(sk_sp<const SkDeferredDisplayList> ddl,SkIPoint offset)376 bool SkSurface_Gpu::onDraw(sk_sp<const SkDeferredDisplayList> ddl, SkIPoint offset) {
377 if (!ddl || !this->isCompatible(ddl->characterization())) {
378 return false;
379 }
380
381 auto direct = fDevice->recordingContext()->asDirectContext();
382 if (!direct) {
383 return false;
384 }
385
386 GrSurfaceProxyView view = fDevice->readSurfaceView();
387
388 direct->priv().createDDLTask(std::move(ddl), view.asRenderTargetProxyRef(), offset);
389 return true;
390 }
391
392 ///////////////////////////////////////////////////////////////////////////////
393
MakeRenderTarget(GrRecordingContext * rContext,const SkSurfaceCharacterization & c,SkBudgeted budgeted)394 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* rContext,
395 const SkSurfaceCharacterization& c,
396 SkBudgeted budgeted) {
397 if (!rContext || !c.isValid()) {
398 return nullptr;
399 }
400
401 if (c.usesGLFBO0()) {
402 // If we are making the surface we will never use FBO0.
403 return nullptr;
404 }
405
406 if (c.vulkanSecondaryCBCompatible()) {
407 return nullptr;
408 }
409
410 auto device = rContext->priv().createDevice(budgeted, c.imageInfo(), SkBackingFit::kExact,
411 c.sampleCount(), GrMipmapped(c.isMipMapped()),
412 c.isProtected(), c.origin(), c.surfaceProps(),
413 skgpu::BaseDevice::InitContents::kClear);
414 if (!device) {
415 return nullptr;
416 }
417
418 sk_sp<SkSurface> result = sk_make_sp<SkSurface_Gpu>(std::move(device));
419 #ifdef SK_DEBUG
420 if (result) {
421 SkASSERT(result->isCompatible(c));
422 }
423 #endif
424
425 return result;
426 }
427
validate_backend_texture(const GrCaps * caps,const GrBackendTexture & tex,int sampleCnt,GrColorType grCT,bool texturable)428 static bool validate_backend_texture(const GrCaps* caps, const GrBackendTexture& tex,
429 int sampleCnt, GrColorType grCT,
430 bool texturable) {
431 if (!tex.isValid()) {
432 return false;
433 }
434
435 GrBackendFormat backendFormat = tex.getBackendFormat();
436 if (!backendFormat.isValid()) {
437 return false;
438 }
439
440 if (!caps->areColorTypeAndFormatCompatible(grCT, backendFormat)) {
441 return false;
442 }
443
444 if (!caps->isFormatAsColorTypeRenderable(grCT, backendFormat, sampleCnt)) {
445 return false;
446 }
447
448 if (texturable && !caps->isFormatTexturable(backendFormat, tex.textureType())) {
449 return false;
450 }
451
452 return true;
453 }
454
MakeRenderTarget(GrRecordingContext * rContext,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips)455 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrRecordingContext* rContext, SkBudgeted budgeted,
456 const SkImageInfo& info, int sampleCount,
457 GrSurfaceOrigin origin, const SkSurfaceProps* props,
458 bool shouldCreateWithMips) {
459 if (!rContext) {
460 return nullptr;
461 }
462 sampleCount = std::max(1, sampleCount);
463 GrMipmapped mipMapped = shouldCreateWithMips ? GrMipmapped::kYes : GrMipmapped::kNo;
464
465 if (!rContext->priv().caps()->mipmapSupport()) {
466 mipMapped = GrMipmapped::kNo;
467 }
468
469 auto device = rContext->priv().createDevice(budgeted, info, SkBackingFit::kExact,
470 sampleCount, mipMapped, GrProtected::kNo, origin,
471 SkSurfacePropsCopyOrDefault(props),
472 skgpu::BaseDevice::InitContents::kClear);
473 if (!device) {
474 return nullptr;
475 }
476 return sk_make_sp<SkSurface_Gpu>(std::move(device));
477 }
478
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)479 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrRecordingContext* rContext,
480 const GrBackendTexture& tex,
481 GrSurfaceOrigin origin,
482 int sampleCnt,
483 SkColorType colorType,
484 sk_sp<SkColorSpace> colorSpace,
485 const SkSurfaceProps* props,
486 SkSurface::TextureReleaseProc textureReleaseProc,
487 SkSurface::ReleaseContext releaseContext) {
488 auto releaseHelper = GrRefCntedCallback::Make(textureReleaseProc, releaseContext);
489
490 if (!rContext) {
491 return nullptr;
492 }
493 sampleCnt = std::max(1, sampleCnt);
494
495 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
496 if (grColorType == GrColorType::kUnknown) {
497 return nullptr;
498 }
499
500 if (!validate_backend_texture(rContext->priv().caps(), tex, sampleCnt, grColorType, true)) {
501 return nullptr;
502 }
503
504 sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
505 tex, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
506 std::move(releaseHelper)));
507 if (!proxy) {
508 return nullptr;
509 }
510
511 auto device = rContext->priv().createDevice(grColorType, std::move(proxy),
512 std::move(colorSpace), origin,
513 SkSurfacePropsCopyOrDefault(props),
514 skgpu::BaseDevice::InitContents::kUninit);
515 if (!device) {
516 return nullptr;
517 }
518
519 return sk_make_sp<SkSurface_Gpu>(std::move(device));
520 }
521
onReplaceBackendTexture(const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,ContentChangeMode mode,TextureReleaseProc releaseProc,ReleaseContext releaseContext)522 bool SkSurface_Gpu::onReplaceBackendTexture(const GrBackendTexture& backendTexture,
523 GrSurfaceOrigin origin,
524 ContentChangeMode mode,
525 TextureReleaseProc releaseProc,
526 ReleaseContext releaseContext) {
527 auto releaseHelper = GrRefCntedCallback::Make(releaseProc, releaseContext);
528
529 auto rContext = fDevice->recordingContext();
530 if (rContext->abandoned()) {
531 return false;
532 }
533 if (!backendTexture.isValid()) {
534 return false;
535 }
536 if (backendTexture.width() != this->width() || backendTexture.height() != this->height()) {
537 return false;
538 }
539 auto* oldRTP = fDevice->targetProxy();
540 auto oldProxy = sk_ref_sp(oldRTP->asTextureProxy());
541 if (!oldProxy) {
542 return false;
543 }
544 auto* oldTexture = oldProxy->peekTexture();
545 if (!oldTexture) {
546 return false;
547 }
548 if (!oldTexture->resourcePriv().refsWrappedObjects()) {
549 return false;
550 }
551 if (oldTexture->backendFormat() != backendTexture.getBackendFormat()) {
552 return false;
553 }
554 if (oldTexture->getBackendTexture().isSameTexture(backendTexture)) {
555 return false;
556 }
557 SkASSERT(oldTexture->asRenderTarget());
558 int sampleCnt = oldTexture->asRenderTarget()->numSamples();
559 GrColorType grColorType = SkColorTypeToGrColorType(this->getCanvas()->imageInfo().colorType());
560 if (!validate_backend_texture(rContext->priv().caps(), backendTexture,
561 sampleCnt, grColorType, true)) {
562 return false;
563 }
564
565 sk_sp<SkColorSpace> colorSpace = fDevice->imageInfo().refColorSpace();
566
567 SkASSERT(sampleCnt > 0);
568 sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
569 backendTexture, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
570 std::move(releaseHelper)));
571 if (!proxy) {
572 return false;
573 }
574
575 return fDevice->replaceBackingProxy(mode, sk_ref_sp(proxy->asRenderTargetProxy()), grColorType,
576 std::move(colorSpace), origin, this->props());
577 }
578
validate_backend_render_target(const GrCaps * caps,const GrBackendRenderTarget & rt,GrColorType grCT)579 bool validate_backend_render_target(const GrCaps* caps, const GrBackendRenderTarget& rt,
580 GrColorType grCT) {
581 if (!caps->areColorTypeAndFormatCompatible(grCT, rt.getBackendFormat())) {
582 return false;
583 }
584
585 if (!caps->isFormatAsColorTypeRenderable(grCT, rt.getBackendFormat(), rt.sampleCnt())) {
586 return false;
587 }
588
589 // We require the stencil bits to be either 0, 8, or 16.
590 int stencilBits = rt.stencilBits();
591 if (stencilBits != 0 && stencilBits != 8 && stencilBits != 16) {
592 return false;
593 }
594
595 return true;
596 }
597
MakeFromBackendRenderTarget(GrRecordingContext * rContext,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,SkSurface::RenderTargetReleaseProc relProc,SkSurface::ReleaseContext releaseContext)598 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrRecordingContext* rContext,
599 const GrBackendRenderTarget& rt,
600 GrSurfaceOrigin origin,
601 SkColorType colorType,
602 sk_sp<SkColorSpace> colorSpace,
603 const SkSurfaceProps* props,
604 SkSurface::RenderTargetReleaseProc relProc,
605 SkSurface::ReleaseContext releaseContext) {
606 auto releaseHelper = GrRefCntedCallback::Make(relProc, releaseContext);
607
608 if (!rContext) {
609 return nullptr;
610 }
611
612 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
613 if (grColorType == GrColorType::kUnknown) {
614 return nullptr;
615 }
616
617 if (!validate_backend_render_target(rContext->priv().caps(), rt, grColorType)) {
618 return nullptr;
619 }
620
621 auto proxyProvider = rContext->priv().proxyProvider();
622 auto proxy = proxyProvider->wrapBackendRenderTarget(rt, std::move(releaseHelper));
623 if (!proxy) {
624 return nullptr;
625 }
626
627 auto device = rContext->priv().createDevice(grColorType, std::move(proxy),
628 std::move(colorSpace), origin,
629 SkSurfacePropsCopyOrDefault(props),
630 skgpu::BaseDevice::InitContents::kUninit);
631 if (!device) {
632 return nullptr;
633 }
634
635 return sk_make_sp<SkSurface_Gpu>(std::move(device));
636 }
637
638 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,GrSurfaceOrigin origin,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps)639 sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrDirectContext* dContext,
640 AHardwareBuffer* hardwareBuffer,
641 GrSurfaceOrigin origin,
642 sk_sp<SkColorSpace> colorSpace,
643 const SkSurfaceProps* surfaceProps) {
644 AHardwareBuffer_Desc bufferDesc;
645 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
646
647 if (!SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT)) {
648 return nullptr;
649 }
650
651 bool isTextureable = SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE);
652
653 GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(dContext,
654 hardwareBuffer,
655 bufferDesc.format,
656 true);
657 if (!backendFormat.isValid()) {
658 return nullptr;
659 }
660
661 if (isTextureable) {
662 GrAHardwareBufferUtils::DeleteImageProc deleteImageProc = nullptr;
663 GrAHardwareBufferUtils::UpdateImageProc updateImageProc = nullptr;
664 GrAHardwareBufferUtils::TexImageCtx deleteImageCtx = nullptr;
665
666 bool isProtectedContent =
667 SkToBool(bufferDesc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
668
669 GrBackendTexture backendTexture =
670 GrAHardwareBufferUtils::MakeBackendTexture(dContext, hardwareBuffer,
671 bufferDesc.width, bufferDesc.height,
672 &deleteImageProc, &updateImageProc,
673 &deleteImageCtx, isProtectedContent,
674 backendFormat, true);
675 if (!backendTexture.isValid()) {
676 return nullptr;
677 }
678
679 SkColorType colorType =
680 GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format);
681
682 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(dContext, backendTexture,
683 origin, 0, colorType, std::move(colorSpace), surfaceProps, deleteImageProc,
684 deleteImageCtx);
685
686 if (!surface) {
687 SkASSERT(deleteImageProc);
688 deleteImageProc(deleteImageCtx);
689 }
690
691 return surface;
692 } else {
693 return nullptr;
694 }
695 }
696 #endif
697
flushAndSubmit(bool syncCpu)698 void SkSurface::flushAndSubmit(bool syncCpu) {
699 this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
700
701 auto direct = GrAsDirectContext(this->recordingContext());
702 if (direct) {
703 direct->submit(syncCpu);
704 }
705 }
706
707 #endif
708