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