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