From 305e6184f8f6405ffb8cd5195c5595a6dba8b796 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 2 Oct 2016 01:10:43 +0100 Subject: [PATCH] Try merging free image lists if failed to allocate one --- src/drawing/Image.cpp | 80 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/src/drawing/Image.cpp b/src/drawing/Image.cpp index 60f6e2c219..c57344d845 100644 --- a/src/drawing/Image.cpp +++ b/src/drawing/Image.cpp @@ -72,21 +72,57 @@ static bool AllocatedListRemove(uint32 baseImageId, uint32 count) } #endif -static uint32 AllocateImageList(uint32 count) +static uint32 GetNumFreeImagesRemaining() { - Guard::Assert(count != 0, GUARD_LINE); + return MAX_IMAGES - _allocatedImageCount; +} - if (!_initialised) - { - _initialised = true; - _freeLists.clear(); - _freeLists.push_back({ BASE_IMAGE_ID, MAX_IMAGES }); +static void InitialiseImageList() +{ + Guard::Assert(!_initialised, GUARD_LINE); + + _freeLists.clear(); + _freeLists.push_back({ BASE_IMAGE_ID, MAX_IMAGES }); #ifdef DEBUG - _allocatedLists.clear(); + _allocatedLists.clear(); #endif - _allocatedImageCount = 0; - } + _allocatedImageCount = 0; + _initialised = true; +} +/** + * Merges all the free lists into one, a process of defragmentation. + */ +static void MergeFreeLists() +{ + _freeLists.sort( + [](const ImageList &a, const ImageList &b) -> bool + { + return a.BaseId < b.BaseId; + }); + for (auto it = _freeLists.begin(); it != _freeLists.end(); it++) + { + bool mergeHappened; + do + { + mergeHappened = false; + auto nextIt = std::next(it); + if (nextIt != _freeLists.end()) + { + if (it->BaseId + it->Count == nextIt->BaseId) + { + // Merge next list into this list + it->Count += nextIt->Count; + _freeLists.erase(nextIt); + mergeHappened = true; + } + } + } while (mergeHappened); + } +} + +static uint32 TryAllocateImageList(uint32 count) +{ for (auto it = _freeLists.begin(); it != _freeLists.end(); it++) { ImageList imageList = *it; @@ -110,6 +146,30 @@ static uint32 AllocateImageList(uint32 count) return INVALID_IMAGE_ID; } +static uint32 AllocateImageList(uint32 count) +{ + Guard::Assert(count != 0, GUARD_LINE); + + if (!_initialised) + { + InitialiseImageList(); + } + + uint32 baseImageId = INVALID_IMAGE_ID; + uint32 freeImagesRemaining = GetNumFreeImagesRemaining(); + if (freeImagesRemaining >= count) + { + baseImageId = TryAllocateImageList(count); + if (baseImageId == INVALID_IMAGE_ID) + { + // Defragment and try again + MergeFreeLists(); + baseImageId = TryAllocateImageList(count); + } + } + return baseImageId; +} + static void FreeImageList(uint32 baseImageId, uint32 count) { Guard::Assert(_initialised, GUARD_LINE);