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