Vulkan: Push constants #104880
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue