Implement descriptor update batching and push descriptors

Batching helps to avoid the need to attach so many objects to the fence cycle, which ends up taking a fair bit of time due to the allocation required.
This commit is contained in:
Billy Laws 2022-10-09 13:58:50 +01:00
parent 62a165b51e
commit 9ce848d4e0
3 changed files with 47 additions and 23 deletions

View File

@ -26,15 +26,23 @@ namespace skyline::gpu::interconnect::maxwell3d {
textures{manager, registerBundle.texturePoolRegisters}, textures{manager, registerBundle.texturePoolRegisters},
directState{activeState.directState} { directState{activeState.directState} {
executor.AddFlushCallback([this] { executor.AddFlushCallback([this] {
if (attachedDescriptorSets) {
ctx.executor.AttachDependency(attachedDescriptorSets);
attachedDescriptorSets = nullptr;
activeDescriptorSet = nullptr;
}
activeState.MarkAllDirty(); activeState.MarkAllDirty();
constantBuffers.MarkAllDirty(); constantBuffers.MarkAllDirty();
samplers.MarkAllDirty(); samplers.MarkAllDirty();
textures.MarkAllDirty(); textures.MarkAllDirty();
quadConversionBufferAttached = false; quadConversionBufferAttached = false;
constantBuffers.DisableQuickBind();
}); });
executor.AddPipelineChangeCallback([this] { executor.AddPipelineChangeCallback([this] {
activeState.MarkAllDirty(); activeState.MarkAllDirty();
activeDescriptorSet = nullptr;
}); });
} }
@ -232,14 +240,23 @@ namespace skyline::gpu::interconnect::maxwell3d {
builder.SetPipeline(pipeline->compiledPipeline.pipeline); builder.SetPipeline(pipeline->compiledPipeline.pipeline);
if (descUpdateInfo) { if (descUpdateInfo) {
auto newSet{std::make_shared<DescriptorAllocator::ActiveDescriptorSet>(ctx.gpu.descriptor.AllocateSet(descUpdateInfo->descriptorSetLayout))}; if (ctx.gpu.traits.supportsPushDescriptors) {
ctx.executor.cycle->AttachObject(newSet); builder.SetDescriptorSetWithPush(descUpdateInfo);
} else {
if (!attachedDescriptorSets)
attachedDescriptorSets = std::make_shared<boost::container::static_vector<DescriptorAllocator::ActiveDescriptorSet, DescriptorBatchSize>>();
// Descriptor set lifetime is bound to the current cycle so we can safely use a raw pointer from now on auto newSet{&attachedDescriptorSets->emplace_back(ctx.gpu.descriptor.AllocateSet(descUpdateInfo->descriptorSetLayout))};
auto *oldSet{activeDescriptorSet}; auto *oldSet{activeDescriptorSet};
activeDescriptorSet = newSet.get(); activeDescriptorSet = newSet;
builder.SetDescriptorSetWithUpdate(descUpdateInfo, activeDescriptorSet, oldSet); builder.SetDescriptorSetWithUpdate(descUpdateInfo, activeDescriptorSet, oldSet);
if (attachedDescriptorSets->size() == DescriptorBatchSize) {
ctx.executor.AttachDependency(attachedDescriptorSets);
attachedDescriptorSets.reset();
}
}
} }
auto stateUpdater{builder.Build()}; auto stateUpdater{builder.Build()};

View File

@ -48,6 +48,8 @@ namespace skyline::gpu::interconnect::maxwell3d {
std::shared_ptr<memory::Buffer> quadConversionBuffer{}; std::shared_ptr<memory::Buffer> quadConversionBuffer{};
bool quadConversionBufferAttached{}; bool quadConversionBufferAttached{};
static constexpr size_t DescriptorBatchSize{0x100};
std::shared_ptr<boost::container::static_vector<DescriptorAllocator::ActiveDescriptorSet, DescriptorBatchSize>> attachedDescriptorSets;
DescriptorAllocator::ActiveDescriptorSet *activeDescriptorSet{}; DescriptorAllocator::ActiveDescriptorSet *activeDescriptorSet{};
size_t UpdateQuadConversionBuffer(u32 count, u32 firstVertex); size_t UpdateQuadConversionBuffer(u32 count, u32 firstVertex);

View File

@ -205,6 +205,9 @@ namespace skyline::gpu::interconnect::maxwell3d {
} }
} }
if constexpr (PushDescriptor) {
commandBuffer.pushDescriptorSetKHR(updateInfo->bindPoint, updateInfo->pipelineLayout, updateInfo->descriptorSetIndex, updateInfo->writes);
} else {
// Set the destination/(source) descriptor set(s) for all writes/(copies) // Set the destination/(source) descriptor set(s) for all writes/(copies)
for (auto &write : updateInfo->writes) for (auto &write : updateInfo->writes)
write.dstSet = **dstSet; write.dstSet = **dstSet;
@ -224,12 +227,14 @@ namespace skyline::gpu::interconnect::maxwell3d {
// Bind the updated descriptor set and we're done! // Bind the updated descriptor set and we're done!
commandBuffer.bindDescriptorSets(updateInfo->bindPoint, updateInfo->pipelineLayout, updateInfo->descriptorSetIndex, **dstSet, {}); commandBuffer.bindDescriptorSets(updateInfo->bindPoint, updateInfo->pipelineLayout, updateInfo->descriptorSetIndex, **dstSet, {});
} }
}
DescriptorUpdateInfo *updateInfo; DescriptorUpdateInfo *updateInfo;
DescriptorAllocator::ActiveDescriptorSet *srcSet; DescriptorAllocator::ActiveDescriptorSet *srcSet;
DescriptorAllocator::ActiveDescriptorSet *dstSet; DescriptorAllocator::ActiveDescriptorSet *dstSet;
}; };
using SetDescriptorSetWithUpdateCmd = CmdHolder<SetDescriptorSetWithUpdateCmdImpl>; using SetDescriptorSetWithUpdateCmd = CmdHolder<SetDescriptorSetCmdImpl<false>>;
using SetDescriptorSetWithPushCmd = CmdHolder<SetDescriptorSetCmdImpl<true>>;
struct SetPipelineCmdImpl { struct SetPipelineCmdImpl {
void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) {