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