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 "SkGr.h"
21 #include "SkImage.h"
22 #include "SkImage_Base.h"
23 #include "SkMipMap.h"
24 
25 #define ASSERT_SINGLE_OWNER \
26     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
27 
GrProxyProvider(GrResourceProvider * resourceProvider,GrResourceCache * resourceCache,sk_sp<const GrCaps> caps,GrSingleOwner * owner)28 GrProxyProvider::GrProxyProvider(GrResourceProvider* resourceProvider,
29                                  GrResourceCache* resourceCache,
30                                  sk_sp<const GrCaps> caps,
31                                  GrSingleOwner* owner)
32         : fResourceProvider(resourceProvider)
33         , fResourceCache(resourceCache)
34         , fAbandoned(false)
35         , fCaps(caps)
36 #ifdef SK_DEBUG
37         , fSingleOwner(owner)
38 #endif
39 {
40 
41 }
42 
~GrProxyProvider()43 GrProxyProvider::~GrProxyProvider() {
44     SkASSERT(!fUniquelyKeyedProxies.count());
45 }
46 
assignUniqueKeyToProxy(const GrUniqueKey & key,GrTextureProxy * proxy)47 bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
48     ASSERT_SINGLE_OWNER
49     SkASSERT(key.isValid());
50     if (this->isAbandoned() || !proxy) {
51         return false;
52     }
53 
54     // If there is already a GrResource with this key then the caller has violated the normal
55     // usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing
56     // if it already existed in the cache).
57     SkASSERT(!fResourceCache || !fResourceCache->findAndRefUniqueResource(key));
58 
59     // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
60     // resources are a special case: the unique keys give us a weak ref so that we can reuse the
61     // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
62     // it will always be released - it is never converted to a scratch resource.
63     if (SkBudgeted::kNo == proxy->isBudgeted() &&
64                     (!proxy->priv().isInstantiated() ||
65                      !proxy->priv().peekSurface()->resourcePriv().refsWrappedObjects())) {
66         return false;
67     }
68 
69     SkASSERT(!fUniquelyKeyedProxies.find(key));     // multiple proxies can't get the same key
70 
71     proxy->cacheAccess().setUniqueKey(this, key);
72     SkASSERT(proxy->getUniqueKey() == key);
73     fUniquelyKeyedProxies.add(proxy);
74     return true;
75 }
76 
adoptUniqueKeyFromSurface(GrTextureProxy * proxy,const GrSurface * surf)77 void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) {
78     SkASSERT(surf->getUniqueKey().isValid());
79     proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey());
80     SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey());
81     // multiple proxies can't get the same key
82     SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey()));
83     fUniquelyKeyedProxies.add(proxy);
84 }
85 
removeUniqueKeyFromProxy(const GrUniqueKey & key,GrTextureProxy * proxy)86 void GrProxyProvider::removeUniqueKeyFromProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
87     ASSERT_SINGLE_OWNER
88     if (this->isAbandoned() || !proxy) {
89         return;
90     }
91     this->processInvalidProxyUniqueKey(key, proxy, true);
92 }
93 
findProxyByUniqueKey(const GrUniqueKey & key,GrSurfaceOrigin origin)94 sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key,
95                                                             GrSurfaceOrigin origin) {
96     ASSERT_SINGLE_OWNER
97 
98     if (this->isAbandoned()) {
99         return nullptr;
100     }
101 
102     sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key));
103     if (result) {
104         SkASSERT(result->origin() == origin);
105     }
106     return result;
107 }
108 
createWrapped(sk_sp<GrTexture> tex,GrSurfaceOrigin origin)109 sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, GrSurfaceOrigin origin) {
110 #ifdef SK_DEBUG
111     if (tex->getUniqueKey().isValid()) {
112         SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey(), origin));
113     }
114 #endif
115 
116     if (tex->asRenderTarget()) {
117         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin));
118     } else {
119         return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin));
120     }
121 }
122 
findOrCreateProxyByUniqueKey(const GrUniqueKey & key,GrSurfaceOrigin origin)123 sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key,
124                                                                     GrSurfaceOrigin origin) {
125     ASSERT_SINGLE_OWNER
126 
127     if (this->isAbandoned()) {
128         return nullptr;
129     }
130 
131     sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key, origin);
132     if (result) {
133         return result;
134     }
135 
136     if (!fResourceCache) {
137         return nullptr;
138     }
139 
140     GrGpuResource* resource = fResourceCache->findAndRefUniqueResource(key);
141     if (!resource) {
142         return nullptr;
143     }
144 
145     sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture());
146     SkASSERT(texture);
147 
148     result = this->createWrapped(std::move(texture), origin);
149     SkASSERT(result->getUniqueKey() == key);
150     // createWrapped should've added this for us
151     SkASSERT(fUniquelyKeyedProxies.find(key));
152     return result;
153 }
154 
createInstantiatedProxy(const GrSurfaceDesc & desc,SkBackingFit fit,SkBudgeted budgeted,uint32_t flags)155 sk_sp<GrTextureProxy> GrProxyProvider::createInstantiatedProxy(const GrSurfaceDesc& desc,
156                                                                SkBackingFit fit,
157                                                                SkBudgeted budgeted,
158                                                                uint32_t flags) {
159     sk_sp<GrTexture> tex;
160 
161     if (SkBackingFit::kApprox == fit) {
162         tex = fResourceProvider->createApproxTexture(desc, flags);
163     } else {
164         tex = fResourceProvider->createTexture(desc, budgeted, flags);
165     }
166     if (!tex) {
167         return nullptr;
168     }
169 
170     return this->createWrapped(std::move(tex), desc.fOrigin);
171 }
172 
createTextureProxy(const GrSurfaceDesc & desc,SkBudgeted budgeted,const void * srcData,size_t rowBytes)173 sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(const GrSurfaceDesc& desc,
174                                                           SkBudgeted budgeted,
175                                                           const void* srcData, size_t rowBytes) {
176     ASSERT_SINGLE_OWNER
177 
178     if (this->isAbandoned()) {
179         return nullptr;
180     }
181 
182     if (srcData) {
183         GrMipLevel mipLevel = { srcData, rowBytes };
184 
185         sk_sp<GrTexture> tex = fResourceProvider->createTexture(desc, budgeted, mipLevel);
186         if (!tex) {
187             return nullptr;
188         }
189 
190         return this->createWrapped(std::move(tex), desc.fOrigin);
191     }
192 
193     return this->createProxy(desc, SkBackingFit::kExact, budgeted);
194 }
195 
createTextureProxy(sk_sp<SkImage> srcImage,GrSurfaceFlags flags,GrSurfaceOrigin origin,int sampleCnt,SkBudgeted budgeted)196 sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(sk_sp<SkImage> srcImage,
197                                                           GrSurfaceFlags flags,
198                                                           GrSurfaceOrigin origin,
199                                                           int sampleCnt,
200                                                           SkBudgeted budgeted) {
201     ASSERT_SINGLE_OWNER
202     SkASSERT(srcImage);
203 
204     if (this->isAbandoned()) {
205         return nullptr;
206     }
207 
208     GrSurfaceDesc desc;
209     desc.fWidth = srcImage->width();
210     desc.fHeight = srcImage->height();
211     desc.fFlags = flags;
212     desc.fOrigin = origin;
213     desc.fSampleCnt = sampleCnt;
214     desc.fConfig = SkImageInfo2GrPixelConfig(as_IB(srcImage)->onImageInfo(), *this->caps());
215 
216     sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
217             [desc, budgeted, srcImage]
218             (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) {
219                 if (!resourceProvider) {
220                     // Nothing to clean up here. Once the proxy (and thus lambda) is deleted the ref
221                     // on srcImage will be released.
222                     return sk_sp<GrTexture>();
223                 }
224                 SkPixmap pixMap;
225                 SkAssertResult(srcImage->peekPixels(&pixMap));
226                 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() };
227 
228                 return resourceProvider->createTexture(desc, budgeted, mipLevel);
229             }, desc, GrMipMapped::kNo, SkBackingFit::kExact, budgeted);
230 
231     if (fResourceProvider) {
232         // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
233         // we're better off instantiating the proxy immediately here.
234         if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
235             return nullptr;
236         }
237     }
238     return proxy;
239 }
240 
createMipMapProxy(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel texels[],int mipLevelCount,SkDestinationSurfaceColorMode mipColorMode)241 sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(
242                                                     const GrSurfaceDesc& desc, SkBudgeted budgeted,
243                                                     const GrMipLevel texels[], int mipLevelCount,
244                                                     SkDestinationSurfaceColorMode mipColorMode) {
245     ASSERT_SINGLE_OWNER
246 
247     if (this->isAbandoned()) {
248         return nullptr;
249     }
250 
251     if (!mipLevelCount) {
252         if (texels) {
253             return nullptr;
254         }
255         return this->createProxy(desc, SkBackingFit::kExact, budgeted);
256     }
257     if (!texels) {
258         return nullptr;
259     }
260 
261     if (1 == mipLevelCount) {
262         return this->createTextureProxy(desc, budgeted, texels[0].fPixels, texels[0].fRowBytes);
263     }
264 
265 #ifdef SK_DEBUG
266     // There are only three states we want to be in when uploading data to a mipped surface.
267     // 1) We have data to upload to all layers
268     // 2) We are not uploading data to any layers
269     // 3) We are only uploading data to the base layer
270     // We check here to make sure we do not have any other state.
271     bool firstLevelHasData = SkToBool(texels[0].fPixels);
272     bool allOtherLevelsHaveData = true, allOtherLevelsLackData = true;
273     for  (int i = 1; i < mipLevelCount; ++i) {
274         if (texels[i].fPixels) {
275             allOtherLevelsLackData = false;
276         } else {
277             allOtherLevelsHaveData = false;
278         }
279     }
280     SkASSERT((firstLevelHasData && allOtherLevelsHaveData) || allOtherLevelsLackData);
281 #endif
282 
283     sk_sp<GrTexture> tex(fResourceProvider->createTexture(desc, budgeted,
284                                                           texels, mipLevelCount,
285                                                           mipColorMode));
286     if (!tex) {
287         return nullptr;
288     }
289 
290     return this->createWrapped(std::move(tex), desc.fOrigin);
291 }
292 
createMipMapProxy(const GrSurfaceDesc & desc,SkBudgeted budgeted)293 sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(const GrSurfaceDesc& desc,
294                                                          SkBudgeted budgeted) {
295     // SkMipMap doesn't include the base level in the level count so we have to add 1
296     int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1;
297 
298     std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]);
299 
300     // We don't want to upload any texel data
301     for (int i = 0; i < mipCount; i++) {
302         texels[i].fPixels = nullptr;
303         texels[i].fRowBytes = 0;
304     }
305 
306     return this->createMipMapProxy(desc, budgeted, texels.get(), mipCount,
307                                    SkDestinationSurfaceColorMode::kLegacy);
308 }
309 
createProxy(const GrSurfaceDesc & desc,SkBackingFit fit,SkBudgeted budgeted,uint32_t flags)310 sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrSurfaceDesc& desc,
311                                                    SkBackingFit fit,
312                                                    SkBudgeted budgeted,
313                                                    uint32_t flags) {
314     SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags);
315 
316     const GrCaps* caps = this->caps();
317 
318     // TODO: move this logic into GrResourceProvider!
319     // TODO: share this testing code with check_texture_creation_params
320     if (!caps->isConfigTexturable(desc.fConfig)) {
321         return nullptr;
322     }
323 
324     bool willBeRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
325     if (willBeRT && !caps->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 1)) {
326         return nullptr;
327     }
328 
329     // We currently do not support multisampled textures
330     if (!willBeRT && desc.fSampleCnt > 1) {
331         return nullptr;
332     }
333 
334     if (willBeRT && !caps->getSampleCount(desc.fSampleCnt, desc.fConfig)) {
335         return nullptr;
336     }
337 
338     int maxSize;
339     if (willBeRT) {
340         maxSize = caps->maxRenderTargetSize();
341     } else {
342         maxSize = caps->maxTextureSize();
343     }
344 
345     if (desc.fWidth > maxSize || desc.fHeight > maxSize || desc.fWidth <= 0 || desc.fHeight <= 0) {
346         return nullptr;
347     }
348 
349     GrSurfaceDesc copyDesc = desc;
350     copyDesc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig);
351 
352 #ifdef SK_DISABLE_DEFERRED_PROXIES
353     // Temporarily force instantiation for crbug.com/769760 and crbug.com/769898
354     sk_sp<GrTexture> tex;
355 
356     if (SkBackingFit::kApprox == fit) {
357         tex = resourceProvider->createApproxTexture(copyDesc, flags);
358     } else {
359         tex = resourceProvider->createTexture(copyDesc, budgeted, flags);
360     }
361 
362     if (!tex) {
363         return nullptr;
364     }
365 
366     return GrSurfaceProxy::MakeWrapped(std::move(tex), copyDesc.fOrigin);
367 #else
368     if (willBeRT) {
369         // We know anything we instantiate later from this deferred path will be
370         // both texturable and renderable
371         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps, copyDesc, fit,
372                                                                     budgeted, flags));
373     }
374 
375     return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags));
376 #endif
377 }
378 
createWrappedTextureProxy(const GrBackendTexture & backendTex,GrSurfaceOrigin origin,GrWrapOwnership ownership,ReleaseProc releaseProc,ReleaseContext releaseCtx)379 sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(
380                                                          const GrBackendTexture& backendTex,
381                                                          GrSurfaceOrigin origin,
382                                                          GrWrapOwnership ownership,
383                                                          ReleaseProc releaseProc,
384                                                          ReleaseContext releaseCtx) {
385     if (this->isAbandoned()) {
386         return nullptr;
387     }
388 
389     GrSurfaceDesc desc;
390     desc.fOrigin = origin;
391     desc.fWidth = backendTex.width();
392     desc.fHeight = backendTex.height();
393     desc.fConfig = backendTex.config();
394     GrMipMapped mipMapped = backendTex.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo;
395 
396     sk_sp<GrReleaseProcHelper> releaseHelper;
397     if (releaseProc) {
398         releaseHelper.reset(new GrReleaseProcHelper(releaseProc, releaseCtx));
399     }
400 
401     sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
402             [backendTex, ownership, releaseHelper]
403             (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) {
404                 if (!resourceProvider) {
405                     // If this had a releaseHelper it will get unrefed when we delete this lambda
406                     // and will call the release proc so that the client knows they can free the
407                     // underlying backend object.
408                     return sk_sp<GrTexture>();
409                 }
410 
411                 sk_sp<GrTexture> tex = resourceProvider->wrapBackendTexture(backendTex,
412                                                                             ownership);
413                 if (!tex) {
414                     return sk_sp<GrTexture>();
415                 }
416                 if (releaseHelper) {
417                     // This gives the texture a ref on the releaseHelper
418                     tex->setRelease(releaseHelper);
419                 }
420                 SkASSERT(!tex->asRenderTarget());   // Strictly a GrTexture
421                 // Make sure we match how we created the proxy with SkBudgeted::kNo
422                 SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted());
423 
424                 return tex;
425             }, desc, mipMapped, SkBackingFit::kExact, SkBudgeted::kNo);
426 
427     if (fResourceProvider) {
428         // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however,
429         // we're better off instantiating the proxy immediately here.
430         if (!proxy->priv().doLazyInstantiation(fResourceProvider)) {
431             return nullptr;
432         }
433     }
434     return proxy;
435 }
436 
createWrappedTextureProxy(const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt)437 sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(const GrBackendTexture& tex,
438                                                                  GrSurfaceOrigin origin,
439                                                                  int sampleCnt) {
440     if (this->isAbandoned()) {
441         return nullptr;
442     }
443 
444     sk_sp<GrTexture> texture(fResourceProvider->wrapRenderableBackendTexture(tex, sampleCnt));
445     if (!texture) {
446         return nullptr;
447     }
448     SkASSERT(texture->asRenderTarget());  // A GrTextureRenderTarget
449 
450     return this->createWrapped(std::move(texture), origin);
451 }
452 
createWrappedRenderTargetProxy(const GrBackendRenderTarget & backendRT,GrSurfaceOrigin origin)453 sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy(
454                                                              const GrBackendRenderTarget& backendRT,
455                                                              GrSurfaceOrigin origin) {
456     if (this->isAbandoned()) {
457         return nullptr;
458     }
459 
460     sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendRenderTarget(backendRT));
461     if (!rt) {
462         return nullptr;
463     }
464     SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget
465     SkASSERT(!rt->getUniqueKey().isValid());
466 
467     return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
468 }
469 
createWrappedRenderTargetProxy(const GrBackendTexture & tex,GrSurfaceOrigin origin,int sampleCnt)470 sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy(const GrBackendTexture& tex,
471                                                                       GrSurfaceOrigin origin,
472                                                                       int sampleCnt) {
473     if (this->isAbandoned()) {
474         return nullptr;
475     }
476 
477     sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendTextureAsRenderTarget(tex, sampleCnt));
478     if (!rt) {
479         return nullptr;
480     }
481     SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget
482     SkASSERT(!rt->getUniqueKey().isValid());
483 
484     return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin));
485 }
486 
createLazyProxy(LazyInstantiateCallback && callback,const GrSurfaceDesc & desc,GrMipMapped mipMapped,SkBackingFit fit,SkBudgeted budgeted)487 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback,
488                                                        const GrSurfaceDesc& desc,
489                                                        GrMipMapped mipMapped,
490                                                        SkBackingFit fit, SkBudgeted budgeted) {
491     SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) ||
492              (desc.fWidth > 0 && desc.fHeight > 0));
493     uint32_t flags = GrResourceProvider::kNoPendingIO_Flag;
494     return sk_sp<GrTextureProxy>(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags) ?
495                                  new GrTextureRenderTargetProxy(std::move(callback), desc,
496                                                                 mipMapped, fit, budgeted, flags) :
497                                  new GrTextureProxy(std::move(callback), desc, mipMapped, fit,
498                                                     budgeted, flags));
499 }
500 
createFullyLazyProxy(LazyInstantiateCallback && callback,Renderable renderable,GrPixelConfig config)501 sk_sp<GrTextureProxy> GrProxyProvider::createFullyLazyProxy(LazyInstantiateCallback&& callback,
502                                                             Renderable renderable,
503                                                             GrPixelConfig config) {
504     GrSurfaceDesc desc;
505     if (Renderable::kYes == renderable) {
506         desc.fFlags = kRenderTarget_GrSurfaceFlag;
507     }
508     desc.fOrigin = kTopLeft_GrSurfaceOrigin;
509     desc.fWidth = -1;
510     desc.fHeight = -1;
511     desc.fConfig = config;
512     desc.fSampleCnt = 1;
513 
514     return this->createLazyProxy(std::move(callback), desc, GrMipMapped::kNo,
515                                  SkBackingFit::kApprox, SkBudgeted::kYes);
516 
517 }
518 
IsFunctionallyExact(GrSurfaceProxy * proxy)519 bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) {
520     return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height()));
521 }
522 
processInvalidProxyUniqueKey(const GrUniqueKey & key)523 void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key) {
524     // Note: this method is called for the whole variety of GrGpuResources so often 'key'
525     // will not be in 'fUniquelyKeyedProxies'.
526     GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key);
527     if (proxy) {
528         this->processInvalidProxyUniqueKey(key, proxy, false);
529     }
530 }
531 
processInvalidProxyUniqueKey(const GrUniqueKey & key,GrTextureProxy * proxy,bool invalidateSurface)532 void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy,
533                                                    bool invalidateSurface) {
534     SkASSERT(proxy);
535     SkASSERT(proxy->getUniqueKey().isValid());
536     SkASSERT(proxy->getUniqueKey() == key);
537 
538     fUniquelyKeyedProxies.remove(key);
539     proxy->cacheAccess().clearUniqueKey();
540 
541     if (invalidateSurface && proxy->priv().isInstantiated()) {
542         GrSurface* surface = proxy->priv().peekSurface();
543         if (surface) {
544             surface->resourcePriv().removeUniqueKey();
545         }
546     }
547 }
548 
removeAllUniqueKeys()549 void GrProxyProvider::removeAllUniqueKeys() {
550     UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies);
551     for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) {
552         GrTextureProxy& tmp = *iter;
553 
554         this->processInvalidProxyUniqueKey(tmp.getUniqueKey(), &tmp, false);
555     }
556     SkASSERT(!fUniquelyKeyedProxies.count());
557 }
558