Skip to content

Commit

Permalink
vk: remove history from DescriptorSetManager (#8193)
Browse files Browse the repository at this point in the history
"history" is a map from a DescriptorSet pointer to a set of
bookkeeping values (we delay "binding" until "commit" so need to
keep values until then). Instead of using a map, we can store
these values in the DescriptorSet itself so that we save on a
map look-up.
  • Loading branch information
poweifeng authored Oct 14, 2024
1 parent 4ee33cd commit a3290d7
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 139 deletions.
31 changes: 15 additions & 16 deletions filament/backend/src/vulkan/VulkanHandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,13 @@ struct VulkanDescriptorSet : public VulkanResource, HwDescriptorSet {
using OnRecycle = std::function<void(VulkanDescriptorSet*)>;

VulkanDescriptorSet(VulkanResourceAllocator* allocator, VkDescriptorSet rawSet,
UniformBufferBitmask const& dynamicUboMask,
uint8_t uniqueDynamicUboCount,
OnRecycle&& onRecycleFn)
: VulkanResource(VulkanResourceType::DESCRIPTOR_SET),
vkSet(rawSet),
dynamicUboMask(dynamicUboMask),
uniqueDynamicUboCount(uniqueDynamicUboCount),
mResources(allocator),
mOnRecycleFn(std::move(onRecycleFn)) {}

Expand All @@ -147,13 +151,24 @@ struct VulkanDescriptorSet : public VulkanResource, HwDescriptorSet {
}
}

void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept {
mOffsets = std::move(offsets);
}

backend::DescriptorSetOffsetArray const* getOffsets() {
return &mOffsets;
}

void acquire(VulkanTexture* texture);

void acquire(VulkanBufferObject* texture);

VkDescriptorSet const vkSet;
UniformBufferBitmask const dynamicUboMask;
uint8_t const uniqueDynamicUboCount;

private:
backend::DescriptorSetOffsetArray mOffsets;
VulkanAcquireOnlyResourceManager mResources;
OnRecycle mOnRecycleFn;
};
Expand Down Expand Up @@ -194,10 +209,6 @@ struct VulkanProgram : public HwProgram, VulkanResource {

inline VkShaderModule getFragmentShader() const { return mInfo->shaders[1]; }

// Get a list of the sampler binding indices so that we don't have to loop through all possible
// samplers.
inline BindingList const& getBindings() const { return mInfo->bindings; }

inline uint32_t getPushConstantRangeCount() const {
return mInfo->pushConstantDescription.getVkRangeCount();
}
Expand Down Expand Up @@ -225,22 +236,10 @@ struct VulkanProgram : public HwProgram, VulkanResource {
struct PipelineInfo {
explicit PipelineInfo(backend::Program const& program) noexcept
: pushConstantDescription(program)
#if FVK_ENABLED_DEBUG_SAMPLER_NAME
, bindingToName(MAX_SAMPLER_COUNT, "")
#endif
{}

BindingList bindings;

VkShaderModule shaders[MAX_SHADER_MODULES] = { VK_NULL_HANDLE };

PushConstantDescription pushConstantDescription;

#if FVK_ENABLED_DEBUG_SAMPLER_NAME
// We store the sampler name mapped from binding index (only for debug purposes).
utils::FixedCapacityVector<std::string> bindingToName;
#endif

};

PipelineInfo* mInfo;
Expand Down
126 changes: 28 additions & 98 deletions filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,70 +347,6 @@ class VulkanDescriptorSetManager::DescriptorSetLayoutManager {
mVkLayouts;
};

class VulkanDescriptorSetManager::DescriptorSetHistory {
private:
using TextureBundle = std::pair<VulkanTexture*, VkImageSubresourceRange>;

public:
DescriptorSetHistory()
: dynamicUboCount(0),
mResources(nullptr) {}

DescriptorSetHistory(UniformBufferBitmask const& dynamicUbo, uint8_t uniqueDynamicUboCount,
VulkanResourceAllocator* allocator, VulkanDescriptorSet* set)
: dynamicUboMask(dynamicUbo),
dynamicUboCount(uniqueDynamicUboCount),
mResources(allocator),
mSet(set),
mBound(false) {
assert_invariant(set);
// initial state is unbound.
unbind();
}

~DescriptorSetHistory() {
if (mSet) {
mResources.clear();
}
}

void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept {
mOffsets = std::move(offsets);
mBound = false;
}

void write(uint8_t binding) noexcept { mBound = false; }

// Ownership will be transfered to the commandbuffer.
void bind(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout,
uint8_t index) noexcept {
VkCommandBuffer const cmdbuffer = commands->buffer();
vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index,
1, &mSet->vkSet, dynamicUboCount, mOffsets.data());

commands->acquire(mSet);
mResources.clear();
mBound = true;
}

void unbind() noexcept {
mResources.acquire(mSet);
mBound = false;
}

bool bound() const noexcept { return mBound; }

UniformBufferBitmask const dynamicUboMask;
uint8_t const dynamicUboCount;

private:
FixedSizeVulkanResourceManager<1> mResources;
VulkanDescriptorSet* mSet = nullptr;

backend::DescriptorSetOffsetArray mOffsets;
bool mBound = false;
};

VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device,
VulkanResourceAllocator* resourceAllocator)
: mDevice(device),
Expand All @@ -423,50 +359,53 @@ VulkanDescriptorSetManager::~VulkanDescriptorSetManager() = default;
void VulkanDescriptorSetManager::terminate() noexcept{
mLayoutManager.reset();
mDescriptorPool.reset();
mHistory.clear();
}

