213 lines
7.7 KiB
C++
213 lines
7.7 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Copyright 2023 Blender Foundation. All rights reserved. */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*/
|
|
|
|
#include "vk_shader_interface.hh"
|
|
#include "vk_context.hh"
|
|
|
|
namespace blender::gpu {
|
|
|
|
void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
|
|
{
|
|
static char PUSH_CONSTANTS_FALLBACK_NAME[] = "push_constants_fallback";
|
|
static size_t PUSH_CONSTANTS_FALLBACK_NAME_LEN = strlen(PUSH_CONSTANTS_FALLBACK_NAME);
|
|
|
|
using namespace blender::gpu::shader;
|
|
|
|
attr_len_ = 0;
|
|
uniform_len_ = info.push_constants_.size();
|
|
ssbo_len_ = 0;
|
|
ubo_len_ = 0;
|
|
image_offset_ = -1;
|
|
|
|
Vector<ShaderCreateInfo::Resource> all_resources;
|
|
all_resources.extend(info.pass_resources_);
|
|
all_resources.extend(info.batch_resources_);
|
|
|
|
for (ShaderCreateInfo::Resource &res : all_resources) {
|
|
switch (res.bind_type) {
|
|
case ShaderCreateInfo::Resource::BindType::IMAGE:
|
|
uniform_len_++;
|
|
break;
|
|
case ShaderCreateInfo::Resource::BindType::SAMPLER:
|
|
image_offset_ = max_ii(image_offset_, res.slot);
|
|
uniform_len_++;
|
|
break;
|
|
case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
|
|
ubo_len_++;
|
|
break;
|
|
case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
|
|
ssbo_len_++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Reserve 1 uniform buffer for push constants fallback. */
|
|
size_t names_size = info.interface_names_size_;
|
|
VKContext &context = *VKContext::get();
|
|
const VKPushConstants::StorageType push_constants_storage_type =
|
|
VKPushConstants::Layout::determine_storage_type(info, context.physical_device_limits_get());
|
|
if (push_constants_storage_type == VKPushConstants::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_++;
|
|
|
|
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(names_size, "name_buffer");
|
|
uint32_t name_buffer_offset = 0;
|
|
|
|
/* Uniform blocks */
|
|
for (const ShaderCreateInfo::Resource &res : all_resources) {
|
|
if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
|
|
copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
|
|
input->location = input->binding = res.slot;
|
|
input++;
|
|
}
|
|
}
|
|
/* Add push constant when using uniform buffer as fallback. */
|
|
int32_t push_constants_fallback_location = -1;
|
|
if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) {
|
|
copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset);
|
|
input->location = input->binding = -1;
|
|
input++;
|
|
}
|
|
|
|
/* Images, Samplers and buffers. */
|
|
for (const ShaderCreateInfo::Resource &res : all_resources) {
|
|
if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
|
|
copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset);
|
|
input->location = input->binding = res.slot;
|
|
input++;
|
|
}
|
|
else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
|
|
copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
|
|
input->location = input->binding = res.slot + image_offset_;
|
|
input++;
|
|
}
|
|
}
|
|
|
|
/* Push constants. */
|
|
int32_t push_constant_location = 1024;
|
|
for (const ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
|
|
copy_input_name(input, push_constant.name, name_buffer_, name_buffer_offset);
|
|
input->location = push_constant_location++;
|
|
input->binding = -1;
|
|
input++;
|
|
}
|
|
|
|
/* Storage buffers */
|
|
for (const ShaderCreateInfo::Resource &res : all_resources) {
|
|
if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
|
|
copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset);
|
|
input->location = input->binding = res.slot;
|
|
input++;
|
|
}
|
|
}
|
|
|
|
sort_inputs();
|
|
|
|
/* Builtin Uniforms */
|
|
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
|
|
GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
|
|
const ShaderInput *uni = this->uniform_get(builtin_uniform_name(u));
|
|
builtins_[u] = (uni != nullptr) ? uni->location : -1;
|
|
}
|
|
|
|
/* Builtin Uniforms Blocks */
|
|
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
|
|
GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
|
|
const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
|
|
builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
|
|
}
|
|
|
|
/* Determine the descriptor set locations after the inputs have been sorted. */
|
|
descriptor_set_locations_ = Array<VKDescriptorSet::Location>(input_tot_len);
|
|
uint32_t descriptor_set_location = 0;
|
|
for (ShaderCreateInfo::Resource &res : all_resources) {
|
|
const ShaderInput *input = shader_input_get(res);
|
|
descriptor_set_location_update(input, descriptor_set_location++);
|
|
}
|
|
|
|
/* Post initializing push constants. */
|
|
/* Determine the binding location of push constants fallback buffer. */
|
|
int32_t push_constant_descriptor_set_location = -1;
|
|
if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) {
|
|
push_constant_descriptor_set_location = descriptor_set_location++;
|
|
const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME);
|
|
descriptor_set_location_update(push_constant_input, push_constants_fallback_location);
|
|
}
|
|
push_constants_layout_.init(
|
|
info, *this, push_constants_storage_type, push_constant_descriptor_set_location);
|
|
}
|
|
|
|
static int32_t shader_input_index(const ShaderInput *shader_inputs,
|
|
const ShaderInput *shader_input)
|
|
{
|
|
int32_t index = (shader_input - shader_inputs);
|
|
return index;
|
|
}
|
|
|
|
void VKShaderInterface::descriptor_set_location_update(const ShaderInput *shader_input,
|
|
const VKDescriptorSet::Location location)
|
|
{
|
|
int32_t index = shader_input_index(inputs_, shader_input);
|
|
descriptor_set_locations_[index] = location;
|
|
}
|
|
|
|
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
|
|
const ShaderInput *shader_input) const
|
|
{
|
|
int32_t index = shader_input_index(inputs_, shader_input);
|
|
return descriptor_set_locations_[index];
|
|
}
|
|
|
|
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
|
|
const shader::ShaderCreateInfo::Resource &resource) const
|
|
{
|
|
const ShaderInput *shader_input = shader_input_get(resource);
|
|
BLI_assert(shader_input);
|
|
return descriptor_set_location(shader_input);
|
|
}
|
|
|
|
const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location(
|
|
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const
|
|
{
|
|
const ShaderInput *shader_input = shader_input_get(bind_type, binding);
|
|
BLI_assert(shader_input);
|
|
return descriptor_set_location(shader_input);
|
|
}
|
|
|
|
const ShaderInput *VKShaderInterface::shader_input_get(
|
|
const shader::ShaderCreateInfo::Resource &resource) const
|
|
{
|
|
return shader_input_get(resource.bind_type, resource.slot);
|
|
}
|
|
|
|
const ShaderInput *VKShaderInterface::shader_input_get(
|
|
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const
|
|
{
|
|
switch (bind_type) {
|
|
case shader::ShaderCreateInfo::Resource::BindType::IMAGE:
|
|
return texture_get(binding + image_offset_);
|
|
case shader::ShaderCreateInfo::Resource::BindType::SAMPLER:
|
|
return texture_get(binding);
|
|
case shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
|
|
return ssbo_get(binding);
|
|
case shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
|
|
return ubo_get(binding);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace blender::gpu
|