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
16 changed files with 337 additions and 73 deletions
Showing only changes of commit 797320c96b - Show all commits

View File

@ -55,6 +55,7 @@ GPU_SHADER_CREATE_INFO(gpu_compute_ssbo_binding_test)
.compute_source("gpu_compute_dummy_test.glsl")
.do_static_compilation(true);
/* Push constants*/
GPU_SHADER_CREATE_INFO(gpu_push_constants_base_test)
.local_group_size(1)
.storage_buf(0, Qualifier::WRITE, "float", "data_out[]")
@ -68,6 +69,23 @@ GPU_SHADER_CREATE_INFO(gpu_push_constants_packed_test)
.push_constant(Type::VEC4, "vec4_in")
.do_static_compilation(true);
/* Push constants size test. */
GPU_SHADER_CREATE_INFO(gpu_push_constants_128bytes_test)
.additional_info("gpu_push_constants_packed_test")
.push_constant(Type::FLOAT, "filler", 20)
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(gpu_push_constants_256bytes_test)
.additional_info("gpu_push_constants_128bytes_test")
.push_constant(Type::FLOAT, "filler2", 32)
.do_static_compilation(true);
/* It is expected that this shader will use uniform buffers and not push constants.*/
GPU_SHADER_CREATE_INFO(gpu_push_constants_512bytes_test)
.additional_info("gpu_push_constants_256bytes_test")
.push_constant(Type::FLOAT, "filler3", 64)
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_shadow_test)
.fragment_source("eevee_shadow_test.glsl")
.additional_info("gpu_shader_test")

View File

@ -77,4 +77,22 @@ static void test_push_constants_packed()
}
GPU_TEST(push_constants_packed)
static void test_push_constants_128bytes()
{
push_constants("gpu_push_constants_128bytes_test");
}
GPU_TEST(push_constants_128bytes)
static void test_push_constants_256bytes()
{
push_constants("gpu_push_constants_256bytes_test");
}
GPU_TEST(push_constants_256bytes)
static void test_push_constants_512bytes()
{
push_constants("gpu_push_constants_512bytes_test");
}
GPU_TEST(push_constants_512bytes)
} // namespace blender::gpu::tests

View File

@ -67,11 +67,27 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_
VKCommandBuffer &command_buffer = context.command_buffer_get();
VKPipeline &pipeline = shader->pipeline_get();
VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get();
VKPushConstants &push_constants = pipeline.push_constants_get();
/* Update push constants based on their storage type.*/
switch (push_constants.storage_type_get()) {
case VKPushConstantsLayout::StorageType::NONE:
break;
case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS:
command_buffer.push_constants(
push_constants, shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL);
break;
case VKPushConstantsLayout::StorageType::STORAGE_BUFFER:
push_constants.update_storage_buffer(context.device_get());
descriptor_set.bind(push_constants.storage_buffer_get(),
push_constants.storage_buffer_binding_get());
break;
}
descriptor_set.update(context.device_get());
command_buffer.bind(
descriptor_set, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_COMPUTE);
command_buffer.push_constants(
pipeline.push_constants_get(), shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL);
command_buffer.dispatch(groups_x_len, groups_y_len, groups_z_len);
}

View File

@ -6,6 +6,7 @@
*/
#include "vk_buffer.hh"
#include "vk_context.hh"
Jeroen-Bakker marked this conversation as resolved Outdated

This include isn't needed

