Skip to content

Commit

Permalink
implement reflection debug dump
Browse files Browse the repository at this point in the history
  • Loading branch information
floooh committed Apr 1, 2024
1 parent 3dde9fe commit 3652d35
Show file tree
Hide file tree
Showing 18 changed files with 361 additions and 84 deletions.
6 changes: 3 additions & 3 deletions src/shdc/input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
code for loading and parsing the input .glsl file with custom-tags
*/
#include "input.h"
#include "types/reflection/uniform.h"
#include "types/reflection/type.h"
#include "types/option.h"
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -170,8 +170,8 @@ static bool validate_ctype_tag(const std::vector<std::string>& tokens, bool in_s
inp.out_error = inp.error(line_index, "@ctype tag cannot be inside a tag block (missing @end?).");
return false;
}
if (!Uniform::is_valid_glsl_uniform_type(tokens[1])) {
inp.out_error = inp.error(line_index, fmt::format("first arg of type tag must be one of {}", Uniform::valid_glsl_uniform_types_as_str()));
if (!Type::is_valid_glsl_type(tokens[1])) {
inp.out_error = inp.error(line_index, fmt::format("first arg of @ctype tag must be one of {}", Type::valid_glsl_types_as_str()));
return false;
}
return true;
Expand Down
4 changes: 2 additions & 2 deletions src/shdc/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ struct Input {
std::map<std::string, Program> programs; // all @program definitions

static Input load_and_parse(const std::string& path, const std::string& module_override);
ErrMsg error(int index, const std::string& msg) const;
ErrMsg warning(int index, const std::string& msg) const;
ErrMsg error(int line_index, const std::string& msg) const;
ErrMsg warning(int line_index, const std::string& msg) const;
void dump_debug(ErrMsg::Format err_fmt) const;
};

Expand Down
3 changes: 3 additions & 0 deletions src/shdc/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ int main(int argc, const char** argv) {
refl.error.print(args.error_format);
return 10;
}
if (args.debug_dump) {
refl.dump_debug(args.error_format);
}

// generate output files
const GenInput gen_input(args, inp, spirvcross, bytecode, refl);
Expand Down
57 changes: 46 additions & 11 deletions src/shdc/reflection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ Reflection Reflection::build(const Args& args, const Input& inp, const std::arra
}
}
}
res.bindings = merge_bindings(snippet_bindings, inp.base_path, res.error);
ErrMsg error;
res.bindings = merge_bindings(snippet_bindings, error);
if (error.valid()) {
res.error = inp.error(0, error.msg);
}
return res;
}

