• 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/GrResourceKey.h"
15 #include "include/private/GrSingleOwner.h"
16 #include "include/private/SkImageInfoPriv.h"
17 #include "src/core/SkAutoPixmapStorage.h"
18 #include "src/core/SkCompressedDataUtils.h"
19 #include "src/core/SkImagePriv.h"
20 #include "src/core/SkMipmap.h"
21 #include "src/core/SkTraceEvent.h"
22 #include "src/gpu/GrCaps.h"
23 #include "src/gpu/GrContextThreadSafeProxyPriv.h"
24 #include "src/gpu/GrDirectContextPriv.h"
25 #include "src/gpu/GrImageContextPriv.h"
26 #include "src/gpu/GrRenderTarget.h"
27 #include "src/gpu/GrResourceProvider.h"
28 #include "src/gpu/GrSurfaceProxy.h"
29 #include "src/gpu/GrSurfaceProxyPriv.h"
30 #include "src/gpu/GrTexture.h"
31 #include "src/gpu/GrTextureProxyCacheAccess.h"
32 #include "src/gpu/GrTextureRenderTargetProxy.h"
33 #include "src/gpu/SkGr.h"
34 #include "src/image/SkImage_Base.h"
35 
36 #ifdef SK_VULKAN
37 #include "include/gpu/vk/GrVkTypes.h"
38 #endif
39 
40 #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fImageContext->priv().singleOwner())
41 
GrProxyProvider(GrImageContext * imageContext)42 GrProxyProvider::GrProxyProvider(GrImageContext* imageContext) : fImageContext(imageContext) {}
43 
~GrProxyProvider()44 GrProxyProvider::~GrProxyProvider() {
45     if (this->renderingDirectly()) {
46         // In DDL-mode a proxy provider can still have extant uniquely keyed proxies (since
47         // they need their unique keys to, potentially, find a cached resource when the
48         // DDL is played) but, in non-DDL-mode they should all have been cleaned up by this point.
49         SkASSERT(!fUniquelyKeyedProxies.count());
50     }
51 }
52 
assignUniqueKeyToProxy(const GrUniqueKey & key,GrTextureProxy * proxy)53 bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
54     ASSERT_SINGLE_OWNER
55     SkASSERT(key.isValid());
56     if (this->isAbandoned() || !proxy) {
57         return false;
58     }
59 
60     // Only the proxyProvider that created a proxy should be assigning unique keys to it.
61     SkASSERT(this->isDDLProvider() == proxy->creatingProvider());
62 
63 #ifdef SK_DEBUG
64     {
65         auto direct = fImageContext->asDirectContext();
66         if (direct) {
67             GrResourceCache* resourceCache = direct->priv().getResourceCache();
68             // If there is already a GrResource with this key then the caller has violated the
69             // normal usage pattern of uniquely keyed resources (e.g., they have created one w/o
70             // first seeing if it already existed in the cache).
71             SkASSERT(!resourceCache->findAndRefUniqueResource(key));
72         }
73     }
74 #endif
75 
76     SkASSERT(!fUniquelyKeyedProxies.find(key));     // multiple proxies can't get the same key
77 
78     proxy->cacheAccess().setUniqueKey(this, key);
79     SkASSERT(proxy->getUniqueKey() == key);
80     fUniquelyKeyedProxies.add(proxy);
81     return true;
82 }
83 
adoptUniqueKeyFromSurface(GrTextureProxy * proxy,const GrSurface * surf)84 void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) {
85     SkASSERT(surf->getUniqueKey().isValid());
86     proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey());
87     SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey());
88     // multiple proxies can't get the same key
89     SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey()));
90     fUniquelyKeyedProxies.add(proxy);
91 }
92 
removeUniqueKeyFromProxy(GrTextureProxy * proxy)93 void GrProxyProvider::removeUniqueKeyFromProxy(GrTextureProxy* proxy) {
94     ASSERT_SINGLE_OWNER
95     SkASSERT(proxy);
96     SkASSERT(proxy->getUniqueKey().isValid());
97 
98     if (this->isAbandoned()) {
99         return;
100     }
101 
102     this->processInvalidUniqueKey(proxy->getUniqueKey(), proxy, InvalidateGPUResource::kYes);
103 }
104 
findProxyByUniqueKey(const GrUniqueKey & key)105 sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key) {
106     ASSERT_SINGLE_OWNER
107 
108     if (this->isAbandoned()) {
109         return nullptr;
110     }
111 
112     GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
113     if (proxy) {
114         return sk_ref_sp(proxy);
115     }
116     return nullptr;
117 }
118 
119 ///////////////////////////////////////////////////////////////////////////////
120 
121 #if GR_TEST_UTILS
testingOnly_createInstantiatedProxy(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected)122 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy(
123         SkISize dimensions,
124         const GrBackendFormat& format,
125         GrRenderable renderable,
126         int renderTargetSampleCnt,
127         SkBackingFit fit,
128         SkBudgeted budgeted,
129         GrProtected isProtected) {
130     ASSERT_SINGLE_OWNER
131     if (this->isAbandoned()) {
132         return nullptr;
133     }
134     auto direct = fImageContext->asDirectContext();
135     if (!direct) {
136         return nullptr;
137     }
138 
139     if (this->caps()->isFormatCompressed(format)) {
140         // TODO: Allow this to go to GrResourceProvider::createCompressedTexture() once we no longer
141         // rely on GrColorType to get a swizzle for the proxy.
142         return nullptr;
143     }
144 
145     GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
146     sk_sp<GrTexture> tex;
147 
148     if (SkBackingFit::kApprox == fit) {
149         tex = resourceProvider->createApproxTexture(dimensions,
150                                                     format,
151                                                     format.textureType(),
152                                                     renderable,
153                                                     renderTargetSampleCnt,
154                                                     isProtected);
155     } else {
156         tex = resourceProvider->createTexture(dimensions,
157                                               format,
158                                               format.textureType(),
159                                               renderable,
160                                               renderTargetSampleCnt,
161                                               GrMipmapped::kNo,
162                                               budgeted,
163                                               isProtected);
164     }
165     if (!tex) {
166         return nullptr;
167     }
168 
169     return this->createWrapped(std::move(tex), UseAllocator::kYes);
170 }
171 
testingOnly_createInstantiatedProxy(SkISize dimensions,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected)172 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy(
173         SkISize dimensions,
174         GrColorType colorType,
175         GrRenderable renderable,
176         int renderTargetSampleCnt,
177         SkBackingFit fit,
178         SkBudgeted budgeted,
179         GrProtected isProtected) {
180     ASSERT_SINGLE_OWNER
181     if (this->isAbandoned()) {
182         return nullptr;
183     }
184     auto format = this->caps()->getDefaultBackendFormat(colorType, renderable);
185     return this->testingOnly_createInstantiatedProxy(dimensions,
186                                                      format,
187                                                      renderable,
188                                                      renderTargetSampleCnt,
189                                                      fit,
190                                                      budgeted,
191                                                      isProtected);
192 }
193 
testingOnly_createWrapped(sk_sp<GrTexture> tex)194 sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createWrapped(sk_sp<GrTexture> tex) {
195     return this->createWrapped(std::move(tex), UseAllocator::kYes);
196 }
197 #endif
198 
createWrapped(sk_sp<GrTexture> tex,UseAllocator useAllocator)199 sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex,
200                                                      UseAllocator useAllocator) {
201 #ifdef SK_DEBUG
202     if (tex->getUniqueKey().isValid()) {
203         SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey()));
204     }
205 #endif
206 
207     if (tex->asRenderTarget()) {
208         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), useAllocator,
209                                                                     this->isDDLProvider()));
210     } else {
211         return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), useAllocator,
212                                                         this->isDDLProvider()));
213     }
214 }
215 
findOrCreateProxyByUniqueKey(const GrUniqueKey & key,UseAllocator useAllocator)216 sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key,
217                                                                     UseAllocator useAllocator) {
218     ASSERT_SINGLE_OWNER
219 
220     if (this->isAbandoned()) {
221         return nullptr;
222     }
223 
224     sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key);
225     if (result) {
226         return result;
227     }
228 
229     auto direct = fImageContext->asDirectContext();
230     if (!direct) {
231         return nullptr;
232     }
233 
234     GrResourceCache* resourceCache = direct->priv().getResourceCache();
235 
236     GrGpuResource* resource = resourceCache->findAndRefUniqueResource(key);
237     if (!resource) {
238         return nullptr;
239     }
240 
241     sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
242     SkASSERT(texture);
243 
244     result = this->createWrapped(std::move(texture), useAllocator);
245     SkASSERT(result->getUniqueKey() == key);
246     // createWrapped should've added this for us
247     SkASSERT(fUniquelyKeyedProxies.find(key));
248     return result;
249 }
250 
findCachedProxyWithColorTypeFallback(const GrUniqueKey & key,GrSurfaceOrigin origin,GrColorType ct,int sampleCnt)251 GrSurfaceProxyView GrProxyProvider::findCachedProxyWithColorTypeFallback(const GrUniqueKey& 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     GrSwizzle 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 GrUniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource)865 void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy,
866                                               InvalidateGPUResource invalidateGPUResource) {
867     this->processInvalidUniqueKeyImpl(key, proxy, invalidateGPUResource, RemoveTableEntry::kYes);
868 }
869 
processInvalidUniqueKeyImpl(const GrUniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource,RemoveTableEntry removeTableEntry)870 void GrProxyProvider::processInvalidUniqueKeyImpl(const GrUniqueKey& key, GrTextureProxy* proxy,
871                                                   InvalidateGPUResource invalidateGPUResource,
872                                                   RemoveTableEntry removeTableEntry) {
873     SkASSERT(key.isValid());
874 
875     if (!proxy) {
876         proxy = fUniquelyKeyedProxies.find(key);
877     }
878     SkASSERT(!proxy || proxy->getUniqueKey() == key);
879 
880     // Locate the corresponding GrGpuResource (if it needs to be invalidated) before clearing the
881     // proxy's unique key. We must do it in this order because 'key' may alias the proxy's key.
882     sk_sp<GrGpuResource> invalidGpuResource;
883     if (InvalidateGPUResource::kYes == invalidateGPUResource) {
884         auto direct = fImageContext->asDirectContext();
885         if (direct) {
886             GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
887             invalidGpuResource = resourceProvider->findByUniqueKey<GrGpuResource>(key);
888         }
889         SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key);
890     }
891 
892     // Note: this method is called for the whole variety of GrGpuResources so often 'key'
893     // will not be in 'fUniquelyKeyedProxies'.
894     if (proxy) {
895         if (removeTableEntry == RemoveTableEntry::kYes) {
896             fUniquelyKeyedProxies.remove(key);
897         }
898         proxy->cacheAccess().clearUniqueKey();
899     }
900 
901     if (invalidGpuResource) {
902         invalidGpuResource->resourcePriv().removeUniqueKey();
903     }
904 }
905 
isDDLProvider() const906 GrDDLProvider GrProxyProvider::isDDLProvider() const {
907     return fImageContext->asDirectContext() ? GrDDLProvider::kNo : GrDDLProvider::kYes;
908 }
909 
contextID() const910 uint32_t GrProxyProvider::contextID() const {
911     return fImageContext->priv().contextID();
912 }
913 
caps() const914 const GrCaps* GrProxyProvider::caps() const {
915     return fImageContext->priv().caps();
916 }
917 
refCaps() const918 sk_sp<const GrCaps> GrProxyProvider::refCaps() const {
919     return fImageContext->priv().refCaps();
920 }
921 
isAbandoned() const922 bool GrProxyProvider::isAbandoned() const {
923     return fImageContext->priv().abandoned();
924 }
925 
orphanAllUniqueKeys()926 void GrProxyProvider::orphanAllUniqueKeys() {
927     fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
928         proxy->fProxyProvider = nullptr;
929     });
930 }
931 
removeAllUniqueKeys()932 void GrProxyProvider::removeAllUniqueKeys() {
933     fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
934         // It's not safe to remove table entries while iterating with foreach(),
935         // but since we're going to remove them all anyway, simply save that for the end.
936         this->processInvalidUniqueKeyImpl(proxy->getUniqueKey(), proxy,
937                                           InvalidateGPUResource::kNo,
938                                           RemoveTableEntry::kNo);
939     });
940     // Removing all those table entries is safe now.
941     fUniquelyKeyedProxies.reset();
942 }
943 
renderingDirectly() const944 bool GrProxyProvider::renderingDirectly() const {
945     return fImageContext->asDirectContext();
946 }
947