This include isn't needed
namespace blender::gpu {

View File

@ -10,11 +10,11 @@
#include "gpu_context_private.hh"
#include "vk_common.hh"
#include "vk_context.hh"
#include "vk_mem_alloc.h"
namespace blender::gpu {
class VKContext;
/**
* Class for handing vulkan buffers (allocation/updating/binding).

View File

@ -10,6 +10,7 @@
#include "vk_context.hh"
#include "vk_memory.hh"
#include "vk_texture.hh"
#include "vk_pipeline.hh"
#include "BLI_assert.h"
@ -75,7 +76,7 @@ void VKCommandBuffer::push_constants(const VKPushConstants &push_constants,
const VkPipelineLayout vk_pipeline_layout,
const VkShaderStageFlags vk_shader_stages)
{
if (push_constants.size_in_bytes() == 0) {
if (push_constants.storage_type_get() != VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) {
return;
}
vkCmdPushConstants(vk_command_buffer_,

View File

@ -8,12 +8,15 @@
#pragma once
#include "vk_common.hh"
#include "vk_pipeline.hh"
#include "BLI_utility_mixins.hh"
namespace blender::gpu {
class VKBuffer;
class VKTexture;
class VKPushConstants;
class VKPipeline;
class VKDescriptorSet;
/** Command buffer to keep track of the life-time of a command buffer.*/
class VKCommandBuffer : NonCopyable, NonMovable {

View File

@ -50,9 +50,8 @@ class VKDescriptorSet : NonCopyable {
*/
uint32_t binding;
Location() = default;
public:
Location() = default;
Location(const ShaderInput *shader_input) : binding(shader_input->location)
{
}

View File

@ -33,7 +33,7 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context,
VkShaderModule compute_module,
VkDescriptorSetLayout &descriptor_set_layout,
VkPipelineLayout &pipeline_layout,
VKPushConstantsLayout &push_constants_layout)
const VKPushConstantsLayout &push_constants_layout)
{
VK_ALLOCATION_CALLBACKS
VkDevice vk_device = context.device_get();
@ -52,13 +52,12 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context,
if (vkCreateComputePipelines(
vk_device, nullptr, 1, &pipeline_info, vk_allocation_callbacks, &vk_pipeline) !=
VK_SUCCESS) {
return VKPipeline();
//return VKPipeline();
}
VKDescriptorSet descriptor_set = context.descriptor_pools_get().allocate(descriptor_set_layout);
VKPushConstants push_constants(push_constants_layout);
return VKPipeline(
vk_pipeline, std::move(descriptor_set), std::move(push_constants));
VKPushConstants push_constants(&push_constants_layout);
return VKPipeline(vk_pipeline, std::move(descriptor_set), std::move(push_constants));
}
VkPipeline VKPipeline::vk_handle() const

View File

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

View File

@ -6,15 +6,17 @@
*/
#include "vk_push_constants.hh"
#include "vk_backend.hh"
#include "vk_shader_interface.hh"
namespace blender::gpu {
static uint32_t to_component_size(const shader::Type /*type*/)
constexpr uint32_t to_component_size(const shader::Type /*type*/)
{
return 4;
}
static uint32_t to_num_components(const shader::Type type)
constexpr uint32_t to_num_components(const shader::Type type)
{
switch (type) {
case shader::Type::FLOAT:
@ -43,7 +45,7 @@ static uint32_t to_num_components(const shader::Type type)
return 0;
}
static uint32_t to_alignment(const shader::Type type)
constexpr uint32_t to_alignment(const shader::Type type)
{
switch (type) {
case shader::Type::FLOAT:
@ -70,38 +72,71 @@ static uint32_t to_alignment(const shader::Type type)
return 0;
}
static void align(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset)
{
uint32_t alignment = to_alignment(push_constant.type);
uint32_t alignment_mask = alignment - 1;
uint32_t offset = *r_offset;
if ((offset & alignment_mask) != 0) {
offset &= ~alignment_mask;
offset += alignment;
*r_offset = offset;
}
}
static void reserve(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset)
{
uint32_t size = to_num_components(push_constant.type) * to_component_size(push_constant.type);
if (push_constant.array_size != 0) {
size *= push_constant.array_size;
}
*r_offset += size;
}
static VKPushConstantsLayout::PushConstantLayout init_constant(
const shader::ShaderCreateInfo::PushConst &push_constant,
const ShaderInput &shader_input,
uint32_t *r_offset)
{
align(push_constant, r_offset);
VKPushConstantsLayout::PushConstantLayout layout;
layout.location = shader_input.location;
layout.type = push_constant.type;
layout.array_size = push_constant.array_size;
layout.offset = *r_offset;
/* Perform alignment. */
uint32_t alignment = to_alignment(push_constant.type);
uint32_t alignment_mask = alignment - 1;
if ((layout.offset & alignment_mask) != 0) {
layout.offset &= ~alignment_mask;
layout.offset += alignment;
}
uint32_t size = to_num_components(push_constant.type) * to_component_size(push_constant.type);
if (push_constant.array_size != 0) {
size *= push_constant.array_size;
}
*r_offset = layout.offset + size;
reserve(push_constant, r_offset);
return layout;
}
VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type(
const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits)
{
if (info.push_constants_.is_empty()) {
return StorageType::NONE;
}
uint32_t offset = 0;
for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
align(push_constant, &offset);
reserve(push_constant, &offset);
}
return offset <= vk_physical_device_limits.maxPushConstantsSize ? StorageType::PUSH_CONSTANTS :
StorageType::STORAGE_BUFFER;
}
void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface)
const VKShaderInterface &interface,
const StorageType storage_type,
const ShaderInput *shader_input)
{
BLI_assert(push_constants.is_empty());
storage_type_ = storage_type;
if (storage_type == StorageType::STORAGE_BUFFER) {
BLI_assert(shader_input);
storage_buffer_binding_ = VKDescriptorSet::Location(shader_input);
}
uint32_t offset = 0;
for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str());
@ -121,16 +156,22 @@ const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find(
}
return nullptr;
}
VKPushConstants::VKPushConstants(VKPushConstantsLayout &layout) : layout_(layout)
VKPushConstants::VKPushConstants() = default;
VKPushConstants::VKPushConstants(const VKPushConstantsLayout *layout) : layout_(layout)
{
data_ = MEM_mallocN(layout.size_in_bytes(), __func__);
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__);
}
}
VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout_)
{
data_ = other.data_;
other.data_ = nullptr;
storage_buffer_ = other.storage_buffer_;
other.storage_buffer_ = nullptr;
}
VKPushConstants::~VKPushConstants()
@ -139,15 +180,37 @@ VKPushConstants::~VKPushConstants()
MEM_freeN(data_);
data_ = nullptr;
}
delete storage_buffer_;
storage_buffer_ = nullptr;
}
VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other)
{
layout_ = other.layout_;
data_ = other.data_;
other.data_ = nullptr;
storage_buffer_ = other.storage_buffer_;
other.storage_buffer_ = nullptr;
return *this;
}
void VKPushConstants::update_storage_buffer(VkDevice /*vk_device*/)
{
BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER);
BLI_assert(storage_buffer_ != nullptr);
BLI_assert(data_ != nullptr);
storage_buffer_->update(data_);
}
VKStorageBuffer &VKPushConstants::storage_buffer_get()
{
BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER);
BLI_assert(storage_buffer_ != nullptr);
return *storage_buffer_;
}
} // namespace blender::gpu

