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
11 changed files with 218 additions and 25 deletions
Showing only changes of commit 0ae03c78f4 - Show all commits

View File

@ -84,6 +84,12 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_
descriptor_set.bind(push_constants.storage_buffer_get(),
push_constants.storage_buffer_binding_get());
break;
case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER:
push_constants.update_uniform_buffer(context.device_get());
descriptor_set.bind(push_constants.uniform_buffer_get(),
push_constants.storage_buffer_binding_get());
break;
}
descriptor_set.update(context.device_get());
command_buffer.bind(

View File

@ -9,6 +9,7 @@
#include "vk_index_buffer.hh"
#include "vk_storage_buffer.hh"
#include "vk_texture.hh"
#include "vk_uniform_buffer.hh"
#include "vk_vertex_buffer.hh"
#include "BLI_assert.h"
@ -47,6 +48,14 @@ void VKDescriptorSet::bind(VKStorageBuffer &buffer, const Location location)
binding.buffer_size = buffer.size_in_bytes();
}
void VKDescriptorSet::bind(VKUniformBuffer &buffer, const Location location)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
binding.vk_buffer = buffer.vk_handle();
binding.buffer_size = buffer.size_in_bytes();
}
void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, const Location location)
{
Binding &binding = ensure_location(location);

View File

@ -16,6 +16,7 @@
namespace blender::gpu {
class VKStorageBuffer;
class VKUniformBuffer;
class VKVertexBuffer;
class VKIndexBuffer;
class VKTexture;
@ -131,6 +132,7 @@ class VKDescriptorSet : NonCopyable {
void bind_as_ssbo(VKVertexBuffer &buffer, Location location);
void bind_as_ssbo(VKIndexBuffer &buffer, Location location);
void bind(VKStorageBuffer &buffer, Location location);
void bind(VKUniformBuffer &buffer, Location location);
void image_bind(VKTexture &texture, Location location);
/**

View File

@ -105,4 +105,65 @@ uint32_t Std430::element_components_len(const shader::Type type)
return 0;
}
uint32_t Std140::component_mem_size(const shader::Type /*type*/)
{
return 4;
}
uint32_t Std140::element_alignment(const shader::Type type)
{
switch (type) {
case shader::Type::FLOAT:
case shader::Type::UINT:
case shader::Type::INT:
case shader::Type::BOOL:
return 4;
case shader::Type::VEC2:
case shader::Type::UVEC2:
case shader::Type::IVEC2:
return 8;
case shader::Type::VEC3:
case shader::Type::UVEC3:
case shader::Type::IVEC3:
case shader::Type::VEC4:
case shader::Type::UVEC4:
case shader::Type::IVEC4:
case shader::Type::MAT3:
case shader::Type::MAT4:
return 16;
default:
BLI_assert_msg(false, "Type not supported as push constant");
}
return 0;
}
uint32_t Std140::element_components_len(const shader::Type type)
{
switch (type) {
case shader::Type::FLOAT:
case shader::Type::UINT:
case shader::Type::INT:
case shader::Type::BOOL:
return 1;
case shader::Type::VEC2:
case shader::Type::UVEC2:
case shader::Type::IVEC2:
return 2;
case shader::Type::VEC3:
case shader::Type::UVEC3:
case shader::Type::IVEC3:
case shader::Type::VEC4:
case shader::Type::UVEC4:
case shader::Type::IVEC4:
return 4;
case shader::Type::MAT3:
return 12;
case shader::Type::MAT4:
return 16;
default:
BLI_assert_msg(false, "Type not supported as push constant");
}
return 0;
}
} // namespace blender::gpu

View File

@ -72,4 +72,16 @@ struct Std430 {
static uint32_t element_components_len(const shader::Type type);
};
/**
* Information about alignment/components and memory size for types when using std140 layout.
*/
struct Std140 {
/** Get the memory size in bytes of a single component using by the given type.*/
static uint32_t component_mem_size(const shader::Type type);
/** Get to alignment of the given type in bytes.*/
static uint32_t element_alignment(const shader::Type type);
/** Get the number of components that should be allocated for the given type.*/
static uint32_t element_components_len(const shader::Type type);
};
} // namespace blender::gpu

View File

