Implement dynamic buffer offsets. Tests: *dynamic* Bug: b/126330097 Change-Id: I7e4f7e3d921acb72878b7728216415ba66f63ec7 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28249 Reviewed-by: Nicolas Capens <nicolascapens@google.com> Tested-by: Ben Clayton <bclayton@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp index c341409..f3721ef 100644 --- a/src/Device/Context.cpp +++ b/src/Device/Context.cpp
@@ -112,11 +112,6 @@ void Context::init() { - for(int i = 0; i < vk::MAX_BOUND_DESCRIPTOR_SETS; i++) - { - descriptorSets[i] = nullptr; - } - // Set vertex streams to null stream for(int i = 0; i < MAX_VERTEX_INPUTS; i++) {
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp index ac63a89..581871f 100644 --- a/src/Device/Context.hpp +++ b/src/Device/Context.hpp
@@ -16,6 +16,7 @@ #define sw_Context_hpp #include "Vulkan/VkConfig.h" +#include "Vulkan/VkDescriptorSet.hpp" #include "Sampler.hpp" #include "Stream.hpp" #include "Point.hpp" @@ -153,7 +154,8 @@ int colorWriteActive(int index); bool colorUsed(); - vk::DescriptorSet *descriptorSets[vk::MAX_BOUND_DESCRIPTOR_SETS]; + vk::DescriptorSet::Bindings descriptorSets = {}; + vk::DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {}; Stream input[MAX_VERTEX_INPUTS]; void *indexBuffer;
diff --git a/src/Device/QuadRasterizer.hpp b/src/Device/QuadRasterizer.hpp index a41464c..456887d 100644 --- a/src/Device/QuadRasterizer.hpp +++ b/src/Device/QuadRasterizer.hpp
@@ -28,7 +28,7 @@ QuadRasterizer(const PixelProcessor::State &state, SpirvShader const *spirvShader); virtual ~QuadRasterizer(); - virtual void generate(); + void generate(); protected: Pointer<Byte> constants;
diff --git a/src/Device/Renderer.cpp b/src/Device/Renderer.cpp index 4a77700..f70f519 100644 --- a/src/Device/Renderer.cpp +++ b/src/Device/Renderer.cpp
@@ -388,10 +388,8 @@ draw->setupPrimitives = setupPrimitives; draw->setupState = setupState; - for(int i = 0; i < vk::MAX_BOUND_DESCRIPTOR_SETS; i++) - { - data->descriptorSets[i] = context->descriptorSets[i]; - } + data->descriptorSets = context->descriptorSets; + data->descriptorDynamicOffsets = context->descriptorDynamicOffsets; for(int i = 0; i < MAX_VERTEX_INPUTS; i++) {
diff --git a/src/Device/Renderer.hpp b/src/Device/Renderer.hpp index 63a5b55..2f1fa61 100644 --- a/src/Device/Renderer.hpp +++ b/src/Device/Renderer.hpp
@@ -23,6 +23,7 @@ #include "System/MutexLock.hpp" #include "System/Thread.hpp" #include "Device/Config.hpp" +#include "Vulkan/VkDescriptorSet.hpp" #include <list> @@ -114,7 +115,8 @@ { const Constants *constants; - vk::DescriptorSet *descriptorSets[vk::MAX_BOUND_DESCRIPTOR_SETS]; + vk::DescriptorSet::Bindings descriptorSets = {}; + vk::DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {}; const void *input[MAX_VERTEX_INPUTS]; unsigned int stride[MAX_VERTEX_INPUTS];
diff --git a/src/Pipeline/ComputeProgram.cpp b/src/Pipeline/ComputeProgram.cpp index 6672ece..293655a 100644 --- a/src/Pipeline/ComputeProgram.cpp +++ b/src/Pipeline/ComputeProgram.cpp
@@ -45,14 +45,9 @@ void ComputeProgram::emit() { - Pointer<Pointer<Byte>> descriptorSetsIn = *Pointer<Pointer<Pointer<Byte>>>(data + OFFSET(Data, descriptorSets)); - size_t numDescriptorSets = routine.pipelineLayout->getNumDescriptorSets(); - for(unsigned int i = 0; i < numDescriptorSets; i++) - { - routine.descriptorSets[i] = descriptorSetsIn[i]; - } - - routine.pushConstants = Pointer<Byte>(data + OFFSET(Data, pushConstants)); + routine.descriptorSets = data + OFFSET(Data, descriptorSets); + routine.descriptorDynamicOffsets = data + OFFSET(Data, descriptorDynamicOffsets); + routine.pushConstants = data + OFFSET(Data, pushConstants); auto &modes = shader->getModes(); @@ -178,13 +173,17 @@ } void ComputeProgram::run( - Routine *routine, void** descriptorSets, PushConstantStorage const &pushConstants, + Routine *routine, + vk::DescriptorSet::Bindings const &descriptorSets, + vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets, + PushConstantStorage const &pushConstants, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { auto runWorkgroup = (void(*)(void*))(routine->getEntry()); Data data; data.descriptorSets = descriptorSets; + data.descriptorDynamicOffsets = descriptorDynamicOffsets; data.numWorkgroups[X] = groupCountX; data.numWorkgroups[Y] = groupCountY; data.numWorkgroups[Z] = groupCountZ;
diff --git a/src/Pipeline/ComputeProgram.hpp b/src/Pipeline/ComputeProgram.hpp index 6b63233..e8265bc0 100644 --- a/src/Pipeline/ComputeProgram.hpp +++ b/src/Pipeline/ComputeProgram.hpp
@@ -19,6 +19,7 @@ #include "Reactor/Reactor.hpp" #include "Device/Context.hpp" +#include "Vulkan/VkDescriptorSet.hpp" #include <functional> @@ -48,7 +49,10 @@ // run executes the compute shader routine for all workgroups. // TODO(bclayton): This probably does not belong here. Consider moving. static void run( - Routine *routine, void** descriptorSets, PushConstantStorage const &pushConstants, + Routine *routine, + vk::DescriptorSet::Bindings const &descriptorSetBindings, + vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets, + PushConstantStorage const &pushConstants, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); protected: @@ -60,7 +64,8 @@ struct Data { - void** descriptorSets; + vk::DescriptorSet::Bindings descriptorSets; + vk::DescriptorSet::DynamicOffsets descriptorDynamicOffsets; uint4 numWorkgroups; uint4 workgroupID; PushConstantStorage pushConstants;
diff --git a/src/Pipeline/PixelProgram.cpp b/src/Pipeline/PixelProgram.cpp index 8d0424e..c64c7ae 100644 --- a/src/Pipeline/PixelProgram.cpp +++ b/src/Pipeline/PixelProgram.cpp
@@ -31,6 +31,8 @@ { enableIndex = 0; + routine.descriptorSets = data + OFFSET(DrawData, descriptorSets); + routine.descriptorDynamicOffsets = data + OFFSET(DrawData, descriptorDynamicOffsets); routine.pushConstants = data + OFFSET(DrawData, pushConstants); auto activeLaneMask = SIMD::Int(0xFFFFFFFF); // TODO: Control this.
diff --git a/src/Pipeline/PixelRoutine.cpp b/src/Pipeline/PixelRoutine.cpp index 782d8b8..7e841e0 100644 --- a/src/Pipeline/PixelRoutine.cpp +++ b/src/Pipeline/PixelRoutine.cpp
@@ -54,18 +54,6 @@ { } - void PixelRoutine::generate() - { - Pointer<Pointer<Byte>> descriptorSets = Pointer<Pointer<Byte>>(data + OFFSET(DrawData, descriptorSets)); - auto numDescriptorSets = routine.pipelineLayout->getNumDescriptorSets(); - for(unsigned int i = 0; i < numDescriptorSets; i++) - { - routine.descriptorSets[i] = descriptorSets[i]; - } - - QuadRasterizer::generate(); - } - void PixelRoutine::quad(Pointer<Byte> cBuffer[RENDERTARGETS], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x, Int &y) { #if PERF_PROFILE
diff --git a/src/Pipeline/PixelRoutine.hpp b/src/Pipeline/PixelRoutine.hpp index 15c9307..e7a3079 100644 --- a/src/Pipeline/PixelRoutine.hpp +++ b/src/Pipeline/PixelRoutine.hpp
@@ -31,8 +31,6 @@ virtual ~PixelRoutine(); - void generate() override; - protected: Float4 z[4]; // Multisampled z Float4 w; // Used as is
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp index 389f838..9a91e16 100644 --- a/src/Pipeline/SpirvShader.cpp +++ b/src/Pipeline/SpirvShader.cpp
@@ -18,6 +18,7 @@ #include "System/Math.hpp" #include "Vulkan/VkBuffer.hpp" #include "Vulkan/VkDebug.hpp" +#include "Vulkan/VkDescriptorSet.hpp" #include "Vulkan/VkPipelineLayout.hpp" #include "Device/Config.hpp" @@ -1722,15 +1723,25 @@ ASSERT(d.DescriptorSet >= 0); ASSERT(d.Binding >= 0); - size_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding); + auto set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet* + auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet); + size_t arrayIndex = 0; // TODO: descriptor arrays + size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex); - Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet* - Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo* - Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(binding + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer* + Pointer<Byte> bufferInfo = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo* + Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(bufferInfo + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer* Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void* - Int offset = *Pointer<Int>(binding + OFFSET(VkDescriptorBufferInfo, offset)); - Pointer<Byte> address = data + offset; - routine->physicalPointers[resultId] = address; + Int offset = *Pointer<Int>(bufferInfo + OFFSET(VkDescriptorBufferInfo, offset)); + if (setLayout->isBindingDynamic(d.Binding)) + { + uint32_t dynamicBindingIndex = + routine->pipelineLayout->getDynamicOffsetBase(d.DescriptorSet) + + setLayout->getDynamicDescriptorOffset(d.Binding) + + arrayIndex; + offset += routine->descriptorDynamicOffsets[dynamicBindingIndex]; + } + + routine->physicalPointers[resultId] = data + offset; break; } case spv::StorageClassPushConstant:
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp index 47f8e32..0314d0a 100644 --- a/src/Pipeline/SpirvShader.hpp +++ b/src/Pipeline/SpirvShader.hpp
@@ -660,7 +660,8 @@ Value inputs = Value{MAX_INTERFACE_COMPONENTS}; Value outputs = Value{MAX_INTERFACE_COMPONENTS}; - std::array<Pointer<Byte>, vk::MAX_BOUND_DESCRIPTOR_SETS> descriptorSets; + Pointer<Pointer<Byte>> descriptorSets; + Pointer<Int> descriptorDynamicOffsets; Pointer<Byte> pushConstants; Int killMask = Int{0};
diff --git a/src/Pipeline/VertexProgram.cpp b/src/Pipeline/VertexProgram.cpp index 71e48c4..a11c80b 100644 --- a/src/Pipeline/VertexProgram.cpp +++ b/src/Pipeline/VertexProgram.cpp
@@ -46,14 +46,9 @@ As<Float4>(Int4((*Pointer<Int>(data + OFFSET(DrawData, instanceID))))); } + routine.descriptorSets = data + OFFSET(DrawData, descriptorSets); + routine.descriptorDynamicOffsets = data + OFFSET(DrawData, descriptorDynamicOffsets); routine.pushConstants = data + OFFSET(DrawData, pushConstants); - - Pointer<Pointer<Byte>> descriptorSets = Pointer<Pointer<Byte>>(data + OFFSET(DrawData, descriptorSets)); - auto numDescriptorSets = routine.pipelineLayout->getNumDescriptorSets(); - for(unsigned int i = 0; i < numDescriptorSets; i++) - { - routine.descriptorSets[i] = descriptorSets[i]; - } } VertexProgram::~VertexProgram()
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp index cd3f72f..75a76cd 100644 --- a/src/Vulkan/VkCommandBuffer.cpp +++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -152,7 +152,7 @@ protected: void play(CommandBuffer::ExecutionState& executionState) override { - executionState.pipelines[pipelineBindPoint] = Cast(pipeline); + executionState.pipelineState[pipelineBindPoint].pipeline = Cast(pipeline); } private: @@ -171,11 +171,12 @@ protected: void play(CommandBuffer::ExecutionState& executionState) override { - ComputePipeline* pipeline = static_cast<ComputePipeline*>( - executionState.pipelines[VK_PIPELINE_BIND_POINT_COMPUTE]); + auto const &pipelineState = executionState.pipelineState[VK_PIPELINE_BIND_POINT_COMPUTE]; + + ComputePipeline* pipeline = static_cast<ComputePipeline*>(pipelineState.pipeline); pipeline->run(groupCountX, groupCountY, groupCountZ, - MAX_BOUND_DESCRIPTOR_SETS, - executionState.boundDescriptorSets[VK_PIPELINE_BIND_POINT_COMPUTE], + pipelineState.descriptorSets, + pipelineState.descriptorDynamicOffsets, executionState.pushConstants); } @@ -198,12 +199,13 @@ { auto cmd = reinterpret_cast<VkDispatchIndirectCommand const *>(Cast(buffer)->getOffsetPointer(offset)); - ComputePipeline* pipeline = static_cast<ComputePipeline*>( - executionState.pipelines[VK_PIPELINE_BIND_POINT_COMPUTE]); + auto const &pipelineState = executionState.pipelineState[VK_PIPELINE_BIND_POINT_COMPUTE]; + + ComputePipeline* pipeline = static_cast<ComputePipeline*>(pipelineState.pipeline); pipeline->run(cmd->x, cmd->y, cmd->z, - MAX_BOUND_DESCRIPTOR_SETS, - executionState.boundDescriptorSets[VK_PIPELINE_BIND_POINT_COMPUTE], - executionState.pushConstants); + pipelineState.descriptorSets, + pipelineState.descriptorDynamicOffsets, + executionState.pushConstants); } private: @@ -304,19 +306,16 @@ void draw(CommandBuffer::ExecutionState& executionState, bool indexed, uint32_t count, uint32_t instanceCount, uint32_t first, int32_t vertexOffset, uint32_t firstInstance) { - GraphicsPipeline* pipeline = static_cast<GraphicsPipeline*>( - executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS]); + auto const &pipelineState = executionState.pipelineState[VK_PIPELINE_BIND_POINT_GRAPHICS]; + + GraphicsPipeline* pipeline = static_cast<GraphicsPipeline*>(pipelineState.pipeline); sw::Context context = pipeline->getContext(); executionState.bindVertexInputs(context, vertexOffset, firstInstance); - const auto& boundDescriptorSets = executionState.boundDescriptorSets[VK_PIPELINE_BIND_POINT_GRAPHICS]; - for(int i = 0; i < vk::MAX_BOUND_DESCRIPTOR_SETS; i++) - { - context.descriptorSets[i] = reinterpret_cast<vk::DescriptorSet*>(boundDescriptorSets[i]); - } - + context.descriptorSets = pipelineState.descriptorSets; + context.descriptorDynamicOffsets = pipelineState.descriptorDynamicOffsets; context.pushConstants = executionState.pushConstants; if (indexed) @@ -683,21 +682,38 @@ struct BindDescriptorSet : public CommandBuffer::Command { - BindDescriptorSet(VkPipelineBindPoint pipelineBindPoint, uint32_t set, const VkDescriptorSet& descriptorSet) - : pipelineBindPoint(pipelineBindPoint), set(set), descriptorSet(descriptorSet) + BindDescriptorSet(VkPipelineBindPoint pipelineBindPoint, uint32_t set, const VkDescriptorSet& descriptorSet, + uint32_t dynamicOffsetCount, uint32_t const *dynamicOffsets) + : pipelineBindPoint(pipelineBindPoint), set(set), descriptorSet(descriptorSet), + dynamicOffsetCount(dynamicOffsetCount) { + for (uint32_t i = 0; i < dynamicOffsetCount; i++) + { + this->dynamicOffsets[i] = dynamicOffsets[i]; + } } void play(CommandBuffer::ExecutionState& executionState) { - ASSERT((pipelineBindPoint < VK_PIPELINE_BIND_POINT_RANGE_SIZE) && (set < MAX_BOUND_DESCRIPTOR_SETS)); - executionState.boundDescriptorSets[pipelineBindPoint][set] = descriptorSet; + ASSERT_OR_RETURN((pipelineBindPoint < VK_PIPELINE_BIND_POINT_RANGE_SIZE) && (set < MAX_BOUND_DESCRIPTOR_SETS)); + auto &pipelineState = executionState.pipelineState[pipelineBindPoint]; + auto pipelineLayout = pipelineState.pipeline->getLayout(); + auto dynamicOffsetBase = pipelineLayout->getDynamicOffsetBase(set); + ASSERT_OR_RETURN(dynamicOffsetBase + dynamicOffsetCount <= MAX_DESCRIPTOR_SET_COMBINED_BUFFERS_DYNAMIC); + + pipelineState.descriptorSets[set] = vk::Cast(descriptorSet); + for (uint32_t i = 0; i < dynamicOffsetCount; i++) + { + pipelineState.descriptorDynamicOffsets[dynamicOffsetBase + i] = dynamicOffsets[i]; + } } private: VkPipelineBindPoint pipelineBindPoint; uint32_t set; const VkDescriptorSet descriptorSet; + uint32_t dynamicOffsetCount; + vk::DescriptorSet::DynamicOffsets dynamicOffsets; }; struct SetPushConstants : public CommandBuffer::Command @@ -974,20 +990,28 @@ UNIMPLEMENTED("setStencilReference"); } -void CommandBuffer::bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, +void CommandBuffer::bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout vkLayout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets) { ASSERT(state == RECORDING); - if(dynamicOffsetCount > 0) - { - UNIMPLEMENTED("bindDescriptorSets"); - } - for(uint32_t i = 0; i < descriptorSetCount; i++) { - addCommand<BindDescriptorSet>(pipelineBindPoint, firstSet + i, pDescriptorSets[i]); + auto descriptorSetIndex = firstSet + i; + auto layout = vk::Cast(vkLayout); + auto setLayout = layout->getDescriptorSetLayout(descriptorSetIndex); + + auto numDynamicDescriptors = setLayout->getDynamicDescriptorCount(); + ASSERT(numDynamicDescriptors == 0 || pDynamicOffsets != nullptr); + ASSERT(dynamicOffsetCount >= numDynamicDescriptors); + + addCommand<BindDescriptorSet>( + pipelineBindPoint, descriptorSetIndex, pDescriptorSets[i], + dynamicOffsetCount, pDynamicOffsets); + + pDynamicOffsets += numDynamicDescriptors; + dynamicOffsetCount -= numDynamicDescriptors; } }
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp index 03a0b20..39b4138 100644 --- a/src/Vulkan/VkCommandBuffer.hpp +++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -17,6 +17,7 @@ #include "VkConfig.h" #include "VkObject.hpp" +#include "VkDescriptorSet.hpp" #include "Device/Context.hpp" #include <memory> #include <vector> @@ -123,11 +124,17 @@ // TODO(sugoi): Move ExecutionState out of CommandBuffer (possibly into Device) struct ExecutionState { + struct PipelineState + { + Pipeline *pipeline = nullptr; + vk::DescriptorSet::Bindings descriptorSets = {}; + vk::DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {}; + }; + sw::Renderer* renderer = nullptr; RenderPass* renderPass = nullptr; Framebuffer* renderPassFramebuffer = nullptr; - Pipeline* pipelines[VK_PIPELINE_BIND_POINT_RANGE_SIZE] = {}; - VkDescriptorSet boundDescriptorSets[VK_PIPELINE_BIND_POINT_RANGE_SIZE][MAX_BOUND_DESCRIPTOR_SETS] = { { VK_NULL_HANDLE } }; + std::array<PipelineState, VK_PIPELINE_BIND_POINT_RANGE_SIZE> pipelineState; sw::PushConstantStorage pushConstants; struct VertexInputBinding
diff --git a/src/Vulkan/VkConfig.h b/src/Vulkan/VkConfig.h index 772f772..3aa5de8 100644 --- a/src/Vulkan/VkConfig.h +++ b/src/Vulkan/VkConfig.h
@@ -62,6 +62,15 @@ enum { + MAX_DESCRIPTOR_SET_UNIFORM_BUFFERS_DYNAMIC = 8, + MAX_DESCRIPTOR_SET_STORAGE_BUFFERS_DYNAMIC = 4, + MAX_DESCRIPTOR_SET_COMBINED_BUFFERS_DYNAMIC = + MAX_DESCRIPTOR_SET_UNIFORM_BUFFERS_DYNAMIC + + MAX_DESCRIPTOR_SET_STORAGE_BUFFERS_DYNAMIC, +}; + +enum +{ MAX_POINT_SIZE = 1, // Large points are not supported. If/when we turn this on, must be >= 64. };
diff --git a/src/Vulkan/VkDescriptorSet.hpp b/src/Vulkan/VkDescriptorSet.hpp new file mode 100644 index 0000000..ca0626b --- /dev/null +++ b/src/Vulkan/VkDescriptorSet.hpp
@@ -0,0 +1,44 @@ +// Copyright 2019 The SwiftShader Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef VK_DESCRIPTOR_SET_HPP_ +#define VK_DESCRIPTOR_SET_HPP_ + +// Intentionally not including VkObject.hpp here due to b/127920555 + +#include <array> +#include <memory> + +namespace vk +{ + class DescriptorSetLayout; + + class DescriptorSet + { + public: + using Bindings = std::array<vk::DescriptorSet*, vk::MAX_BOUND_DESCRIPTOR_SETS>; + using DynamicOffsets = std::array<uint32_t, vk::MAX_DESCRIPTOR_SET_COMBINED_BUFFERS_DYNAMIC>; + + DescriptorSetLayout* layout; + uint8_t data[]; + }; + + inline DescriptorSet* Cast(VkDescriptorSet object) + { + return reinterpret_cast<DescriptorSet*>(object); + } + +} // namespace vk + +#endif // VK_DESCRIPTOR_SET_HPP_
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp index 4b65eca..7a5dcca 100644 --- a/src/Vulkan/VkDescriptorSetLayout.cpp +++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -13,6 +13,7 @@ // limitations under the License. #include "VkDescriptorSetLayout.hpp" +#include "VkDescriptorSet.hpp" #include "System/Types.hpp" #include <algorithm> @@ -134,7 +135,7 @@ } } - ASSERT(false); // Bindings should always be found + DABORT("Invalid DescriptorSetLayout binding: %d", int(binding)); return 0; } @@ -164,10 +165,63 @@ } } -size_t DescriptorSetLayout::getBindingOffset(uint32_t binding) const +size_t DescriptorSetLayout::getBindingCount() const +{ + return bindingCount; +} + +size_t DescriptorSetLayout::getBindingOffset(uint32_t binding, uint32_t arrayElement) const { uint32_t index = getBindingIndex(binding); - return bindingOffsets[index] + OFFSET(DescriptorSet, data[0]); + auto typeSize = GetDescriptorSize(bindings[index].descriptorType); + return bindingOffsets[index] + OFFSET(DescriptorSet, data[0]) + (typeSize * arrayElement); +} + +bool DescriptorSetLayout::isDynamic(VkDescriptorType type) +{ + return type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || + type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; +} + +bool DescriptorSetLayout::isBindingDynamic(uint32_t binding) const +{ + uint32_t index = getBindingIndex(binding); + return isDynamic(bindings[index].descriptorType); +} + +size_t DescriptorSetLayout::getDynamicDescriptorCount() const +{ + size_t count = 0; + for (size_t i = 0; i < bindingCount; i++) + { + if (isDynamic(bindings[i].descriptorType)) + { + count += bindings[i].descriptorCount; + } + } + return count; +} + +size_t DescriptorSetLayout::getDynamicDescriptorOffset(uint32_t binding) const +{ + uint32_t n = getBindingIndex(binding); + ASSERT(isDynamic(bindings[n].descriptorType)); + + size_t index = 0; + for (uint32_t i = 0; i < n; i++) + { + if (isDynamic(bindings[i].descriptorType)) + { + index += bindings[i].descriptorCount; + } + } + return index; +} + +VkDescriptorSetLayoutBinding const & DescriptorSetLayout::getBindingLayout(uint32_t binding) const +{ + ASSERT(binding < bindingCount); + return bindings[binding]; } uint8_t* DescriptorSetLayout::getOffsetPointer(DescriptorSet *descriptorSet, uint32_t binding, uint32_t arrayElement, uint32_t count, size_t* typeSize) const
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp index 8cad112..b086626 100644 --- a/src/Vulkan/VkDescriptorSetLayout.hpp +++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -20,18 +20,7 @@ namespace vk { -class DescriptorSetLayout; - -struct DescriptorSet -{ - vk::DescriptorSetLayout* layout; - uint8_t data[]; -}; - -inline DescriptorSet* Cast(VkDescriptorSet object) -{ - return reinterpret_cast<DescriptorSet*>(object); -} +class DescriptorSet; class DescriptorSetLayout : public Object<DescriptorSetLayout, VkDescriptorSetLayout> { @@ -47,15 +36,43 @@ static void CopyDescriptorSet(const VkCopyDescriptorSet& descriptorCopies); void initialize(VkDescriptorSet descriptorSet); + + // Returns the total size of the descriptor set in bytes. size_t getDescriptorSetAllocationSize() const; - size_t getBindingOffset(uint32_t binding) const; + // Returns the number of bindings in the descriptor set. + size_t getBindingCount() const; + + // Returns the byte offset from the base address of the descriptor set for + // the given binding and array element within that binding. + size_t getBindingOffset(uint32_t binding, uint32_t arrayElement) const; + + // Returns the number of descriptors across all bindings that are dynamic + // (see isBindingDynamic). + size_t getDynamicDescriptorCount() const; + + // Returns the relative offset into the pipeline's dynamic offsets array for + // the given binding. This offset should be added to the base offset + // returned by PipelineLayout::getDynamicOffsetBase() to produce the + // starting index for dynamic descriptors. + size_t getDynamicDescriptorOffset(uint32_t binding) const; + + // Returns true if the given binding is of type: + // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC or + // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC + bool isBindingDynamic(uint32_t binding) const; + + // Returns the VkDescriptorSetLayoutBinding for the binding with the given + // index. + VkDescriptorSetLayoutBinding const & getBindingLayout(uint32_t binding) const; + uint8_t* getOffsetPointer(DescriptorSet *descriptorSet, uint32_t binding, uint32_t arrayElement, uint32_t count, size_t* typeSize) const; private: size_t getDescriptorSetDataSize() const; uint32_t getBindingIndex(uint32_t binding) const; static const uint8_t* GetInputData(const VkWriteDescriptorSet& descriptorWrites); + static bool isDynamic(VkDescriptorType type); VkDescriptorSetLayoutCreateFlags flags; uint32_t bindingCount;
diff --git a/src/Vulkan/VkDescriptorUpdateTemplate.cpp b/src/Vulkan/VkDescriptorUpdateTemplate.cpp index 1a814e8..1b72419 100644 --- a/src/Vulkan/VkDescriptorUpdateTemplate.cpp +++ b/src/Vulkan/VkDescriptorUpdateTemplate.cpp
@@ -13,6 +13,7 @@ // limitations under the License. #include "VkDescriptorUpdateTemplate.hpp" +#include "VkDescriptorSet.hpp" #include "VkDescriptorSetLayout.hpp" #include <cstring>
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp index c4591fc..2d2f5a7 100644 --- a/src/Vulkan/VkPhysicalDevice.cpp +++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -162,9 +162,9 @@ 128, // maxPerStageResources 96, // maxDescriptorSetSamplers 72, // maxDescriptorSetUniformBuffers - 8, // maxDescriptorSetUniformBuffersDynamic + MAX_DESCRIPTOR_SET_UNIFORM_BUFFERS_DYNAMIC, // maxDescriptorSetUniformBuffersDynamic 24, // maxDescriptorSetStorageBuffers - 4, // maxDescriptorSetStorageBuffersDynamic + MAX_DESCRIPTOR_SET_STORAGE_BUFFERS_DYNAMIC, // maxDescriptorSetStorageBuffersDynamic 96, // maxDescriptorSetSampledImages 24, // maxDescriptorSetStorageImages 4, // maxDescriptorSetInputAttachments
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp index 4cb0240..50b83f4 100644 --- a/src/Vulkan/VkPipeline.cpp +++ b/src/Vulkan/VkPipeline.cpp
@@ -517,11 +517,13 @@ } void ComputePipeline::run(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, - size_t numDescriptorSets, VkDescriptorSet *descriptorSets, sw::PushConstantStorage const &pushConstants) + vk::DescriptorSet::Bindings const &descriptorSets, + vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets, + sw::PushConstantStorage const &pushConstants) { ASSERT_OR_RETURN(routine != nullptr); sw::ComputeProgram::run( - routine, reinterpret_cast<void**>(descriptorSets), pushConstants, + routine, descriptorSets, descriptorDynamicOffsets, pushConstants, groupCountX, groupCountY, groupCountZ); }
diff --git a/src/Vulkan/VkPipeline.hpp b/src/Vulkan/VkPipeline.hpp index c43a8e9..b220027 100644 --- a/src/Vulkan/VkPipeline.hpp +++ b/src/Vulkan/VkPipeline.hpp
@@ -16,6 +16,7 @@ #define VK_PIPELINE_HPP_ #include "VkObject.hpp" +#include "Vulkan/VkDescriptorSet.hpp" #include "Device/Renderer.hpp" namespace sw { class SpirvShader; } @@ -104,7 +105,9 @@ void compileShaders(const VkAllocationCallbacks* pAllocator, const VkComputePipelineCreateInfo* pCreateInfo); void run(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, - size_t numDescriptorSets, VkDescriptorSet *descriptorSets, sw::PushConstantStorage const &pushConstants); + vk::DescriptorSet::Bindings const &descriptorSets, + vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets, + sw::PushConstantStorage const &pushConstants); protected: sw::SpirvShader *shader = nullptr;
diff --git a/src/Vulkan/VkPipelineLayout.cpp b/src/Vulkan/VkPipelineLayout.cpp index fcc6c66..1c80ca7 100644 --- a/src/Vulkan/VkPipelineLayout.cpp +++ b/src/Vulkan/VkPipelineLayout.cpp
@@ -31,6 +31,16 @@ size_t pushConstantRangesSize = pCreateInfo->pushConstantRangeCount * sizeof(VkPushConstantRange); pushConstantRanges = reinterpret_cast<VkPushConstantRange*>(hostMem); memcpy(pushConstantRanges, pCreateInfo->pPushConstantRanges, pushConstantRangesSize); + hostMem += pushConstantRangesSize; + + dynamicOffsetBases = reinterpret_cast<uint32_t*>(hostMem); + uint32_t dynamicOffsetBase = 0; + for (uint32_t i = 0; i < setLayoutCount; i++) + { + ASSERT_OR_RETURN(dynamicOffsetBase < MAX_DESCRIPTOR_SET_COMBINED_BUFFERS_DYNAMIC); + dynamicOffsetBases[i] = dynamicOffsetBase; + dynamicOffsetBase += setLayouts[i]->getDynamicDescriptorCount(); + } } void PipelineLayout::destroy(const VkAllocationCallbacks* pAllocator) @@ -41,7 +51,8 @@ size_t PipelineLayout::ComputeRequiredAllocationSize(const VkPipelineLayoutCreateInfo* pCreateInfo) { return (pCreateInfo->setLayoutCount * sizeof(DescriptorSetLayout*)) + - (pCreateInfo->pushConstantRangeCount * sizeof(VkPushConstantRange)); + (pCreateInfo->pushConstantRangeCount * sizeof(VkPushConstantRange)) + + (pCreateInfo->setLayoutCount * sizeof(uint32_t)); // dynamicOffsetBases } size_t PipelineLayout::getNumDescriptorSets() const @@ -49,10 +60,16 @@ return setLayoutCount; } -size_t PipelineLayout::getBindingOffset(size_t descriptorSet, size_t binding) const +DescriptorSetLayout const* PipelineLayout::getDescriptorSetLayout(size_t descriptorSet) const { ASSERT(descriptorSet < setLayoutCount); - return setLayouts[descriptorSet]->getBindingOffset(binding); + return setLayouts[descriptorSet]; +} + +uint32_t PipelineLayout::getDynamicOffsetBase(size_t descriptorSet) const +{ + ASSERT(descriptorSet < setLayoutCount); + return dynamicOffsetBases[descriptorSet]; } } // namespace vk
diff --git a/src/Vulkan/VkPipelineLayout.hpp b/src/Vulkan/VkPipelineLayout.hpp index 5723317..57dc9ca 100644 --- a/src/Vulkan/VkPipelineLayout.hpp +++ b/src/Vulkan/VkPipelineLayout.hpp
@@ -30,13 +30,18 @@ static size_t ComputeRequiredAllocationSize(const VkPipelineLayoutCreateInfo* pCreateInfo); size_t getNumDescriptorSets() const; - size_t getBindingOffset(size_t descriptorSet, size_t binding) const; + DescriptorSetLayout const* getDescriptorSetLayout(size_t descriptorSet) const; + + // Returns the starting index into the pipeline's dynamic offsets array for + // the given descriptor set. + uint32_t getDynamicOffsetBase(size_t descriptorSet) const; private: uint32_t setLayoutCount = 0; DescriptorSetLayout** setLayouts = nullptr; uint32_t pushConstantRangeCount = 0; VkPushConstantRange* pushConstantRanges = nullptr; + uint32_t* dynamicOffsetBases = nullptr; // Base offset per set layout. }; static inline PipelineLayout* Cast(VkPipelineLayout object)