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