From cab8a8934623e935953603348c36e06c2b899e8d Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Fri, 20 Mar 2026 17:57:27 -0700 Subject: [PATCH] vk: make fbo eviction time configurable (#9808) The previous eviction time is too large (40), then causes memory to bloat over time. We set the default to 3 (as in triple buffering), but make it a configurable option via VulkanPlatform. Fixes #9786 --- .../backend/platforms/VulkanPlatform.h | 6 +++ filament/backend/src/vulkan/VulkanDriver.cpp | 3 +- .../backend/src/vulkan/VulkanFboCache.cpp | 51 +++++++++++-------- filament/backend/src/vulkan/VulkanFboCache.h | 3 +- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/filament/backend/include/backend/platforms/VulkanPlatform.h b/filament/backend/include/backend/platforms/VulkanPlatform.h index 86af3c0183..7c2ba81b8e 100644 --- a/filament/backend/include/backend/platforms/VulkanPlatform.h +++ b/filament/backend/include/backend/platforms/VulkanPlatform.h @@ -177,6 +177,12 @@ public: * presentation. Default is true. */ bool transitionSwapChainImageLayoutForPresent = true; + + /** + * The number of frames before an unused framebuffer is evicted from the cache. + * Default is 3. + */ + uint32_t timeBeforeEvictionFbo = 3; }; /** diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 870d4ac938..e48baf910f 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -260,7 +260,8 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context, mPipelineCache(*this, mPlatform->getDevice(), mContext), mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()), mBufferCache(mContext, mResourceManager, mAllocator), - mFramebufferCache(mPlatform->getDevice()), + mFramebufferCache(mPlatform->getDevice(), + mPlatform->getCustomization().timeBeforeEvictionFbo), mYcbcrConversionCache(mPlatform->getDevice()), mSamplerCache(mPlatform->getDevice()), mBlitter(mPlatform->getPhysicalDevice(), &mCommands), diff --git a/filament/backend/src/vulkan/VulkanFboCache.cpp b/filament/backend/src/vulkan/VulkanFboCache.cpp index 185739f583..e4aabdaf44 100644 --- a/filament/backend/src/vulkan/VulkanFboCache.cpp +++ b/filament/backend/src/vulkan/VulkanFboCache.cpp @@ -20,6 +20,7 @@ #include "VulkanHandles.h" #include "vulkan/utils/Image.h" +#include #include // If any VkRenderPass or VkFramebuffer is unused for more than TIME_BEFORE_EVICTION frames, it @@ -62,8 +63,9 @@ bool VulkanFboCache::FboKeyEqualFn::operator()(const FboKey& k1, const FboKey& k return true; } -VulkanFboCache::VulkanFboCache(VkDevice device) - : mDevice(device) {} +VulkanFboCache::VulkanFboCache(VkDevice device, uint32_t timeBeforeEvictionFbo) + : mDevice(device), + mTimeBeforeEvictionFbo(timeBeforeEvictionFbo) {} VulkanFboCache::~VulkanFboCache() { FILAMENT_CHECK_POSTCONDITION(mFramebufferCache.empty() && mRenderPassCache.empty()) @@ -376,31 +378,36 @@ void VulkanFboCache::gc() noexcept { FVK_SYSTRACE_START("fbocache::gc"); // If this is one of the first few frames, return early to avoid wrapping unsigned integers. - if (++mCurrentTime <= TIME_BEFORE_EVICTION) { - return; - } - const uint32_t evictTime = mCurrentTime - TIME_BEFORE_EVICTION; + ++mCurrentTime; - for (FboMap::iterator iter = mFramebufferCache.begin(); iter != mFramebufferCache.end(); ) { - const FboVal fbo = iter->second; - if (fbo.timestamp < evictTime && fbo.handle) { - mRenderPassRefCount[iter->first.renderPass]--; + if (UTILS_UNLIKELY(mCurrentTime > mTimeBeforeEvictionFbo)) { + const uint32_t evictTimeFbo = mCurrentTime - mTimeBeforeEvictionFbo; + for (FboMap::iterator iter = mFramebufferCache.begin(); iter != mFramebufferCache.end();) { + const FboVal fbo = iter->second; + if (fbo.timestamp < evictTimeFbo && fbo.handle) { + mRenderPassRefCount[iter->first.renderPass]--; - // erase(iterator) returns the iterator to the next element. - iter = mFramebufferCache.erase(iter); - } else { - ++iter; + // erase(iterator) returns the iterator to the next element. + iter = mFramebufferCache.erase(iter); + } else { + ++iter; + } } } - for (RenderPassMap::iterator iter = mRenderPassCache.begin(); iter != mRenderPassCache.end(); ) { - const VkRenderPass handle = iter->second.handle->getVkRenderPass(); - if (iter->second.timestamp < evictTime && handle && mRenderPassRefCount[handle] == 0) { - // erase(iterator) returns the iterator to the next element. - iter = mRenderPassCache.erase(iter); - mRenderPassRefCount.erase(handle); - } else { - ++iter; + if (UTILS_UNLIKELY(mCurrentTime > TIME_BEFORE_EVICTION)) { + const uint32_t evictTimeRp = mCurrentTime - TIME_BEFORE_EVICTION; + for (RenderPassMap::iterator iter = mRenderPassCache.begin(); + iter != mRenderPassCache.end();) { + const VkRenderPass handle = iter->second.handle->getVkRenderPass(); + if (iter->second.timestamp < evictTimeRp && handle && + mRenderPassRefCount[handle] == 0) { + // erase(iterator) returns the iterator to the next element. + iter = mRenderPassCache.erase(iter); + mRenderPassRefCount.erase(handle); + } else { + ++iter; + } } } diff --git a/filament/backend/src/vulkan/VulkanFboCache.h b/filament/backend/src/vulkan/VulkanFboCache.h index 8ac2840480..2668f78e36 100644 --- a/filament/backend/src/vulkan/VulkanFboCache.h +++ b/filament/backend/src/vulkan/VulkanFboCache.h @@ -100,7 +100,7 @@ public: bool operator()(const FboKey& k1, const FboKey& k2) const; }; - explicit VulkanFboCache(VkDevice device); + explicit VulkanFboCache(VkDevice device, uint32_t timeBeforeEvictionFbo); ~VulkanFboCache(); // Retrieves or creates a VkFramebuffer handle. @@ -130,6 +130,7 @@ private: RenderPassMap mRenderPassCache; tsl::robin_map mRenderPassRefCount; uint32_t mCurrentTime = 0; + uint32_t mTimeBeforeEvictionFbo; }; } // namespace filament::backend