View File

@ -3,6 +3,17 @@
/** \file
* \ingroup gpu
*
* Push constants is a way to quickly provide a small amount of uniform data to shaders. It should
* be much quicker than UBOs but a huge limitation is the size of data - spec requires 128 bytes to
* be available for a push constant range. Hardware vendors may support more, but compared to other
* means it is still very little (for example 256 bytes).
*
* Due to this size requirements we try to use push constants when it fits on the device. If it
* doesn't fit we fallback to use an uniform buffer.
*
* Shader developers are responsible to fine-tune the performance of the shader. One way to do this
* is to tailor what will be sent as a push constant to keep the push constants within the limits.
*/
#pragma once
@ -10,12 +21,27 @@
#include "BLI_utility_mixins.hh"
#include "BLI_vector.hh"
#include "gpu_shader_create_info.hh"
#include "vk_common.hh"
#include "vk_shader_interface.hh"
//#include "vk_context.hh"
#include "vk_descriptor_set.hh"
#include "vk_storage_buffer.hh"
namespace blender::gpu {
class VKShaderInterface;
/**
* Describe the layout of the push constants and the storage type that should be used.
*/
struct VKPushConstantsLayout {
/* Should the push constant use regular push constants or a buffer.*/
enum class StorageType {
NONE,
PUSH_CONSTANTS,
STORAGE_BUFFER,
};
struct PushConstantLayout {
/* TODO: location requires sequential lookups, we should make the location index based for
* quicker access. */
@ -29,10 +55,34 @@ struct VKPushConstantsLayout {
private:
Vector<PushConstantLayout> push_constants;
uint32_t size_in_bytes_;
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:
void init(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface);
static StorageType determine_storage_type(
const shader::ShaderCreateInfo &info,
const VkPhysicalDeviceLimits &vk_physical_device_limits);
void init(const shader::ShaderCreateInfo &info,
const VKShaderInterface &interface,
StorageType storage_type,
const ShaderInput *shader_input);
/**
* Return the storage type that is used.
*/
StorageType storage_type_get() const
{
return storage_type_;
}
VKDescriptorSet::Location storage_buffer_binding_get() const
{
return storage_buffer_binding_;
}
uint32_t size_in_bytes() const
{
@ -42,16 +92,16 @@ struct VKPushConstantsLayout {
const PushConstantLayout *find(int32_t location) const;
};
static VKPushConstantsLayout dummy_layout;
class VKPushConstants : NonCopyable {
private:
VKPushConstantsLayout &layout_ = dummy_layout;
const VKPushConstantsLayout *layout_ = nullptr;
void *data_ = nullptr;
VKStorageBuffer *storage_buffer_ = nullptr;
public:
VKPushConstants() = default;
VKPushConstants(VKPushConstantsLayout &layout);
VKPushConstants();
VKPushConstants(const VKPushConstantsLayout *layout);
VKPushConstants(VKPushConstants &&other);
virtual ~VKPushConstants();
@ -64,9 +114,22 @@ class VKPushConstants : NonCopyable {
size_t size_in_bytes() const
{
return layout_.size_in_bytes();
return layout_->size_in_bytes();
}
VKPushConstantsLayout::StorageType storage_type_get() const
{
return layout_->storage_type_get();
}
VKDescriptorSet::Location storage_buffer_binding_get() const
{
return layout_->storage_buffer_binding_get();
}
void update_storage_buffer(VkDevice vk_device);
VKStorageBuffer &storage_buffer_get();
const void *data() const
{
return data_;
@ -78,14 +141,15 @@ class VKPushConstants : NonCopyable {
int32_t array_size,
const T *input_data)
{
const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_.find(location);
const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_->find(
location);
if (push_constant_layout == nullptr) {
/* Currently the builtin uniforms are set using a predefined location each time a shader is
* bound.*/
/* TODO: Currently the builtin uniforms are set using a predefined location each time a
* shader is bound. This needs to be fixed in the VKShaderInterface.*/
return;
}
BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <=
layout_.size_in_bytes(),
layout_->size_in_bytes(),
"Tried to write outside the push constant allocated memory.");
uint8_t *bytes = static_cast<uint8_t *>(data_);
T *dst = static_cast<T *>(static_cast<void *>(&bytes[push_constant_layout->offset]));

View File

@ -680,8 +680,7 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info)
if (!finalize_descriptor_set_layouts(vk_device, *vk_interface, *info)) {
return false;
}
push_constants_layout_.init(*info, *vk_interface);
if (!finalize_pipeline_layout(vk_device, *info)) {
if (!finalize_pipeline_layout(vk_device, *vk_interface)) {
return false;
}
@ -700,7 +699,11 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info)
BLI_assert(fragment_module_ == VK_NULL_HANDLE);
BLI_assert(compute_module_ != VK_NULL_HANDLE);
compute_pipeline_ = VKPipeline::create_compute_pipeline(
*context_, compute_module_, layout_, pipeline_layout_, push_constants_layout_);
*context_,
compute_module_,
layout_,
pipeline_layout_,
vk_interface->push_constants_layout_get());
result = compute_pipeline_.is_valid();
}
@ -744,7 +747,7 @@ bool VKShader::finalize_graphics_pipeline(VkDevice /*vk_device */)
}
bool VKShader::finalize_pipeline_layout(VkDevice vk_device,
const shader::ShaderCreateInfo & /*info*/)
const VKShaderInterface &shader_interface)
{
VK_ALLOCATION_CALLBACKS
@ -755,9 +758,14 @@ bool VKShader::finalize_pipeline_layout(VkDevice vk_device,
pipeline_info.flags = 0;
pipeline_info.setLayoutCount = layout_count;
pipeline_info.pSetLayouts = &layout_;
if (push_constants_layout_.size_in_bytes() != 0) {
/* Setup push constants. */
const VKPushConstantsLayout &push_constants_layout =
shader_interface.push_constants_layout_get();
if (push_constants_layout.storage_type_get() ==
VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) {
push_constant_range.offset = 0;
push_constant_range.size = push_constants_layout_.size_in_bytes();
push_constant_range.size = push_constants_layout.size_in_bytes();
push_constant_range.stageFlags = VK_SHADER_STAGE_ALL;
pipeline_info.pushConstantRangeCount = 1;
pipeline_info.pPushConstantRanges = &push_constant_range;
@ -881,6 +889,21 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
return 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);
VkDescriptorSetLayoutBinding binding = {};
binding.binding = push_constants_layout.storage_buffer_binding_get();
binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
binding.descriptorCount = 1;
binding.stageFlags = VK_SHADER_STAGE_ALL;
binding.pImmutableSamplers = nullptr;
return binding;
}
static void add_descriptor_set_layout_bindings(
const VKShaderInterface &interface,
const Vector<shader::ShaderCreateInfo::Resource> &resources,
@ -895,6 +918,13 @@ static void add_descriptor_set_layout_bindings(
r_bindings.append(create_descriptor_set_layout_binding(*shader_input, resource));
}
/* Add push constants to the descriptor when push constants are stored in a storage buffer.*/
const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get();
if (push_constants_layout.storage_type_get() ==
VKPushConstantsLayout::StorageType::STORAGE_BUFFER) {
r_bindings.append(create_descriptor_set_layout_binding(push_constants_layout));
}
}
static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout(
@ -912,11 +942,19 @@ static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout(
return set_info;
}
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;
}
bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device,
const VKShaderInterface &shader_interface,
const shader::ShaderCreateInfo &info)
{
if (info.pass_resources_.is_empty() && info.batch_resources_.is_empty()) {
if (!descriptor_sets_needed(shader_interface, info)) {
return true;
}
@ -981,18 +1019,13 @@ void VKShader::uniform_float(int location, int comp_len, int array_size, const f
pipeline_get().push_constants_get().push_constant_set(location, comp_len, array_size, data);
}
void VKShader::uniform_int(int /*location*/,
int /*comp_len*/,
int /*array_size*/,
const int * /*data*/)
void VKShader::uniform_int(int location, int comp_len, int array_size, const int *data)
{
pipeline_get().push_constants_get().push_constant_set(location, comp_len, array_size, data);
}
std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) const
{
if (info.name_ == "workbench_next_prepass_ptcloud_opaque_flat_texture_clip") {
printf("%s\n", info.name_.c_str());
}
VKShaderInterface interface;
interface.init(info);
std::stringstream ss;
@ -1013,9 +1046,19 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co
print_resource_alias(ss, res);
}
if (!info.push_constants_.is_empty()) {
/* Push constants. */
const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get();
const VKPushConstantsLayout::StorageType push_constants_storage =
push_constants_layout.storage_type_get();
if (push_constants_storage != VKPushConstantsLayout::StorageType::NONE) {
ss << "\n/* Push Constants. */\n";
ss << "layout(push_constant) uniform constants\n";
if (push_constants_storage == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) {
ss << "layout(push_constant) uniform constants\n";
}
else /* VKPushConstantsLayout::StorageType::STORAGE_BUFFER*/ {
ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get()
<< ", std430) buffer constants\n";
}
ss << "{\n";
for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) {
ss << " " << to_string(uniform.type) << " pc_" << uniform.name;
@ -1044,12 +1087,6 @@ std::string VKShader::vertex_interface_declare(const shader::ShaderCreateInfo &i
ss << "layout(location = " << attr.index << ") ";
ss << "in " << to_string(attr.type) << " " << attr.name << ";\n";
}
/* NOTE(D4490): Fix a bug where shader without any vertex attributes do not behave correctly.
*/
if (GPU_type_matches_ex(GPU_DEVICE_APPLE, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL) &&
info.vertex_inputs_.is_empty()) {
ss << "in float gpu_dummy_workaround;\n";
}
ss << "\n/* Interfaces. */\n";
int location = 0;
for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
@ -1223,6 +1260,9 @@ VKPipeline &VKShader::pipeline_get()
const VKShaderInterface &VKShader::interface_get() const
{
BLI_assert_msg(interface != nullptr,
"Unable to access the shader interface when finalizing the shader, use the "
"instance created in the finalize method.");
return *static_cast<const VKShaderInterface *>(interface);
}

View File

@ -11,7 +11,7 @@
#include "vk_backend.hh"
#include "vk_context.hh"
#include "vk_push_constants.hh"
#include "vk_pipeline.hh"
#include "BLI_string_ref.hh"
@ -28,7 +28,6 @@ class VKShader : public Shader {
bool compilation_failed_ = false;
VkDescriptorSetLayout layout_ = VK_NULL_HANDLE;
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
VKPushConstantsLayout push_constants_layout_;
VKPipeline compute_pipeline_;
public:
@ -80,7 +79,7 @@ class VKShader : public Shader {
bool finalize_descriptor_set_layouts(VkDevice vk_device,
const VKShaderInterface &shader_interface,
const shader::ShaderCreateInfo &info);
bool finalize_pipeline_layout(VkDevice vk_device, const shader::ShaderCreateInfo &info);
bool finalize_pipeline_layout(VkDevice vk_device, const VKShaderInterface &shader_interface);
bool finalize_graphics_pipeline(VkDevice vk_device);
bool is_graphics_shader() const

View File

@ -6,6 +6,7 @@
*/
#include "vk_shader_interface.hh"
#include "vk_context.hh"
namespace blender::gpu {
@ -40,15 +41,26 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
break;
}
}
/* 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::STORAGE_BUFFER) {
ssbo_len_++;
names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1;
}
/* Make sure that the image slots don't overlap with the sampler slots.*/
image_offset_ += 1;
image_offset_++;
int32_t input_tot_len = ubo_len_ + uniform_len_ + ssbo_len_;
inputs_ = static_cast<ShaderInput *>(
MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__));
ShaderInput *input = inputs_;
name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer");
name_buffer_ = (char *)MEM_mallocN(names_size, "name_buffer");
uint32_t name_buffer_offset = 0;
int32_t location = 0;
@ -101,6 +113,23 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
}
}
/* Push constant post initialization.*/
/*
* 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++;
input->binding = -1;
push_constants_fallback_input = input;
input++;
}
push_constants_layout_.init(
info, *this, push_constants_storage_type, push_constants_fallback_input);
sort_inputs();
}

View File

@ -10,6 +10,8 @@
#include "gpu_shader_create_info.hh"
#include "gpu_shader_interface.hh"
#include "vk_push_constants.hh"
namespace blender::gpu {
class VKShaderInterface : public ShaderInterface {
private:
@ -22,6 +24,13 @@ class VKShaderInterface : public ShaderInterface {
*/
uint32_t image_offset_ = 0;
VKPushConstantsLayout push_constants_layout_;
public:
static constexpr StringRefNull PUSH_CONSTANTS_FALLBACK_NAME = StringRefNull(
"push_constants_fallback", 23);
static constexpr size_t PUSH_CONSTANTS_FALLBACK_NAME_LEN = PUSH_CONSTANTS_FALLBACK_NAME.size();
public:
VKShaderInterface() = default;
@ -35,5 +44,10 @@ 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_;
}
};
} // namespace blender::gpu