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