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