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/GrBackendSurface.h"
20 #include "include/gpu/GrContextThreadSafeProxy.h"
21 #include "include/gpu/GrDirectContext.h"
22 #include "include/gpu/GrRecordingContext.h"
23 #include "include/gpu/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/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, true)) {
508 return false;
509 }
510
511 sk_sp<SkColorSpace> colorSpace = fDevice->imageInfo().refColorSpace();
512
513 SkASSERT(sampleCnt > 0);
514 sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
515 backendTexture,
516 sampleCnt,
517 kBorrow_GrWrapOwnership,
518 GrWrapCacheable::kNo,
519 std::move(releaseHelper)));
520 if (!proxy) {
521 return false;
522 }
523
524 return fDevice->replaceBackingProxy(mode,
525 sk_ref_sp(proxy->asRenderTargetProxy()),
526 grColorType,
527 std::move(colorSpace),
528 origin,
529 this->props());
530 }
531
validate_backend_render_target(const GrCaps * caps,const GrBackendRenderTarget & rt,GrColorType grCT)532 bool validate_backend_render_target(const GrCaps* caps,
533 const GrBackendRenderTarget& rt,
534 GrColorType grCT) {
535 if (!caps->areColorTypeAndFormatCompatible(grCT, rt.getBackendFormat())) {
536 return false;
537 }
538
539 if (!caps->isFormatAsColorTypeRenderable(grCT, rt.getBackendFormat(), rt.sampleCnt())) {
540 return false;
541 }
542
543 // We require the stencil bits to be either 0, 8, or 16.
544 int stencilBits = rt.stencilBits();
545 if (stencilBits != 0 && stencilBits != 8 && stencilBits != 16) {
546 return false;
547 }
548
549 return true;
550 }
551
552 namespace SkSurfaces {
RenderTarget(GrRecordingContext * rContext,const GrSurfaceCharacterization & c,skgpu::Budgeted budgeted)553 sk_sp<SkSurface> RenderTarget(GrRecordingContext* rContext,
554 const GrSurfaceCharacterization& c,
555 skgpu::Budgeted budgeted) {
556 if (!rContext || !c.isValid()) {
557 return nullptr;
558 }
559
560 if (c.usesGLFBO0()) {
561 // If we are making the surface we will never use FBO0.
562 return nullptr;
563 }
564
565 if (c.vulkanSecondaryCBCompatible()) {
566 return nullptr;
567 }
568
569 auto device = rContext->priv().createDevice(budgeted,
570 c.imageInfo(),
571 SkBackingFit::kExact,
572 c.sampleCount(),
573 skgpu::Mipmapped(c.isMipMapped()),
574 c.isProtected(),
575 c.origin(),
576 c.surfaceProps(),
577 skgpu::ganesh::Device::InitContents::kClear);
578 if (!device) {
579 return nullptr;
580 }
581
582 sk_sp<SkSurface> result = sk_make_sp<SkSurface_Ganesh>(std::move(device));
583 #ifdef SK_DEBUG
584 if (result) {
585 SkASSERT(result->isCompatible(c));
586 }
587 #endif
588
589 return result;
590 }
591
RenderTarget(GrRecordingContext * rContext,skgpu::Budgeted budgeted,const SkImageInfo & info,int sampleCount,GrSurfaceOrigin origin,const SkSurfaceProps * props,bool shouldCreateWithMips,bool isProtected)592 sk_sp<SkSurface> RenderTarget(GrRecordingContext* rContext,
593 skgpu::Budgeted budgeted,
594 const SkImageInfo& info,
595 int sampleCount,
596 GrSurfaceOrigin origin,
597 const SkSurfaceProps* props,
598 bool shouldCreateWithMips,
599 bool isProtected) {
600 if (!rContext) {
601 return nullptr;
602 }
603 sampleCount = std::max(1, sampleCount);
604 skgpu::Mipmapped mipmapped =
605 shouldCreateWithMips ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
606
607 if (!rContext->priv().caps()->mipmapSupport()) {
608 mipmapped = skgpu::Mipmapped::kNo;
609 }
610
611 auto device = rContext->priv().createDevice(budgeted,
612 info,
613 SkBackingFit::kExact,
614 sampleCount,
615 mipmapped,
616 GrProtected(isProtected),
617 origin,
618 SkSurfacePropsCopyOrDefault(props),
619 skgpu::ganesh::Device::InitContents::kClear);
620 if (!device) {
621 return nullptr;
622 }
623 return sk_make_sp<SkSurface_Ganesh>(std::move(device));
624 }
625
WrapBackendTexture(GrRecordingContext * rContext,const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)626 sk_sp<SkSurface> WrapBackendTexture(GrRecordingContext* rContext,
627 const GrBackendTexture& tex,
628 GrSurfaceOrigin origin,
629 int sampleCnt,
630 SkColorType colorType,
631 sk_sp<SkColorSpace> colorSpace,
632 const SkSurfaceProps* props,
633 TextureReleaseProc textureReleaseProc,
634 ReleaseContext releaseContext) {
635 auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
636
637 if (!rContext) {
638 RENDERENGINE_ABORTF("%s failed due to a null context ", __func__);
639 return nullptr;
640 }
641 sampleCnt = std::max(1, sampleCnt);
642
643 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
644 if (grColorType == GrColorType::kUnknown) {
645 RENDERENGINE_ABORTF("%s failed due to an unsupported colorType %d", __func__, colorType);
646 return nullptr;
647 }
648
649 if (!validate_backend_texture(rContext->priv().caps(), tex, sampleCnt, grColorType, true)) {
650 return nullptr;
651 }
652
653 sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
654 tex,
655 sampleCnt,
656 kBorrow_GrWrapOwnership,
657 GrWrapCacheable::kNo,
658 std::move(releaseHelper)));
659 if (!proxy) {
660 // TODO(scroggo,kjlubick) inline this into Android's AutoBackendTexture.cpp so we
661 // don't have a sometimes-dependency on the GL backend.
662 #ifdef SK_IN_RENDERENGINE
663 GrGLTextureInfo textureInfo;
664 bool retrievedTextureInfo = GrBackendTextures::GetGLTextureInfo(tex, &textureInfo);
665 RENDERENGINE_ABORTF(
666 "%s failed to wrap the texture into a renderable target "
667 "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i texType: %i"
668 "\n\t\tGrGLTextureInfo: success: %i fTarget: %u fFormat: %u"
669 "\n\tmaxRenderTargetSize: %d",
670 __func__,
671 tex.width(),
672 tex.height(),
673 tex.hasMipmaps(),
674 tex.isProtected(),
675 static_cast<int>(tex.textureType()),
676 retrievedTextureInfo,
677 textureInfo.fTarget,
678 textureInfo.fFormat,
679 rContext->priv().caps()->maxRenderTargetSize());
680 #endif
681 return nullptr;
682 }
683
684 auto device = rContext->priv().createDevice(grColorType,
685 std::move(proxy),
686 std::move(colorSpace),
687 origin,
688 SkSurfacePropsCopyOrDefault(props),
689 skgpu::ganesh::Device::InitContents::kUninit);
690 if (!device) {
691 RENDERENGINE_ABORTF("%s failed to wrap the renderTarget into a surface", __func__);
692 return nullptr;
693 }
694
695 return sk_make_sp<SkSurface_Ganesh>(std::move(device));
696 }
697
WrapBackendRenderTarget(GrRecordingContext * rContext,const GrBackendRenderTarget & rt,GrSurfaceOrigin origin,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * props,RenderTargetReleaseProc relProc,ReleaseContext releaseContext)698 sk_sp<SkSurface> WrapBackendRenderTarget(GrRecordingContext* rContext,
699 const GrBackendRenderTarget& rt,
700 GrSurfaceOrigin origin,
701 SkColorType colorType,
702 sk_sp<SkColorSpace> colorSpace,
703 const SkSurfaceProps* props,
704 RenderTargetReleaseProc relProc,
705 ReleaseContext releaseContext) {
706 auto releaseHelper = skgpu::RefCntedCallback::Make(relProc, releaseContext);
707
708 if (!rContext) {
709 return nullptr;
710 }
711
712 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
713 if (grColorType == GrColorType::kUnknown) {
714 return nullptr;
715 }
716
717 if (!validate_backend_render_target(rContext->priv().caps(), rt, grColorType)) {
718 return nullptr;
719 }
720
721 auto proxyProvider = rContext->priv().proxyProvider();
722 auto proxy = proxyProvider->wrapBackendRenderTarget(rt, std::move(releaseHelper));
723 if (!proxy) {
724 return nullptr;
725 }
726
727 auto device = rContext->priv().createDevice(grColorType,
728 std::move(proxy),
729 std::move(colorSpace),
730 origin,
731 SkSurfacePropsCopyOrDefault(props),
732 skgpu::ganesh::Device::InitContents::kUninit);
733 if (!device) {
734 return nullptr;
735 }
736
737 return sk_make_sp<SkSurface_Ganesh>(std::move(device));
738 }
739
GetBackendTexture(SkSurface * surface,BackendHandleAccess access)740 GrBackendTexture GetBackendTexture(SkSurface* surface, BackendHandleAccess access) {
741 if (surface == nullptr) {
742 return GrBackendTexture();
743 }
744 auto sb = asSB(surface);
745 if (!sb->isGaneshBacked()) {
746 return GrBackendTexture();
747 }
748 return static_cast<SkSurface_Ganesh*>(surface)->getBackendTexture(access);
749 }
750
GetBackendRenderTarget(SkSurface * surface,BackendHandleAccess access)751 GrBackendRenderTarget GetBackendRenderTarget(SkSurface* surface, BackendHandleAccess access) {
752 if (surface == nullptr) {
753 return GrBackendRenderTarget();
754 }
755 auto sb = asSB(surface);
756 if (!sb->isGaneshBacked()) {
757 return GrBackendRenderTarget();
758 }
759 return static_cast<SkSurface_Ganesh*>(surface)->getBackendRenderTarget(access);
760 }
761
ResolveMSAA(SkSurface * surface)762 void ResolveMSAA(SkSurface* surface) {
763 if (!surface) {
764 return;
765 }
766 auto sb = asSB(surface);
767 if (!sb->isGaneshBacked()) {
768 return;
769 }
770 auto gs = static_cast<SkSurface_Ganesh*>(surface);
771 gs->resolveMSAA();
772 }
773
774 } // namespace SkSurfaces
775
776 namespace skgpu::ganesh {
Flush(SkSurface * surface)777 GrSemaphoresSubmitted Flush(SkSurface* surface) {
778 if (!surface) {
779 return GrSemaphoresSubmitted::kNo;
780 }
781 if (auto rContext = surface->recordingContext(); rContext != nullptr) {
782 return rContext->asDirectContext()->flush(surface, {});
783 }
784 return GrSemaphoresSubmitted::kNo;
785 }
786
Flush(sk_sp<SkSurface> surface)787 GrSemaphoresSubmitted Flush(sk_sp<SkSurface> surface) {
788 if (!surface) {
789 return GrSemaphoresSubmitted::kNo;
790 }
791 if (auto rContext = surface->recordingContext(); rContext != nullptr) {
792 return rContext->asDirectContext()->flush(surface.get(), {});
793 }
794 return GrSemaphoresSubmitted::kNo;
795 }
796
FlushAndSubmit(SkSurface * surface)797 void FlushAndSubmit(SkSurface* surface) {
798 if (!surface) {
799 return;
800 }
801 if (auto rContext = surface->recordingContext(); rContext != nullptr) {
802 rContext->asDirectContext()->flushAndSubmit(surface, GrSyncCpu::kNo);
803 }
804 }
805
FlushAndSubmit(sk_sp<SkSurface> surface)806 void FlushAndSubmit(sk_sp<SkSurface> surface) {
807 if (!surface) {
808 return;
809 }
810 if (auto rContext = surface->recordingContext(); rContext != nullptr) {
811 rContext->asDirectContext()->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
812 }
813 }
814
815 } // namespace skgpu::ganesh
816