1 /*
2 * Copyright 2018 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/GrProxyProvider.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkImage.h"
12 #include "include/gpu/GrDirectContext.h"
13 #include "include/private/base/SingleOwner.h"
14 #include "include/private/gpu/ganesh/GrImageContext.h"
15 #include "src/core/SkAutoPixmapStorage.h"
16 #include "src/core/SkCompressedDataUtils.h"
17 #include "src/core/SkImageInfoPriv.h"
18 #include "src/core/SkImagePriv.h"
19 #include "src/core/SkMipmap.h"
20 #include "src/core/SkTraceEvent.h"
21 #include "src/gpu/ganesh/GrCaps.h"
22 #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h"
23 #include "src/gpu/ganesh/GrDirectContextPriv.h"
24 #include "src/gpu/ganesh/GrImageContextPriv.h"
25 #include "src/gpu/ganesh/GrRenderTarget.h"
26 #include "src/gpu/ganesh/GrResourceProvider.h"
27 #include "src/gpu/ganesh/GrSurfaceProxy.h"
28 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
29 #include "src/gpu/ganesh/GrTexture.h"
30 #include "src/gpu/ganesh/GrTextureProxyCacheAccess.h"
31 #include "src/gpu/ganesh/GrTextureRenderTargetProxy.h"
32 #include "src/gpu/ganesh/SkGr.h"
33 #include "src/image/SkImage_Base.h"
34
35 #ifdef SK_VULKAN
36 #include "include/gpu/vk/GrVkTypes.h"
37 #endif
38
39 #define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(fImageContext->priv().singleOwner())
40
GrProxyProvider(GrImageContext * imageContext)41 GrProxyProvider::GrProxyProvider(GrImageContext* imageContext) : fImageContext(imageContext) {}
42
~GrProxyProvider()43 GrProxyProvider::~GrProxyProvider() {
44 if (this->renderingDirectly()) {
45 // In DDL-mode a proxy provider can still have extant uniquely keyed proxies (since
46 // they need their unique keys to, potentially, find a cached resource when the
47 // DDL is played) but, in non-DDL-mode they should all have been cleaned up by this point.
48 SkASSERT(!fUniquelyKeyedProxies.count());
49 }
50 }
51
assignUniqueKeyToProxy(const skgpu::UniqueKey & key,GrTextureProxy * proxy)52 bool GrProxyProvider::assignUniqueKeyToProxy(const skgpu::UniqueKey& key, GrTextureProxy* proxy) {
53 ASSERT_SINGLE_OWNER
54 SkASSERT(key.isValid());
55 if (this->isAbandoned() || !proxy) {
56 return false;
57 }
58
59 // Only the proxyProvider that created a proxy should be assigning unique keys to it.
60 SkASSERT(this->isDDLProvider() == proxy->creatingProvider());
61
62 #ifdef SK_DEBUG
63 {
64 auto direct = fImageContext->asDirectContext();
65 if (direct) {
66 GrResourceCache* resourceCache = direct->priv().getResourceCache();
67 // If there is already a GrResource with this key then the caller has violated the
68 // normal usage pattern of uniquely keyed resources (e.g., they have created one w/o
69 // first seeing if it already existed in the cache).
70 SkASSERT(!resourceCache->findAndRefUniqueResource(key));
71 }
72 }
73 #endif
74
75 SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key
76
77 proxy->cacheAccess().setUniqueKey(this, key);
78 SkASSERT(proxy->getUniqueKey() == key);
79 fUniquelyKeyedProxies.add(proxy);
80 return true;
81 }
82
adoptUniqueKeyFromSurface(GrTextureProxy * proxy,const GrSurface * surf)83 void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) {
84 SkASSERT(surf->getUniqueKey().isValid());
85 proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey());
86 SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey());
87 // multiple proxies can't get the same key
88 SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey()));
89 fUniquelyKeyedProxies.add(proxy);
90 }
91
removeUniqueKeyFromProxy(GrTextureProxy * proxy)92 void GrProxyProvider::removeUniqueKeyFromProxy(GrTextureProxy* proxy) {
93 ASSERT_SINGLE_OWNER
94 SkASSERT(proxy);
95 SkASSERT(proxy->getUniqueKey().isValid());
96
97 if (this->isAbandoned()) {
98 return;
99 }
100
101 this->processInvalidUniqueKey(proxy->getUniqueKey(), proxy, InvalidateGPUResource::kYes);
102 }
103
findProxyByUniqueKey(const skgpu::UniqueKey & key)104 sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const skgpu::UniqueKey& key) {
105 ASSERT_SINGLE_OWNER
106
107 if (this->isAbandoned()) {
108 return nullptr;
109 }
110
111 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
112 if (proxy) {
113 return sk_ref_sp(proxy);
114 }
115 return nullptr;
116 }
117
118 ///////////////////////////////////////////////////////////////////////////////
119
120 #if GR_TEST_UTILS
testingOnly_createInstantiatedProxy(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected)121 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy(
122 SkISize dimensions,
123 const GrBackendFormat& format,
124 GrRenderable renderable,
125 int renderTargetSampleCnt,
126 SkBackingFit fit,
127 skgpu::Budgeted budgeted,
128 GrProtected isProtected) {
129 ASSERT_SINGLE_OWNER
130 if (this->isAbandoned()) {
131 return nullptr;
132 }
133 auto direct = fImageContext->asDirectContext();
134 if (!direct) {
135 return nullptr;
136 }
137
138 if (this->caps()->isFormatCompressed(format)) {
139 // TODO: Allow this to go to GrResourceProvider::createCompressedTexture() once we no longer
140 // rely on GrColorType to get a swizzle for the proxy.
141 return nullptr;
142 }
143
144 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
145 sk_sp<GrTexture> tex;
146
147 if (SkBackingFit::kApprox == fit) {
148 tex = resourceProvider->createApproxTexture(
149 dimensions,
150 format,
151 format.textureType(),
152 renderable,
153 renderTargetSampleCnt,
154 isProtected,
155 /*label=*/"InstantiatedProxyViaApproxTexture_Test");
156 } else {
157 tex = resourceProvider->createTexture(dimensions,
158 format,
159 format.textureType(),
160 renderable,
161 renderTargetSampleCnt,
162 GrMipmapped::kNo,
163 budgeted,
164 isProtected,
165 /*label=*/"InstantiatedProxyViaTexture_Test");
166 }
167 if (!tex) {
168 return nullptr;
169 }
170
171 return this->createWrapped(std::move(tex), UseAllocator::kYes);
172 }
173
testingOnly_createInstantiatedProxy(SkISize dimensions,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected)174 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy(
175 SkISize dimensions,
176 GrColorType colorType,
177 GrRenderable renderable,
178 int renderTargetSampleCnt,
179 SkBackingFit fit,
180 skgpu::Budgeted budgeted,
181 GrProtected isProtected) {
182 ASSERT_SINGLE_OWNER
183 if (this->isAbandoned()) {
184 return nullptr;
185 }
186 auto format = this->caps()->getDefaultBackendFormat(colorType, renderable);
187 return this->testingOnly_createInstantiatedProxy(dimensions,
188 format,
189 renderable,
190 renderTargetSampleCnt,
191 fit,
192 budgeted,
193 isProtected);
194 }
195
testingOnly_createWrapped(sk_sp<GrTexture> tex)196 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createWrapped(sk_sp<GrTexture> tex) {
197 return this->createWrapped(std::move(tex), UseAllocator::kYes);
198 }
199 #endif
200
createWrapped(sk_sp<GrTexture> tex,UseAllocator useAllocator)201 sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex,
202 UseAllocator useAllocator) {
203 #ifdef SK_DEBUG
204 if (tex->getUniqueKey().isValid()) {
205 SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey()));
206 }
207 #endif
208
209 if (tex->asRenderTarget()) {
210 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(
211 std::move(tex), useAllocator, this->isDDLProvider()));
212 } else {
213 return sk_sp<GrTextureProxy>(
214 new GrTextureProxy(std::move(tex), useAllocator, this->isDDLProvider()));
215 }
216 }
217
findOrCreateProxyByUniqueKey(const skgpu::UniqueKey & key,UseAllocator useAllocator)218 sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const skgpu::UniqueKey& key,
219 UseAllocator useAllocator) {
220 ASSERT_SINGLE_OWNER
221
222 if (this->isAbandoned()) {
223 return nullptr;
224 }
225
226 sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key);
227 if (result) {
228 return result;
229 }
230
231 auto direct = fImageContext->asDirectContext();
232 if (!direct) {
233 return nullptr;
234 }
235
236 GrResourceCache* resourceCache = direct->priv().getResourceCache();
237
238 GrGpuResource* resource = resourceCache->findAndRefUniqueResource(key);
239 if (!resource) {
240 return nullptr;
241 }
242
243 sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
244 SkASSERT(texture);
245
246 result = this->createWrapped(std::move(texture), useAllocator);
247 SkASSERT(result->getUniqueKey() == key);
248 // createWrapped should've added this for us
249 SkASSERT(fUniquelyKeyedProxies.find(key));
250 return result;
251 }
252
findCachedProxyWithColorTypeFallback(const skgpu::UniqueKey & key,GrSurfaceOrigin origin,GrColorType ct,int sampleCnt)253 GrSurfaceProxyView GrProxyProvider::findCachedProxyWithColorTypeFallback(
254 const skgpu::UniqueKey& key,
255 GrSurfaceOrigin origin,
256 GrColorType ct,
257 int sampleCnt) {
258 auto proxy = this->findOrCreateProxyByUniqueKey(key);
259 if (!proxy) {
260 return {};
261 }
262 const GrCaps* caps = fImageContext->priv().caps();
263
264 // Assume that we used a fallback color type if and only if the proxy is renderable.
265 if (proxy->asRenderTargetProxy()) {
266 GrBackendFormat expectedFormat;
267 std::tie(ct, expectedFormat) = caps->getFallbackColorTypeAndFormat(ct, sampleCnt);
268 SkASSERT(expectedFormat == proxy->backendFormat());
269 }
270 skgpu::Swizzle swizzle = caps->getReadSwizzle(proxy->backendFormat(), ct);
271 return {std::move(proxy), origin, swizzle};
272 }
273
createProxyFromBitmap(const SkBitmap & bitmap,GrMipmapped mipmapped,SkBackingFit fit,skgpu::Budgeted budgeted)274 sk_sp<GrTextureProxy> GrProxyProvider::createProxyFromBitmap(const SkBitmap& bitmap,
275 GrMipmapped mipmapped,
276 SkBackingFit fit,
277 skgpu::Budgeted budgeted) {
278 ASSERT_SINGLE_OWNER
279 SkASSERT(fit == SkBackingFit::kExact || mipmapped == GrMipmapped::kNo);
280
281 if (this->isAbandoned()) {
282 return nullptr;
283 }
284
285 if (!SkImageInfoIsValid(bitmap.info())) {
286 return nullptr;
287 }
288
289 ATRACE_ANDROID_FRAMEWORK("Upload %sTexture [%ux%u]",
290 GrMipmapped::kYes == mipmapped ? "MipMap " : "",
291 bitmap.width(), bitmap.height());
292
293 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap
294 // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the
295 // upload of the data to the gpu can happen at anytime and the bitmap may change by then.
296 SkBitmap copyBitmap = bitmap;
297 if (!this->renderingDirectly() && !bitmap.isImmutable()) {
298 copyBitmap.allocPixels();
299 if (!bitmap.readPixels(copyBitmap.pixmap())) {
300 return nullptr;
301 }
302 if (mipmapped == GrMipmapped::kYes && bitmap.fMips) {
303 copyBitmap.fMips = sk_sp<SkMipmap>(SkMipmap::Build(copyBitmap.pixmap(),
304 nullptr,
305 false));
306 for (int i = 0; i < copyBitmap.fMips->countLevels(); ++i) {
307 SkMipmap::Level src, dst;
308 bitmap.fMips->getLevel(i, &src);
309 copyBitmap.fMips->getLevel(i, &dst);
310 src.fPixmap.readPixels(dst.fPixmap);
311 }
312 }
313 copyBitmap.setImmutable();
314 }
315
316 sk_sp<GrTextureProxy> proxy;
317 if (mipmapped == GrMipmapped::kNo || !SkMipmap::ComputeLevelCount(copyBitmap.dimensions())) {
318 proxy = this->createNonMippedProxyFromBitmap(copyBitmap, fit, budgeted);
319 } else {
320 proxy = this->createMippedProxyFromBitmap(copyBitmap, budgeted);
321 }
322
323 if (!proxy) {
324 return nullptr;
325 }
326
327 auto direct = fImageContext->asDirectContext();
328 if (direct) {
329 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
330
331 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
332 // we're better off instantiating the proxy immediately here.
333 if (!proxy->priv().doLazyInstantiation(resourceProvider)) {
334 return nullptr;
335 }
336 }
337 return proxy;
338 }
339
createNonMippedProxyFromBitmap(const SkBitmap & bitmap,SkBackingFit fit,skgpu::Budgeted budgeted)340 sk_sp<GrTextureProxy> GrProxyProvider::createNonMippedProxyFromBitmap(const SkBitmap& bitmap,
341 SkBackingFit fit,
342 skgpu::Budgeted budgeted) {
343 auto dims = bitmap.dimensions();
344
345 auto colorType = SkColorTypeToGrColorType(bitmap.colorType());
346 GrBackendFormat format = this->caps()->getDefaultBackendFormat(colorType, GrRenderable::kNo);
347 if (!format.isValid()) {
348 return nullptr;
349 }
350
351 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
352 [bitmap](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) {
353 SkASSERT(desc.fMipmapped == GrMipmapped::kNo);
354 GrMipLevel mipLevel = {bitmap.getPixels(), bitmap.rowBytes(), nullptr};
355 auto colorType = SkColorTypeToGrColorType(bitmap.colorType());
356 return LazyCallbackResult(resourceProvider->createTexture(desc.fDimensions,
357 desc.fFormat,
358 desc.fTextureType,
359 colorType,
360 desc.fRenderable,
361 desc.fSampleCnt,
362 desc.fBudgeted,
363 desc.fFit,
364 desc.fProtected,
365 mipLevel,
366 desc.fLabel));
367 },
368 format, dims, GrMipmapped::kNo, GrMipmapStatus::kNotAllocated,
369 GrInternalSurfaceFlags::kNone, fit, budgeted, GrProtected::kNo, UseAllocator::kYes,
370 "ProxyProvider_CreateNonMippedProxyFromBitmap");
371
372 if (!proxy) {
373 return nullptr;
374 }
375 SkASSERT(proxy->dimensions() == bitmap.dimensions());
376 return proxy;
377 }
378
createMippedProxyFromBitmap(const SkBitmap & bitmap,skgpu::Budgeted budgeted)379 sk_sp<GrTextureProxy> GrProxyProvider::createMippedProxyFromBitmap(const SkBitmap& bitmap,
380 skgpu::Budgeted budgeted) {
381 SkASSERT(this->caps()->mipmapSupport());
382
383 auto colorType = SkColorTypeToGrColorType(bitmap.colorType());
384 GrBackendFormat format = this->caps()->getDefaultBackendFormat(colorType, GrRenderable::kNo);
385 if (!format.isValid()) {
386 return nullptr;
387 }
388
389 sk_sp<SkMipmap> mipmaps = bitmap.fMips;
390 if (!mipmaps) {
391 mipmaps.reset(SkMipmap::Build(bitmap.pixmap(), nullptr));
392 if (!mipmaps) {
393 return nullptr;
394 }
395 }
396
397 auto dims = bitmap.dimensions();
398
399 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
400 [bitmap, mipmaps](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) {
401 const int mipLevelCount = mipmaps->countLevels() + 1;
402 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
403 auto colorType = SkColorTypeToGrColorType(bitmap.colorType());
404
405 texels[0].fPixels = bitmap.getPixels();
406 texels[0].fRowBytes = bitmap.rowBytes();
407
408 for (int i = 1; i < mipLevelCount; ++i) {
409 SkMipmap::Level generatedMipLevel;
410 mipmaps->getLevel(i - 1, &generatedMipLevel);
411 texels[i].fPixels = generatedMipLevel.fPixmap.addr();
412 texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes();
413 SkASSERT(texels[i].fPixels);
414 SkASSERT(generatedMipLevel.fPixmap.colorType() == bitmap.colorType());
415 }
416 return LazyCallbackResult(resourceProvider->createTexture(desc.fDimensions,
417 desc.fFormat,
418 desc.fTextureType,
419 colorType,
420 GrRenderable::kNo,
421 1,
422 desc.fBudgeted,
423 GrMipmapped::kYes,
424 GrProtected::kNo,
425 texels.get(),
426 desc.fLabel));
427 },
428 format, dims, GrMipmapped::kYes, GrMipmapStatus::kValid, GrInternalSurfaceFlags::kNone,
429 SkBackingFit::kExact,
430 budgeted,
431 GrProtected::kNo,
432 UseAllocator::kYes,
433 "ProxyProvider_CreateMippedProxyFromBitmap");
434
435 if (!proxy) {
436 return nullptr;
437 }
438
439 SkASSERT(proxy->dimensions() == bitmap.dimensions());
440
441 return proxy;
442 }
443
createProxy(const GrBackendFormat & format,SkISize dimensions,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipmapped,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,std::string_view label,GrInternalSurfaceFlags surfaceFlags,GrSurfaceProxy::UseAllocator useAllocator)444 sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrBackendFormat& format,
445 SkISize dimensions,
446 GrRenderable renderable,
447 int renderTargetSampleCnt,
448 GrMipmapped mipmapped,
449 SkBackingFit fit,
450 skgpu::Budgeted budgeted,
451 GrProtected isProtected,
452 std::string_view label,
453 GrInternalSurfaceFlags surfaceFlags,
454 GrSurfaceProxy::UseAllocator useAllocator) {
455 ASSERT_SINGLE_OWNER
456 if (this->isAbandoned()) {
457 return nullptr;
458 }
459
460 const GrCaps* caps = this->caps();
461
462 if (caps->isFormatCompressed(format)) {
463 // Deferred proxies for compressed textures are not supported.
464 return nullptr;
465 }
466
467 if (GrMipmapped::kYes == mipmapped) {
468 // SkMipmap doesn't include the base level in the level count so we have to add 1
469 int mipCount = SkMipmap::ComputeLevelCount(dimensions.fWidth, dimensions.fHeight) + 1;
470 if (1 == mipCount) {
471 mipmapped = GrMipmapped::kNo;
472 }
473 }
474
475 if (!caps->validateSurfaceParams(dimensions,
476 format,
477 renderable,
478 renderTargetSampleCnt,
479 mipmapped,
480 GrTextureType::k2D)) {
481 return nullptr;
482 }
483 GrMipmapStatus mipmapStatus = (GrMipmapped::kYes == mipmapped)
484 ? GrMipmapStatus::kDirty
485 : GrMipmapStatus::kNotAllocated;
486 if (renderable == GrRenderable::kYes) {
487 renderTargetSampleCnt = caps->getRenderTargetSampleCount(renderTargetSampleCnt, format);
488 SkASSERT(renderTargetSampleCnt);
489 GrInternalSurfaceFlags extraFlags = caps->getExtraSurfaceFlagsForDeferredRT();
490 // We know anything we instantiate later from this deferred path will be
491 // both texturable and renderable
492 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps,
493 format,
494 dimensions,
495 renderTargetSampleCnt,
496 mipmapped,
497 mipmapStatus,
498 fit,
499 budgeted,
500 isProtected,
501 surfaceFlags | extraFlags,
502 useAllocator,
503 this->isDDLProvider(),
504 label));
505 }
506
507 return sk_sp<GrTextureProxy>(new GrTextureProxy(format,
508 dimensions,
509 mipmapped,
510 mipmapStatus,
511 fit,
512 budgeted,
513 isProtected,
514 surfaceFlags,
515 useAllocator,
516 this->isDDLProvider(),
517 label));
518 }
519
createCompressedTextureProxy(SkISize dimensions,skgpu::Budgeted budgeted,GrMipmapped mipmapped,GrProtected isProtected,SkImage::CompressionType compressionType,sk_sp<SkData> data)520 sk_sp<GrTextureProxy> GrProxyProvider::createCompressedTextureProxy(
521 SkISize dimensions,
522 skgpu::Budgeted budgeted,
523 GrMipmapped mipmapped,
524 GrProtected isProtected,
525 SkImage::CompressionType compressionType,
526 sk_sp<SkData> data) {
527 ASSERT_SINGLE_OWNER
528 if (this->isAbandoned()) {
529 return nullptr;
530 }
531
532 GrBackendFormat format = this->caps()->getBackendFormatFromCompressionType(compressionType);
533
534 if (!this->caps()->isFormatTexturable(format, GrTextureType::k2D)) {
535 return nullptr;
536 }
537
538 GrMipmapStatus mipmapStatus = (GrMipmapped::kYes == mipmapped) ? GrMipmapStatus::kValid
539 : GrMipmapStatus::kNotAllocated;
540
541 sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
542 [data](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) {
543 return LazyCallbackResult(
544 resourceProvider->createCompressedTexture(desc.fDimensions,
545 desc.fFormat,
546 desc.fBudgeted,
547 desc.fMipmapped,
548 desc.fProtected,
549 data.get(),
550 desc.fLabel));
551 },
552 format,
553 dimensions,
554 mipmapped,
555 mipmapStatus,
556 GrInternalSurfaceFlags::kReadOnly,
557 SkBackingFit::kExact,
558 skgpu::Budgeted::kYes,
559 GrProtected::kNo,
560 UseAllocator::kYes,
561 "ProxyProvider_CreateCompressedTextureProxy");
562
563 if (!proxy) {
564 return nullptr;
565 }
566
567 auto direct = fImageContext->asDirectContext();
568 if (direct) {
569 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
570 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
571 // we're better off instantiating the proxy immediately here.
572 if (!proxy->priv().doLazyInstantiation(resourceProvider)) {
573 return nullptr;
574 }
575 }
576 return proxy;
577 }
578
wrapBackendTexture(const GrBackendTexture & backendTex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType,sk_sp<skgpu::RefCntedCallback> releaseHelper)579 sk_sp<GrTextureProxy> GrProxyProvider::wrapBackendTexture(
580 const GrBackendTexture& backendTex,
581 GrWrapOwnership ownership,
582 GrWrapCacheable cacheable,
583 GrIOType ioType,
584 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
585 SkASSERT(ioType != kWrite_GrIOType);
586
587 if (this->isAbandoned()) {
588 return nullptr;
589 }
590
591 // This is only supported on a direct GrContext.
592 auto direct = fImageContext->asDirectContext();
593 if (!direct) {
594 return nullptr;
595 }
596
597 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
598
599 sk_sp<GrTexture> tex =
600 resourceProvider->wrapBackendTexture(backendTex, ownership, cacheable, ioType);
601 if (!tex) {
602 return nullptr;
603 }
604
605 if (releaseHelper) {
606 tex->setRelease(std::move(releaseHelper));
607 }
608
609 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture
610 // Make sure we match how we created the proxy with skgpu::Budgeted::kNo
611 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
612
613 return sk_sp<GrTextureProxy>(
614 new GrTextureProxy(std::move(tex), UseAllocator::kNo, this->isDDLProvider()));
615 }
616
wrapCompressedBackendTexture(const GrBackendTexture & beTex,GrWrapOwnership ownership,GrWrapCacheable cacheable,sk_sp<skgpu::RefCntedCallback> releaseHelper)617 sk_sp<GrTextureProxy> GrProxyProvider::wrapCompressedBackendTexture(
618 const GrBackendTexture& beTex,
619 GrWrapOwnership ownership,
620 GrWrapCacheable cacheable,
621 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
622 if (this->isAbandoned()) {
623 return nullptr;
624 }
625
626 // This is only supported on a direct GrContext.
627 auto direct = fImageContext->asDirectContext();
628 if (!direct) {
629 return nullptr;
630 }
631
632 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
633
634 sk_sp<GrTexture> tex = resourceProvider->wrapCompressedBackendTexture(beTex, ownership,
635 cacheable);
636 if (!tex) {
637 return nullptr;
638 }
639
640 if (releaseHelper) {
641 tex->setRelease(std::move(releaseHelper));
642 }
643
644 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture
645 // Make sure we match how we created the proxy with skgpu::Budgeted::kNo
646 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
647
648 return sk_sp<GrTextureProxy>(
649 new GrTextureProxy(std::move(tex), UseAllocator::kNo, this->isDDLProvider()));
650 }
651
wrapRenderableBackendTexture(const GrBackendTexture & backendTex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable,sk_sp<skgpu::RefCntedCallback> releaseHelper)652 sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture(
653 const GrBackendTexture& backendTex,
654 int sampleCnt,
655 GrWrapOwnership ownership,
656 GrWrapCacheable cacheable,
657 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
658 if (this->isAbandoned()) {
659 return nullptr;
660 }
661
662 // This is only supported on a direct GrContext.
663 auto direct = fImageContext->asDirectContext();
664 if (!direct) {
665 return nullptr;
666 }
667
668 const GrCaps* caps = this->caps();
669
670 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
671
672 sampleCnt = caps->getRenderTargetSampleCount(sampleCnt, backendTex.getBackendFormat());
673 SkASSERT(sampleCnt);
674
675 sk_sp<GrTexture> tex = resourceProvider->wrapRenderableBackendTexture(
676 backendTex, sampleCnt, ownership, cacheable);
677 if (!tex) {
678 return nullptr;
679 }
680
681 if (releaseHelper) {
682 tex->setRelease(std::move(releaseHelper));
683 }
684
685 SkASSERT(tex->asRenderTarget()); // A GrTextureRenderTarget
686 // Make sure we match how we created the proxy with skgpu::Budgeted::kNo
687 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
688
689 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(
690 std::move(tex), UseAllocator::kNo, this->isDDLProvider()));
691 }
692
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT,sk_sp<skgpu::RefCntedCallback> releaseHelper)693 sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget(
694 const GrBackendRenderTarget& backendRT,
695 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
696 if (this->isAbandoned()) {
697 return nullptr;
698 }
699
700 // This is only supported on a direct GrContext.
701 auto direct = fImageContext->asDirectContext();
702 if (!direct) {
703 return nullptr;
704 }
705
706 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
707
708 sk_sp<GrRenderTarget> rt = resourceProvider->wrapBackendRenderTarget(backendRT);
709 if (!rt) {
710 return nullptr;
711 }
712
713 if (releaseHelper) {
714 rt->setRelease(std::move(releaseHelper));
715 }
716
717 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable
718 SkASSERT(!rt->getUniqueKey().isValid());
719 // Make sure we match how we created the proxy with skgpu::Budgeted::kNo
720 SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
721
722 return sk_sp<GrRenderTargetProxy>(
723 new GrRenderTargetProxy(std::move(rt), UseAllocator::kNo, {}));
724 }
725
726 #ifdef SK_VULKAN
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)727 sk_sp<GrRenderTargetProxy> GrProxyProvider::wrapVulkanSecondaryCBAsRenderTarget(
728 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
729 if (this->isAbandoned()) {
730 return nullptr;
731 }
732
733 // This is only supported on a direct GrContext.
734 auto direct = fImageContext->asDirectContext();
735 if (!direct) {
736 return nullptr;
737 }
738
739 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
740
741 sk_sp<GrRenderTarget> rt = resourceProvider->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
742 vkInfo);
743 if (!rt) {
744 return nullptr;
745 }
746
747 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable
748 SkASSERT(!rt->getUniqueKey().isValid());
749 // This proxy should be unbudgeted because we're just wrapping an external resource
750 SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
751
752 GrColorType colorType = SkColorTypeToGrColorType(imageInfo.colorType());
753
754 if (!this->caps()->isFormatAsColorTypeRenderable(
755 colorType, GrBackendFormat::MakeVk(vkInfo.fFormat), /*sampleCount=*/1)) {
756 return nullptr;
757 }
758
759 return sk_sp<GrRenderTargetProxy>(
760 new GrRenderTargetProxy(std::move(rt),
761 UseAllocator::kNo,
762 GrRenderTargetProxy::WrapsVkSecondaryCB::kYes));
763 }
764 #else
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo &,const GrVkDrawableInfo &)765 sk_sp<GrRenderTargetProxy> GrProxyProvider::wrapVulkanSecondaryCBAsRenderTarget(
766 const SkImageInfo&, const GrVkDrawableInfo&) {
767 return nullptr;
768 }
769 #endif
770
CreatePromiseProxy(GrContextThreadSafeProxy * threadSafeProxy,LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,GrMipmapped mipmapped)771 sk_sp<GrTextureProxy> GrProxyProvider::CreatePromiseProxy(GrContextThreadSafeProxy* threadSafeProxy,
772 LazyInstantiateCallback&& callback,
773 const GrBackendFormat& format,
774 SkISize dimensions,
775 GrMipmapped mipmapped) {
776 if (threadSafeProxy->priv().abandoned()) {
777 return nullptr;
778 }
779 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) ||
780 (dimensions.fWidth > 0 && dimensions.fHeight > 0));
781
782 if (dimensions.fWidth > threadSafeProxy->priv().caps()->maxTextureSize() ||
783 dimensions.fHeight > threadSafeProxy->priv().caps()->maxTextureSize()) {
784 return nullptr;
785 }
786 if (!threadSafeProxy->priv().caps()->isFormatTexturable(format, format.textureType())) {
787 return nullptr;
788 }
789 // Ganesh assumes that, when wrapping a mipmapped backend texture from a client, that its
790 // mipmaps are fully fleshed out.
791 GrMipmapStatus mipmapStatus = (GrMipmapped::kYes == mipmapped) ? GrMipmapStatus::kValid
792 : GrMipmapStatus::kNotAllocated;
793
794 // We pass kReadOnly here since we should treat content of the client's texture as immutable.
795 // The promise API provides no way for the client to indicate that the texture is protected.
796 auto proxy = sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback),
797 format,
798 dimensions,
799 mipmapped,
800 mipmapStatus,
801 SkBackingFit::kExact,
802 skgpu::Budgeted::kNo,
803 GrProtected::kNo,
804 GrInternalSurfaceFlags::kReadOnly,
805 GrSurfaceProxy::UseAllocator::kYes,
806 GrDDLProvider::kYes,
807 /*label=*/"PromiseProxy"));
808 proxy->priv().setIsPromiseProxy();
809 return proxy;
810 }
811
createLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,GrMipmapped mipmapped,GrMipmapStatus mipmapStatus,GrInternalSurfaceFlags surfaceFlags,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,GrSurfaceProxy::UseAllocator useAllocator,std::string_view label)812 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
813 const GrBackendFormat& format,
814 SkISize dimensions,
815 GrMipmapped mipmapped,
816 GrMipmapStatus mipmapStatus,
817 GrInternalSurfaceFlags surfaceFlags,
818 SkBackingFit fit,
819 skgpu::Budgeted budgeted,
820 GrProtected isProtected,
821 GrSurfaceProxy::UseAllocator useAllocator,
822 std::string_view label) {
823 ASSERT_SINGLE_OWNER
824 if (this->isAbandoned()) {
825 return nullptr;
826 }
827 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) ||
828 (dimensions.fWidth > 0 && dimensions.fHeight > 0));
829
830 if (!format.isValid() || format.backend() != fImageContext->backend()) {
831 return nullptr;
832 }
833
834 if (dimensions.fWidth > this->caps()->maxTextureSize() ||
835 dimensions.fHeight > this->caps()->maxTextureSize()) {
836 return nullptr;
837 }
838
839 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback),
840 format,
841 dimensions,
842 mipmapped,
843 mipmapStatus,
844 fit,
845 budgeted,
846 isProtected,
847 surfaceFlags,
848 useAllocator,
849 this->isDDLProvider(),
850 label));
851 }
852
createLazyRenderTargetProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,int sampleCnt,GrInternalSurfaceFlags surfaceFlags,const TextureInfo * textureInfo,GrMipmapStatus mipmapStatus,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,bool wrapsVkSecondaryCB,UseAllocator useAllocator)853 sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy(
854 LazyInstantiateCallback&& callback,
855 const GrBackendFormat& format,
856 SkISize dimensions,
857 int sampleCnt,
858 GrInternalSurfaceFlags surfaceFlags,
859 const TextureInfo* textureInfo,
860 GrMipmapStatus mipmapStatus,
861 SkBackingFit fit,
862 skgpu::Budgeted budgeted,
863 GrProtected isProtected,
864 bool wrapsVkSecondaryCB,
865 UseAllocator useAllocator) {
866 ASSERT_SINGLE_OWNER
867 if (this->isAbandoned()) {
868 return nullptr;
869 }
870 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) ||
871 (dimensions.fWidth > 0 && dimensions.fHeight > 0));
872
873 if (dimensions.fWidth > this->caps()->maxRenderTargetSize() ||
874 dimensions.fHeight > this->caps()->maxRenderTargetSize()) {
875 return nullptr;
876 }
877
878 if (textureInfo) {
879 // Wrapped vulkan secondary command buffers don't support texturing since we won't have an
880 // actual VkImage to texture from.
881 SkASSERT(!wrapsVkSecondaryCB);
882 return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(
883 *this->caps(),
884 std::move(callback),
885 format,
886 dimensions,
887 sampleCnt,
888 textureInfo->fMipmapped,
889 mipmapStatus,
890 fit,
891 budgeted,
892 isProtected,
893 surfaceFlags,
894 useAllocator,
895 this->isDDLProvider(),
896 /*label=*/"TextureRenderTarget_LazyRenderTargetProxy"));
897 }
898
899 GrRenderTargetProxy::WrapsVkSecondaryCB vkSCB =
900 wrapsVkSecondaryCB ? GrRenderTargetProxy::WrapsVkSecondaryCB::kYes
901 : GrRenderTargetProxy::WrapsVkSecondaryCB::kNo;
902
903 return sk_sp<GrRenderTargetProxy>(
904 new GrRenderTargetProxy(std::move(callback),
905 format,
906 dimensions,
907 sampleCnt,
908 fit,
909 budgeted,
910 isProtected,
911 surfaceFlags,
912 useAllocator,
913 vkSCB,
914 /*label=*/"RenderTargetProxy_LazyRenderTargetProxy"));
915 }
916
MakeFullyLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrProtected isProtected,const GrCaps & caps,UseAllocator useAllocator)917 sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallback&& callback,
918 const GrBackendFormat& format,
919 GrRenderable renderable,
920 int renderTargetSampleCnt,
921 GrProtected isProtected,
922 const GrCaps& caps,
923 UseAllocator useAllocator) {
924 if (!format.isValid()) {
925 return nullptr;
926 }
927
928 SkASSERT(renderTargetSampleCnt == 1 || renderable == GrRenderable::kYes);
929 // TODO: If we ever have callers requesting specific surface flags then we shouldn't use the
930 // extra deferred flags here. Instead those callers should all pass in exactly what they want.
931 // However, as of today all uses of this essentially create a deferred proxy in the end.
932 GrInternalSurfaceFlags surfaceFlags = caps.getExtraSurfaceFlagsForDeferredRT();
933
934 // MakeFullyLazyProxy is only called at flush time so we know these texture proxies are
935 // not being created by a DDL provider.
936 static constexpr SkISize kLazyDims = {-1, -1};
937 if (GrRenderable::kYes == renderable) {
938 return sk_sp<GrTextureProxy>(
939 new GrTextureRenderTargetProxy(caps,
940 std::move(callback),
941 format,
942 kLazyDims,
943 renderTargetSampleCnt,
944 GrMipmapped::kNo,
945 GrMipmapStatus::kNotAllocated,
946 SkBackingFit::kApprox,
947 skgpu::Budgeted::kYes,
948 isProtected,
949 surfaceFlags,
950 useAllocator,
951 GrDDLProvider::kNo,
952 /*label=*/"TextureRenderTarget_FullyLazyProxy"));
953 } else {
954 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback),
955 format,
956 kLazyDims,
957 GrMipmapped::kNo,
958 GrMipmapStatus::kNotAllocated,
959 SkBackingFit::kApprox,
960 skgpu::Budgeted::kYes,
961 isProtected,
962 surfaceFlags,
963 useAllocator,
964 GrDDLProvider::kNo,
965 /*label=*/"Texture_FullyLazyProxy"));
966 }
967 }
968
processInvalidUniqueKey(const skgpu::UniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource)969 void GrProxyProvider::processInvalidUniqueKey(const skgpu::UniqueKey& key,
970 GrTextureProxy* proxy,
971 InvalidateGPUResource invalidateGPUResource) {
972 this->processInvalidUniqueKeyImpl(key, proxy, invalidateGPUResource, RemoveTableEntry::kYes);
973 }
974
processInvalidUniqueKeyImpl(const skgpu::UniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource,RemoveTableEntry removeTableEntry)975 void GrProxyProvider::processInvalidUniqueKeyImpl(const skgpu::UniqueKey& key,
976 GrTextureProxy* proxy,
977 InvalidateGPUResource invalidateGPUResource,
978 RemoveTableEntry removeTableEntry) {
979 SkASSERT(key.isValid());
980
981 if (!proxy) {
982 proxy = fUniquelyKeyedProxies.find(key);
983 }
984 SkASSERT(!proxy || proxy->getUniqueKey() == key);
985
986 // Locate the corresponding GrGpuResource (if it needs to be invalidated) before clearing the
987 // proxy's unique key. We must do it in this order because 'key' may alias the proxy's key.
988 sk_sp<GrGpuResource> invalidGpuResource;
989 if (InvalidateGPUResource::kYes == invalidateGPUResource) {
990 auto direct = fImageContext->asDirectContext();
991 if (direct) {
992 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
993 invalidGpuResource = resourceProvider->findByUniqueKey<GrGpuResource>(key);
994 }
995 SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key);
996 }
997
998 // Note: this method is called for the whole variety of GrGpuResources so often 'key'
999 // will not be in 'fUniquelyKeyedProxies'.
1000 if (proxy) {
1001 if (removeTableEntry == RemoveTableEntry::kYes) {
1002 fUniquelyKeyedProxies.remove(key);
1003 }
1004 proxy->cacheAccess().clearUniqueKey();
1005 }
1006
1007 if (invalidGpuResource) {
1008 invalidGpuResource->resourcePriv().removeUniqueKey();
1009 }
1010 }
1011
isDDLProvider() const1012 GrDDLProvider GrProxyProvider::isDDLProvider() const {
1013 return fImageContext->asDirectContext() ? GrDDLProvider::kNo : GrDDLProvider::kYes;
1014 }
1015
contextID() const1016 uint32_t GrProxyProvider::contextID() const {
1017 return fImageContext->priv().contextID();
1018 }
1019
caps() const1020 const GrCaps* GrProxyProvider::caps() const {
1021 return fImageContext->priv().caps();
1022 }
1023
refCaps() const1024 sk_sp<const GrCaps> GrProxyProvider::refCaps() const {
1025 return fImageContext->priv().refCaps();
1026 }
1027
isAbandoned() const1028 bool GrProxyProvider::isAbandoned() const {
1029 return fImageContext->priv().abandoned();
1030 }
1031
orphanAllUniqueKeys()1032 void GrProxyProvider::orphanAllUniqueKeys() {
1033 fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
1034 proxy->fProxyProvider = nullptr;
1035 });
1036 }
1037
removeAllUniqueKeys()1038 void GrProxyProvider::removeAllUniqueKeys() {
1039 fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
1040 // It's not safe to remove table entries while iterating with foreach(),
1041 // but since we're going to remove them all anyway, simply save that for the end.
1042 this->processInvalidUniqueKeyImpl(proxy->getUniqueKey(), proxy,
1043 InvalidateGPUResource::kNo,
1044 RemoveTableEntry::kNo);
1045 });
1046 // Removing all those table entries is safe now.
1047 fUniquelyKeyedProxies.reset();
1048 }
1049
renderingDirectly() const1050 bool GrProxyProvider::renderingDirectly() const {
1051 return fImageContext->asDirectContext();
1052 }
1053