Vulkan: Clearing Storage Buffers #105487

Merged
Jeroen Bakker merged 94 commits from Jeroen-Bakker/blender:vulkan-storage-buffer-clear into main 2023-03-17 13:48:50 +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()) {
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,
VkShaderModule compute_module,
VkDescriptorSetLayout &descriptor_set_layout,
VkPipelineLayout &pipeline_layout,
const VKPushConstantsLayout &push_constants_layout)
VKPipeline VKPipeline::create_compute_pipeline(
VKContext &context,
VkShaderModule compute_module,
VkDescriptorSetLayout &descriptor_set_layout,
VkPipelineLayout &pipeline_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,10 +70,10 @@ void init_struct(const shader::ShaderCreateInfo &info,
align_end_of_struct<Std140>(r_offset);
}
void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
const StorageType storage_type,
const VKDescriptorSet::Location location)
void VKPushConstants::Layout::init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
const StorageType storage_type,
const VKDescriptorSet::Location location)
{
BLI_assert(push_constants.is_empty());
storage_type_ = storage_type;
@ -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

@ -30,108 +30,6 @@ namespace blender::gpu {
class VKShaderInterface;
class VKUniformBuffer;
/**
* Describe the layout of the push constants and the storage type that should be used.
*/
struct VKPushConstantsLayout {
/* Different methods to store push constants.*/
enum class StorageType {
/** Push constants aren't in use.*/
NONE,
/** Store push constants as regular vulkan push constants.*/
PUSH_CONSTANTS,
/**
* Fallback when push constants doesn't meet the device requirements.
*/
UNIFORM_BUFFER,
};
static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::PUSH_CONSTANTS;
static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER;
struct PushConstantLayout {
/* Used as lookup based on ShaderInput.*/
int32_t location;
/** Offset in the push constant data (in bytes). */
uint32_t offset;
shader::Type type;
int array_size;
};
private:
Vector<PushConstantLayout> push_constants;
uint32_t size_in_bytes_ = 0;
StorageType storage_type_ = StorageType::NONE;
/**
* Binding index in the descriptor set when the push constants use an uniform buffer.
*/
VKDescriptorSet::Location storage_buffer_binding_;
public:
/**
* Return the desired storage type that can fit the push constants of the given shader create
* info, matching the device limits.
*
* 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.
*/
static StorageType determine_storage_type(
const shader::ShaderCreateInfo &info,
const VkPhysicalDeviceLimits &vk_physical_device_limits);
/**
* Initialize the push constants of the given shader create info with the
* binding location.
*
* interface: Uniform locations of the interface are used as lookup key.
* storage_type: The type of storage for push constants to use.
* location: When storage_type=StorageType::UNIFORM_BUFFER this contains
* the location in the descriptor set where the uniform buffer can be
* bound.
*/
void init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
StorageType storage_type,
VKDescriptorSet::Location location);
/**
* Return the storage type that is used.
*/
StorageType storage_type_get() const
{
return storage_type_;
}
/**
* Get the binding location for the uniform buffer.
*
* Only valid when storage_type=StorageType::UNIFORM_BUFFER.
*/
VKDescriptorSet::Location storage_buffer_binding_get() const
{
return storage_buffer_binding_;
}
/**
* Get the size needed to store the push constants.
*/
uint32_t size_in_bytes() const
{
return size_in_bytes_;
}
/**
* Find the push constant layout for the given location.
* Location = ShaderInput.location.
*/
const PushConstantLayout *find(int32_t location) const;
};
/**
* Container to store push constants in a buffer.
*
@ -145,14 +43,118 @@ struct VKPushConstantsLayout {
* data.
*/
class VKPushConstants : NonCopyable {
public:
/** Different methods to store push constants.*/
enum class StorageType {
/** Push constants aren't in use.*/
NONE,
/** Store push constants as regular vulkan push constants.*/
PUSH_CONSTANTS,
/**
* Fallback when push constants doesn't meet the device requirements.
*/
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 PushConstant {
/* Used as lookup based on ShaderInput.*/
int32_t location;
/** Offset in the push constant data (in bytes). */
uint32_t offset;
shader::Type type;
int array_size;
};
private:
Vector<PushConstant> push_constants;
uint32_t size_in_bytes_ = 0;
StorageType storage_type_ = StorageType::NONE;
/**
* Binding index in the descriptor set when the push constants use an uniform buffer.
*/
VKDescriptorSet::Location storage_buffer_binding_;
public:
/**
* Return the desired storage type that can fit the push constants of the given shader create
* info, matching the device limits.
*
* 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.
*/
static StorageType determine_storage_type(
const shader::ShaderCreateInfo &info,
const VkPhysicalDeviceLimits &vk_physical_device_limits);
/**
* Initialize the push constants of the given shader create info with the
* binding location.
*
* interface: Uniform locations of the interface are used as lookup key.
* storage_type: The type of storage for push constants to use.
* location: When storage_type=StorageType::UNIFORM_BUFFER this contains
* the location in the descriptor set where the uniform buffer can be
* bound.
*/
void init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
StorageType storage_type,
VKDescriptorSet::Location location);
/**
* Return the storage type that is used.
*/
StorageType storage_type_get() const
{
return storage_type_;
}
/**
* Get the binding location for the uniform buffer.
*
* Only valid when storage_type=StorageType::UNIFORM_BUFFER.
*/
VKDescriptorSet::Location storage_buffer_binding_get() const
{
return storage_buffer_binding_;
}
/**
* Get the size needed to store the push constants.
*/
uint32_t size_in_bytes() const
{
return size_in_bytes_;
}
/**
* Find the push constant layout for the given location.
* Location = ShaderInput.location.
*/
const PushConstant *find(int32_t location) const;
};
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_;
}