diff --git a/shared/source/helpers/bindless_heaps_helper.cpp b/shared/source/helpers/bindless_heaps_helper.cpp index 773173816b..383afae461 100644 --- a/shared/source/helpers/bindless_heaps_helper.cpp +++ b/shared/source/helpers/bindless_heaps_helper.cpp @@ -14,6 +14,7 @@ #include "shared/source/indirect_heap/indirect_heap.h" #include "shared/source/memory_manager/allocation_properties.h" #include "shared/source/memory_manager/memory_manager.h" +#include "shared/source/os_interface/os_context.h" namespace NEO { @@ -61,20 +62,59 @@ GraphicsAllocation *BindlessHeapsHelper::getHeapAllocation(size_t heapSize, size return this->memManager->allocateGraphicsMemoryWithProperties(properties); } +void BindlessHeapsHelper::clearStateDirtyForContext(uint32_t osContextId) { + std::lock_guard autolock(this->mtx); + + stateCacheDirtyForContext.reset(osContextId); +} + +bool BindlessHeapsHelper::getStateDirtyForContext(uint32_t osContextId) { + std::lock_guard autolock(this->mtx); + + return stateCacheDirtyForContext.test(osContextId); +} + SurfaceStateInHeapInfo BindlessHeapsHelper::allocateSSInHeap(size_t ssSize, GraphicsAllocation *surfaceAllocation, BindlesHeapType heapType) { auto heap = surfaceStateHeaps[heapType].get(); std::lock_guard autolock(this->mtx); if (heapType == BindlesHeapType::GLOBAL_SSH) { - int index = getReusedSshVectorIndex(ssSize); + if (!allocateFromReusePool) { + if ((surfaceStateInHeapVectorReuse[releasePoolIndex][0].size() + surfaceStateInHeapVectorReuse[releasePoolIndex][1].size()) > reuseSlotCountThreshold) { - if (surfaceStateInHeapVectorReuse[index].size()) { - SurfaceStateInHeapInfo surfaceStateFromVector = surfaceStateInHeapVectorReuse[index].back(); - surfaceStateInHeapVectorReuse[index].pop_back(); - return surfaceStateFromVector; + // invalidate all contexts + stateCacheDirtyForContext.set(); + allocateFromReusePool = true; + allocatePoolIndex = releasePoolIndex; + releasePoolIndex = allocatePoolIndex == 0 ? 1 : 0; + } + } + + if (allocateFromReusePool) { + int index = getReusedSshVectorIndex(ssSize); + + if (surfaceStateInHeapVectorReuse[allocatePoolIndex][index].size()) { + SurfaceStateInHeapInfo surfaceStateFromVector = surfaceStateInHeapVectorReuse[allocatePoolIndex][index].back(); + surfaceStateInHeapVectorReuse[allocatePoolIndex][index].pop_back(); + + if (surfaceStateInHeapVectorReuse[allocatePoolIndex][index].empty()) { + allocateFromReusePool = false; + + // copy remaining slots from allocate pool to release pool + int otherSizeIndex = index == 0 ? 1 : 0; + surfaceStateInHeapVectorReuse[releasePoolIndex][otherSizeIndex].insert(surfaceStateInHeapVectorReuse[releasePoolIndex][otherSizeIndex].end(), + surfaceStateInHeapVectorReuse[allocatePoolIndex][otherSizeIndex].begin(), + surfaceStateInHeapVectorReuse[allocatePoolIndex][otherSizeIndex].end()); + + surfaceStateInHeapVectorReuse[allocatePoolIndex][otherSizeIndex].clear(); + } + + return surfaceStateFromVector; + } } } + void *ptrInHeap = getSpaceInHeap(ssSize, heapType); SurfaceStateInHeapInfo bindlesInfo = {nullptr, 0, nullptr}; @@ -128,14 +168,13 @@ bool BindlessHeapsHelper::growHeap(BindlesHeapType heapType) { return true; } -void BindlessHeapsHelper::placeSSAllocationInReuseVectorOnFreeMemory(GraphicsAllocation *gfxAllocation) { - auto ssAllocatedInfo = gfxAllocation->getBindlessInfo(); - - if (ssAllocatedInfo.heapAllocation != nullptr) { +void BindlessHeapsHelper::releaseSSToReusePool(const SurfaceStateInHeapInfo &surfStateInfo) { + if (surfStateInfo.heapAllocation != nullptr) { std::lock_guard autolock(this->mtx); - int index = getReusedSshVectorIndex(ssAllocatedInfo.ssSize); - surfaceStateInHeapVectorReuse[index].push_back(std::move(ssAllocatedInfo)); + int index = getReusedSshVectorIndex(surfStateInfo.ssSize); + surfaceStateInHeapVectorReuse[releasePoolIndex][index].push_back(std::move(surfStateInfo)); } + return; } diff --git a/shared/source/helpers/bindless_heaps_helper.h b/shared/source/helpers/bindless_heaps_helper.h index 4f4e671a3a..651a6fdd66 100644 --- a/shared/source/helpers/bindless_heaps_helper.h +++ b/shared/source/helpers/bindless_heaps_helper.h @@ -10,6 +10,7 @@ #include "shared/source/helpers/heap_helper.h" #include "shared/source/memory_manager/graphics_allocation.h" +#include #include #include #include @@ -18,7 +19,6 @@ namespace NEO { class IndirectHeap; - class BindlessHeapsHelper { public: enum BindlesHeapType { @@ -41,7 +41,7 @@ class BindlessHeapsHelper { uint32_t getDefaultBorderColorOffset(); uint32_t getAlphaBorderColorOffset(); IndirectHeap *getHeap(BindlesHeapType heapType); - void placeSSAllocationInReuseVectorOnFreeMemory(GraphicsAllocation *gfxAllocation); + void releaseSSToReusePool(const SurfaceStateInHeapInfo &surfStateInfo); bool isGlobalDshSupported() { return globalBindlessDsh; } @@ -55,6 +55,8 @@ class BindlessHeapsHelper { } return index; } + bool getStateDirtyForContext(uint32_t osContextId); + void clearStateDirtyForContext(uint32_t osContextId); protected: const size_t surfaceStateSize; @@ -65,7 +67,14 @@ class BindlessHeapsHelper { std::unique_ptr surfaceStateHeaps[BindlesHeapType::NUM_HEAP_TYPES]; GraphicsAllocation *borderColorStates; std::vector ssHeapsAllocations; - std::vector surfaceStateInHeapVectorReuse[2]; + + size_t reuseSlotCountThreshold = 512; + uint32_t allocatePoolIndex = 0; + uint32_t releasePoolIndex = 0; + bool allocateFromReusePool = false; + std::array, 2> surfaceStateInHeapVectorReuse[2]; + std::bitset<64> stateCacheDirtyForContext; + std::mutex mtx; DeviceBitfield deviceBitfield; bool globalBindlessDsh = false; diff --git a/shared/source/memory_manager/memory_manager.cpp b/shared/source/memory_manager/memory_manager.cpp index c508a872b1..ce1df135ad 100644 --- a/shared/source/memory_manager/memory_manager.cpp +++ b/shared/source/memory_manager/memory_manager.cpp @@ -245,7 +245,7 @@ void MemoryManager::freeGraphicsMemory(GraphicsAllocation *gfxAllocation, bool i return; } if (ApiSpecificConfig::getGlobalBindlessHeapConfiguration() && executionEnvironment.rootDeviceEnvironments[gfxAllocation->getRootDeviceIndex()]->getBindlessHeapsHelper() != nullptr) { - executionEnvironment.rootDeviceEnvironments[gfxAllocation->getRootDeviceIndex()]->getBindlessHeapsHelper()->placeSSAllocationInReuseVectorOnFreeMemory(gfxAllocation); + executionEnvironment.rootDeviceEnvironments[gfxAllocation->getRootDeviceIndex()]->getBindlessHeapsHelper()->releaseSSToReusePool(gfxAllocation->getBindlessInfo()); } const bool hasFragments = gfxAllocation->fragmentsStorage.fragmentCount != 0; const bool isLocked = gfxAllocation->isLocked(); diff --git a/shared/test/common/mocks/mock_bindless_heaps_helper.h b/shared/test/common/mocks/mock_bindless_heaps_helper.h index 3494c83322..e043d8f63d 100644 --- a/shared/test/common/mocks/mock_bindless_heaps_helper.h +++ b/shared/test/common/mocks/mock_bindless_heaps_helper.h @@ -29,13 +29,18 @@ class MockBindlesHeapsHelper : public BindlessHeapsHelper { } using BindlesHeapType = BindlessHeapsHelper::BindlesHeapType; + using BaseClass::allocateFromReusePool; + using BaseClass::allocatePoolIndex; using BaseClass::borderColorStates; using BaseClass::globalBindlessDsh; using BaseClass::growHeap; using BaseClass::isMultiOsContextCapable; using BaseClass::memManager; + using BaseClass::releasePoolIndex; + using BaseClass::reuseSlotCountThreshold; using BaseClass::rootDeviceIndex; using BaseClass::ssHeapsAllocations; + using BaseClass::stateCacheDirtyForContext; using BaseClass::surfaceStateHeaps; using BaseClass::surfaceStateInHeapVectorReuse; using BaseClass::surfaceStateSize; diff --git a/shared/test/unit_test/helpers/bindless_heaps_helper_tests.cpp b/shared/test/unit_test/helpers/bindless_heaps_helper_tests.cpp index 0854600743..f25b127581 100644 --- a/shared/test/unit_test/helpers/bindless_heaps_helper_tests.cpp +++ b/shared/test/unit_test/helpers/bindless_heaps_helper_tests.cpp @@ -233,8 +233,11 @@ TEST_F(BindlessHeapsHelperTests, givenBindlessHeapHelperWhenFreeGraphicsMemoryIs auto ssInHeapInfo = alloc->getBindlessInfo(); memManager->freeGraphicsMemory(alloc); - EXPECT_EQ(bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[0].size(), 1u); - auto ssInHeapInfoFromReuseVector = bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[0].front(); + + auto freePoolIndex = bindlessHeapHelperPtr->releasePoolIndex; + + EXPECT_EQ(bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[freePoolIndex][0].size(), 1u); + auto ssInHeapInfoFromReuseVector = bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[freePoolIndex][0].front(); EXPECT_EQ(ssInHeapInfoFromReuseVector.surfaceStateOffset, ssInHeapInfo.surfaceStateOffset); EXPECT_EQ(ssInHeapInfoFromReuseVector.ssPtr, ssInHeapInfo.ssPtr); @@ -245,8 +248,8 @@ TEST_F(BindlessHeapsHelperTests, givenBindlessHeapHelperWhenFreeGraphicsMemoryIs auto ssInHeapInfo2 = alloc2->getBindlessInfo(); memManager->freeGraphicsMemory(alloc2); - EXPECT_EQ(bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[1].size(), 1u); - ssInHeapInfoFromReuseVector = bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[1].front(); + EXPECT_EQ(bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[freePoolIndex][1].size(), 1u); + ssInHeapInfoFromReuseVector = bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[freePoolIndex][1].front(); EXPECT_EQ(ssInHeapInfoFromReuseVector.surfaceStateOffset, ssInHeapInfo2.surfaceStateOffset); EXPECT_EQ(ssInHeapInfoFromReuseVector.ssPtr, ssInHeapInfo2.ssPtr); } @@ -268,7 +271,7 @@ TEST_F(BindlessHeapsHelperTests, givenBindlessHeapHelperWhenAllocatingBindlessSl memManager->freeGraphicsMemory(alloc); } -TEST_F(BindlessHeapsHelperTests, givenBindlessHeapHelperPreviousAllocationThenItShouldBeReused) { +TEST_F(BindlessHeapsHelperTests, givenBindlessHeapHelperPreviousAllocationThenItShouldNotBeReusedIfThresholdNotReached) { DebugManagerStateRestore dbgRestorer; DebugManager.flags.UseBindlessMode.set(1); auto bindlessHeapHelper = std::make_unique(getMemoryManager(), false, rootDeviceIndex, devBitfield); @@ -279,17 +282,21 @@ TEST_F(BindlessHeapsHelperTests, givenBindlessHeapHelperPreviousAllocationThenIt auto ssInHeapInfo = alloc->getBindlessInfo(); memManager->freeGraphicsMemory(alloc); - EXPECT_EQ(bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[0].size(), 1u); + + auto freePoolIndex = bindlessHeapHelperPtr->releasePoolIndex; + + EXPECT_EQ(bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[freePoolIndex][0].size(), 1u); MockGraphicsAllocation *alloc2 = new MockGraphicsAllocation; memManager->allocateBindlessSlot(alloc2); - auto reusedSSinHeapInfo = alloc2->getBindlessInfo(); + auto newSSinHeapInfo = alloc2->getBindlessInfo(); - EXPECT_EQ(bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[0].size(), 0u); - EXPECT_EQ(ssInHeapInfo.surfaceStateOffset, reusedSSinHeapInfo.surfaceStateOffset); - EXPECT_EQ(ssInHeapInfo.ssPtr, reusedSSinHeapInfo.ssPtr); + EXPECT_NE(bindlessHeapHelperPtr->surfaceStateInHeapVectorReuse[freePoolIndex][0].size(), 0u); + EXPECT_NE(ssInHeapInfo.surfaceStateOffset, newSSinHeapInfo.surfaceStateOffset); + EXPECT_NE(ssInHeapInfo.ssPtr, newSSinHeapInfo.ssPtr); memManager->freeGraphicsMemory(alloc2); } + TEST_F(BindlessHeapsHelperTests, givenDeviceWhenBindlessHeapHelperInitializedThenCorrectDeviceBitFieldIsUsed) { DebugManagerStateRestore dbgRestorer; DebugManager.flags.UseBindlessMode.set(1); @@ -297,3 +304,228 @@ TEST_F(BindlessHeapsHelperTests, givenDeviceWhenBindlessHeapHelperInitializedThe auto bindlessHeapHelper = std::make_unique(getMemoryManager(), false, rootDeviceIndex, deviceBitfield); EXPECT_EQ(reinterpret_cast(getMemoryManager())->recentlyPassedDeviceBitfield, deviceBitfield); } + +TEST_F(BindlessHeapsHelperTests, givenBindlessHeapHelperWhenCreatedThenAllocateAndReleasePoolIndicesAreInitializedToZero) { + auto bindlessHeapHelper = std::make_unique(getMemoryManager(), false, rootDeviceIndex, devBitfield); + + EXPECT_FALSE(bindlessHeapHelper->allocateFromReusePool); + EXPECT_EQ(0u, bindlessHeapHelper->allocatePoolIndex); + EXPECT_EQ(0u, bindlessHeapHelper->releasePoolIndex); + + EXPECT_EQ(0u, bindlessHeapHelper->stateCacheDirtyForContext.to_ulong()); +} + +TEST_F(BindlessHeapsHelperTests, givenFreeSlotsExceedingThresholdInResuePoolWhenNewSlotsAllocatedThenSlotsAreAllocatedFromReusePool) { + auto bindlessHeapHelper = std::make_unique(getMemoryManager(), false, rootDeviceIndex, devBitfield); + bindlessHeapHelper->reuseSlotCountThreshold = 4; + + size_t size = bindlessHeapHelper->surfaceStateSize; + + SurfaceStateInHeapInfo ssInHeapInfos[5]; + + ssInHeapInfos[0] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[1] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + // allocate double size for image + ssInHeapInfos[2] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[3] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[4] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + + EXPECT_FALSE(bindlessHeapHelper->allocateFromReusePool); + + for (int i = 0; i < 5; i++) { + bindlessHeapHelper->releaseSSToReusePool(ssInHeapInfos[i]); + ssInHeapInfos[i] = {0}; + } + + ssInHeapInfos[4] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + EXPECT_TRUE(bindlessHeapHelper->allocateFromReusePool); + + EXPECT_EQ(0u, bindlessHeapHelper->allocatePoolIndex); + EXPECT_EQ(1u, bindlessHeapHelper->releasePoolIndex); + + EXPECT_EQ(std::numeric_limits::max(), bindlessHeapHelper->stateCacheDirtyForContext.to_ullong()); +} + +TEST_F(BindlessHeapsHelperTests, givenReusePoolExhaustedWhenNewSlotsAllocatedThenSlotsAreNotResuedAndStateCacheDirtyFlagsAreNotSet) { + auto bindlessHeapHelper = std::make_unique(getMemoryManager(), false, rootDeviceIndex, devBitfield); + bindlessHeapHelper->reuseSlotCountThreshold = 4; + + size_t size = bindlessHeapHelper->surfaceStateSize; + + SurfaceStateInHeapInfo ssInHeapInfos[5]; + + ssInHeapInfos[0] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[1] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + // allocate double size for image + ssInHeapInfos[2] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[3] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[4] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + + EXPECT_FALSE(bindlessHeapHelper->allocateFromReusePool); + + for (int i = 0; i < 5; i++) { + bindlessHeapHelper->releaseSSToReusePool(ssInHeapInfos[i]); + ssInHeapInfos[i] = {0}; + } + EXPECT_FALSE(bindlessHeapHelper->allocateFromReusePool); + EXPECT_EQ(0u, bindlessHeapHelper->allocatePoolIndex); + EXPECT_EQ(0u, bindlessHeapHelper->releasePoolIndex); + + for (int i = 0; i < 3; i++) { + ssInHeapInfos[i] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + } + + EXPECT_EQ(0u, bindlessHeapHelper->allocatePoolIndex); + EXPECT_EQ(1u, bindlessHeapHelper->releasePoolIndex); + + auto allocatePoolIndex = bindlessHeapHelper->allocatePoolIndex; + auto releasePoolIndex = bindlessHeapHelper->releasePoolIndex; + + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][0].size(), 0u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][1].size(), 2u); + + bindlessHeapHelper->stateCacheDirtyForContext.reset(); + + ssInHeapInfos[3] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + EXPECT_NE(0u, ssInHeapInfos[3].surfaceStateOffset); + EXPECT_NE(nullptr, ssInHeapInfos[3].ssPtr); + + EXPECT_FALSE(bindlessHeapHelper->allocateFromReusePool); + EXPECT_EQ(0u, bindlessHeapHelper->stateCacheDirtyForContext.to_ullong()); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][0].size(), 0u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][1].size(), 0u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][0].size(), 0u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][1].size(), 2u); +} + +TEST_F(BindlessHeapsHelperTests, givenReleasedSlotsToSecondPoolWhenThresholdReachedThenPoolsAreSwitchedAndSlotsAllocatedFromReusePool) { + auto bindlessHeapHelper = std::make_unique(getMemoryManager(), false, rootDeviceIndex, devBitfield); + bindlessHeapHelper->reuseSlotCountThreshold = 4; + + size_t size = bindlessHeapHelper->surfaceStateSize; + + SurfaceStateInHeapInfo ssInHeapInfos[5]; + + ssInHeapInfos[0] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[1] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + // allocate double size for image + ssInHeapInfos[2] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[3] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[4] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + + for (int i = 0; i < 5; i++) { + bindlessHeapHelper->releaseSSToReusePool(ssInHeapInfos[i]); + ssInHeapInfos[i] = {0}; + } + + for (int i = 0; i < 3; i++) { + ssInHeapInfos[i] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + } + + EXPECT_EQ(0u, bindlessHeapHelper->allocatePoolIndex); + EXPECT_EQ(1u, bindlessHeapHelper->releasePoolIndex); + + auto allocatePoolIndex = bindlessHeapHelper->allocatePoolIndex; + auto releasePoolIndex = bindlessHeapHelper->releasePoolIndex; + + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][0].size(), 0u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][1].size(), 2u); + + for (int i = 0; i < 3; i++) { + bindlessHeapHelper->releaseSSToReusePool(ssInHeapInfos[i]); + ssInHeapInfos[i] = {0}; + } + + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][0].size(), 3u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][1].size(), 2u); + + ssInHeapInfos[3] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + + EXPECT_EQ(1u, bindlessHeapHelper->allocatePoolIndex); + EXPECT_EQ(0u, bindlessHeapHelper->releasePoolIndex); + + allocatePoolIndex = bindlessHeapHelper->allocatePoolIndex; + releasePoolIndex = bindlessHeapHelper->releasePoolIndex; + + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][1].size(), 1u); + + ssInHeapInfos[4] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][1].size(), 0u); + EXPECT_FALSE(bindlessHeapHelper->allocateFromReusePool); + + bindlessHeapHelper->releaseSSToReusePool(ssInHeapInfos[3]); + bindlessHeapHelper->releaseSSToReusePool(ssInHeapInfos[4]); + + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][0].size(), 0u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][1].size(), 0u); + + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][0].size(), 3u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][1].size(), 2u); + + bindlessHeapHelper->stateCacheDirtyForContext.reset(); + + ssInHeapInfos[0] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + + EXPECT_EQ(0u, bindlessHeapHelper->allocatePoolIndex); + EXPECT_EQ(1u, bindlessHeapHelper->releasePoolIndex); + EXPECT_EQ(std::numeric_limits::max(), bindlessHeapHelper->stateCacheDirtyForContext.to_ullong()); + EXPECT_TRUE(bindlessHeapHelper->allocateFromReusePool); + + allocatePoolIndex = bindlessHeapHelper->allocatePoolIndex; + releasePoolIndex = bindlessHeapHelper->releasePoolIndex; + + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][0].size(), 3u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][1].size(), 1u); + + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][0].size(), 0u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[releasePoolIndex][1].size(), 0u); + + for (int i = 0; i < 8; i++) { + bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + } + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][0].size(), 0u); + EXPECT_FALSE(bindlessHeapHelper->allocateFromReusePool); +} + +TEST_F(BindlessHeapsHelperTests, givenFreeSlotsInReusePoolForONeSizeWhenAllocatingDifferentSizeThenNewSlotFromHeapIsAllocated) { + auto bindlessHeapHelper = std::make_unique(getMemoryManager(), false, rootDeviceIndex, devBitfield); + bindlessHeapHelper->reuseSlotCountThreshold = 4; + + size_t size = bindlessHeapHelper->surfaceStateSize; + + SurfaceStateInHeapInfo ssInHeapInfos[5]; + + ssInHeapInfos[0] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[1] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[2] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[3] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + ssInHeapInfos[4] = bindlessHeapHelper->allocateSSInHeap(size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + + for (int i = 0; i < 5; i++) { + bindlessHeapHelper->releaseSSToReusePool(ssInHeapInfos[i]); + ssInHeapInfos[i] = {0}; + } + + ssInHeapInfos[0] = bindlessHeapHelper->allocateSSInHeap(2 * size, nullptr, BindlessHeapsHelper::BindlesHeapType::GLOBAL_SSH); + + EXPECT_EQ(0u, bindlessHeapHelper->allocatePoolIndex); + EXPECT_EQ(1u, bindlessHeapHelper->releasePoolIndex); + + EXPECT_NE(0u, ssInHeapInfos[0].surfaceStateOffset); + EXPECT_NE(nullptr, ssInHeapInfos[0].ssPtr); + + auto allocatePoolIndex = bindlessHeapHelper->allocatePoolIndex; + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][0].size(), 5u); + EXPECT_EQ(bindlessHeapHelper->surfaceStateInHeapVectorReuse[allocatePoolIndex][1].size(), 0u); +} + +TEST_F(BindlessHeapsHelperTests, givenBindlessHelperWhenGettingAndClearingDirstyStateForContextThenCorrectFlagIsReturnedAdCleard) { + auto bindlessHeapHelper = std::make_unique(getMemoryManager(), false, rootDeviceIndex, devBitfield); + + EXPECT_FALSE(bindlessHeapHelper->getStateDirtyForContext(1)); + bindlessHeapHelper->stateCacheDirtyForContext.set(3); + EXPECT_TRUE(bindlessHeapHelper->getStateDirtyForContext(3)); + + bindlessHeapHelper->clearStateDirtyForContext(3); + EXPECT_FALSE(bindlessHeapHelper->getStateDirtyForContext(3)); +} \ No newline at end of file