Expand Down Expand Up @@ -221,7 +225,7 @@ StageReflection Reflection::parse_snippet_reflection(const Compiler& compiler, c
if (out_error.valid()) {
return refl;
}
for (size_t m_index = 0; m_index < ub_type.member_types.size(); m_index++) {
for (uint32_t m_index = 0; m_index < ub_type.member_types.size(); m_index++) {
Uniform refl_uniform;
refl_uniform.name = compiler.get_member_name(ub_res.base_type_id, m_index);
const SPIRType& m_type = compiler.get_type(ub_type.member_types[m_index]);
Expand Down Expand Up @@ -308,7 +312,7 @@ StageReflection Reflection::parse_snippet_reflection(const Compiler& compiler, c
return refl;
}

Bindings Reflection::merge_bindings(const std::vector<Bindings>& in_bindings, const std::string& inp_base_path, ErrMsg& out_error) {
Bindings Reflection::merge_bindings(const std::vector<Bindings>& in_bindings, ErrMsg& out_error) {
Bindings out_bindings;
out_error = ErrMsg();
for (const Bindings& src_bindings: in_bindings) {
Expand All @@ -319,21 +323,35 @@ Bindings Reflection::merge_bindings(const std::vector<Bindings>& in_bindings, co
if (other_ub) {
// another uniform block of the same name exists, make sure it's identical
if (!ub.equals(*other_ub)) {
out_error = ErrMsg::error(inp_base_path, 0, fmt::format("conflicting uniform block definitions found for '{}'", ub.struct_name));
out_error = ErrMsg::error(fmt::format("conflicting uniform block definitions found for '{}'", ub.struct_name));
return Bindings();
}
} else {
out_bindings.uniform_blocks.push_back(ub);
}
}

// merge identical storage buffers
for (const StorageBuffer& sbuf: src_bindings.storage_buffers) {
const StorageBuffer* other_sbuf = out_bindings.find_storage_buffer_by_name(sbuf.struct_refl.name);
if (other_sbuf) {
// another storage buffer of the same name exists, make sure it's identical
if (!sbuf.equals(*other_sbuf)) {
out_error = ErrMsg::error(fmt::format("conflicting storage buffer definitions found for '{}'", sbuf.struct_refl.name));
return Bindings();
}
} else {
out_bindings.storage_buffers.push_back(sbuf);
}
}

// merge identical images
for (const Image& img: src_bindings.images) {
const Image* other_img = out_bindings.find_image_by_name(img.name);
if (other_img) {
// another image of the same name exists, make sure it's identical
if (!img.equals(*other_img)) {
out_error = ErrMsg::error(inp_base_path, 0, fmt::format("conflicting texture definitions found for '{}'", img.name));
out_error = ErrMsg::error(fmt::format("conflicting texture definitions found for '{}'", img.name));
return Bindings();
}
} else {
Expand All @@ -347,7 +365,7 @@ Bindings Reflection::merge_bindings(const std::vector<Bindings>& in_bindings, co
if (other_smp) {
// another sampler of the same name exists, make sure it's identical
if (!smp.equals(*other_smp)) {
out_error = ErrMsg::error(inp_base_path, 0, fmt::format("conflicting sampler definitions found for '{}'", smp.name));
out_error = ErrMsg::error(fmt::format("conflicting sampler definitions found for '{}'", smp.name));
return Bindings();
}
} else {
Expand All @@ -361,7 +379,7 @@ Bindings Reflection::merge_bindings(const std::vector<Bindings>& in_bindings, co
if (other_img_smp) {
// another image sampler of the same name exists, make sure it's identical
if (!img_smp.equals(*other_img_smp)) {
out_error = ErrMsg::error(inp_base_path, 0, fmt::format("conflicting image-sampler definition found for '{}'", img_smp.name));
out_error = ErrMsg::error(fmt::format("conflicting image-sampler definition found for '{}'", img_smp.name));
return Bindings();
}
} else {
Expand Down Expand Up @@ -402,9 +420,9 @@ Type Reflection::parse_struct_item(const Compiler& compiler, const TypeID& struc
return out;
}
if (out.base_type == Type::Struct) {
out.size = compiler.get_declared_struct_size_runtime_array(item_type, 1);
out.size = (int) compiler.get_declared_struct_size_runtime_array(item_type, 1);
} else {
out.size = compiler.get_declared_struct_member_size(struct_type, item_index);
out.size = (int) compiler.get_declared_struct_member_size(struct_type, item_index);
}
out.vecsize = item_type.vecsize;
out.columns = item_type.columns;
Expand All @@ -420,7 +438,7 @@ Type Reflection::parse_struct_item(const Compiler& compiler, const TypeID& struc
return out;
}
if (out.base_type == Type::Struct) {
for (size_t nested_item_index = 0; nested_item_index < item_type.member_types.size(); nested_item_index++) {
for (uint32_t nested_item_index = 0; nested_item_index < item_type.member_types.size(); nested_item_index++) {
const Type nested_type = parse_struct_item(compiler, item_type_id, nested_item_index, out_error);
if (out_error.valid()) {
return out;
Expand All @@ -441,7 +459,7 @@ Type Reflection::parse_toplevel_struct(const Compiler& compiler, const TypeID& s
}
out.base_type = Type::Struct;
out.size = (int) compiler.get_declared_struct_size_runtime_array(struct_type, 1);
for (size_t item_index = 0; item_index < struct_type.member_types.size(); item_index++) {
for (uint32_t item_index = 0; item_index < struct_type.member_types.size(); item_index++) {
const Type item_type = parse_struct_item(compiler, struct_type_id, item_index, out_error);
if (out_error.valid()) {
return out;
Expand All @@ -451,4 +469,21 @@ Type Reflection::parse_toplevel_struct(const Compiler& compiler, const TypeID& s
return out;
}

void Reflection::dump_debug(ErrMsg::Format err_fmt) const {
const std::string indent = " ";
const std::string indent2 = indent + " ";
fmt::print(stderr, "Reflection:\n");
if (error.valid()) {
fmt::print(stderr, "{}error: {}\n", indent, error.as_string(err_fmt));
} else {
fmt::print(stderr, "{}error: not set\n", indent);
}
fmt::print(stderr, "{}merged bindings:\n", indent);
bindings.dump_debug(indent2);
fmt::print(stderr, "{}programs:\n", indent);
for (const auto& prog: progs) {
prog.dump_debug(indent2);
}
}

} // namespace
12 changes: 8 additions & 4 deletions src/shdc/reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@ struct Reflection {
static Reflection build(const Args& args, const Input& inp, const std::array<Spirvcross,Slang::Num>& spirvcross);
// parse per-snippet reflection info for a compiled shader source
static StageReflection parse_snippet_reflection(const spirv_cross::Compiler& compiler, const Snippet& snippet, Slang::Enum slang, ErrMsg& out_error);
// print a debug dump to stderr
void dump_debug(ErrMsg::Format err_fmt) const;

private:
// create a set of unique resource bindings from shader snippet input bindings
static Bindings merge_bindings(const std::vector<Bindings>& in_bindings, ErrMsg& out_error);
// parse a struct
static Type parse_toplevel_struct(const spirv_cross::Compiler& compiler, const spirv_cross::TypeID& type_id, const std::string& name, ErrMsg& out_error);
// parse a struct item
static Type parse_struct_item(const spirv_cross::Compiler& compiler, const spirv_cross::TypeID& struct_type_id, uint32_t item_index, ErrMsg& out_error);

private:
// create a set of unique resource bindings from shader snippet input bindings
static Bindings merge_bindings(const std::vector<Bindings>& in_bindings, const std::string& inp_base_path, ErrMsg& out_error);
// debug-dump a bindings struct
static void dump_bindings(const std::string& indent, const Bindings& bindings);
};

} // namespace reflection
37 changes: 0 additions & 37 deletions src/shdc/spirvcross.cc
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,6 @@ Spirvcross Spirvcross::translate(const Input& inp, const Spirv& spirv, Slang::En
return spv_cross;
}

// FIXME: most of this should go into Reflection::dump_debug()
void Spirvcross::dump_debug(ErrMsg::Format err_fmt, Slang::Enum slang) const {
fmt::print(stderr, "Spirvcross ({}):\n", Slang::to_str(slang));
if (error.valid()) {
Expand All @@ -504,42 +503,6 @@ void Spirvcross::dump_debug(ErrMsg::Format err_fmt, Slang::Enum slang) const {
for (const std::string& line: lines) {
fmt::print(stderr, " {}\n", line);
}
fmt::print(stderr, " reflection for snippet {}:\n", source.snippet_index);
fmt::print(stderr, " stage: {}\n", source.stage_refl.stage_name);
fmt::print(stderr, " entry: {}\n", source.stage_refl.entry_point);
fmt::print(stderr, " inputs:\n");
for (const StageAttr& attr: source.stage_refl.inputs) {
if (attr.slot >= 0) {
fmt::print(stderr, " {}: slot={}, sem_name={}, sem_index={}\n", attr.name, attr.slot, attr.sem_name, attr.sem_index);
}
}
fmt::print(stderr, " outputs:\n");
for (const StageAttr& attr: source.stage_refl.outputs) {
if (attr.slot >= 0) {
fmt::print(stderr, " {}: slot={}, sem_name={}, sem_index={}\n", attr.name, attr.slot, attr.sem_name, attr.sem_index);
}
}
for (const UniformBlock& ub: source.stage_refl.bindings.uniform_blocks) {
fmt::print(stderr, " uniform block: {}, slot: {}, size: {}\n", ub.struct_name, ub.slot, ub.size);
for (const Uniform& uniform: ub.uniforms) {
fmt::print(stderr, " member: {}, type: {}, array_count: {}, offset: {}\n",
uniform.name,
Uniform::type_to_str(uniform.type),
uniform.array_count,
uniform.offset);
}
}
for (const Image& img: source.stage_refl.bindings.images) {
fmt::print(stderr, " image: {}, slot: {}, type: {}, sampletype: {}\n",
img.name, img.slot, ImageType::to_str(img.type), ImageSampleType::to_str(img.sample_type));
}
for (const Sampler& smp: source.stage_refl.bindings.samplers) {
fmt::print(stderr, " sampler: {}, slot: {}\n", smp.name, smp.slot);
}
for (const ImageSampler& img_smp: source.stage_refl.bindings.image_samplers) {
fmt::print(stderr, " image sampler: {}, slot: {}, image: {}, sampler: {}\n",
img_smp.name, img_smp.slot, img_smp.image_name, img_smp.sampler_name);
}
fmt::print(stderr, "\n");
}
fmt::print(stderr, "\n");
Expand Down
61 changes: 53 additions & 8 deletions src/shdc/types/reflection/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,40 @@ struct Bindings {
std::vector<ImageSampler> image_samplers;

const UniformBlock* find_uniform_block_by_slot(int slot) const;
const StorageBuffer* find_storage_buffer_by_slot(int slot) const;
const Image* find_image_by_slot(int slot) const;
const Sampler* find_sampler_by_slot(int slot) const;
const ImageSampler* find_image_sampler_by_slot(int slot) const;

const UniformBlock* find_uniform_block_by_name(const std::string& name) const;
const StorageBuffer* find_storage_buffer_by_name(const std::string& name) const;
const Image* find_image_by_name(const std::string& name) const;
const Sampler* find_sampler_by_name(const std::string& name) const;
const ImageSampler* find_image_sampler_by_name(const std::string& name) const;

void dump_debug(const std::string& indent) const;
};

inline const UniformBlock* Bindings::find_uniform_block_by_slot(int slot) const {
for (const UniformBlock& ub: this->uniform_blocks) {
for (const UniformBlock& ub: uniform_blocks) {
if (ub.slot == slot) {
return &ub;
}
}
return nullptr;
}

inline const StorageBuffer* Bindings::find_storage_buffer_by_slot(int slot) const {
for (const StorageBuffer& sbuf: storage_buffers) {
if (sbuf.slot == slot) {
return &sbuf;
}
}
return nullptr;
}

inline const Image* Bindings::find_image_by_slot(int slot) const {
for (const Image& img: this->images) {
for (const Image& img: images) {
if (img.slot == slot) {
return &img;
}
Expand All @@ -44,7 +57,7 @@ inline const Image* Bindings::find_image_by_slot(int slot) const {
}

inline const Sampler* Bindings::find_sampler_by_slot(int slot) const {
for (const Sampler& smp: this->samplers) {
for (const Sampler& smp: samplers) {
if (smp.slot == slot) {
return &smp;
}
Expand All @@ -53,7 +66,7 @@ inline const Sampler* Bindings::find_sampler_by_slot(int slot) const {
}

inline const ImageSampler* Bindings::find_image_sampler_by_slot(int slot) const {
for (const ImageSampler& img_smp: this->image_samplers) {
for (const ImageSampler& img_smp: image_samplers) {
if (img_smp.slot == slot) {
return &img_smp;
}
Expand All @@ -62,16 +75,25 @@ inline const ImageSampler* Bindings::find_image_sampler_by_slot(int slot) const
}

inline const UniformBlock* Bindings::find_uniform_block_by_name(const std::string& name) const {
for (const UniformBlock& ub: this->uniform_blocks) {
for (const UniformBlock& ub: uniform_blocks) {
if (ub.struct_name == name) {
return &ub;
}
}
return nullptr;
}

inline const StorageBuffer* Bindings::find_storage_buffer_by_name(const std::string& name) const {
for (const StorageBuffer& sbuf: storage_buffers) {
if (sbuf.struct_refl.name == name) {
return &sbuf;
}
}
return nullptr;
}

inline const Image* Bindings::find_image_by_name(const std::string& name) const {
for (const Image& img: this->images) {
for (const Image& img: images) {
if (img.name == name) {
return &img;
}
Expand All @@ -80,7 +102,7 @@ inline const Image* Bindings::find_image_by_name(const std::string& name) const
}

inline const Sampler* Bindings::find_sampler_by_name(const std::string& name) const {
for (const Sampler& smp: this->samplers) {
for (const Sampler& smp: samplers) {
if (smp.name == name) {
return &smp;
}
Expand All @@ -89,12 +111,35 @@ inline const Sampler* Bindings::find_sampler_by_name(const std::string& name) co
}

inline const ImageSampler* Bindings::find_image_sampler_by_name(const std::string& name) const {
for (const ImageSampler& img_smp: this->image_samplers) {
for (const ImageSampler& img_smp: image_samplers) {
if (img_smp.name == name) {
return &img_smp;
}
}
return nullptr;
}

inline void Bindings::dump_debug(const std::string& indent) const {
fmt::print(stderr, "{}uniform_blocks:\n", indent);
for (const auto& ub: uniform_blocks) {
ub.dump_debug(indent);
}
fmt::print(stderr, "{}storage_buffers:\n", indent);
for (const auto& sbuf: storage_buffers) {
sbuf.dump_debug(indent);
}
fmt::print(stderr, "{}images:\n", indent);
for (const auto& img: images) {
img.dump_debug(indent);
}
fmt::print(stderr, "{}samplers:\n", indent);
for (const auto& smp: samplers) {
smp.dump_debug(indent);
}
fmt::print(stderr, "{}image_samplers:\n", indent);
for (const auto& img_smp: image_samplers) {
img_smp.dump_debug(indent);
}
}

} // namespace
Loading

0 comments on commit 3652d35

Please # to comment.