From 3dd6153eb73e967ee99917879bf4aba237a98f0b Mon Sep 17 00:00:00 2001 From: "Yan, Shaobo" Date: Mon, 27 May 2019 04:35:03 +0000 Subject: [PATCH] Dynamic Buffer Offset : Vulkan Backend In a typical application, most draws will use different uniforms values for things like the world position and orientation. In the current state of WebGPU this means that a new bind group needs to be created for each draw to set the right uniforms. Bind group creation is expected to be more expensive than recording draws because they incur an allocation. This feature is to reduce the number of bind groups that need to be created. The patch implements dynamic buffer offset on vulkan backend. But Vulkan takes dynamic offset as uint32_t type, which is not the same size as the VkDeviceSize used to create buffers so we cast them for now. Bug=dawn:55 Change-Id: I6163866feb040d1a653f9a20d2ce22d80509968e Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7461 Commit-Queue: Shaobo Yan Reviewed-by: Corentin Wallez Reviewed-by: Kai Ninomiya --- src/dawn_native/vulkan/BindGroupLayoutVk.cpp | 8 ++-- src/dawn_native/vulkan/BindGroupVk.cpp | 8 ++-- src/dawn_native/vulkan/CommandBufferVk.cpp | 38 ++++++++++++++++--- .../end2end/DynamicBufferOffsetTests.cpp | 3 +- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/dawn_native/vulkan/BindGroupLayoutVk.cpp b/src/dawn_native/vulkan/BindGroupLayoutVk.cpp index c6ea3f9991..83f58381b9 100644 --- a/src/dawn_native/vulkan/BindGroupLayoutVk.cpp +++ b/src/dawn_native/vulkan/BindGroupLayoutVk.cpp @@ -50,8 +50,9 @@ namespace dawn_native { namespace vulkan { case dawn::BindingType::StorageBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; case dawn::BindingType::DynamicUniformBuffer: + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; case dawn::BindingType::DynamicStorageBuffer: - UNREACHABLE(); + return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; default: UNREACHABLE(); } @@ -121,16 +122,15 @@ namespace dawn_native { namespace vulkan { auto ToDescriptorType = [](dawn::BindingType type) -> DescriptorType { switch (type) { case dawn::BindingType::UniformBuffer: + case dawn::BindingType::DynamicUniformBuffer: return UNIFORM_BUFFER; case dawn::BindingType::Sampler: return SAMPLER; case dawn::BindingType::SampledTexture: return SAMPLED_IMAGE; case dawn::BindingType::StorageBuffer: - return STORAGE_BUFFER; - case dawn::BindingType::DynamicUniformBuffer: case dawn::BindingType::DynamicStorageBuffer: - UNREACHABLE(); + return STORAGE_BUFFER; default: UNREACHABLE(); } diff --git a/src/dawn_native/vulkan/BindGroupVk.cpp b/src/dawn_native/vulkan/BindGroupVk.cpp index 1fb8a7ccbf..30d59698cc 100644 --- a/src/dawn_native/vulkan/BindGroupVk.cpp +++ b/src/dawn_native/vulkan/BindGroupVk.cpp @@ -81,7 +81,9 @@ namespace dawn_native { namespace vulkan { switch (layoutInfo.types[bindingIndex]) { case dawn::BindingType::UniformBuffer: - case dawn::BindingType::StorageBuffer: { + case dawn::BindingType::StorageBuffer: + case dawn::BindingType::DynamicUniformBuffer: + case dawn::BindingType::DynamicStorageBuffer: { BufferBinding binding = GetBindingAsBufferBinding(bindingIndex); writeBufferInfo[numWrites].buffer = ToBackend(binding.buffer)->GetHandle(); @@ -109,10 +111,6 @@ namespace dawn_native { namespace vulkan { write.pImageInfo = &writeImageInfo[numWrites]; } break; - case dawn::BindingType::DynamicUniformBuffer: - case dawn::BindingType::DynamicStorageBuffer: - UNREACHABLE(); - break; default: UNREACHABLE(); } diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp index 3c81af40ce..89fbbac4c0 100644 --- a/src/dawn_native/vulkan/CommandBufferVk.cpp +++ b/src/dawn_native/vulkan/CommandBufferVk.cpp @@ -105,9 +105,21 @@ namespace dawn_native { namespace vulkan { class DescriptorSetTracker { public: - void OnSetBindGroup(uint32_t index, VkDescriptorSet set) { + void OnSetBindGroup(uint32_t index, + VkDescriptorSet set, + uint32_t dynamicOffsetCount, + uint64_t* dynamicOffsets) { mDirtySets.set(index); mSets[index] = set; + mDynamicOffsetCounts[index] = dynamicOffsetCount; + if (dynamicOffsetCount > 0) { + // Vulkan backend use uint32_t as dynamic offsets type, it is not correct. + // Vulkan should use VkDeviceSize. Dawn vulkan backend has to handle this. + for (uint32_t i = 0; i < dynamicOffsetCount; ++i) { + ASSERT(dynamicOffsets[i] <= std::numeric_limits::max()); + mDynamicOffsets[index][i] = static_cast(dynamicOffsets[i]); + } + } } void OnPipelineLayoutChange(PipelineLayout* layout) { @@ -131,9 +143,11 @@ namespace dawn_native { namespace vulkan { void Flush(Device* device, VkCommandBuffer commands, VkPipelineBindPoint bindPoint) { for (uint32_t dirtyIndex : IterateBitSet(mDirtySets)) { - device->fn.CmdBindDescriptorSets(commands, bindPoint, - mCurrentLayout->GetHandle(), dirtyIndex, 1, - &mSets[dirtyIndex], 0, nullptr); + device->fn.CmdBindDescriptorSets( + commands, bindPoint, mCurrentLayout->GetHandle(), dirtyIndex, 1, + &mSets[dirtyIndex], mDynamicOffsetCounts[dirtyIndex], + mDynamicOffsetCounts[dirtyIndex] > 0 ? mDynamicOffsets[dirtyIndex].data() + : nullptr); } mDirtySets.reset(); } @@ -142,6 +156,8 @@ namespace dawn_native { namespace vulkan { PipelineLayout* mCurrentLayout = nullptr; std::array mSets; std::bitset mDirtySets; + std::array mDynamicOffsetCounts; + std::array, kMaxBindGroups> mDynamicOffsets; }; void RecordBeginRenderPass(VkCommandBuffer commands, @@ -414,8 +430,13 @@ namespace dawn_native { namespace vulkan { case Command::SetBindGroup: { SetBindGroupCmd* cmd = mCommands.NextCommand(); VkDescriptorSet set = ToBackend(cmd->group.Get())->GetHandle(); + uint64_t* dynamicOffsets = nullptr; + if (cmd->dynamicOffsetCount > 0) { + dynamicOffsets = mCommands.NextData(cmd->dynamicOffsetCount); + } - descriptorSets.OnSetBindGroup(cmd->index, set); + descriptorSets.OnSetBindGroup(cmd->index, set, cmd->dynamicOffsetCount, + dynamicOffsets); } break; case Command::SetComputePipeline: { @@ -552,8 +573,13 @@ namespace dawn_native { namespace vulkan { case Command::SetBindGroup: { SetBindGroupCmd* cmd = mCommands.NextCommand(); VkDescriptorSet set = ToBackend(cmd->group.Get())->GetHandle(); + uint64_t* dynamicOffsets = nullptr; + if (cmd->dynamicOffsetCount > 0) { + dynamicOffsets = mCommands.NextData(cmd->dynamicOffsetCount); + } - descriptorSets.OnSetBindGroup(cmd->index, set); + descriptorSets.OnSetBindGroup(cmd->index, set, cmd->dynamicOffsetCount, + dynamicOffsets); } break; case Command::SetBlendColor: { diff --git a/src/tests/end2end/DynamicBufferOffsetTests.cpp b/src/tests/end2end/DynamicBufferOffsetTests.cpp index ba12de1458..5916d04f61 100644 --- a/src/tests/end2end/DynamicBufferOffsetTests.cpp +++ b/src/tests/end2end/DynamicBufferOffsetTests.cpp @@ -56,7 +56,6 @@ class DynamicBufferOffsetTests : public DawnTest { } // Create objects to use as resources inside test bind groups. - const void* mappedData = nullptr; dawn::BindGroup mBindGroup; dawn::BindGroupLayout mBindGroupLayout; dawn::Buffer mUniformBuffer; @@ -212,4 +211,4 @@ TEST_P(DynamicBufferOffsetTests, SetDynamicOffestsComputePipeline) { kMinDynamicBufferOffsetAlignment, expectedData.size()); } -DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests, MetalBackend); +DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests, MetalBackend, VulkanBackend);