@ -9,13 +9,14 @@
#include "vk_backend.hh"
#include "vk_memory.hh"
#include "vk_shader_interface.hh"
#include "vk_storage_buffer.hh"
#include "vk_uniform_buffer.hh"
namespace blender::gpu {
template<typename Layout>
static void align(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset)
template<typename Layout> static void align(const shader::Type &type, uint32_t *r_offset)
{
uint32_t alignment = Layout::element_alignment(push_constant.type);
uint32_t alignment = Layout::element_alignment(type);
uint32_t alignment_mask = alignment - 1;
uint32_t offset = *r_offset;
if ((offset & alignment_mask) != 0) {
@ -42,7 +43,7 @@ static VKPushConstantsLayout::PushConstantLayout init_constant(
const ShaderInput &shader_input,
uint32_t *r_offset)
{
align<Layout>(push_constant, r_offset);
align<Layout>(push_constant.type, r_offset);
VKPushConstantsLayout::PushConstantLayout layout;
layout.location = shader_input.location;
@ -54,6 +55,21 @@ static VKPushConstantsLayout::PushConstantLayout init_constant(
return layout;
}
template<typename Layout>
uint32_t struct_size(Span<shader::ShaderCreateInfo::PushConst> push_constants)
{
uint32_t offset = 0;
for (const shader::ShaderCreateInfo::PushConst &push_constant : push_constants) {
align<Layout>(push_constant.type, &offset);
reserve<Layout>(push_constant, &offset);
}
/* Make sure result is aligned to 64 bytes.*/
align<Layout>(shader::Type::VEC4, &offset);
return offset;
}
VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type(
const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits)
{
@ -61,13 +77,9 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type
return StorageType::NONE;
}
uint32_t offset = 0;
for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
align<Std430>(push_constant, &offset);
reserve<Std430>(push_constant, &offset);
}
return offset <= vk_physical_device_limits.maxPushConstantsSize ? StorageType::PUSH_CONSTANTS :
StorageType::STORAGE_BUFFER;
uint32_t size = struct_size<Std430>(info.push_constants_);
return size <= vk_physical_device_limits.maxPushConstantsSize ? StorageType::PUSH_CONSTANTS :
StorageType::STORAGE_BUFFER;
}
void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info,
@ -77,7 +89,7 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info,
{
BLI_assert(push_constants.is_empty());
storage_type_ = storage_type;
if (storage_type == StorageType::STORAGE_BUFFER) {
if (ELEM(storage_type, StorageType::STORAGE_BUFFER, StorageType::UNIFORM_BUFFER)) {
BLI_assert(shader_input);
storage_buffer_binding_ = VKDescriptorSet::Location(shader_input);
}
@ -85,7 +97,12 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info,
for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str());
BLI_assert(shader_input);
push_constants.append(init_constant<Std430>(push_constant, *shader_input, &offset));
if (storage_type == StorageType::UNIFORM_BUFFER) {
push_constants.append(init_constant<Std140>(push_constant, *shader_input, &offset));
}
else {
push_constants.append(init_constant<Std430>(push_constant, *shader_input, &offset));
}
}
size_in_bytes_ = offset;
}
@ -100,12 +117,23 @@ const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find(
}
return nullptr;
}
VKPushConstants::VKPushConstants() = default;
VKPushConstants::VKPushConstants(const VKPushConstantsLayout *layout) : layout_(layout)
{
data_ = MEM_mallocN(layout->size_in_bytes(), __func__);
if (storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) {
storage_buffer_ = new VKStorageBuffer(size_in_bytes(), GPU_USAGE_DYNAMIC, __func__);
switch (storage_type_get()) {
case VKPushConstantsLayout::StorageType::STORAGE_BUFFER:
storage_buffer_ = new VKStorageBuffer(size_in_bytes(), GPU_USAGE_DYNAMIC, __func__);
break;
case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER:
uniform_buffer_ = new VKUniformBuffer(size_in_bytes(), __func__);
break;
case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS:
case VKPushConstantsLayout::StorageType::NONE:
break;
}
}
@ -116,6 +144,9 @@ VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout
storage_buffer_ = other.storage_buffer_;
other.storage_buffer_ = nullptr;
uniform_buffer_ = other.uniform_buffer_;
other.uniform_buffer_ = nullptr;
}
VKPushConstants::~VKPushConstants()
@ -127,6 +158,9 @@ VKPushConstants::~VKPushConstants()
delete storage_buffer_;
storage_buffer_ = nullptr;
delete uniform_buffer_;
uniform_buffer_ = nullptr;
}
VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other)
@ -157,4 +191,19 @@ VKStorageBuffer &VKPushConstants::storage_buffer_get()
return *storage_buffer_;
}
void VKPushConstants::update_uniform_buffer(VkDevice /*vk_device*/)
{
BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER);
BLI_assert(uniform_buffer_ != nullptr);
BLI_assert(data_ != nullptr);
uniform_buffer_->update(data_);
}
VKUniformBuffer &VKPushConstants::uniform_buffer_get()
{
BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER);
BLI_assert(uniform_buffer_ != nullptr);
return *uniform_buffer_;
}
} // namespace blender::gpu

View File

