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
10 changed files with 95 additions and 57 deletions
Showing only changes of commit 56cbef9e02 - Show all commits

View File

@ -20,6 +20,7 @@ class VKUniformBuffer;
class VKVertexBuffer;
class VKIndexBuffer;
class VKTexture;
class VKShaderInterface;
/**
* In vulkan shader resources (images and buffers) are grouped in descriptor sets.
@ -51,12 +52,13 @@ class VKDescriptorSet : NonCopyable {
*/
uint32_t binding;
public:
Location() = default;
Location(const ShaderInput *shader_input) : binding(shader_input->location)
Location(uint32_t binding) : binding(binding)
{
}
public:
Location() = default;
bool operator==(const Location &other) const
{
return binding == other.binding;
@ -68,6 +70,7 @@ class VKDescriptorSet : NonCopyable {
}
friend struct Binding;
friend class VKShaderInterface;
};
private:

View File

@ -24,9 +24,9 @@ void VKIndexBuffer::bind_as_ssbo(uint binding)
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const ShaderInput *shader_input = shader_interface.shader_input_get(
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, shader_input);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, location);
}
void VKIndexBuffer::read(uint32_t *data) const

View File

@ -85,13 +85,12 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type
void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
const StorageType storage_type,
const ShaderInput *shader_input)
const VKDescriptorSet::Location location)
{
BLI_assert(push_constants.is_empty());
storage_type_ = storage_type;
if (ELEM(storage_type, StorageType::STORAGE_BUFFER, StorageType::UNIFORM_BUFFER)) {
BLI_assert(shader_input);
storage_buffer_binding_ = VKDescriptorSet::Location(shader_input);
storage_buffer_binding_ = location;
}
uint32_t offset = 0;
for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
@ -173,6 +172,9 @@ VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other)
storage_buffer_ = other.storage_buffer_;
other.storage_buffer_ = nullptr;
uniform_buffer_ = other.uniform_buffer_;
other.uniform_buffer_ = nullptr;
return *this;
}

View File

@ -85,7 +85,7 @@ struct VKPushConstantsLayout {
void init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
StorageType storage_type,
const ShaderInput *shader_input);
VKDescriptorSet::Location location);
/**
* Return the storage type that is used.

View File

@ -326,10 +326,10 @@ static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifie
}
static void print_resource(std::ostream &os,
const ShaderInput &shader_input,
const VKDescriptorSet::Location location,
const ShaderCreateInfo::Resource &res)
{
os << "layout(binding = " << shader_input.location;
os << "layout(binding = " << (uint32_t)location;
if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
os << ", " << to_string(res.image.format);
}
@ -379,12 +379,8 @@ static void print_resource(std::ostream &os,
const VKShaderInterface &shader_interface,
const ShaderCreateInfo::Resource &res)
{
const ShaderInput *shader_input = shader_interface.shader_input_get(res);
if (shader_input == nullptr) {
BLI_assert_msg(shader_input, "Cannot find shader input for resource");
return;
}
print_resource(os, *shader_input, res);
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(res);
print_resource(os, location, res);
}
static void print_resource_alias(std::ostream &os, const ShaderCreateInfo::Resource &res)
@ -877,10 +873,10 @@ static VkDescriptorType descriptor_type(const shader::ShaderCreateInfo::Resource
}
static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
const ShaderInput &shader_input, const shader::ShaderCreateInfo::Resource &resource)
const VKDescriptorSet::Location location, const shader::ShaderCreateInfo::Resource &resource)
{
VkDescriptorSetLayoutBinding binding = {};
binding.binding = shader_input.location;
binding.binding = location;
binding.descriptorType = descriptor_type(resource);
binding.descriptorCount = 1;
binding.stageFlags = VK_SHADER_STAGE_ALL;
@ -914,13 +910,8 @@ static void add_descriptor_set_layout_bindings(
Vector<VkDescriptorSetLayoutBinding> &r_bindings)
{
for (const shader::ShaderCreateInfo::Resource &resource : resources) {
const ShaderInput *shader_input = interface.shader_input_get(resource);
if (shader_input == nullptr) {
BLI_assert_msg(shader_input, "Cannot find shader input for resource.");
continue;
}
r_bindings.append(create_descriptor_set_layout_binding(*shader_input, resource));
const VKDescriptorSet::Location location = interface.descriptor_set_location(resource);
r_bindings.append(create_descriptor_set_layout_binding(location, resource));
}
/* Add push constants to the descriptor when push constants are stored in a storage buffer.*/

View File

