193 lines
5.9 KiB
C++
193 lines
5.9 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*/
|
|
|
|
#include "vk_push_constants.hh"
|
|
#include "vk_backend.hh"
|
|
#include "vk_context.hh"
|
|
#include "vk_memory_layout.hh"
|
|
#include "vk_shader.hh"
|
|
#include "vk_shader_interface.hh"
|
|
#include "vk_storage_buffer.hh"
|
|
#include "vk_uniform_buffer.hh"
|
|
|
|
namespace blender::gpu {
|
|
|
|
template<typename LayoutT>
|
|
static VKPushConstants::Layout::PushConstant init_constant(
|
|
const shader::ShaderCreateInfo::PushConst &push_constant,
|
|
const ShaderInput &shader_input,
|
|
uint32_t *r_offset)
|
|
{
|
|
align<LayoutT>(push_constant.type, push_constant.array_size, r_offset);
|
|
|
|
VKPushConstants::Layout::PushConstant layout;
|
|
layout.location = shader_input.location;
|
|
layout.type = push_constant.type;
|
|
layout.array_size = push_constant.array_size;
|
|
layout.offset = *r_offset;
|
|
|
|
reserve<LayoutT>(push_constant.type, push_constant.array_size, r_offset);
|
|
return layout;
|
|
}
|
|
|
|
template<typename LayoutT>
|
|
uint32_t struct_size(Span<shader::ShaderCreateInfo::PushConst> push_constants)
|
|
{
|
|
uint32_t offset = 0;
|
|
for (const shader::ShaderCreateInfo::PushConst &push_constant : push_constants) {
|
|
align<LayoutT>(push_constant.type, push_constant.array_size, &offset);
|
|
reserve<LayoutT>(push_constant.type, push_constant.array_size, &offset);
|
|
}
|
|
|
|
align_end_of_struct<LayoutT>(&offset);
|
|
return offset;
|
|
}
|
|
|
|
VKPushConstants::StorageType VKPushConstants::Layout::determine_storage_type(
|
|
const shader::ShaderCreateInfo &info, const VKDevice &device)
|
|
{
|
|
if (info.push_constants_.is_empty()) {
|
|
return StorageType::NONE;
|
|
}
|
|
|
|
uint32_t max_push_constants_size =
|
|
device.physical_device_properties_get().limits.maxPushConstantsSize;
|
|
uint32_t size = struct_size<Std430>(info.push_constants_);
|
|
return size <= max_push_constants_size ? STORAGE_TYPE_DEFAULT : STORAGE_TYPE_FALLBACK;
|
|
}
|
|
|
|
template<typename LayoutT>
|
|
void init_struct(const shader::ShaderCreateInfo &info,
|
|
const VKShaderInterface &interface,
|
|
Vector<VKPushConstants::Layout::PushConstant> &r_struct,
|
|
uint32_t *r_offset)
|
|
{
|
|
for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
|
|
const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str());
|
|
r_struct.append(init_constant<LayoutT>(push_constant, *shader_input, r_offset));
|
|
}
|
|
align_end_of_struct<Std140>(r_offset);
|
|
}
|
|
|
|
void VKPushConstants::Layout::init(const shader::ShaderCreateInfo &info,
|
|
const VKShaderInterface &interface,
|
|
const StorageType storage_type,
|
|
const VKDescriptorSet::Location location)
|
|
{
|
|
BLI_assert(push_constants.is_empty());
|
|
storage_type_ = storage_type;
|
|
|
|
size_in_bytes_ = 0;
|
|
if (storage_type == StorageType::UNIFORM_BUFFER) {
|
|
descriptor_set_location_ = location;
|
|
init_struct<Std140>(info, interface, push_constants, &size_in_bytes_);
|
|
}
|
|
else {
|
|
init_struct<Std430>(info, interface, push_constants, &size_in_bytes_);
|
|
}
|
|
}
|
|
|
|
const VKPushConstants::Layout::PushConstant *VKPushConstants::Layout::find(int32_t location) const
|
|
{
|
|
for (const PushConstant &push_constant : push_constants) {
|
|
if (push_constant.location == location) {
|
|
return &push_constant;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void VKPushConstants::Layout::debug_print() const
|
|
{
|
|
std::ostream &stream = std::cout;
|
|
stream << "VKPushConstants::Layout::debug_print()\n";
|
|
for (const PushConstant &push_constant : push_constants) {
|
|
stream << " - location:" << push_constant.location;
|
|
stream << ", offset:" << push_constant.offset;
|
|
stream << ", array_size:" << push_constant.array_size;
|
|
stream << "\n";
|
|
}
|
|
}
|
|
|
|
VKPushConstants::VKPushConstants() = default;
|
|
VKPushConstants::VKPushConstants(const Layout *layout) : layout_(layout)
|
|
{
|
|
data_ = MEM_mallocN(layout->size_in_bytes(), __func__);
|
|
}
|
|
|
|
VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout_)
|
|
{
|
|
data_ = other.data_;
|
|
other.data_ = nullptr;
|
|
}
|
|
|
|
VKPushConstants::~VKPushConstants()
|
|
{
|
|
if (data_ != nullptr) {
|
|
MEM_freeN(data_);
|
|
data_ = nullptr;
|
|
}
|
|
}
|
|
|
|
VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other)
|
|
{
|
|
layout_ = other.layout_;
|
|
|
|
data_ = other.data_;
|
|
other.data_ = nullptr;
|
|
|
|
return *this;
|
|
}
|
|
|
|
void VKPushConstants::update(VKContext &context)
|
|
{
|
|
VKShader *shader = static_cast<VKShader *>(context.shader);
|
|
VKCommandBuffers &command_buffers = context.command_buffers_get();
|
|
VKDescriptorSetTracker &descriptor_set = context.descriptor_set_get();
|
|
|
|
switch (layout_get().storage_type_get()) {
|
|
case VKPushConstants::StorageType::NONE:
|
|
break;
|
|
|
|
case VKPushConstants::StorageType::PUSH_CONSTANTS:
|
|
command_buffers.push_constants(*this,
|
|
shader->vk_pipeline_layout_get(),
|
|
shader->is_graphics_shader() ? VK_SHADER_STAGE_ALL_GRAPHICS :
|
|
VK_SHADER_STAGE_COMPUTE_BIT);
|
|
break;
|
|
|
|
case VKPushConstants::StorageType::UNIFORM_BUFFER:
|
|
update_uniform_buffer();
|
|
descriptor_set.bind(*uniform_buffer_get(), layout_get().descriptor_set_location_get());
|
|
break;
|
|
}
|
|
}
|
|
|
|
void VKPushConstants::update_uniform_buffer()
|
|
{
|
|
BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER);
|
|
BLI_assert(data_ != nullptr);
|
|
VKContext &context = *VKContext::get();
|
|
std::unique_ptr<VKUniformBuffer> &uniform_buffer = tracked_resource_for(context, is_dirty_);
|
|
uniform_buffer->update(data_);
|
|
is_dirty_ = false;
|
|
}
|
|
|
|
std::unique_ptr<VKUniformBuffer> &VKPushConstants::uniform_buffer_get()
|
|
{
|
|
BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER);
|
|
return active_resource();
|
|
}
|
|
|
|
std::unique_ptr<VKUniformBuffer> VKPushConstants::create_resource(VKContext & /*context*/)
|
|
{
|
|
return std::make_unique<VKUniformBuffer>(layout_->size_in_bytes(), __func__);
|
|
}
|
|
|
|
} // namespace blender::gpu
|