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)