@ -62,30 +62,29 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
int32_t input_tot_len = ubo_len_ + uniform_len_ + ssbo_len_;
inputs_ = static_cast<ShaderInput *>(
MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__));
descriptor_set_locations_ = Array<VKDescriptorSet::Location>(input_tot_len);
ShaderInput *input = inputs_;
name_buffer_ = (char *)MEM_mallocN(names_size, "name_buffer");
uint32_t name_buffer_offset = 0;
int32_t location = 0;
uint32_t descriptor_set_location = 0;
/* Uniform blocks */
for (const ShaderCreateInfo::Resource &res : all_resources) {
if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
input->location = location++;
input->binding = res.slot;
input->location = input->binding = res.slot;
descriptor_set_location_update(input, descriptor_set_location++);
input++;
}
}
/* Add push constant when using uniform buffer as fallback. */
int32_t push_constants_fallback_location = -1;
ShaderInput *push_constants_fallback_input = nullptr;
if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) {
copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset);
input->location = push_constants_fallback_location = location++;
input->binding = -1;
push_constants_fallback_input = input;
input->location = input->binding = -1;
push_constants_fallback_location = descriptor_set_location++;
descriptor_set_location_update(input, push_constants_fallback_location);
input++;
}
@ -93,14 +92,14 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
for (const ShaderCreateInfo::Resource &res : all_resources) {
if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset);
input->location = location++;
input->binding = res.slot;
input->location = input->binding = res.slot;
descriptor_set_location_update(input, descriptor_set_location++);
input++;
}
else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
input->location = location++;
input->binding = res.slot + image_offset_;
input->location = input->binding = res.slot + image_offset_;
descriptor_set_location_update(input, descriptor_set_location++);
input++;
}
}
@ -109,7 +108,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
/* NOTE: Push constants must be added after other uniform resources as resources have strict
* rules for their 'location' due to descriptor sets. Push constants only need an unique location
* as it is only used by the GPU module internally.*/
int32_t push_constant_location = location + 1024;
int32_t push_constant_location = 1024;
for (const ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
copy_input_name(input, push_constant.name, name_buffer_, name_buffer_offset);
input->location = push_constant_location++;
@ -121,8 +120,8 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
for (const ShaderCreateInfo::Resource &res : all_resources) {
if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset);
input->location = location++;
input->binding = res.slot;
input->location = input->binding = res.slot;
descriptor_set_location_update(input, descriptor_set_location++);
input++;
}
}
@ -134,16 +133,46 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
*/
if (push_constants_storage_type == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) {
copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset);
input->location = push_constants_fallback_location = location++;
input->binding = -1;
push_constants_fallback_input = input;
input->location = input->binding = -1;
push_constants_fallback_location = descriptor_set_location++;
descriptor_set_location_update(input, push_constants_fallback_location);
input++;
}
push_constants_layout_.init(
info, *this, push_constants_storage_type, push_constants_fallback_input);
info, *this, push_constants_storage_type, push_constants_fallback_location);
sort_inputs();
debug_print();
// debug_print();
}
void VKShaderInterface::descriptor_set_location_update(const ShaderInput *shader_input,
const VKDescriptorSet::Location location)
{
int32_t index = (shader_input - inputs_) / sizeof(ShaderInput);
descriptor_set_locations_[index] = location;
}
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
const ShaderInput *shader_input) const
{
int32_t index = (shader_input - inputs_) / sizeof(ShaderInput);
return descriptor_set_locations_[index];
}
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
const shader::ShaderCreateInfo::Resource &resource) const
{
const ShaderInput *shader_input = shader_input_get(resource);
BLI_assert(shader_input);
return descriptor_set_location(shader_input);
}
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const
{
const ShaderInput *shader_input = shader_input_get(bind_type, binding);
BLI_assert(shader_input);
return descriptor_set_location(shader_input);
}
const ShaderInput *VKShaderInterface::shader_input_get(

View File

@ -10,6 +10,8 @@
#include "gpu_shader_create_info.hh"
#include "gpu_shader_interface.hh"
#include "BLI_array.hh"
#include "vk_push_constants.hh"
namespace blender::gpu {
@ -25,6 +27,7 @@ class VKShaderInterface : public ShaderInterface {
uint32_t image_offset_ = 0;
VKPushConstantsLayout push_constants_layout_;
Array<VKDescriptorSet::Location> descriptor_set_locations_;
public:
static constexpr StringRefNull PUSH_CONSTANTS_FALLBACK_NAME = StringRefNull(
@ -35,6 +38,18 @@ class VKShaderInterface : public ShaderInterface {
VKShaderInterface() = default;
void init(const shader::ShaderCreateInfo &info);
const VKDescriptorSet::Location descriptor_set_location(
const shader::ShaderCreateInfo::Resource &resource) const;
const VKDescriptorSet::Location descriptor_set_location(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
const VKPushConstantsLayout &push_constants_layout_get() const
{
return push_constants_layout_;
}
private:
/**
* Retrieve the shader input for the given resource.
*
@ -44,10 +59,8 @@ class VKShaderInterface : public ShaderInterface {
const ShaderInput *shader_input_get(const shader::ShaderCreateInfo::Resource &resource) const;
const ShaderInput *shader_input_get(
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
const VKPushConstantsLayout &push_constants_layout_get() const
{
return push_constants_layout_;
}
const VKDescriptorSet::Location descriptor_set_location(const ShaderInput *shader_input) const;
void descriptor_set_location_update(const ShaderInput *shader_input,
const VKDescriptorSet::Location location);
};
} // namespace blender::gpu

View File

@ -34,9 +34,9 @@ void VKStorageBuffer::bind(int slot)
}
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const ShaderInput *shader_input = shader_interface.shader_input_get(
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, slot);
shader->pipeline_get().descriptor_set_get().bind(*this, shader_input);
shader->pipeline_get().descriptor_set_get().bind(*this, location);
}
void VKStorageBuffer::unbind()

View File

@ -227,8 +227,8 @@ void VKTexture::image_bind(int binding)
}
VKContext &context = *VKContext::get();
VKShader *shader = static_cast<VKShader *>(context.shader);
VKDescriptorSet::Location location(shader->interface_get().shader_input_get(
shader::ShaderCreateInfo::Resource::BindType::IMAGE, binding));
const VKDescriptorSet::Location location = shader->interface_get().descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::IMAGE, binding);
shader->pipeline_get().descriptor_set_get().image_bind(*this, location);
}

View File

@ -27,9 +27,9 @@ void VKVertexBuffer::bind_as_ssbo(uint binding)
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const ShaderInput *shader_input = shader_interface.shader_input_get(
const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, shader_input);
shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, location);
}
void VKVertexBuffer::bind_as_texture(uint /*binding*/)