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