Vulkan: Push constants #104880

Merged
Jeroen Bakker merged 73 commits from Jeroen-Bakker/blender:vulkan-push-constants into main 2023-03-06 12:29:06 +01:00
9 changed files with 156 additions and 158 deletions
Showing only changes of commit d20bf06825 - Show all commits

View File

@ -71,15 +71,15 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_
/* Update push constants based on their storage type.*/
switch (push_constants.layout_get().storage_type_get()) {
Jeroen-Bakker marked this conversation as resolved
Review

I may be missing something, but this whole switch block feels like it does not belong here. It looks way too specific to me.

Would rather see that logic as part of the VKPushConstants class itself, but no idea if this is doable in practice... At the very least would have it in a dedicated util function of VKBackend otherwise?

I may be missing something, but this whole `switch` block feels like it does not belong here. It looks way too specific to me. Would rather see that logic as part of the `VKPushConstants` class itself, but no idea if this is doable in practice... At the very least would have it in a dedicated util function of `VKBackend` otherwise?
Review

Yes you're right, will move this part into a method of VKPushConstants.

Yes you're right, will move this part into a method of VKPushConstants.
case VKPushConstantsLayout::StorageType::NONE:
case VKPushConstants::StorageType::NONE:
break;
case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS:
case VKPushConstants::StorageType::PUSH_CONSTANTS:
command_buffer.push_constants(
push_constants, shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL);
break;
case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER:
case VKPushConstants::StorageType::UNIFORM_BUFFER:
push_constants.update_uniform_buffer();
descriptor_set.bind(push_constants.uniform_buffer_get(),
push_constants.layout_get().storage_buffer_binding_get());

View File

@ -77,7 +77,7 @@ void VKCommandBuffer::push_constants(const VKPushConstants &push_constants,
const VkShaderStageFlags vk_shader_stages)
{
BLI_assert(push_constants.layout_get().storage_type_get() ==
VKPushConstantsLayout::StorageType::PUSH_CONSTANTS);
VKPushConstants::StorageType::PUSH_CONSTANTS);
vkCmdPushConstants(vk_command_buffer_,
vk_pipeline_layout,
vk_shader_stages,

View File

@ -29,11 +29,12 @@ VKPipeline::~VKPipeline()
}
}
VKPipeline VKPipeline::create_compute_pipeline(VKContext &context,
VKPipeline VKPipeline::create_compute_pipeline(
VKContext &context,
VkShaderModule compute_module,
VkDescriptorSetLayout &descriptor_set_layout,
VkPipelineLayout &pipeline_layout,
const VKPushConstantsLayout &push_constants_layout)
const VKPushConstants::Layout &push_constants_layout)
{
VK_ALLOCATION_CALLBACKS
VkDevice vk_device = context.device_get();

View File

@ -44,7 +44,7 @@ class VKPipeline : NonCopyable {
VkShaderModule compute_module,
VkDescriptorSetLayout &descriptor_set_layout,
VkPipelineLayout &pipeline_layouts,
const VKPushConstantsLayout &push_constants_layout);
const VKPushConstants::Layout &push_constants_layout);
VKDescriptorSet &descriptor_set_get()
{

View File

@ -15,14 +15,14 @@
namespace blender::gpu {
template<typename Layout>
static VKPushConstantsLayout::PushConstantLayout init_constant(
static VKPushConstants::Layout::PushConstant init_constant(
const shader::ShaderCreateInfo::PushConst &push_constant,
const ShaderInput &shader_input,
uint32_t *r_offset)
{
align<Layout>(push_constant.type, push_constant.array_size, r_offset);
VKPushConstantsLayout::PushConstantLayout layout;
VKPushConstants::Layout::PushConstant layout;
layout.location = shader_input.location;
layout.type = push_constant.type;
layout.array_size = push_constant.array_size;
@ -45,7 +45,7 @@ uint32_t struct_size(Span<shader::ShaderCreateInfo::PushConst> push_constants)
return offset;
}
VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type(
VKPushConstants::StorageType VKPushConstants::Layout::determine_storage_type(
const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits)
{
if (info.push_constants_.is_empty()) {
@ -60,7 +60,7 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type
template<typename Layout>
void init_struct(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
Vector<VKPushConstantsLayout::PushConstantLayout> &r_struct,
Vector<VKPushConstants::Layout::PushConstant> &r_struct,
uint32_t *r_offset)
{
for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
@ -70,7 +70,7 @@ void init_struct(const shader::ShaderCreateInfo &info,
align_end_of_struct<Std140>(r_offset);
}
void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info,
void VKPushConstants::Layout::init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
const StorageType storage_type,
const VKDescriptorSet::Location location)
@ -88,10 +88,9 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info,
}
}
const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find(
int32_t location) const
const VKPushConstants::Layout::PushConstant *VKPushConstants::Layout::find(int32_t location) const
{
for (const PushConstantLayout &push_constant : push_constants) {
for (const PushConstant &push_constant : push_constants) {
if (push_constant.location == location) {
return &push_constant;
}
@ -100,16 +99,16 @@ const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find(
}
VKPushConstants::VKPushConstants() = default;
VKPushConstants::VKPushConstants(const VKPushConstantsLayout *layout) : layout_(layout)
VKPushConstants::VKPushConstants(const Layout *layout) : layout_(layout)
{
data_ = MEM_mallocN(layout->size_in_bytes(), __func__);
switch (layout_->storage_type_get()) {
case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER:
case StorageType::UNIFORM_BUFFER:
uniform_buffer_ = new VKUniformBuffer(layout_->size_in_bytes(), __func__);
break;
case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS:
case VKPushConstantsLayout::StorageType::NONE:
case StorageType::PUSH_CONSTANTS:
case StorageType::NONE:
break;
}
}
@ -149,7 +148,7 @@ VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other)
void VKPushConstants::update_uniform_buffer()
{
BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER);
BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER);
BLI_assert(uniform_buffer_ != nullptr);
BLI_assert(data_ != nullptr);
uniform_buffer_->update(data_);
@ -157,7 +156,7 @@ void VKPushConstants::update_uniform_buffer()
VKUniformBuffer &VKPushConstants::uniform_buffer_get()
{
BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER);
BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER);
BLI_assert(uniform_buffer_ != nullptr);
return *uniform_buffer_;
}

View File

@ -31,10 +31,20 @@ class VKShaderInterface;
class VKUniformBuffer;
/**
* Describe the layout of the push constants and the storage type that should be used.
* Container to store push constants in a buffer.
*
* Can handle buffers with different memory layouts (std140/std430)
* Which memory layout is used is based on the storage type.
*
* VKPushConstantsLayout only describes the buffer, an instance of this
* class can handle setting/modifying/duplicating push constants.
*
* It should also keep track of the submissions in order to reuse the allocated
* data.
*/
struct VKPushConstantsLayout {
/* Different methods to store push constants.*/
class VKPushConstants : NonCopyable {
public:
/** Different methods to store push constants.*/
enum class StorageType {
/** Push constants aren't in use.*/
NONE,
@ -47,10 +57,15 @@ struct VKPushConstantsLayout {
*/
UNIFORM_BUFFER,
};
/**
* Describe the layout of the push constants and the storage type that should be used.
*/
struct Layout {
static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::PUSH_CONSTANTS;
static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER;
struct PushConstantLayout {
struct PushConstant {
/* Used as lookup based on ShaderInput.*/
int32_t location;
@ -61,7 +76,7 @@ struct VKPushConstantsLayout {
};
private:
Vector<PushConstantLayout> push_constants;
Vector<PushConstant> push_constants;
uint32_t size_in_bytes_ = 0;
StorageType storage_type_ = StorageType::NONE;
/**
@ -77,8 +92,8 @@ struct VKPushConstantsLayout {
* Returns:
* - StorageType::NONE: No push constants are needed.
* - StorageType::PUSH_CONSTANTS: Regular vulkan push constants can be used.
* - StorageType::UNIFORM_BUFFER: The push constants don't fit in the limits of the given device.
* A uniform buffer should be used as a fallback method.
* - StorageType::UNIFORM_BUFFER: The push constants don't fit in the limits of the given
* device. A uniform buffer should be used as a fallback method.
*/
static StorageType determine_storage_type(
const shader::ShaderCreateInfo &info,
@ -129,30 +144,17 @@ struct VKPushConstantsLayout {
* Find the push constant layout for the given location.
* Location = ShaderInput.location.
*/
const PushConstantLayout *find(int32_t location) const;
};
const PushConstant *find(int32_t location) const;
};
/**
* Container to store push constants in a buffer.
*
* Can handle buffers with different memory layouts (std140/std430)
* Which memory layout is used is based on the storage type.
*
* VKPushConstantsLayout only describes the buffer, an instance of this
* class can handle setting/modifying/duplicating push constants.
*
* It should also keep track of the submissions in order to reuse the allocated
* data.
*/
class VKPushConstants : NonCopyable {
private:
const VKPushConstantsLayout *layout_ = nullptr;
const Layout *layout_ = nullptr;
void *data_ = nullptr;
VKUniformBuffer *uniform_buffer_ = nullptr;
public:
VKPushConstants();
VKPushConstants(const VKPushConstantsLayout *layout);
VKPushConstants(const Layout *layout);
VKPushConstants(VKPushConstants &&other);
virtual ~VKPushConstants();
@ -163,7 +165,7 @@ class VKPushConstants : NonCopyable {
return 0;
}
const VKPushConstantsLayout &layout_get() const
const Layout &layout_get() const
{
return *layout_;
}
@ -212,14 +214,12 @@ class VKPushConstants : NonCopyable {
int32_t array_size,
const T *input_data)
{
const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_->find(
location);
const Layout::PushConstant *push_constant_layout = layout_->find(location);
BLI_assert(push_constant_layout);
uint8_t *bytes = static_cast<uint8_t *>(data_);
T *dst = static_cast<T *>(static_cast<void *>(&bytes[push_constant_layout->offset]));
if (layout_->storage_type_get() == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS ||
array_size == 0) {
if (layout_->storage_type_get() == StorageType::PUSH_CONSTANTS || array_size == 0) {
BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <=
layout_->size_in_bytes(),
"Tried to write outside the push constant allocated memory.");

View File

@ -756,10 +756,9 @@ bool VKShader::finalize_pipeline_layout(VkDevice vk_device,
pipeline_info.pSetLayouts = &layout_;
/* Setup push constants. */
const VKPushConstantsLayout &push_constants_layout =
const VKPushConstants::Layout &push_constants_layout =
shader_interface.push_constants_layout_get();
if (push_constants_layout.storage_type_get() ==
VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) {
if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::PUSH_CONSTANTS) {
push_constant_range.offset = 0;
push_constant_range.size = push_constants_layout.size_in_bytes();
push_constant_range.stageFlags = VK_SHADER_STAGE_ALL;
@ -886,10 +885,10 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
}
static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
const VKPushConstantsLayout &push_constants_layout)
const VKPushConstants::Layout &push_constants_layout)
{
BLI_assert(push_constants_layout.storage_type_get() ==
VKPushConstantsLayout::StorageType::UNIFORM_BUFFER);
VKPushConstants::StorageType::UNIFORM_BUFFER);
VkDescriptorSetLayoutBinding binding = {};
binding.binding = push_constants_layout.storage_buffer_binding_get();
binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@ -911,9 +910,8 @@ static void add_descriptor_set_layout_bindings(
}
/* Add push constants to the descriptor when push constants are stored in an uniform buffer.*/
const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get();
if (push_constants_layout.storage_type_get() ==
VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) {
const VKPushConstants::Layout &push_constants_layout = interface.push_constants_layout_get();
if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::UNIFORM_BUFFER) {
r_bindings.append(create_descriptor_set_layout_binding(push_constants_layout));
}
}
@ -938,7 +936,7 @@ static bool descriptor_sets_needed(const VKShaderInterface &shader_interface,
{
return !info.pass_resources_.is_empty() || !info.batch_resources_.is_empty() ||
shader_interface.push_constants_layout_get().storage_type_get() ==
VKPushConstantsLayout::StorageType::UNIFORM_BUFFER;
VKPushConstants::StorageType::UNIFORM_BUFFER;
}
bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device,
@ -1038,15 +1036,15 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co
}
/* Push constants. */
const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get();
const VKPushConstantsLayout::StorageType push_constants_storage =
const VKPushConstants::Layout &push_constants_layout = interface.push_constants_layout_get();
const VKPushConstants::StorageType push_constants_storage =
push_constants_layout.storage_type_get();
if (push_constants_storage != VKPushConstantsLayout::StorageType::NONE) {
if (push_constants_storage != VKPushConstants::StorageType::NONE) {
ss << "\n/* Push Constants. */\n";
if (push_constants_storage == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) {
if (push_constants_storage == VKPushConstants::StorageType::PUSH_CONSTANTS) {
ss << "layout(push_constant) uniform constants\n";
}
else if (push_constants_storage == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) {
else if (push_constants_storage == VKPushConstants::StorageType::UNIFORM_BUFFER) {
ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get()
<< ", std140) uniform constants\n";
}

View File

@ -45,9 +45,9 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
/* Reserve 1 storage buffer for push constants fallback. */
size_t names_size = info.interface_names_size_;
VKContext &context = *VKContext::get();
const VKPushConstantsLayout::StorageType push_constants_storage_type =
VKPushConstantsLayout::determine_storage_type(info, context.physical_device_limits_get());
if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) {
const VKPushConstants::StorageType push_constants_storage_type =
VKPushConstants::Layout::determine_storage_type(info, context.physical_device_limits_get());
if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) {
ubo_len_++;
names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1;
}
@ -73,7 +73,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
}
/* Add push constant when using uniform buffer as fallback. */
int32_t push_constants_fallback_location = -1;
if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) {
if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) {
copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset);
input->location = input->binding = -1;
input++;
@ -138,7 +138,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
/* Post initializing push constants.*/
/* Determine the binding location of push constants fallback buffer.*/
int32_t push_constant_descriptor_set_location = -1;
if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) {
if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) {
push_constant_descriptor_set_location = descriptor_set_location++;
const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str());
descriptor_set_location_update(push_constant_input, push_constants_fallback_location);

View File

@ -29,7 +29,7 @@ class VKShaderInterface : public ShaderInterface {
uint32_t image_offset_ = 0;
Array<VKDescriptorSet::Location> descriptor_set_locations_;
VKPushConstantsLayout push_constants_layout_;
VKPushConstants::Layout push_constants_layout_;
public:
/**
@ -49,8 +49,8 @@ class VKShaderInterface : public ShaderInterface {
const VKDescriptorSet::Location descriptor_set_location(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
/** Get the VKPushConstantsLayout of the shader.*/
const VKPushConstantsLayout &push_constants_layout_get() const
/** Get the Layout of the shader.*/
const VKPushConstants::Layout &push_constants_layout_get() const
{
return push_constants_layout_;
}