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