Prevent circular buffer overflow during UboManager reallocation (#9714)
When UboManager::reallocate() is triggered, a large number of material instances may be invalidated simultaneously. This leads to a massive spike in descriptor set updates and command generation, which can overflow the circular buffer. To prevent this, we now flush commands in batches, we trigger a flush whenever the command buffer usage exceeds half of its capacity. (Like what RenderPass::Executor::execute does) BUGS = [474264976, 479079631]
This commit is contained in:
@@ -735,14 +735,21 @@ void FEngine::prepare(DriverApi& driver) {
|
||||
}
|
||||
|
||||
UboManager* uboManager = mUboManager;
|
||||
size_t const capacity = getMinCommandBufferSize();
|
||||
for (auto& materialInstanceList: mMaterialInstances) {
|
||||
materialInstanceList.second.forEach([&driver, uboManager](FMaterialInstance const* item) {
|
||||
// post-process materials instances must be commited explicitly because their
|
||||
// parameters are typically not set at this point in time.
|
||||
if (item->getMaterial()->getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||
item->commit(driver, uboManager);
|
||||
}
|
||||
});
|
||||
materialInstanceList.second.forEach(
|
||||
[this, &driver, uboManager, capacity](FMaterialInstance const* item) {
|
||||
// post-process materials instances must be commited explicitly because their
|
||||
// parameters are typically not set at this point in time.
|
||||
if (item->getMaterial()->getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||
// If the remaining space is less than half the capacity, we flush right
|
||||
// away to allow some headroom for commands that might come later.
|
||||
if (UTILS_UNLIKELY(driver.getCircularBuffer().getUsed() > capacity / 2)) {
|
||||
flush();
|
||||
}
|
||||
item->commit(driver, uboManager);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (useUboBatching) {
|
||||
|
||||
Reference in New Issue
Block a user