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