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