Lines Matching full:resource
16 #include "src/gpu/graphite/Resource.h"
66 Resource* back = *(fNonpurgeableResources.end() - 1); in shutdown()
73 Resource* top = fPurgeableQueue.peek(); in shutdown()
82 void ResourceCache::insertResource(Resource* resource) { in insertResource() argument
84 SkASSERT(resource); in insertResource()
85 SkASSERT(!this->isInCache(resource)); in insertResource()
86 SkASSERT(!resource->wasDestroyed()); in insertResource()
87 SkASSERT(!resource->isPurgeable()); in insertResource()
88 SkASSERT(resource->key().isValid()); in insertResource()
91 SkASSERT(resource->ownership() == Ownership::kOwned); in insertResource()
95 // want to have them all returned before adding the budget for the new resource in case we need in insertResource()
96 // to purge things. However, if the new resource has a memory size of 0, then we just skip in insertResource()
97 // returning resources (which has overhead for each call) since the new resource won't be in insertResource()
99 if (resource->gpuMemorySize() > 0) { in insertResource()
103 resource->registerWithCache(sk_ref_sp(this)); in insertResource()
104 resource->refCache(); in insertResource()
108 this->setResourceTimestamp(resource, this->getNextTimestamp()); in insertResource()
109 resource->updateAccessTime(); in insertResource()
111 this->addToNonpurgeableArray(resource); in insertResource()
115 if (resource->key().shareable() == Shareable::kYes) { in insertResource()
116 fResourceMap.insert(resource->key(), resource); in insertResource()
119 if (resource->budgeted() == skgpu::Budgeted::kYes) { in insertResource()
120 fBudgetedBytes += resource->gpuMemorySize(); in insertResource()
126 Resource* ResourceCache::findAndRefResource(const GraphiteResourceKey& key, in findAndRefResource()
132 Resource* resource = fResourceMap.find(key); in findAndRefResource() local
133 if (!resource) { in findAndRefResource()
136 // So we only call it if we first failed to find a matching resource. in findAndRefResource()
138 resource = fResourceMap.find(key); in findAndRefResource()
141 if (resource) { in findAndRefResource()
143 SkASSERT(resource->budgeted() == skgpu::Budgeted::kYes); in findAndRefResource()
145 // If a resource is not shareable (i.e. scratch resource) then we remove it from the map in findAndRefResource()
147 fResourceMap.remove(key, resource); in findAndRefResource()
149 resource->makeUnbudgeted(); in findAndRefResource()
150 fBudgetedBytes -= resource->gpuMemorySize(); in findAndRefResource()
152 SkDEBUGCODE(resource->fNonShareableInCache = false;) in findAndRefResource()
157 this->refAndMakeResourceMRU(resource); in findAndRefResource()
163 // processReturnedResources, we delay calling it until now so we don't end up purging a resource in findAndRefResource()
173 return resource; in findAndRefResource()
176 void ResourceCache::refAndMakeResourceMRU(Resource* resource) { in refAndMakeResourceMRU() argument
177 SkASSERT(resource); in refAndMakeResourceMRU()
178 SkASSERT(this->isInCache(resource)); in refAndMakeResourceMRU()
180 if (this->inPurgeableQueue(resource)) { in refAndMakeResourceMRU()
182 this->removeFromPurgeableQueue(resource); in refAndMakeResourceMRU()
183 this->addToNonpurgeableArray(resource); in refAndMakeResourceMRU()
185 resource->initialUsageRef(); in refAndMakeResourceMRU()
187 this->setResourceTimestamp(resource, this->getNextTimestamp()); in refAndMakeResourceMRU()
191 bool ResourceCache::returnResource(Resource* resource, LastRemovedRef removedRef) { in returnResource() argument
199 SkASSERT(resource); in returnResource()
201 // When a non-shareable resource's CB and Usage refs are both zero, give it a chance prepare in returnResource()
204 if (resource->shouldDeleteASAP() == Resource::DeleteASAP::kNo && in returnResource()
205 resource->key().shareable() == Shareable::kNo && in returnResource()
207 resource->prepareForReturnToCache([resource] { resource->initialUsageRef(); }); in returnResource()
208 // Check if resource was re-ref'ed. In that case exit without adding to the queue. in returnResource()
209 if (resource->hasUsageRef()) { in returnResource()
214 // We only allow one instance of a Resource to be in the return queue at a time. We do this so in returnResource()
218 // decided to have multiple instances of a Resource. Even if an earlier returned instance of a in returnResource()
219 // Resource triggers that Resource to get purged from the cache, the Resource itself wouldn't in returnResource()
221 if (*resource->accessReturnIndex() >= 0) { in returnResource()
222 // If the resource is already in the return queue we promote the LastRemovedRef to be in returnResource()
225 SkASSERT(*resource->accessReturnIndex() < (int)fReturnQueue.size()); in returnResource()
226 fReturnQueue[*resource->accessReturnIndex()].second = removedRef; in returnResource()
232 SkASSERT(nextResource.first != resource); in returnResource()
236 fReturnQueue.push_back(std::make_pair(resource, removedRef)); in returnResource()
237 *resource->accessReturnIndex() = fReturnQueue.size() - 1; in returnResource()
238 resource->refCache(); in returnResource()
244 // so that we can drop the fReturnMutex. When we process a Resource we may need to grab its in processReturnedResources()
245 // UnrefMutex. This could cause a deadlock if on another thread the Resource has the UnrefMutex in processReturnedResources()
256 auto [resource, ref] = nextResource; in processReturnedResources()
257 SkASSERT(*resource->accessReturnIndex() >= 0); in processReturnedResources()
258 *resource->accessReturnIndex() = -1; in processReturnedResources()
270 auto [resource, ref] = nextResource; in processReturnedResources()
271 // We need this check here to handle the following scenario. A Resource is sitting in the in processReturnedResources()
272 // ReturnQueue (say from kUsage last ref) and the Resource still has a command buffer ref in processReturnedResources()
275 // thread. The Resource cannot be added to the ReturnQueue since the lock is held. Back in in processReturnedResources()
276 // the ResourceCache (we'll drop the ReturnMutex) and when we try to return the Resource we in processReturnedResources()
277 // will see that it is purgeable. If we are overbudget it is possible that the Resource gets in processReturnedResources()
279 // call will actually block here on the Resource's UnrefMutex which is held from the command in processReturnedResources()
283 // processReturnedResources the next time, we don't want this Resource added back into the in processReturnedResources()
284 // cache, thus we have the check here. The Resource will then get deleted when we call in processReturnedResources()
286 if (*resource->accessCacheIndex() != -1) { in processReturnedResources()
287 this->returnResourceToCache(resource, ref); in processReturnedResources()
290 resource->unrefCache(); in processReturnedResources()
295 void ResourceCache::returnResourceToCache(Resource* resource, LastRemovedRef removedRef) { in returnResourceToCache() argument
296 // A resource should not have been destroyed when placed into the return queue. Also before in returnResourceToCache()
299 // resources can be added. Thus we should not end up in a situation where a resource gets in returnResourceToCache()
301 SkASSERT(!resource->wasDestroyed()); in returnResourceToCache()
303 SkASSERT(this->isInCache(resource)); in returnResourceToCache()
305 if (resource->key().shareable() == Shareable::kYes) { in returnResourceToCache()
307 SkASSERT(fResourceMap.find(resource->key())); in returnResourceToCache()
309 SkDEBUGCODE(resource->fNonShareableInCache = true;) in returnResourceToCache()
310 resource->setLabel("Scratch"); in returnResourceToCache()
311 fResourceMap.insert(resource->key(), resource); in returnResourceToCache()
312 if (resource->budgeted() == skgpu::Budgeted::kNo) { in returnResourceToCache()
313 resource->makeBudgeted(); in returnResourceToCache()
314 fBudgetedBytes += resource->gpuMemorySize(); in returnResourceToCache()
319 // If we weren't using multiple threads, it is ok to assume a resource that isn't purgeable must in returnResourceToCache()
321 // threads, it is possible that a resource became purgeable while we are in the middle of in returnResourceToCache()
322 // returning resources. For example, a resource could have 1 usage and 1 command buffer ref. We in returnResourceToCache()
323 // then unref the usage which puts the resource in the return queue. Then the ResourceCache in returnResourceToCache()
324 // thread locks the ReturnQueue as it returns the Resource. At this same time another thread in returnResourceToCache()
325 // unrefs the command buffer usage but can't add the Resource to the ReturnQueue as it is in returnResourceToCache()
327 // Resource (from the kUsage ref) to return it to the cache it will look like it is purgeable in returnResourceToCache()
328 // since all refs are zero. Thus we will move the Resource from the non purgeable to purgeable in returnResourceToCache()
329 // queue. Then later when we return the command buffer ref, the Resource will have already been in returnResourceToCache()
331 if (!resource->isPurgeable() || this->inPurgeableQueue(resource)) { in returnResourceToCache()
336 this->setResourceTimestamp(resource, this->getNextTimestamp()); in returnResourceToCache()
338 this->removeFromNonpurgeableArray(resource); in returnResourceToCache()
340 if (resource->shouldDeleteASAP() == Resource::DeleteASAP::kYes) { in returnResourceToCache()
341 this->purgeResource(resource); in returnResourceToCache()
343 resource->updateAccessTime(); in returnResourceToCache()
344 fPurgeableQueue.insert(resource); in returnResourceToCache()
345 fPurgeableBytes += resource->gpuMemorySize(); in returnResourceToCache()
350 void ResourceCache::addToNonpurgeableArray(Resource* resource) { in addToNonpurgeableArray() argument
352 *fNonpurgeableResources.append() = resource; in addToNonpurgeableArray()
353 *resource->accessCacheIndex() = index; in addToNonpurgeableArray()
356 void ResourceCache::removeFromNonpurgeableArray(Resource* resource) { in removeFromNonpurgeableArray() argument
357 int* index = resource->accessCacheIndex(); in removeFromNonpurgeableArray()
360 Resource* tail = *(fNonpurgeableResources.end() - 1); in removeFromNonpurgeableArray()
361 SkASSERT(fNonpurgeableResources[*index] == resource); in removeFromNonpurgeableArray()
368 void ResourceCache::removeFromPurgeableQueue(Resource* resource) { in removeFromPurgeableQueue() argument
369 fPurgeableQueue.remove(resource); in removeFromPurgeableQueue()
370 fPurgeableBytes -= resource->gpuMemorySize(); in removeFromPurgeableQueue()
372 // flag for whether the Resource has been purged from the cache or not. So we need to make sure in removeFromPurgeableQueue()
374 *resource->accessCacheIndex() = -1; in removeFromPurgeableQueue()
377 bool ResourceCache::inPurgeableQueue(Resource* resource) const { in inPurgeableQueue()
378 SkASSERT(this->isInCache(resource)); in inPurgeableQueue()
379 int index = *resource->accessCacheIndex(); in inPurgeableQueue()
380 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) { in inPurgeableQueue()
386 void ResourceCache::purgeResource(Resource* resource) { in purgeResource() argument
387 SkASSERT(resource->isPurgeable()); in purgeResource()
390 "size", resource->gpuMemorySize()); in purgeResource()
392 fResourceMap.remove(resource->key(), resource); in purgeResource()
394 if (resource->shouldDeleteASAP() == Resource::DeleteASAP::kNo) { in purgeResource()
395 SkASSERT(this->inPurgeableQueue(resource)); in purgeResource()
396 this->removeFromPurgeableQueue(resource); in purgeResource()
398 SkASSERT(!this->isInCache(resource)); in purgeResource()
401 fBudgetedBytes -= resource->gpuMemorySize(); in purgeResource()
402 resource->unrefCache(); in purgeResource()
415 Resource* resource = fPurgeableQueue.peek(); in purgeAsNeeded() local
416 SkASSERT(!resource->wasDestroyed()); in purgeAsNeeded()
417 SkASSERT(fResourceMap.find(resource->key())); in purgeAsNeeded()
419 if (resource->timestamp() == kMaxTimestamp) { in purgeAsNeeded()
420 // If we hit a resource that is at kMaxTimestamp, then we've hit the part of the in purgeAsNeeded()
423 SkASSERT(resource->gpuMemorySize() == 0); in purgeAsNeeded()
427 this->purgeResource(resource); in purgeAsNeeded()
462 SkTDArray<Resource*> resourcesToPurge; in purgeResources()
464 Resource* resource = fPurgeableQueue.at(i); in purgeResources() local
466 const skgpu::StdSteadyClock::time_point resourceTime = resource->lastAccessTime(); in purgeResources()
471 SkASSERT(resource->isPurgeable()); in purgeResources()
472 *resourcesToPurge.append() = resource; in purgeResources()
498 SkTDArray<Resource*> sortedPurgeableResources; in getNextTimestamp()
521 // Correct the index in the nonpurgeable array stored on the resource post-sort. in getNextTimestamp()
551 void ResourceCache::setResourceTimestamp(Resource* resource, uint32_t timestamp) { in setResourceTimestamp() argument
553 if (resource->gpuMemorySize() == 0) { in setResourceTimestamp()
556 resource->setTimestamp(timestamp); in setResourceTimestamp()
570 const GraphiteResourceKey& ResourceCache::MapTraits::GetKey(const Resource& r) { in GetKey()
578 bool ResourceCache::CompareTimestamp(Resource* const& a, Resource* const& b) { in CompareTimestamp()
582 int* ResourceCache::AccessResourceIndex(Resource* const& res) { in AccessResourceIndex()
588 // Reduce the frequency of validations for large resource counts. in validate()
609 void update(Resource* resource) { in validate()
610 const GraphiteResourceKey& key = resource->key(); in validate()
614 SkASSERT(resource->hasCacheRef()); in validate()
618 SkASSERT(resource->ownership() == Ownership::kOwned); in validate()
625 if (resource->isUsableAsScratch()) { in validate()
627 SkASSERT(!resource->hasUsageRef()); in validate()
629 SkASSERT(fResourceMap->has(resource, key)); in validate()
630 SkASSERT(resource->budgeted() == skgpu::Budgeted::kYes); in validate()
632 SkASSERT(!fResourceMap->has(resource, key)); in validate()
636 SkASSERT(fResourceMap->has(resource, key)); in validate()
637 SkASSERT(resource->budgeted() == skgpu::Budgeted::kYes); in validate()
640 if (resource->budgeted() == skgpu::Budgeted::kYes) { in validate()
641 fBudgetedBytes += resource->gpuMemorySize(); in validate()
644 if (resource->gpuMemorySize() == 0) { in validate()
645 SkASSERT(resource->timestamp() == kMaxTimestamp); in validate()
647 SkASSERT(resource->timestamp() < kMaxTimestamp); in validate()
650 int index = *resource->accessCacheIndex(); in validate()
651 if (index < fPurgeableQueue->count() && fPurgeableQueue->at(index) == resource) { in validate()
652 SkASSERT(resource->isPurgeable()); in validate()
653 fPurgeableBytes += resource->gpuMemorySize(); in validate()
660 fResourceMap.foreach([&](const Resource& resource) { in validate() argument
661 SkASSERT(resource.isUsableAsScratch() || resource.key().shareable() == Shareable::kYes); in validate()
662 SkASSERT(resource.budgeted() == skgpu::Budgeted::kYes); in validate()
669 // we won't put a Resource into that queue unless all refs are zero. Thus there is no way for in validate()
670 // that resource to be made non-purgeable without going through the cache (which will switch in validate()
676 // queue yet. Its also possible that Resource hasn't been added to the ReturnQueue yet (thread in validate()
708 bool ResourceCache::isInCache(const Resource* resource) const { in isInCache()
709 int index = *resource->accessCacheIndex(); in isInCache()
713 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) { in isInCache()
716 if (index < fNonpurgeableResources.size() && fNonpurgeableResources[index] == resource) { in isInCache()
719 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache."); in isInCache()
737 Resource* ResourceCache::topOfPurgeableQueue() { in topOfPurgeableQueue()