vk: delay destruction
This commit is contained in:
@@ -332,6 +332,7 @@ void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
|
||||
void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||
uint8_t binding, fvkmemory::resource_ptr<VulkanBufferObject> bufferObject,
|
||||
VkDeviceSize offset, VkDeviceSize size) noexcept {
|
||||
prepareForUpdate(set);
|
||||
VkDescriptorBufferInfo const info = {
|
||||
.buffer = bufferObject->getVkBuffer(),
|
||||
.offset = offset,
|
||||
@@ -368,20 +369,15 @@ void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescr
|
||||
// Build a new descriptor set from the new layout
|
||||
VkDescriptorSetLayout const genLayout = set->boundLayout;
|
||||
VkDescriptorSet const newSet = getVkSet(layout->count, genLayout);
|
||||
Bitmask const ubo = layout->bitmask.ubo | layout->bitmask.dynamicUbo;
|
||||
Bitmask samplers = layout->bitmask.sampler;
|
||||
samplers.unset(binding);
|
||||
|
||||
// Each bitmask denotes a binding index, and separated into two stages - vertex and buffer
|
||||
// We fold the two stages into just the lower half of the bits to denote a combined set of
|
||||
// bindings.
|
||||
Bitmask const copyBindings = foldBitsInHalf(ubo | samplers);
|
||||
VkDescriptorSet const srcSet = set->getVkSet();
|
||||
copySet(srcSet, newSet, copyBindings);
|
||||
copySet(srcSet, newSet, layout);
|
||||
set->addNewSet(newSet,
|
||||
[this, layoutCount = layout->count, genLayout, newSet](VulkanDescriptorSet*) {
|
||||
this->manualRecycle(layoutCount, genLayout, newSet);
|
||||
});
|
||||
} else {
|
||||
prepareForUpdate(set);
|
||||
}
|
||||
|
||||
VkDescriptorSet const vkset = set->getVkSet();
|
||||
@@ -448,21 +444,41 @@ void VulkanDescriptorSetCache::manualRecycle(VulkanDescriptorSetLayout::Count co
|
||||
|
||||
void VulkanDescriptorSetCache::gc() { mStashedSets = {}; }
|
||||
|
||||
void VulkanDescriptorSetCache::prepareForUpdate(
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set) noexcept {
|
||||
if (set->isBound()) {
|
||||
auto layout = set->getLayout();
|
||||
VkDescriptorSetLayout const vklayout = set->boundLayout;
|
||||
VkDescriptorSet const newSet = mDescriptorPool->obtainSet(layout->count, vklayout);
|
||||
copySet(set->getVkSet(), newSet, layout);
|
||||
set->addNewSet(newSet,
|
||||
[this, layoutCount = layout->count, vklayout, newSet](VulkanDescriptorSet*) {
|
||||
this->manualRecycle(layoutCount, vklayout, newSet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetCache::copySet(VkDescriptorSet srcSet, VkDescriptorSet dstSet,
|
||||
fvkutils::SamplerBitmask bindings) const {
|
||||
// TODO: fix the size for better memory management
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) const {
|
||||
Bitmask const ubo = layout->bitmask.ubo | layout->bitmask.dynamicUbo;
|
||||
Bitmask const samplers = layout->bitmask.sampler;
|
||||
Bitmask const inputAttachments = layout->bitmask.inputAttachment;
|
||||
Bitmask const bindings = foldBitsInHalf(ubo | samplers | inputAttachments);
|
||||
|
||||
std::vector<VkCopyDescriptorSet> copies;
|
||||
bindings.forEachSetBit([&](size_t index) {
|
||||
copies.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,
|
||||
.srcSet = srcSet,
|
||||
.srcBinding = (uint32_t) index,
|
||||
.dstSet = dstSet,
|
||||
.dstBinding = (uint32_t) index,
|
||||
.descriptorCount = 1,
|
||||
.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,
|
||||
.srcSet = srcSet,
|
||||
.srcBinding = (uint32_t) index,
|
||||
.dstSet = dstSet,
|
||||
.dstBinding = (uint32_t) index,
|
||||
.descriptorCount = 1,
|
||||
});
|
||||
});
|
||||
vkUpdateDescriptorSets(mDevice, 0, nullptr, copies.size(), copies.data());
|
||||
if (!copies.empty()) {
|
||||
vkUpdateDescriptorSets(mDevice, 0, nullptr, (uint32_t) copies.size(), copies.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -90,8 +90,10 @@ public:
|
||||
void resetCachedState() noexcept { mLastBoundInfo = {}; }
|
||||
|
||||
private:
|
||||
void prepareForUpdate(fvkmemory::resource_ptr<VulkanDescriptorSet> set) noexcept;
|
||||
|
||||
void copySet(VkDescriptorSet srcSet, VkDescriptorSet destSet,
|
||||
fvkutils::SamplerBitmask copyBindings) const;
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) const;
|
||||
|
||||
class DescriptorInfinitePool;
|
||||
|
||||
|
||||
@@ -260,8 +260,8 @@ void VulkanDescriptorSet::gc() {
|
||||
|
||||
void VulkanDescriptorSet::addNewSet(VkDescriptorSet vkSet, OnRecycle&& onRecycleFn) {
|
||||
gc();
|
||||
mCurrentSetIndex = mSets.size();
|
||||
mSets.push_back({ vkSet, std::move(onRecycleFn) });
|
||||
mCurrentSetIndex = (uint8_t) (mSets.size() - 1);
|
||||
}
|
||||
|
||||
PushConstantDescription::PushConstantDescription(backend::Program const& program) {
|
||||
|
||||
@@ -191,7 +191,8 @@ public:
|
||||
void referencedBy(VulkanCommandBuffer& commands);
|
||||
|
||||
bool isBound() const {
|
||||
return bool(mSets[mCurrentSetIndex].fenceStatus);
|
||||
auto const& set = mSets[mCurrentSetIndex];
|
||||
return set.fenceStatus && set.fenceStatus->getStatus() != VK_SUCCESS;
|
||||
}
|
||||
|
||||
// The current layout used by the descriptor set. This one will match the bindings, including
|
||||
|
||||
@@ -780,10 +780,16 @@ void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands,
|
||||
VkCommandBuffer const cmdbuf = commands->buffer();
|
||||
VkImageLayout const layout =
|
||||
fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
||||
|
||||
const bool isDepth = fvkutils::isVkDepthFormat(mState->mVkFormat);
|
||||
|
||||
VkImageMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccessMask = static_cast<VkAccessFlags>(isDepth ? (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)
|
||||
: (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)),
|
||||
.oldLayout = layout,
|
||||
.newLayout = layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -791,9 +797,13 @@ void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands,
|
||||
.image = mState->mTextureImage,
|
||||
.subresourceRange = range,
|
||||
};
|
||||
|
||||
VkPipelineStageFlags dstStage = isDepth ? (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT)
|
||||
: VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
dstStage,
|
||||
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
@@ -802,9 +812,13 @@ void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands,
|
||||
VkCommandBuffer const cmdbuf = commands->buffer();
|
||||
VkImageLayout const layout
|
||||
= fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
||||
|
||||
const bool isDepth = fvkutils::isVkDepthFormat(mState->mVkFormat);
|
||||
|
||||
VkImageMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.srcAccessMask = static_cast<VkAccessFlags>(isDepth ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
|
||||
: VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.oldLayout = layout,
|
||||
.newLayout = layout,
|
||||
@@ -813,7 +827,12 @@ void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands,
|
||||
.image = mState->mTextureImage,
|
||||
.subresourceRange = range,
|
||||
};
|
||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
|
||||
VkPipelineStageFlags srcStage = isDepth ? (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT)
|
||||
: VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(cmdbuf, srcStage,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,23 +41,55 @@ void ResourceManager::gc() noexcept {
|
||||
list.clear();
|
||||
};
|
||||
|
||||
FrameGcList frameGc;
|
||||
|
||||
{
|
||||
// Note that we're not copying mThreadSafeGcList because the objects here do not have
|
||||
// resource_ptrs to other handle objects, so their desctruction would not add more elements
|
||||
// to mThreadSafeGcList.
|
||||
std::unique_lock<utils::Mutex> lock(mThreadSafeGcListMutex);
|
||||
destroyAll(mThreadSafeGcList);
|
||||
std::swap(frameGc.threadSafeGcList, mThreadSafeGcList);
|
||||
}
|
||||
|
||||
GcList gcs;
|
||||
std::swap(gcs, mGcList);
|
||||
destroyAll(gcs);
|
||||
std::swap(frameGc.gcList, mGcList);
|
||||
|
||||
mFramesGcList.push_back(std::move(frameGc));
|
||||
|
||||
if (mFramesGcList.size() > 4) {
|
||||
FrameGcList oldest = std::move(mFramesGcList.front());
|
||||
mFramesGcList.erase(mFramesGcList.begin());
|
||||
destroyAll(oldest.threadSafeGcList);
|
||||
destroyAll(oldest.gcList);
|
||||
}
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void ResourceManager::terminate() noexcept {
|
||||
while (!mThreadSafeGcList.empty() || !mGcList.empty()) {
|
||||
gc();
|
||||
auto destroyAll = [this](GcList& list) {
|
||||
for (auto const& [type, id]: list) {
|
||||
destroyWithType(type, id);
|
||||
}
|
||||
list.clear();
|
||||
};
|
||||
|
||||
while (!mThreadSafeGcList.empty() || !mGcList.empty() || !mFramesGcList.empty()) {
|
||||
if (!mFramesGcList.empty()) {
|
||||
FrameGcList oldest = std::move(mFramesGcList.front());
|
||||
mFramesGcList.erase(mFramesGcList.begin());
|
||||
destroyAll(oldest.threadSafeGcList);
|
||||
destroyAll(oldest.gcList);
|
||||
}
|
||||
|
||||
GcList threadSafeList;
|
||||
{
|
||||
std::unique_lock<utils::Mutex> lock(mThreadSafeGcListMutex);
|
||||
std::swap(threadSafeList, mThreadSafeGcList);
|
||||
}
|
||||
destroyAll(threadSafeList);
|
||||
|
||||
GcList gcs;
|
||||
std::swap(gcs, mGcList);
|
||||
destroyAll(gcs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,12 @@ private:
|
||||
GcList mThreadSafeGcList;
|
||||
GcList mGcList;
|
||||
|
||||
struct FrameGcList {
|
||||
GcList threadSafeGcList;
|
||||
GcList gcList;
|
||||
};
|
||||
std::vector<FrameGcList> mFramesGcList;
|
||||
|
||||
template<typename D>
|
||||
friend struct resource_ptr;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user