This commit is contained in:
xsl
2025-09-04 10:54:47 +08:00
commit 6bc8f61b18
1808 changed files with 208268 additions and 0 deletions
+455
View File
@@ -0,0 +1,455 @@
/* Copyright (c) 2019-2020, Arm Limited and Contributors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "spirv_reflection.h"
namespace vkb
{
namespace
{
template <ShaderResourceType T>
inline void read_shader_resource(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
LOGE("Not implemented! Read shader resources of type.");
}
template <spv::Decoration T>
inline void read_resource_decoration(const spirv_cross::Compiler & /*compiler*/,
const spirv_cross::Resource & /*resource*/,
ShaderResource & /*shader_resource*/,
const ShaderVariant & /* variant */)
{
LOGE("Not implemented! Read resources decoration of type.");
}
template <>
inline void read_resource_decoration<spv::DecorationLocation>(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
shader_resource.location = compiler.get_decoration(resource.id, spv::DecorationLocation);
}
template <>
inline void read_resource_decoration<spv::DecorationDescriptorSet>(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
shader_resource.set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
}
template <>
inline void read_resource_decoration<spv::DecorationBinding>(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
shader_resource.binding = compiler.get_decoration(resource.id, spv::DecorationBinding);
}
template <>
inline void read_resource_decoration<spv::DecorationInputAttachmentIndex>(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
shader_resource.input_attachment_index = compiler.get_decoration(resource.id, spv::DecorationInputAttachmentIndex);
}
template <>
inline void read_resource_decoration<spv::DecorationNonWritable>(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
shader_resource.qualifiers |= ShaderResourceQualifiers::NonWritable;
}
template <>
inline void read_resource_decoration<spv::DecorationNonReadable>(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
shader_resource.qualifiers |= ShaderResourceQualifiers::NonReadable;
}
inline void read_resource_vec_size(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
const auto &spirv_type = compiler.get_type_from_variable(resource.id);
shader_resource.vec_size = spirv_type.vecsize;
shader_resource.columns = spirv_type.columns;
}
inline void read_resource_array_size(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
const auto &spirv_type = compiler.get_type_from_variable(resource.id);
shader_resource.array_size = spirv_type.array.size() ? spirv_type.array[0] : 1;
}
inline void read_resource_size(const spirv_cross::Compiler &compiler,
const spirv_cross::Resource &resource,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
const auto &spirv_type = compiler.get_type_from_variable(resource.id);
size_t array_size = 0;
if (variant.get_runtime_array_sizes().count(resource.name) != 0)
{
array_size = variant.get_runtime_array_sizes().at(resource.name);
}
shader_resource.size = to_u32(compiler.get_declared_struct_size_runtime_array(spirv_type, array_size));
}
inline void read_resource_size(const spirv_cross::Compiler & compiler,
const spirv_cross::SPIRConstant &constant,
ShaderResource & shader_resource,
const ShaderVariant & variant)
{
auto spirv_type = compiler.get_type(constant.constant_type);
switch (spirv_type.basetype)
{
case spirv_cross::SPIRType::BaseType::Boolean:
case spirv_cross::SPIRType::BaseType::Char:
case spirv_cross::SPIRType::BaseType::Int:
case spirv_cross::SPIRType::BaseType::UInt:
case spirv_cross::SPIRType::BaseType::Float:
shader_resource.size = 4;
break;
case spirv_cross::SPIRType::BaseType::Int64:
case spirv_cross::SPIRType::BaseType::UInt64:
case spirv_cross::SPIRType::BaseType::Double:
shader_resource.size = 8;
break;
default:
shader_resource.size = 0;
break;
}
}
template <>
inline void read_shader_resource<ShaderResourceType::Input>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto input_resources = compiler.get_shader_resources().stage_inputs;
for (auto &resource : input_resources)
{
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::Input;
shader_resource.stages = stage;
shader_resource.name = resource.name;
read_resource_vec_size(compiler, resource, shader_resource, variant);
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationLocation>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
template <>
inline void read_shader_resource<ShaderResourceType::InputAttachment>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits /*stage*/,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto subpass_resources = compiler.get_shader_resources().subpass_inputs;
for (auto &resource : subpass_resources)
{
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::InputAttachment;
shader_resource.stages = VK_SHADER_STAGE_FRAGMENT_BIT;
shader_resource.name = resource.name;
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationInputAttachmentIndex>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationDescriptorSet>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationBinding>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
template <>
inline void read_shader_resource<ShaderResourceType::Output>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto output_resources = compiler.get_shader_resources().stage_outputs;
for (auto &resource : output_resources)
{
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::Output;
shader_resource.stages = stage;
shader_resource.name = resource.name;
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_vec_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationLocation>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
template <>
inline void read_shader_resource<ShaderResourceType::Image>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto image_resources = compiler.get_shader_resources().separate_images;
for (auto &resource : image_resources)
{
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::Image;
shader_resource.stages = stage;
shader_resource.name = resource.name;
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationDescriptorSet>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationBinding>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
template <>
inline void read_shader_resource<ShaderResourceType::ImageSampler>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto image_resources = compiler.get_shader_resources().sampled_images;
for (auto &resource : image_resources)
{
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::ImageSampler;
shader_resource.stages = stage;
shader_resource.name = resource.name;
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationDescriptorSet>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationBinding>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
template <>
inline void read_shader_resource<ShaderResourceType::ImageStorage>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto storage_resources = compiler.get_shader_resources().storage_images;
for (auto &resource : storage_resources)
{
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::ImageStorage;
shader_resource.stages = stage;
shader_resource.name = resource.name;
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationNonReadable>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationNonWritable>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationDescriptorSet>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationBinding>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
template <>
inline void read_shader_resource<ShaderResourceType::Sampler>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto sampler_resources = compiler.get_shader_resources().separate_samplers;
for (auto &resource : sampler_resources)
{
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::Sampler;
shader_resource.stages = stage;
shader_resource.name = resource.name;
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationDescriptorSet>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationBinding>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
template <>
inline void read_shader_resource<ShaderResourceType::BufferUniform>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto uniform_resources = compiler.get_shader_resources().uniform_buffers;
for (auto &resource : uniform_resources)
{
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::BufferUniform;
shader_resource.stages = stage;
shader_resource.name = resource.name;
read_resource_size(compiler, resource, shader_resource, variant);
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationDescriptorSet>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationBinding>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
template <>
inline void read_shader_resource<ShaderResourceType::BufferStorage>(const spirv_cross::Compiler &compiler,
VkShaderStageFlagBits stage,
std::vector<ShaderResource> &resources,
const ShaderVariant & variant)
{
auto storage_resources = compiler.get_shader_resources().storage_buffers;
for (auto &resource : storage_resources)
{
ShaderResource shader_resource;
shader_resource.type = ShaderResourceType::BufferStorage;
shader_resource.stages = stage;
shader_resource.name = resource.name;
read_resource_size(compiler, resource, shader_resource, variant);
read_resource_array_size(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationNonReadable>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationNonWritable>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationDescriptorSet>(compiler, resource, shader_resource, variant);
read_resource_decoration<spv::DecorationBinding>(compiler, resource, shader_resource, variant);
resources.push_back(shader_resource);
}
}
} // namespace
bool SPIRVReflection::reflect_shader_resources(VkShaderStageFlagBits stage, const std::vector<uint32_t> &spirv, std::vector<ShaderResource> &resources, const ShaderVariant &variant)
{
spirv_cross::CompilerGLSL compiler{spirv};
auto opts = compiler.get_common_options();
opts.enable_420pack_extension = true;
compiler.set_common_options(opts);
parse_shader_resources(compiler, stage, resources, variant);
parse_push_constants(compiler, stage, resources, variant);
parse_specialization_constants(compiler, stage, resources, variant);
return true;
}
void SPIRVReflection::parse_shader_resources(const spirv_cross::Compiler &compiler, VkShaderStageFlagBits stage, std::vector<ShaderResource> &resources, const ShaderVariant &variant)
{
read_shader_resource<ShaderResourceType::Input>(compiler, stage, resources, variant);
read_shader_resource<ShaderResourceType::InputAttachment>(compiler, stage, resources, variant);
read_shader_resource<ShaderResourceType::Output>(compiler, stage, resources, variant);
read_shader_resource<ShaderResourceType::Image>(compiler, stage, resources, variant);
read_shader_resource<ShaderResourceType::ImageSampler>(compiler, stage, resources, variant);
read_shader_resource<ShaderResourceType::ImageStorage>(compiler, stage, resources, variant);
read_shader_resource<ShaderResourceType::Sampler>(compiler, stage, resources, variant);
read_shader_resource<ShaderResourceType::BufferUniform>(compiler, stage, resources, variant);
read_shader_resource<ShaderResourceType::BufferStorage>(compiler, stage, resources, variant);
}
void SPIRVReflection::parse_push_constants(const spirv_cross::Compiler &compiler, VkShaderStageFlagBits stage, std::vector<ShaderResource> &resources, const ShaderVariant &variant)
{
auto shader_resources = compiler.get_shader_resources();
for (auto &resource : shader_resources.push_constant_buffers)
{
const auto &spivr_type = compiler.get_type_from_variable(resource.id);
std::uint32_t offset = std::numeric_limits<std::uint32_t>::max();
for (auto i = 0U; i < spivr_type.member_types.size(); ++i)
{
auto mem_offset = compiler.get_member_decoration(spivr_type.self, i, spv::DecorationOffset);
offset = std::min(offset, mem_offset);
}
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::PushConstant;
shader_resource.stages = stage;
shader_resource.name = resource.name;
shader_resource.offset = offset;
read_resource_size(compiler, resource, shader_resource, variant);
shader_resource.size -= shader_resource.offset;
resources.push_back(shader_resource);
}
}
void SPIRVReflection::parse_specialization_constants(const spirv_cross::Compiler &compiler, VkShaderStageFlagBits stage, std::vector<ShaderResource> &resources, const ShaderVariant &variant)
{
auto specialization_constants = compiler.get_specialization_constants();
for (auto &resource : specialization_constants)
{
auto &spirv_value = compiler.get_constant(resource.id);
ShaderResource shader_resource{};
shader_resource.type = ShaderResourceType::SpecializationConstant;
shader_resource.stages = stage;
shader_resource.name = compiler.get_name(resource.id);
shader_resource.offset = 0;
shader_resource.constant_id = resource.constant_id;
read_resource_size(compiler, spirv_value, shader_resource, variant);
resources.push_back(shader_resource);
}
}
} // namespace vkb