// bind() is not really binding the set but just stashing until we have all the info
// (pipelinelayout).
void VulkanDescriptorSetManager::bind(uint8_t setIndex, VulkanDescriptorSet* set,
backend::DescriptorSetOffsetArray&& offsets) {
auto history = mHistory[set].get();
history->setOffsets(std::move(offsets));

auto lastHistory = mStashedSets[setIndex];
if (lastHistory) {
lastHistory->unbind();
}
mStashedSets[setIndex] = history;
set->setOffsets(std::move(offsets));
mStashedSets[setIndex] = set;
}

void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands,
VkPipelineLayout pipelineLayout, DescriptorSetMask const& setMask) {
DescriptorSetHistoryArray& updateSets = mStashedSets;

// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
// actual set of sets that *needs* to be bound.
DescriptorSetMask curMask = setMask;

auto& updateSets = mStashedSets;
auto& lastBoundSets = mLastBoundInfo.boundSets;

setMask.forEachSetBit([&](size_t index) {
if (!updateSets[index] || updateSets[index]->bound()) {
if (!updateSets[index] || updateSets[index] == lastBoundSets[index]) {
curMask.unset(index);
}
});

BoundInfo nextInfo = {
pipelineLayout,
setMask,
updateSets,
};
if (curMask.none() && mLastBoundInfo == nextInfo) {
if (curMask.none() &&
(mLastBoundInfo.pipelineLayout == pipelineLayout && mLastBoundInfo.setMask == setMask &&
mLastBoundInfo.boundSets == updateSets)) {
return;
}

curMask.forEachSetBit([&updateSets, commands, pipelineLayout](size_t index) {
updateSets[index]->bind(commands, pipelineLayout, index);
// This code actually binds the descriptor sets.
auto set = updateSets[index];
VkCommandBuffer const cmdbuffer = commands->buffer();
vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index,
1, &set->vkSet, set->uniqueDynamicUboCount, set->getOffsets()->data());
commands->acquire(set);
});
mLastBoundInfo = nextInfo;

mStashedSets = {};

mLastBoundInfo = {
pipelineLayout,
setMask,
updateSets,
};
}

void VulkanDescriptorSetManager::updateBuffer(VulkanDescriptorSet* set, uint8_t binding,
Expand All @@ -478,9 +417,8 @@ void VulkanDescriptorSetManager::updateBuffer(VulkanDescriptorSet* set, uint8_t
};

VkDescriptorType type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
auto& history = mHistory[set];

if (history->dynamicUboMask.test(binding)) {
if (set->dynamicUboMask.test(binding)) {
type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
}
VkWriteDescriptorSet const descriptorWrite = {
Expand All @@ -494,7 +432,6 @@ void VulkanDescriptorSetManager::updateBuffer(VulkanDescriptorSet* set, uint8_t
};
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
set->acquire(bufferObject);
history->write(binding);
}

void VulkanDescriptorSetManager::updateSampler(VulkanDescriptorSet* set, uint8_t binding,
Expand Down Expand Up @@ -526,7 +463,6 @@ void VulkanDescriptorSetManager::updateSampler(VulkanDescriptorSet* set, uint8_t
};
vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr);
set->acquire(texture);
mHistory[set]->write(binding);
}

void VulkanDescriptorSetManager::updateInputAttachment(VulkanDescriptorSet* set,
Expand All @@ -539,30 +475,24 @@ void VulkanDescriptorSetManager::createSet(Handle<HwDescriptorSet> handle,
auto const vkSet = mDescriptorPool->obtainSet(layout);
auto const& count = layout->count;
auto const vklayout = layout->getVkLayout();
VulkanDescriptorSet* set = mResourceAllocator->construct<VulkanDescriptorSet>(handle,
mResourceAllocator, vkSet, [vkSet, count, vklayout, this](VulkanDescriptorSet* set) {
mResourceAllocator->construct<VulkanDescriptorSet>(handle, mResourceAllocator, vkSet,
layout->bitmask.dynamicUbo, layout->count.dynamicUbo,
[vkSet, count, vklayout, this](VulkanDescriptorSet* set) {
eraseSetFromHistory(set);
mDescriptorPool->recycle(count, vklayout, vkSet);
});
mHistory[set] = std::make_unique<DescriptorSetHistory>(layout->bitmask.dynamicUbo,
layout->count.dynamicUbo, mResourceAllocator, set);
}

void VulkanDescriptorSetManager::destroySet(Handle<HwDescriptorSet> handle) {
VulkanDescriptorSet* set = mResourceAllocator->handle_cast<VulkanDescriptorSet*>(handle);
eraseSetFromHistory(set);
}

void VulkanDescriptorSetManager::initVkLayout(VulkanDescriptorSetLayout* layout) {
layout->setVkLayout(mLayoutManager->getVkLayout(layout));
}

void VulkanDescriptorSetManager::eraseSetFromHistory(VulkanDescriptorSet* set) {
DescriptorSetHistory* history = mHistory[set].get();
mHistory.erase(set);

for (uint8_t i = 0; i < mStashedSets.size(); ++i) {
if (mStashedSets[i] == history) {
if (mStashedSets[i] == set) {
mStashedSets[i] = nullptr;
}
}
Expand Down
33 changes: 8 additions & 25 deletions filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,43 +74,26 @@ class VulkanDescriptorSetManager {
void initVkLayout(VulkanDescriptorSetLayout* layout);

private:
class DescriptorSetHistory;
class DescriptorSetLayoutManager;
class DescriptorInfinitePool;

void eraseSetFromHistory(VulkanDescriptorSet* set);

using DescriptorSetHistoryArray =
std::array<DescriptorSetHistory*, UNIQUE_DESCRIPTOR_SET_COUNT>;

struct BoundInfo {
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
DescriptorSetMask setMask;
DescriptorSetHistoryArray boundSets;

bool operator==(BoundInfo const& info) const {
if (pipelineLayout != info.pipelineLayout || setMask != info.setMask) {
return false;
}
bool equal = true;
setMask.forEachSetBit([&](size_t i) {
if (boundSets[i] != info.boundSets[i]) {
equal = false;
}
});
return equal;
}
};
using DescriptorSetArray =
std::array<VulkanDescriptorSet*, UNIQUE_DESCRIPTOR_SET_COUNT>;

VkDevice mDevice;
VulkanResourceAllocator* mResourceAllocator;
std::unique_ptr<DescriptorSetLayoutManager> mLayoutManager;
std::unique_ptr<DescriptorInfinitePool> mDescriptorPool;
std::pair<VulkanAttachment, VkDescriptorImageInfo> mInputAttachment;
std::unordered_map<VulkanDescriptorSet*, std::unique_ptr<DescriptorSetHistory>> mHistory;
DescriptorSetHistoryArray mStashedSets = {};
DescriptorSetArray mStashedSets = {};

BoundInfo mLastBoundInfo;
struct {
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
DescriptorSetMask setMask;
DescriptorSetArray boundSets;
} mLastBoundInfo;
};

}// namespace filament::backend
Expand Down

0 comments on commit a3290d7

Please sign in to comment.