* Delete entries from the sprite cache to remove the requested number of bytes. * Sprite data is removed in order of LRU values. * The total number of bytes removed may be larger than the number requested. * @param to_remove Requested number of bytes to remove. */
| 702 | * @param to_remove Requested number of bytes to remove. |
| 703 | */ |
| 704 | static void DeleteEntriesFromSpriteCache(size_t to_remove) |
| 705 | { |
| 706 | const size_t initial_in_use = _spritecache_bytes_used; |
| 707 | |
| 708 | struct SpriteInfo { |
| 709 | uint32_t lru; |
| 710 | SpriteID id; |
| 711 | size_t size; |
| 712 | |
| 713 | bool operator<(const SpriteInfo &other) const |
| 714 | { |
| 715 | return this->lru < other.lru; |
| 716 | } |
| 717 | }; |
| 718 | |
| 719 | std::vector<SpriteInfo> candidates; // max heap, ordered by LRU |
| 720 | size_t candidate_bytes = 0; // total bytes that would be released when clearing all sprites in candidates |
| 721 | |
| 722 | auto push = [&](SpriteInfo info) { |
| 723 | candidates.push_back(info); |
| 724 | std::push_heap(candidates.begin(), candidates.end()); |
| 725 | candidate_bytes += info.size; |
| 726 | }; |
| 727 | |
| 728 | auto pop = [&]() { |
| 729 | candidate_bytes -= candidates.front().size; |
| 730 | std::pop_heap(candidates.begin(), candidates.end()); |
| 731 | candidates.pop_back(); |
| 732 | }; |
| 733 | |
| 734 | SpriteID i = 0; |
| 735 | for (; i != static_cast<SpriteID>(_spritecache.size()) && candidate_bytes < to_remove; i++) { |
| 736 | const SpriteCache *sc = GetSpriteCache(i); |
| 737 | if (sc->ptr != nullptr) { |
| 738 | push({ sc->lru, i, sc->length }); |
| 739 | if (candidate_bytes >= to_remove) break; |
| 740 | } |
| 741 | } |
| 742 | /* candidates now contains enough bytes to meet to_remove. |
| 743 | * only sprites with LRU values <= the maximum (i.e. the top of the heap) need to be considered */ |
| 744 | for (; i != static_cast<SpriteID>(_spritecache.size()); i++) { |
| 745 | const SpriteCache *sc = GetSpriteCache(i); |
| 746 | if (sc->ptr != nullptr && sc->lru <= candidates.front().lru) { |
| 747 | push({ sc->lru, i, sc->length }); |
| 748 | while (!candidates.empty() && candidate_bytes - candidates.front().size >= to_remove) { |
| 749 | pop(); |
| 750 | } |
| 751 | } |
| 752 | } |
| 753 | |
| 754 | for (const auto &it : candidates) { |
| 755 | GetSpriteCache(it.id)->ClearSpriteData(); |
| 756 | } |
| 757 | |
| 758 | Debug(sprite, 3, "DeleteEntriesFromSpriteCache, deleted: {}, freed: {}, in use: {} --> {}, requested: {}", |
| 759 | candidates.size(), candidate_bytes, initial_in_use, _spritecache_bytes_used, to_remove); |
| 760 | } |
| 761 |
no test coverage detected