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