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