@ -24,12 +24,12 @@
#include "gpu_shader_create_info.hh"
#include "vk_common.hh"
//#include "vk_context.hh"
#include "vk_descriptor_set.hh"
#include "vk_storage_buffer.hh"
namespace blender::gpu {
class VKShaderInterface;
class VKUniformBuffer;
class VKStorageBuffer;
/**
* Describe the layout of the push constants and the storage type that should be used.
@ -40,6 +40,7 @@ struct VKPushConstantsLayout {
NONE,
PUSH_CONSTANTS,
STORAGE_BUFFER,
UNIFORM_BUFFER,
};
struct PushConstantLayout {
@ -98,6 +99,7 @@ class VKPushConstants : NonCopyable {
const VKPushConstantsLayout *layout_ = nullptr;
void *data_ = nullptr;
VKStorageBuffer *storage_buffer_ = nullptr;
VKUniformBuffer *uniform_buffer_ = nullptr;
public:
VKPushConstants();
@ -130,6 +132,9 @@ class VKPushConstants : NonCopyable {
void update_storage_buffer(VkDevice vk_device);
VKStorageBuffer &storage_buffer_get();
void update_uniform_buffer(VkDevice vk_device);
VKUniformBuffer &uniform_buffer_get();
const void *data() const
{
return data_;

View File

@ -892,11 +892,15 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
const VKPushConstantsLayout &push_constants_layout)
{
BLI_assert(push_constants_layout.storage_type_get() ==
VKPushConstantsLayout::StorageType::STORAGE_BUFFER);
BLI_assert(ELEM(push_constants_layout.storage_type_get(),
VKPushConstantsLayout::StorageType::STORAGE_BUFFER,
VKPushConstantsLayout::StorageType::UNIFORM_BUFFER));
VkDescriptorSetLayoutBinding binding = {};
binding.binding = push_constants_layout.storage_buffer_binding_get();
binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
binding.descriptorType = push_constants_layout.storage_type_get() ==
VKPushConstantsLayout::StorageType::STORAGE_BUFFER ?
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER :
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
binding.descriptorCount = 1;
binding.stageFlags = VK_SHADER_STAGE_ALL;
binding.pImmutableSamplers = nullptr;
@ -946,8 +950,9 @@ static bool descriptor_sets_needed(const VKShaderInterface &shader_interface,
const shader::ShaderCreateInfo &info)
{
return !info.pass_resources_.is_empty() || !info.batch_resources_.is_empty() ||
shader_interface.push_constants_layout_get().storage_type_get() ==
VKPushConstantsLayout::StorageType::STORAGE_BUFFER;
ELEM(shader_interface.push_constants_layout_get().storage_type_get(),
VKPushConstantsLayout::StorageType::STORAGE_BUFFER,
VKPushConstantsLayout::StorageType::UNIFORM_BUFFER);
}
bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device,
@ -1055,6 +1060,10 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co
if (push_constants_storage == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) {
ss << "layout(push_constant) uniform constants\n";
}
else if (push_constants_storage == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) {
ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get()
<< ", std140) uniform constants\n";
}
else /* VKPushConstantsLayout::StorageType::STORAGE_BUFFER*/ {
ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get()
<< ", std430) buffer constants\n";

View File

@ -51,6 +51,10 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
ssbo_len_++;
names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1;
}
else if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) {
ubo_len_++;
names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1;
}
/* Make sure that the image slots don't overlap with the sampler slots.*/
image_offset_++;
@ -74,6 +78,16 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
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++;
}
/* Images, Samplers and buffers. */
for (const ShaderCreateInfo::Resource &res : all_resources) {
@ -118,8 +132,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
* When using storage buffer storage type we need to add it to the the name list here.
* Also determine the location as this is used inside the descriptor set as its binding number.
*/
int32_t push_constants_fallback_location = -1;
ShaderInput *push_constants_fallback_input = nullptr;
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++;

View File

@ -6,11 +6,22 @@
*/
#include "vk_uniform_buffer.hh"
#include "vk_context.hh"
namespace blender::gpu {
void VKUniformBuffer::update(const void * /*data*/)
void VKUniformBuffer::update(const void *data)
{
VKContext &context = *VKContext::get();
if (!buffer_.is_allocated()) {
allocate(context);
}
buffer_.update(context, data);
}
void VKUniformBuffer::allocate(VKContext &context)
{
buffer_.create(context, size_in_bytes_, GPU_USAGE_STATIC, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
}
void VKUniformBuffer::clear_to_zero()

View File

@ -9,9 +9,13 @@
#include "gpu_uniform_buffer_private.hh"
#include "vk_buffer.hh"
namespace blender::gpu {
class VKUniformBuffer : public UniformBuf {
VKBuffer buffer_;
public:
VKUniformBuffer(int size, const char *name) : UniformBuf(size, name)
{
@ -22,6 +26,19 @@ class VKUniformBuffer : public UniformBuf {
void bind(int slot) override;
void bind_as_ssbo(int slot) override;
void unbind() override;
VkBuffer vk_handle() const
{
return buffer_.vk_handle();
}
size_t size_in_bytes() const
{
return size_in_bytes_;
}
private:
void allocate(VKContext &context);
};
} // namespace blender::gpu