Vulkan: Push constants #104880
|
@ -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.*/
|
||||
Jeroen-Bakker marked this conversation as resolved
|
||||
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")
|
||||
|
|
|
@ -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
|
|
@ -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()) {
|
||||
Jeroen-Bakker marked this conversation as resolved
Bastien Montagne
commented
I may be missing something, but this whole Would rather see that logic as part of the I may be missing something, but this whole `switch` block feels like it does not belong here. It looks way too specific to me.
Would rather see that logic as part of the `VKPushConstants` class itself, but no idea if this is doable in practice... At the very least would have it in a dedicated util function of `VKBackend` otherwise?
Jeroen Bakker
commented
Yes you're right, will move this part into a method of VKPushConstants. Yes you're right, will move this part into a method of VKPushConstants.
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "vk_buffer.hh"
|
||||
#include "vk_context.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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_,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -50,9 +50,8 @@ class VKDescriptorSet : NonCopyable {
|
|||
*/
|
||||
uint32_t binding;
|
||||
|
||||
Location() = default;
|
||||
|
||||
public:
|
||||
Location() = default;
|
||||
Location(const ShaderInput *shader_input) : binding(shader_input->location)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
Jeroen-Bakker marked this conversation as resolved
Jeroen Bakker
commented
This should be fixed. This should be fixed.
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
Jeroen-Bakker marked this conversation as resolved
Jeroen Bakker
commented
Add Add `const VKPushConstantsLayout& layout_get() const` as API and clean up the interface.
|
||||
{
|
||||
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]));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Jeroen-Bakker marked this conversation as resolved
Jeroen Bakker
commented
Also check for uniform_buffer Also check for uniform_buffer
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Remove line as this is vulkan specific.