• 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 "GrProxyProvider.h"
9 
10 #include "GrCaps.h"
11 #include "GrRenderTarget.h"
12 #include "GrResourceKey.h"
13 #include "GrResourceProvider.h"
14 #include "GrSurfaceProxy.h"
15 #include "GrSurfaceProxyPriv.h"
16 #include "GrTexture.h"
17 #include "GrTextureProxyCacheAccess.h"
18 #include "GrTextureRenderTargetProxy.h"
19 #include "../private/GrSingleOwner.h"
20 #include "SkAutoPixmapStorage.h"
21 #include "SkBitmap.h"
22 #include "SkGr.h"
23 #include "SkImage.h"
24 #include "SkImage_Base.h"
25 #include "SkImageInfoPriv.h"
26 #include "SkImagePriv.h"
27 #include "SkMipMap.h"
28 #include "SkTraceEvent.h"
29 
30 #define ASSERT_SINGLE_OWNER \
31     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
32 
GrProxyProvider(GrResourceProvider * resourceProvider,GrResourceCache * resourceCache,sk_sp<const GrCaps> caps,GrSingleOwner * owner)33 GrProxyProvider::GrProxyProvider(GrResourceProvider* resourceProvider,
34                                  GrResourceCache* resourceCache,
35                                  sk_sp<const GrCaps> caps,
36                                  GrSingleOwner* owner)
37         : fResourceProvider(resourceProvider)
38         , fResourceCache(resourceCache)
39         , fAbandoned(false)
40         , fCaps(caps)
41         , fContextUniqueID(resourceCache->contextUniqueID())
42 #ifdef SK_DEBUG
43         , fSingleOwner(owner)
44 #endif
45 {
46     SkASSERT(fResourceProvider);
47     SkASSERT(fResourceCache);
48     SkASSERT(fCaps);
49     SkASSERT(fSingleOwner);
50 }
51 
GrProxyProvider(uint32_t contextUniqueID,sk_sp<const GrCaps> caps,GrSingleOwner * owner)52 GrProxyProvider::GrProxyProvider(uint32_t contextUniqueID,
53                                  sk_sp<const GrCaps> caps,
54                                  GrSingleOwner* owner)
55         : fResourceProvider(nullptr)
56         , fResourceCache(nullptr)
57         , fAbandoned(false)
58         , fCaps(caps)
59         , fContextUniqueID(contextUniqueID)
60 #ifdef SK_DEBUG
61         , fSingleOwner(owner)
62 #endif
63 {
64     SkASSERT(fContextUniqueID != SK_InvalidUniqueID);
65     SkASSERT(fCaps);
66     SkASSERT(fSingleOwner);
67 }
68 
~GrProxyProvider()69 GrProxyProvider::~GrProxyProvider() {
70     if (fResourceCache) {
71         // In DDL-mode a proxy provider can still have extant uniquely keyed proxies (since
72         // they need their unique keys to, potentially, find a cached resource when the
73         // DDL is played) but, in non-DDL-mode they should all have been cleaned up by this point.
74         SkASSERT(!fUniquelyKeyedProxies.count());
75     }
76 }
77 
assignUniqueKeyToProxy(const GrUniqueKey & key,GrTextureProxy * proxy)78 bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
79     ASSERT_SINGLE_OWNER
80     SkASSERT(key.isValid());
81     if (this->isAbandoned() || !proxy) {
82         return false;
83     }
84 
85     // If there is already a GrResource with this key then the caller has violated the normal
86     // usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing
87     // if it already existed in the cache).
88     SkASSERT(!fResourceCache || !fResourceCache->findAndRefUniqueResource(key));
89 
90     SkASSERT(!fUniquelyKeyedProxies.find(key));     // multiple proxies can't get the same key
91 
92     proxy->cacheAccess().setUniqueKey(this, key);
93     SkASSERT(proxy->getUniqueKey() == key);
94     fUniquelyKeyedProxies.add(proxy);
95     return true;
96 }
97 
adoptUniqueKeyFromSurface(GrTextureProxy * proxy,const GrSurface * surf)98 void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) {
99     SkASSERT(surf->getUniqueKey().isValid());
100     proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey());
101     SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey());
102     // multiple proxies can't get the same key
103     SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey()));
104     fUniquelyKeyedProxies.add(proxy);
105 }
106 
removeUniqueKeyFromProxy(GrTextureProxy * proxy)107 void GrProxyProvider::removeUniqueKeyFromProxy(GrTextureProxy* proxy) {
108     ASSERT_SINGLE_OWNER
109     SkASSERT(proxy);
110     SkASSERT(proxy->getUniqueKey().isValid());
111 
112     if (this->isAbandoned()) {
113         return;
114     }
115 
116     this->processInvalidUniqueKey(proxy->getUniqueKey(), proxy, InvalidateGPUResource::kYes);
117 }
118 
findProxyByUniqueKey(const GrUniqueKey & key,GrSurfaceOrigin origin)119 sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key,
120                                                             GrSurfaceOrigin origin) {
121     ASSERT_SINGLE_OWNER
122 
123     if (this->isAbandoned()) {
124         return nullptr;
125     }
126 
127     sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key));
128     if (result) {
129         SkASSERT(result->origin() == origin);
130     }
131     return result;
132 }
133 
createWrapped(sk_sp<GrTexture> tex,GrSurfaceOrigin origin)134 sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, GrSurfaceOrigin origin) {
135 #ifdef SK_DEBUG
136     if (tex->getUniqueKey().isValid()) {
137         SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey(), origin));
138     }
139 #endif
140 
141     if (tex->asRenderTarget()) {
142         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin));
143     } else {
144         return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin));
145     }
146 }
147 
findOrCreateProxyByUniqueKey(const GrUniqueKey & key,GrSurfaceOrigin origin)148 sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key,
149                                                                     GrSurfaceOrigin origin) {
150     ASSERT_SINGLE_OWNER
151 
152     if (this->isAbandoned()) {
153         return nullptr;
154     }
155 
156     sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key, origin);
157     if (result) {
158         return result;
159     }
160 
161     if (!fResourceCache) {
162         return nullptr;
163     }
164 
165     GrGpuResource* resource = fResourceCache->findAndRefUniqueResource(key);
166     if (!resource) {
167         return nullptr;
168     }
169 
170     sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
171     SkASSERT(texture);
172 
173     result = this->createWrapped(std::move(texture), origin);
174     SkASSERT(result->getUniqueKey() == key);
175     // createWrapped should've added this for us
176     SkASSERT(fUniquelyKeyedProxies.find(key));
177     return result;
178 }
179 
createTextureProxy(sk_sp<SkImage> srcImage,GrSurfaceDescFlags descFlags,int sampleCnt,SkBudgeted budgeted,SkBackingFit fit,GrInternalSurfaceFlags surfaceFlags)180 sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(sk_sp<SkImage> srcImage,
181                                                           GrSurfaceDescFlags descFlags,
182                                                           int sampleCnt,
183                                                           SkBudgeted budgeted,
184                                                           SkBackingFit fit,
185                                                           GrInternalSurfaceFlags surfaceFlags) {
186     ASSERT_SINGLE_OWNER
187     SkASSERT(srcImage);
188 
189     if (this->isAbandoned()) {
190         return nullptr;
191     }
192 
193     SkImageInfo info = as_IB(srcImage)->onImageInfo();
194     GrPixelConfig config = SkImageInfo2GrPixelConfig(info);
195 
196     if (kUnknown_GrPixelConfig == config) {
197         return nullptr;
198     }
199 
200     GrBackendFormat format = fCaps->getBackendFormatFromColorType(info.colorType());
201     if (!format.isValid()) {
202         return nullptr;
203     }
204 
205     if (!this->caps()->isConfigTexturable(config)) {
206         SkBitmap copy8888;
207         if (!copy8888.tryAllocPixels(info.makeColorType(kRGBA_8888_SkColorType)) ||
208             !srcImage->readPixels(copy8888.pixmap(), 0, 0)) {
209             return nullptr;
210         }
211         copy8888.setImmutable();
212         srcImage = SkMakeImageFromRasterBitmap(copy8888, kNever_SkCopyPixelsMode);
213         config = kRGBA_8888_GrPixelConfig;
214     }
215 
216     if (SkToBool(descFlags & kRenderTarget_GrSurfaceFlag)) {
217         sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, config);
218         if (!sampleCnt) {
219             return nullptr;
220         }
221     }
222 
223     if (SkToBool(descFlags & kRenderTarget_GrSurfaceFlag)) {
224         if (fCaps->usesMixedSamples() && sampleCnt > 1) {
225             surfaceFlags |= GrInternalSurfaceFlags::kMixedSampled;
226         }
227     }
228 
229     GrSurfaceDesc desc;
230     desc.fWidth = srcImage->width();
231     desc.fHeight = srcImage->height();
232     desc.fFlags = descFlags;
233     desc.fSampleCnt = sampleCnt;
234     desc.fConfig = config;
235 
236     sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
237             [desc, budgeted, srcImage, fit, surfaceFlags](GrResourceProvider* resourceProvider) {
238                 if (!resourceProvider) {
239                     // Nothing to clean up here. Once the proxy (and thus lambda) is deleted the ref
240                     // on srcImage will be released.
241                     return sk_sp<GrTexture>();
242                 }
243                 SkPixmap pixMap;
244                 SkAssertResult(srcImage->peekPixels(&pixMap));
245                 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() };
246 
247                 auto resourceProviderFlags = GrResourceProvider::Flags::kNone;
248                 if (surfaceFlags & GrInternalSurfaceFlags::kNoPendingIO) {
249                     resourceProviderFlags |= GrResourceProvider::Flags::kNoPendingIO;
250                 }
251                 return resourceProvider->createTexture(desc, budgeted, fit, mipLevel,
252                                                        resourceProviderFlags);
253             },
254             format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, surfaceFlags, fit, budgeted);
255 
256     if (!proxy) {
257         return nullptr;
258     }
259 
260     if (fResourceProvider) {
261         // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
262         // we're better off instantiating the proxy immediately here.
263         if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
264             return nullptr;
265         }
266     }
267 
268     SkASSERT(proxy->width() == desc.fWidth);
269     SkASSERT(proxy->height() == desc.fHeight);
270     return proxy;
271 }
272 
createMipMapProxy(const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,SkBudgeted budgeted)273 sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(const GrBackendFormat& format,
274                                                          const GrSurfaceDesc& desc,
275                                                          GrSurfaceOrigin origin,
276                                                          SkBudgeted budgeted) {
277     ASSERT_SINGLE_OWNER
278 
279     if (this->isAbandoned()) {
280         return nullptr;
281     }
282 
283     return this->createProxy(format, desc, origin, GrMipMapped::kYes, SkBackingFit::kExact,
284                              budgeted, GrInternalSurfaceFlags::kNone);
285 }
286 
createMipMapProxyFromBitmap(const SkBitmap & bitmap)287 sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxyFromBitmap(const SkBitmap& bitmap) {
288     if (!SkImageInfoIsValid(bitmap.info())) {
289         return nullptr;
290     }
291 
292     ATRACE_ANDROID_FRAMEWORK("Upload MipMap Texture [%ux%u]", bitmap.width(), bitmap.height());
293 
294     // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap
295     // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the
296     // upload of the data to the gpu can happen at anytime and the bitmap may change by then.
297     SkCopyPixelsMode copyMode = this->recordingDDL() ? kIfMutable_SkCopyPixelsMode
298                                                      : kNever_SkCopyPixelsMode;
299     sk_sp<SkImage> baseLevel = SkMakeImageFromRasterBitmap(bitmap, copyMode);
300     if (!baseLevel) {
301         return nullptr;
302     }
303 
304     // This was never going to have mips anyway
305     if (0 == SkMipMap::ComputeLevelCount(baseLevel->width(), baseLevel->height())) {
306         return this->createTextureProxy(baseLevel, kNone_GrSurfaceFlags, 1, SkBudgeted::kYes,
307                                         SkBackingFit::kExact);
308     }
309 
310     const GrBackendFormat format = fCaps->getBackendFormatFromColorType(bitmap.info().colorType());
311     if (!format.isValid()) {
312         return nullptr;
313     }
314 
315     GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info());
316     if (!this->caps()->isConfigTexturable(desc.fConfig)) {
317         SkBitmap copy8888;
318         if (!copy8888.tryAllocPixels(bitmap.info().makeColorType(kRGBA_8888_SkColorType)) ||
319             !bitmap.readPixels(copy8888.pixmap())) {
320             return nullptr;
321         }
322         copy8888.setImmutable();
323         baseLevel = SkMakeImageFromRasterBitmap(copy8888, kNever_SkCopyPixelsMode);
324         desc.fConfig = kRGBA_8888_GrPixelConfig;
325     }
326 
327     SkPixmap pixmap;
328     SkAssertResult(baseLevel->peekPixels(&pixmap));
329     sk_sp<SkMipMap> mipmaps(SkMipMap::Build(pixmap, nullptr));
330     if (!mipmaps) {
331         return nullptr;
332     }
333 
334     sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
335             [desc, baseLevel, mipmaps](GrResourceProvider* resourceProvider) {
336                 if (!resourceProvider) {
337                     return sk_sp<GrTexture>();
338                 }
339 
340                 const int mipLevelCount = mipmaps->countLevels() + 1;
341                 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
342 
343                 SkPixmap pixmap;
344                 SkAssertResult(baseLevel->peekPixels(&pixmap));
345 
346                 // DDL TODO: Instead of copying all this info into GrMipLevels we should just plumb
347                 // the use of SkMipMap down through Ganesh.
348                 texels[0].fPixels = pixmap.addr();
349                 texels[0].fRowBytes = pixmap.rowBytes();
350 
351                 for (int i = 1; i < mipLevelCount; ++i) {
352                     SkMipMap::Level generatedMipLevel;
353                     mipmaps->getLevel(i - 1, &generatedMipLevel);
354                     texels[i].fPixels = generatedMipLevel.fPixmap.addr();
355                     texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes();
356                     SkASSERT(texels[i].fPixels);
357                 }
358 
359                 return resourceProvider->createTexture(desc, SkBudgeted::kYes, texels.get(),
360                                                        mipLevelCount);
361             },
362             format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kYes, SkBackingFit::kExact,
363             SkBudgeted::kYes);
364 
365     if (!proxy) {
366         return nullptr;
367     }
368 
369     if (fResourceProvider) {
370         // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
371         // we're better off instantiating the proxy immediately here.
372         if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
373             return nullptr;
374         }
375     }
376     return proxy;
377 }
378 
createProxy(const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrMipMapped mipMapped,SkBackingFit fit,SkBudgeted budgeted,GrInternalSurfaceFlags surfaceFlags)379 sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrBackendFormat& format,
380                                                    const GrSurfaceDesc& desc,
381                                                    GrSurfaceOrigin origin,
382                                                    GrMipMapped mipMapped,
383                                                    SkBackingFit fit,
384                                                    SkBudgeted budgeted,
385                                                    GrInternalSurfaceFlags surfaceFlags) {
386     if (GrMipMapped::kYes == mipMapped) {
387         // SkMipMap doesn't include the base level in the level count so we have to add 1
388         int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1;
389         if (1 == mipCount) {
390             mipMapped = GrMipMapped::kNo;
391         }
392     }
393 
394     if (!this->caps()->validateSurfaceDesc(desc, mipMapped)) {
395         return nullptr;
396     }
397     GrSurfaceDesc copyDesc = desc;
398     if (desc.fFlags & kRenderTarget_GrSurfaceFlag) {
399         copyDesc.fSampleCnt =
400                 this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig);
401     }
402 
403     if (copyDesc.fFlags & kRenderTarget_GrSurfaceFlag) {
404         // We know anything we instantiate later from this deferred path will be
405         // both texturable and renderable
406         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*this->caps(), format, copyDesc,
407                                                                     origin, mipMapped,
408                                                                     fit, budgeted, surfaceFlags));
409     }
410 
411     return sk_sp<GrTextureProxy>(new GrTextureProxy(format, copyDesc, origin, mipMapped,
412                                                     fit, budgeted, surfaceFlags));
413 }
414 
createProxy(sk_sp<SkData> data,const GrSurfaceDesc & desc)415 sk_sp<GrTextureProxy> GrProxyProvider::createProxy(sk_sp<SkData> data, const GrSurfaceDesc& desc) {
416     if (!this->caps()->isConfigTexturable(desc.fConfig)) {
417         return nullptr;
418     }
419 
420     const GrColorType ct = GrPixelConfigToColorType(desc.fConfig);
421     const GrBackendFormat format = fCaps->getBackendFormatFromGrColorType(ct, GrSRGBEncoded::kNo);
422 
423     sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
424         [desc, data](GrResourceProvider* resourceProvider) {
425             if (!resourceProvider) {
426                 return sk_sp<GrTexture>();
427             }
428 
429             GrMipLevel texels;
430             texels.fPixels = data->data();
431             texels.fRowBytes = GrBytesPerPixel(desc.fConfig)*desc.fWidth;
432             return resourceProvider->createTexture(desc, SkBudgeted::kYes, &texels, 1);
433         },
434         format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, SkBackingFit::kExact,
435         SkBudgeted::kYes);
436 
437     if (!proxy) {
438         return nullptr;
439     }
440 
441     if (fResourceProvider) {
442         // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
443         // we're better off instantiating the proxy immediately here.
444         if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
445             return nullptr;
446         }
447     }
448     return proxy;
449 }
450 
wrapBackendTexture(const GrBackendTexture & backendTex,GrSurfaceOrigin origin,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType,ReleaseProc releaseProc,ReleaseContext releaseCtx)451 sk_sp<GrTextureProxy> GrProxyProvider::wrapBackendTexture(const GrBackendTexture& backendTex,
452                                                           GrSurfaceOrigin origin,
453                                                           GrWrapOwnership ownership,
454                                                           GrWrapCacheable cacheable,
455                                                           GrIOType ioType,
456                                                           ReleaseProc releaseProc,
457                                                           ReleaseContext releaseCtx) {
458     SkASSERT(ioType != kWrite_GrIOType);
459     if (this->isAbandoned()) {
460         return nullptr;
461     }
462 
463     // This is only supported on a direct GrContext.
464     if (!fResourceProvider) {
465         return nullptr;
466     }
467 
468     sk_sp<GrTexture> tex =
469             fResourceProvider->wrapBackendTexture(backendTex, ownership, cacheable, ioType);
470     if (!tex) {
471         return nullptr;
472     }
473 
474     sk_sp<GrReleaseProcHelper> releaseHelper;
475     if (releaseProc) {
476         releaseHelper.reset(new GrReleaseProcHelper(releaseProc, releaseCtx));
477         // This gives the texture a ref on the releaseHelper
478         tex->setRelease(releaseHelper);
479     }
480 
481     SkASSERT(!tex->asRenderTarget());  // Strictly a GrTexture
482     // Make sure we match how we created the proxy with SkBudgeted::kNo
483     SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
484 
485     return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin));
486 }
487 
wrapRenderableBackendTexture(const GrBackendTexture & backendTex,GrSurfaceOrigin origin,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)488 sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture(
489         const GrBackendTexture& backendTex, GrSurfaceOrigin origin, int sampleCnt,
490         GrWrapOwnership ownership, GrWrapCacheable cacheable) {
491     if (this->isAbandoned()) {
492         return nullptr;
493     }
494 
495     // This is only supported on a direct GrContext.
496     if (!fResourceProvider) {
497         return nullptr;
498     }
499 
500     sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config());
501     if (!sampleCnt) {
502         return nullptr;
503     }
504 
505     sk_sp<GrTexture> tex = fResourceProvider->wrapRenderableBackendTexture(backendTex, sampleCnt,
506                                                                            ownership, cacheable);
507     if (!tex) {
508         return nullptr;
509     }
510 
511     SkASSERT(tex->asRenderTarget());  // A GrTextureRenderTarget
512     // Make sure we match how we created the proxy with SkBudgeted::kNo
513     SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType());
514 
515     return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin));
516 }
517 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT,GrSurfaceOrigin origin)518 sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget(
519         const GrBackendRenderTarget& backendRT, GrSurfaceOrigin origin) {
520     if (this->isAbandoned()) {
521         return nullptr;
522     }
523 
524     // This is only supported on a direct GrContext.
525     if (!fResourceProvider) {
526         return nullptr;
527     }
528 
529     sk_sp<GrRenderTarget> rt = fResourceProvider->wrapBackendRenderTarget(backendRT);
530     if (!rt) {
531         return nullptr;
532     }
533     SkASSERT(!rt->asTexture());  // A GrRenderTarget that's not textureable
534     SkASSERT(!rt->getUniqueKey().isValid());
535     // Make sure we match how we created the proxy with SkBudgeted::kNo
536     SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
537 
538     return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(rt), origin));
539 }
540 
wrapBackendTextureAsRenderTarget(const GrBackendTexture & backendTex,GrSurfaceOrigin origin,int sampleCnt)541 sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendTextureAsRenderTarget(
542         const GrBackendTexture& backendTex, GrSurfaceOrigin origin, int sampleCnt) {
543     if (this->isAbandoned()) {
544         return nullptr;
545     }
546 
547     // This is only supported on a direct GrContext.
548     if (!fResourceProvider) {
549         return nullptr;
550     }
551 
552     sk_sp<GrRenderTarget> rt =
553             fResourceProvider->wrapBackendTextureAsRenderTarget(backendTex, sampleCnt);
554     if (!rt) {
555         return nullptr;
556     }
557     SkASSERT(!rt->asTexture());  // A GrRenderTarget that's not textureable
558     SkASSERT(!rt->getUniqueKey().isValid());
559     // This proxy should be unbudgeted because we're just wrapping an external resource
560     SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
561 
562     return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
563 }
564 
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)565 sk_sp<GrRenderTargetProxy> GrProxyProvider::wrapVulkanSecondaryCBAsRenderTarget(
566         const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
567     if (this->isAbandoned()) {
568         return nullptr;
569     }
570 
571     // This is only supported on a direct GrContext.
572     if (!fResourceProvider) {
573         return nullptr;
574     }
575 
576     sk_sp<GrRenderTarget> rt = fResourceProvider->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
577                                                                                       vkInfo);
578 
579     if (!rt) {
580         return nullptr;
581     }
582     SkASSERT(!rt->asTexture());  // A GrRenderTarget that's not textureable
583     SkASSERT(!rt->getUniqueKey().isValid());
584     // This proxy should be unbudgeted because we're just wrapping an external resource
585     SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType());
586 
587     // All Vulkan surfaces uses top left origins.
588     return sk_sp<GrRenderTargetProxy>(
589             new GrRenderTargetProxy(std::move(rt),
590                                     kTopLeft_GrSurfaceOrigin,
591                                     GrRenderTargetProxy::WrapsVkSecondaryCB::kYes));
592 }
593 
createLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrMipMapped mipMapped,SkBackingFit fit,SkBudgeted budgeted)594 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
595                                                        const GrBackendFormat& format,
596                                                        const GrSurfaceDesc& desc,
597                                                        GrSurfaceOrigin origin,
598                                                        GrMipMapped mipMapped,
599                                                        SkBackingFit fit,
600                                                        SkBudgeted budgeted) {
601     return this->createLazyProxy(std::move(callback), format, desc, origin, mipMapped,
602                                  GrInternalSurfaceFlags::kNone, fit, budgeted);
603 }
604 
createLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrMipMapped mipMapped,GrInternalSurfaceFlags surfaceFlags,SkBackingFit fit,SkBudgeted budgeted)605 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
606                                                        const GrBackendFormat& format,
607                                                        const GrSurfaceDesc& desc,
608                                                        GrSurfaceOrigin origin,
609                                                        GrMipMapped mipMapped,
610                                                        GrInternalSurfaceFlags surfaceFlags,
611                                                        SkBackingFit fit,
612                                                        SkBudgeted budgeted) {
613     // For non-ddl draws always make lazy proxy's single use.
614     LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse
615                                                        : LazyInstantiationType::kMultipleUse;
616     return this->createLazyProxy(std::move(callback), format, desc, origin, mipMapped, surfaceFlags,
617                                  fit, budgeted, lazyType);
618 }
619 
createLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrMipMapped mipMapped,GrInternalSurfaceFlags surfaceFlags,SkBackingFit fit,SkBudgeted budgeted,LazyInstantiationType lazyType)620 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
621                                                        const GrBackendFormat& format,
622                                                        const GrSurfaceDesc& desc,
623                                                        GrSurfaceOrigin origin,
624                                                        GrMipMapped mipMapped,
625                                                        GrInternalSurfaceFlags surfaceFlags,
626                                                        SkBackingFit fit,
627                                                        SkBudgeted budgeted,
628                                                        LazyInstantiationType lazyType) {
629     SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
630              (desc.fWidth > 0 && desc.fHeight > 0));
631 
632     if (desc.fWidth > fCaps->maxTextureSize() || desc.fHeight > fCaps->maxTextureSize()) {
633         return nullptr;
634     }
635 
636 
637 #ifdef SK_DEBUG
638     if (SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)) {
639         if (SkToBool(surfaceFlags & GrInternalSurfaceFlags::kMixedSampled)) {
640             SkASSERT(fCaps->usesMixedSamples() && desc.fSampleCnt > 1);
641         }
642     }
643 #endif
644 
645     return sk_sp<GrTextureProxy>(
646             SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)
647                     ? new GrTextureRenderTargetProxy(std::move(callback), lazyType, format, desc,
648                                                      origin, mipMapped, fit, budgeted, surfaceFlags)
649                     : new GrTextureProxy(std::move(callback), lazyType, format, desc, origin,
650                                          mipMapped, fit, budgeted, surfaceFlags));
651 }
652 
createLazyRenderTargetProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrSurfaceOrigin origin,GrInternalSurfaceFlags surfaceFlags,const TextureInfo * textureInfo,SkBackingFit fit,SkBudgeted budgeted)653 sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy(
654         LazyInstantiateCallback&& callback, const GrBackendFormat& format,
655         const GrSurfaceDesc& desc, GrSurfaceOrigin origin, GrInternalSurfaceFlags surfaceFlags,
656         const TextureInfo* textureInfo, SkBackingFit fit, SkBudgeted budgeted) {
657     SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
658              (desc.fWidth > 0 && desc.fHeight > 0));
659 
660     if (desc.fWidth > fCaps->maxRenderTargetSize() || desc.fHeight > fCaps->maxRenderTargetSize()) {
661         return nullptr;
662     }
663 
664     SkASSERT(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags));
665 
666 #ifdef SK_DEBUG
667     if (SkToBool(surfaceFlags & GrInternalSurfaceFlags::kMixedSampled)) {
668         SkASSERT(fCaps->usesMixedSamples() && desc.fSampleCnt > 1);
669     }
670 #endif
671 
672     using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType;
673     // For non-ddl draws always make lazy proxy's single use.
674     LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse
675                                                        : LazyInstantiationType::kMultipleUse;
676 
677     if (textureInfo) {
678         return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(
679                 std::move(callback), lazyType, format, desc, origin, textureInfo->fMipMapped,
680                 fit, budgeted, surfaceFlags));
681     }
682 
683     return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(
684             std::move(callback), lazyType, format, desc, origin, fit, budgeted, surfaceFlags));
685 }
686 
MakeFullyLazyProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,Renderable renderable,GrSurfaceOrigin origin,GrPixelConfig config,const GrCaps & caps)687 sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallback&& callback,
688                                                           const GrBackendFormat& format,
689                                                           Renderable renderable,
690                                                           GrSurfaceOrigin origin,
691                                                           GrPixelConfig config,
692                                                           const GrCaps& caps) {
693     GrSurfaceDesc desc;
694     GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNoPendingIO;
695     if (Renderable::kYes == renderable) {
696         desc.fFlags = kRenderTarget_GrSurfaceFlag;
697     }
698     desc.fWidth = -1;
699     desc.fHeight = -1;
700     desc.fConfig = config;
701     desc.fSampleCnt = 1;
702 
703     return sk_sp<GrTextureProxy>(
704             (Renderable::kYes == renderable)
705                     ? new GrTextureRenderTargetProxy(
706                               std::move(callback), LazyInstantiationType::kSingleUse, format, desc,
707                               origin, GrMipMapped::kNo, SkBackingFit::kApprox, SkBudgeted::kYes,
708                               surfaceFlags)
709                     : new GrTextureProxy(std::move(callback), LazyInstantiationType::kSingleUse,
710                                          format, desc, origin, GrMipMapped::kNo,
711                                          SkBackingFit::kApprox, SkBudgeted::kYes, surfaceFlags));
712 }
713 
IsFunctionallyExact(GrSurfaceProxy * proxy)714 bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) {
715     const bool isInstantiated = proxy->isInstantiated();
716     // A proxy is functionally exact if:
717     //   it is exact (obvs)
718     //   when it is instantiated it will be exact (i.e., power of two dimensions)
719     //   it is already instantiated and the proxy covers the entire backing surface
720     return proxy->priv().isExact() ||
721            (!isInstantiated && SkIsPow2(proxy->width()) && SkIsPow2(proxy->height())) ||
722            (isInstantiated && proxy->worstCaseWidth() == proxy->width() &&
723                               proxy->worstCaseHeight() == proxy->height());
724 }
725 
processInvalidUniqueKey(const GrUniqueKey & key,GrTextureProxy * proxy,InvalidateGPUResource invalidateGPUResource)726 void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy,
727                                               InvalidateGPUResource invalidateGPUResource) {
728     SkASSERT(key.isValid());
729 
730     if (!proxy) {
731         proxy = fUniquelyKeyedProxies.find(key);
732     }
733     SkASSERT(!proxy || proxy->getUniqueKey() == key);
734 
735     // Locate the corresponding GrGpuResource (if it needs to be invalidated) before clearing the
736     // proxy's unique key. We must do it in this order because 'key' may alias the proxy's key.
737     sk_sp<GrGpuResource> invalidGpuResource;
738     if (InvalidateGPUResource::kYes == invalidateGPUResource) {
739         if (proxy && proxy->isInstantiated()) {
740             invalidGpuResource = sk_ref_sp(proxy->peekSurface());
741         }
742         if (!invalidGpuResource && fResourceProvider) {
743             invalidGpuResource = fResourceProvider->findByUniqueKey<GrGpuResource>(key);
744         }
745         SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key);
746     }
747 
748     // Note: this method is called for the whole variety of GrGpuResources so often 'key'
749     // will not be in 'fUniquelyKeyedProxies'.
750     if (proxy) {
751         fUniquelyKeyedProxies.remove(key);
752         proxy->cacheAccess().clearUniqueKey();
753     }
754 
755     if (invalidGpuResource) {
756         invalidGpuResource->resourcePriv().removeUniqueKey();
757     }
758 }
759 
orphanAllUniqueKeys()760 void GrProxyProvider::orphanAllUniqueKeys() {
761     UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies);
762     for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) {
763         GrTextureProxy& tmp = *iter;
764 
765         tmp.fProxyProvider = nullptr;
766     }
767 }
768 
removeAllUniqueKeys()769 void GrProxyProvider::removeAllUniqueKeys() {
770     UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies);
771     for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) {
772         GrTextureProxy& tmp = *iter;
773 
774         this->processInvalidUniqueKey(tmp.getUniqueKey(), &tmp, InvalidateGPUResource::kNo);
775     }
776     SkASSERT(!fUniquelyKeyedProxies.count());
777 }
778