diff --git a/format_all.sh b/format_all.sh index d053acf4..05efeb3e 100755 --- a/format_all.sh +++ b/format_all.sh @@ -1,6 +1,6 @@ #!/bin/bash -for file in spirv_*.{cpp,hpp} include/spirv_cross/*.{hpp,h} samples/cpp/*.cpp +for file in spirv_*.{cpp,hpp} include/spirv_cross/*.{hpp,h} samples/cpp/*.cpp main.cpp do echo "Formatting file: $file ..." clang-format -style=file -i $file diff --git a/main.cpp b/main.cpp index bffa229d..a9c368c0 100644 --- a/main.cpp +++ b/main.cpp @@ -16,13 +16,14 @@ #include "spirv_cpp.hpp" #include "spirv_msl.hpp" +#include #include -#include +#include #include #include #include +#include #include -#include #include using namespace spv; @@ -32,182 +33,185 @@ using namespace std; struct CLIParser; struct CLICallbacks { - void add(const char *cli, const function &func) - { - callbacks[cli] = func; - } - unordered_map> callbacks; - function error_handler; - function default_handler; + void add(const char *cli, const function &func) + { + callbacks[cli] = func; + } + unordered_map> callbacks; + function error_handler; + function default_handler; }; struct CLIParser { - CLIParser(CLICallbacks cbs_, int argc_, char *argv_[]) - : cbs(move(cbs_)), argc(argc_), argv(argv_) - {} + CLIParser(CLICallbacks cbs_, int argc_, char *argv_[]) + : cbs(move(cbs_)) + , argc(argc_) + , argv(argv_) + { + } - bool parse() - { - try - { - while (argc && !ended_state) - { - const char *next = *argv++; - argc--; + bool parse() + { + try + { + while (argc && !ended_state) + { + const char *next = *argv++; + argc--; - if (*next != '-' && cbs.default_handler) - { - cbs.default_handler(next); - } - else - { - auto itr = cbs.callbacks.find(next); - if (itr == ::end(cbs.callbacks)) - { - throw logic_error("Invalid argument.\n"); - } + if (*next != '-' && cbs.default_handler) + { + cbs.default_handler(next); + } + else + { + auto itr = cbs.callbacks.find(next); + if (itr == ::end(cbs.callbacks)) + { + throw logic_error("Invalid argument.\n"); + } - itr->second(*this); - } - } + itr->second(*this); + } + } - return true; - } - catch (...) - { - if (cbs.error_handler) - { - cbs.error_handler(); - } - return false; - } - } + return true; + } + catch (...) + { + if (cbs.error_handler) + { + cbs.error_handler(); + } + return false; + } + } - void end() - { - ended_state = true; - } + void end() + { + ended_state = true; + } - uint32_t next_uint() - { - if (!argc) - { - throw logic_error("Tried to parse uint, but nothing left in arguments.\n"); - } + uint32_t next_uint() + { + if (!argc) + { + throw logic_error("Tried to parse uint, but nothing left in arguments.\n"); + } - uint32_t val = stoul(*argv); - if (val > numeric_limits::max()) - { - throw out_of_range("next_uint() out of range.\n"); - } + uint32_t val = stoul(*argv); + if (val > numeric_limits::max()) + { + throw out_of_range("next_uint() out of range.\n"); + } - argc--; - argv++; + argc--; + argv++; - return val; - } + return val; + } - double next_double() - { - if (!argc) - { - throw logic_error("Tried to parse double, but nothing left in arguments.\n"); - } + double next_double() + { + if (!argc) + { + throw logic_error("Tried to parse double, but nothing left in arguments.\n"); + } - double val = stod(*argv); + double val = stod(*argv); - argc--; - argv++; + argc--; + argv++; - return val; - } + return val; + } - const char *next_string() - { - if (!argc) - { - throw logic_error("Tried to parse string, but nothing left in arguments.\n"); - } + const char *next_string() + { + if (!argc) + { + throw logic_error("Tried to parse string, but nothing left in arguments.\n"); + } - const char *ret = *argv; - argc--; - argv++; - return ret; - } + const char *ret = *argv; + argc--; + argv++; + return ret; + } - CLICallbacks cbs; - int argc; - char **argv; - bool ended_state = false; + CLICallbacks cbs; + int argc; + char **argv; + bool ended_state = false; }; static vector read_spirv_file(const char *path) { - FILE *file = fopen(path, "rb"); - if (!file) - { - fprintf(stderr, "Failed to open SPIRV file: %s\n", path); - return {}; - } + FILE *file = fopen(path, "rb"); + if (!file) + { + fprintf(stderr, "Failed to open SPIRV file: %s\n", path); + return {}; + } - fseek(file, 0, SEEK_END); - long len = ftell(file) / sizeof(uint32_t); - rewind(file); + fseek(file, 0, SEEK_END); + long len = ftell(file) / sizeof(uint32_t); + rewind(file); - vector spirv(len); - if (fread(spirv.data(), sizeof(uint32_t), len, file) != size_t(len)) - spirv.clear(); + vector spirv(len); + if (fread(spirv.data(), sizeof(uint32_t), len, file) != size_t(len)) + spirv.clear(); - fclose(file); - return spirv; + fclose(file); + return spirv; } static bool write_string_to_file(const char *path, const char *string) { - FILE *file = fopen(path, "w"); - if (!file) - { - fprintf(file, "Failed to write file: %s\n", path); - return false; - } + FILE *file = fopen(path, "w"); + if (!file) + { + fprintf(file, "Failed to write file: %s\n", path); + return false; + } - fprintf(file, "%s", string); - fclose(file); - return true; + fprintf(file, "%s", string); + fclose(file); + return true; } static void print_resources(const Compiler &compiler, const char *tag, const vector &resources) { - fprintf(stderr, "%s\n", tag); - fprintf(stderr, "=============\n\n"); - for (auto &res : resources) - { - auto &type = compiler.get_type(res.type_id); - auto mask = compiler.get_decoration_mask(res.id); + fprintf(stderr, "%s\n", tag); + fprintf(stderr, "=============\n\n"); + for (auto &res : resources) + { + auto &type = compiler.get_type(res.type_id); + auto mask = compiler.get_decoration_mask(res.id); - // If we don't have a name, use the fallback for the type instead of the variable - // for SSBOs and UBOs since those are the only meaningful names to use externally. - // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks. - bool is_push_constant = compiler.get_storage_class(res.id) == StorageClassPushConstant; - bool is_block = (compiler.get_decoration_mask(type.self) & - ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0; - uint32_t fallback_id = !is_push_constant && is_block ? res.type_id : res.id; + // If we don't have a name, use the fallback for the type instead of the variable + // for SSBOs and UBOs since those are the only meaningful names to use externally. + // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks. + bool is_push_constant = compiler.get_storage_class(res.id) == StorageClassPushConstant; + bool is_block = (compiler.get_decoration_mask(type.self) & + ((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0; + uint32_t fallback_id = !is_push_constant && is_block ? res.type_id : res.id; - fprintf(stderr, " ID %03u : %s", res.id, - !res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str()); + fprintf(stderr, " ID %03u : %s", res.id, + !res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str()); - if (mask & (1ull << DecorationLocation)) - fprintf(stderr, " (Location : %u)", compiler.get_decoration(res.id, DecorationLocation)); - if (mask & (1ull << DecorationDescriptorSet)) - fprintf(stderr, " (Set : %u)", compiler.get_decoration(res.id, DecorationDescriptorSet)); - if (mask & (1ull << DecorationBinding)) - fprintf(stderr, " (Binding : %u)", compiler.get_decoration(res.id, DecorationBinding)); - if (mask & (1ull << DecorationInputAttachmentIndex)) - fprintf(stderr, " (Attachment : %u)", compiler.get_decoration(res.id, DecorationInputAttachmentIndex)); - fprintf(stderr, "\n"); - } - fprintf(stderr, "=============\n\n"); + if (mask & (1ull << DecorationLocation)) + fprintf(stderr, " (Location : %u)", compiler.get_decoration(res.id, DecorationLocation)); + if (mask & (1ull << DecorationDescriptorSet)) + fprintf(stderr, " (Set : %u)", compiler.get_decoration(res.id, DecorationDescriptorSet)); + if (mask & (1ull << DecorationBinding)) + fprintf(stderr, " (Binding : %u)", compiler.get_decoration(res.id, DecorationBinding)); + if (mask & (1ull << DecorationInputAttachmentIndex)) + fprintf(stderr, " (Attachment : %u)", compiler.get_decoration(res.id, DecorationInputAttachmentIndex)); + fprintf(stderr, "\n"); + } + fprintf(stderr, "=============\n\n"); } static void print_resources(const Compiler &compiler, const ShaderResources &res) @@ -227,278 +231,354 @@ static void print_resources(const Compiler &compiler, const ShaderResources &res switch (static_cast(i)) { - case ExecutionModeInvocations: - fprintf(stderr, " Invocations: %u\n", arg0); - break; + case ExecutionModeInvocations: + fprintf(stderr, " Invocations: %u\n", arg0); + break; - case ExecutionModeLocalSize: - fprintf(stderr, " LocalSize: (%u, %u, %u)\n", arg0, arg1, arg2); - break; + case ExecutionModeLocalSize: + fprintf(stderr, " LocalSize: (%u, %u, %u)\n", arg0, arg1, arg2); + break; - case ExecutionModeOutputVertices: - fprintf(stderr, " OutputVertices: %u\n", arg0); - break; + case ExecutionModeOutputVertices: + fprintf(stderr, " OutputVertices: %u\n", arg0); + break; -#define CHECK_MODE(m) case ExecutionMode##m: fprintf(stderr, " %s\n", #m); break - CHECK_MODE(SpacingEqual); - CHECK_MODE(SpacingFractionalEven); - CHECK_MODE(SpacingFractionalOdd); - CHECK_MODE(VertexOrderCw); - CHECK_MODE(VertexOrderCcw); - CHECK_MODE(PixelCenterInteger); - CHECK_MODE(OriginUpperLeft); - CHECK_MODE(OriginLowerLeft); - CHECK_MODE(EarlyFragmentTests); - CHECK_MODE(PointMode); - CHECK_MODE(Xfb); - CHECK_MODE(DepthReplacing); - CHECK_MODE(DepthGreater); - CHECK_MODE(DepthLess); - CHECK_MODE(DepthUnchanged); - CHECK_MODE(LocalSizeHint); - CHECK_MODE(InputPoints); - CHECK_MODE(InputLines); - CHECK_MODE(InputLinesAdjacency); - CHECK_MODE(Triangles); - CHECK_MODE(InputTrianglesAdjacency); - CHECK_MODE(Quads); - CHECK_MODE(Isolines); - CHECK_MODE(OutputPoints); - CHECK_MODE(OutputLineStrip); - CHECK_MODE(OutputTriangleStrip); - CHECK_MODE(VecTypeHint); - CHECK_MODE(ContractionOff); +#define CHECK_MODE(m) \ + case ExecutionMode##m: \ + fprintf(stderr, " %s\n", #m); \ + break + CHECK_MODE(SpacingEqual); + CHECK_MODE(SpacingFractionalEven); + CHECK_MODE(SpacingFractionalOdd); + CHECK_MODE(VertexOrderCw); + CHECK_MODE(VertexOrderCcw); + CHECK_MODE(PixelCenterInteger); + CHECK_MODE(OriginUpperLeft); + CHECK_MODE(OriginLowerLeft); + CHECK_MODE(EarlyFragmentTests); + CHECK_MODE(PointMode); + CHECK_MODE(Xfb); + CHECK_MODE(DepthReplacing); + CHECK_MODE(DepthGreater); + CHECK_MODE(DepthLess); + CHECK_MODE(DepthUnchanged); + CHECK_MODE(LocalSizeHint); + CHECK_MODE(InputPoints); + CHECK_MODE(InputLines); + CHECK_MODE(InputLinesAdjacency); + CHECK_MODE(Triangles); + CHECK_MODE(InputTrianglesAdjacency); + CHECK_MODE(Quads); + CHECK_MODE(Isolines); + CHECK_MODE(OutputPoints); + CHECK_MODE(OutputLineStrip); + CHECK_MODE(OutputTriangleStrip); + CHECK_MODE(VecTypeHint); + CHECK_MODE(ContractionOff); - default: - break; + default: + break; } } fprintf(stderr, "\n"); - print_resources(compiler, "subpass inputs", res.subpass_inputs); - print_resources(compiler, "inputs", res.stage_inputs); - print_resources(compiler, "outputs", res.stage_outputs); - print_resources(compiler, "textures", res.sampled_images); - print_resources(compiler, "images", res.storage_images); - print_resources(compiler, "ssbos", res.storage_buffers); - print_resources(compiler, "ubos", res.uniform_buffers); - print_resources(compiler, "push", res.push_constant_buffers); - print_resources(compiler, "counters", res.atomic_counters); + print_resources(compiler, "subpass inputs", res.subpass_inputs); + print_resources(compiler, "inputs", res.stage_inputs); + print_resources(compiler, "outputs", res.stage_outputs); + print_resources(compiler, "textures", res.sampled_images); + print_resources(compiler, "images", res.storage_images); + print_resources(compiler, "ssbos", res.storage_buffers); + print_resources(compiler, "ubos", res.uniform_buffers); + print_resources(compiler, "push", res.push_constant_buffers); + print_resources(compiler, "counters", res.atomic_counters); } static void print_push_constant_resources(const Compiler &compiler, const vector &res) { - for (auto &block : res) - { - auto ranges = compiler.get_active_buffer_ranges(block.id); - fprintf(stderr, "Active members in buffer: %s\n", - !block.name.empty() ? block.name.c_str() : compiler.get_fallback_name(block.id).c_str()); + for (auto &block : res) + { + auto ranges = compiler.get_active_buffer_ranges(block.id); + fprintf(stderr, "Active members in buffer: %s\n", + !block.name.empty() ? block.name.c_str() : compiler.get_fallback_name(block.id).c_str()); - fprintf(stderr, "==================\n\n"); - for (auto &range : ranges) - { - const auto &name = compiler.get_member_name(block.type_id, range.index); + fprintf(stderr, "==================\n\n"); + for (auto &range : ranges) + { + const auto &name = compiler.get_member_name(block.type_id, range.index); - fprintf(stderr, "Member #%3u (%s): Offset: %4u, Range: %4u\n", - range.index, !name.empty() ? name.c_str() : compiler.get_fallback_member_name(range.index).c_str(), - unsigned(range.offset), unsigned(range.range)); - } - fprintf(stderr, "==================\n\n"); - } + fprintf(stderr, "Member #%3u (%s): Offset: %4u, Range: %4u\n", range.index, + !name.empty() ? name.c_str() : compiler.get_fallback_member_name(range.index).c_str(), + unsigned(range.offset), unsigned(range.range)); + } + fprintf(stderr, "==================\n\n"); + } } struct PLSArg { - PlsFormat format; - string name; + PlsFormat format; + string name; +}; + +struct Remap +{ + string src_name; + string dst_name; + unsigned components; }; struct CLIArguments { - const char *input = nullptr; - const char *output = nullptr; - const char *cpp_interface_name = nullptr; - uint32_t version = 0; - bool es = false; - bool set_version = false; - bool set_es = false; - bool dump_resources = false; - bool force_temporary = false; - bool flatten_ubo = false; - bool fixup = false; - vector pls_in; - vector pls_out; + const char *input = nullptr; + const char *output = nullptr; + const char *cpp_interface_name = nullptr; + uint32_t version = 0; + bool es = false; + bool set_version = false; + bool set_es = false; + bool dump_resources = false; + bool force_temporary = false; + bool flatten_ubo = false; + bool fixup = false; + vector pls_in; + vector pls_out; + vector remaps; + vector extensions; - uint32_t iterations = 1; - bool cpp = false; - bool metal = false; - bool vulkan_semantics = false; + uint32_t iterations = 1; + bool cpp = false; + bool metal = false; + bool vulkan_semantics = false; }; static void print_help() { - fprintf(stderr, "Usage: spirv-cross [--output ] [SPIR-V file] [--es] [--no-es] [--version ] [--dump-resources] [--help] [--force-temporary] [--cpp] [--cpp-interface-name ] [--metal] [--vulkan-semantics] [--flatten-ubo] [--fixup-clipspace] [--iterations iter] [--pls-in format input-name] [--pls-out format output-name]\n"); + fprintf(stderr, "Usage: spirv-cross [--output ] [SPIR-V file] [--es] [--no-es] [--version ] [--dump-resources] [--help] [--force-temporary] [--cpp] [--cpp-interface-name ] " + "[--metal] [--vulkan-semantics] [--flatten-ubo] [--fixup-clipspace] [--iterations iter] [--pls-in " + "format input-name] [--pls-out format output-name] [--remap source_name target_name components] " + "[--extension ext]\n"); } -static vector remap_pls(const vector &pls_variables, const vector &resources, const vector *secondary_resources) +static bool remap_generic(Compiler &compiler, const vector &resources, const Remap &remap) { - vector ret; + auto itr = + find_if(begin(resources), end(resources), [&remap](const Resource &res) { return res.name == remap.src_name; }); - for (auto &pls : pls_variables) - { - bool found = false; - for (auto &res : resources) - { - if (res.name == pls.name) - { - ret.push_back({ res.id, pls.format }); - found = true; - break; - } - } + if (itr != end(resources)) + { + compiler.set_remapped_variable_state(itr->id, true); + compiler.set_name(itr->id, remap.dst_name); + compiler.set_subpass_input_remapped_components(itr->id, remap.components); + return true; + } + else + return false; +} - if (!found && secondary_resources) - { - for (auto &res : *secondary_resources) - { - if (res.name == pls.name) - { - ret.push_back({ res.id, pls.format }); - found = true; - break; - } - } - } +static vector remap_pls(const vector &pls_variables, const vector &resources, + const vector *secondary_resources) +{ + vector ret; - if (!found) - fprintf(stderr, "Did not find stage input/output/target with name \"%s\".\n", - pls.name.c_str()); - } + for (auto &pls : pls_variables) + { + bool found = false; + for (auto &res : resources) + { + if (res.name == pls.name) + { + ret.push_back({ res.id, pls.format }); + found = true; + break; + } + } - return ret; + if (!found && secondary_resources) + { + for (auto &res : *secondary_resources) + { + if (res.name == pls.name) + { + ret.push_back({ res.id, pls.format }); + found = true; + break; + } + } + } + + if (!found) + fprintf(stderr, "Did not find stage input/output/target with name \"%s\".\n", pls.name.c_str()); + } + + return ret; } static PlsFormat pls_format(const char *str) { - if (!strcmp(str, "r11f_g11f_b10f")) return PlsR11FG11FB10F; - else if (!strcmp(str, "r32f")) return PlsR32F; - else if (!strcmp(str, "rg16f")) return PlsRG16F; - else if (!strcmp(str, "rg16")) return PlsRG16; - else if (!strcmp(str, "rgb10_a2")) return PlsRGB10A2; - else if (!strcmp(str, "rgba8")) return PlsRGBA8; - else if (!strcmp(str, "rgba8i")) return PlsRGBA8I; - else if (!strcmp(str, "rgba8ui")) return PlsRGBA8UI; - else if (!strcmp(str, "rg16i")) return PlsRG16I; - else if (!strcmp(str, "rgb10_a2ui")) return PlsRGB10A2UI; - else if (!strcmp(str, "rg16ui")) return PlsRG16UI; - else if (!strcmp(str, "r32ui")) return PlsR32UI; - else return PlsNone; + if (!strcmp(str, "r11f_g11f_b10f")) + return PlsR11FG11FB10F; + else if (!strcmp(str, "r32f")) + return PlsR32F; + else if (!strcmp(str, "rg16f")) + return PlsRG16F; + else if (!strcmp(str, "rg16")) + return PlsRG16; + else if (!strcmp(str, "rgb10_a2")) + return PlsRGB10A2; + else if (!strcmp(str, "rgba8")) + return PlsRGBA8; + else if (!strcmp(str, "rgba8i")) + return PlsRGBA8I; + else if (!strcmp(str, "rgba8ui")) + return PlsRGBA8UI; + else if (!strcmp(str, "rg16i")) + return PlsRG16I; + else if (!strcmp(str, "rgb10_a2ui")) + return PlsRGB10A2UI; + else if (!strcmp(str, "rg16ui")) + return PlsRG16UI; + else if (!strcmp(str, "r32ui")) + return PlsR32UI; + else + return PlsNone; } int main(int argc, char *argv[]) { - CLIArguments args; - CLICallbacks cbs; + CLIArguments args; + CLICallbacks cbs; - cbs.add("--help", [](CLIParser &parser) { print_help(); parser.end(); }); - cbs.add("--output", [&args](CLIParser &parser) { args.output = parser.next_string(); }); - cbs.add("--es", [&args](CLIParser &) { args.es = true; args.set_es = true; }); - cbs.add("--no-es", [&args](CLIParser &) { args.es = false; args.set_es = true; }); - cbs.add("--version", [&args](CLIParser &parser) { args.version = parser.next_uint(); args.set_version = true; }); - cbs.add("--dump-resources", [&args](CLIParser &) { args.dump_resources = true; }); - cbs.add("--force-temporary", [&args](CLIParser &) { args.force_temporary = true; }); - cbs.add("--flatten-ubo", [&args](CLIParser &) { args.flatten_ubo = true; }); - cbs.add("--fixup-clipspace", [&args](CLIParser &) { args.fixup = true; }); - cbs.add("--iterations", [&args](CLIParser &parser) { args.iterations = parser.next_uint(); }); - cbs.add("--cpp", [&args](CLIParser &) { args.cpp = true; }); - cbs.add("--cpp-interface-name", [&args](CLIParser &parser) { args.cpp_interface_name = parser.next_string(); }); - cbs.add("--metal", [&args](CLIParser &) { args.metal = true; }); - cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; }); + cbs.add("--help", [](CLIParser &parser) { + print_help(); + parser.end(); + }); + cbs.add("--output", [&args](CLIParser &parser) { args.output = parser.next_string(); }); + cbs.add("--es", [&args](CLIParser &) { + args.es = true; + args.set_es = true; + }); + cbs.add("--no-es", [&args](CLIParser &) { + args.es = false; + args.set_es = true; + }); + cbs.add("--version", [&args](CLIParser &parser) { + args.version = parser.next_uint(); + args.set_version = true; + }); + cbs.add("--dump-resources", [&args](CLIParser &) { args.dump_resources = true; }); + cbs.add("--force-temporary", [&args](CLIParser &) { args.force_temporary = true; }); + cbs.add("--flatten-ubo", [&args](CLIParser &) { args.flatten_ubo = true; }); + cbs.add("--fixup-clipspace", [&args](CLIParser &) { args.fixup = true; }); + cbs.add("--iterations", [&args](CLIParser &parser) { args.iterations = parser.next_uint(); }); + cbs.add("--cpp", [&args](CLIParser &) { args.cpp = true; }); + cbs.add("--cpp-interface-name", [&args](CLIParser &parser) { args.cpp_interface_name = parser.next_string(); }); + cbs.add("--metal", [&args](CLIParser &) { args.metal = true; }); + cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; }); + cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); }); + cbs.add("--remap", [&args](CLIParser &parser) { + string src = parser.next_string(); + string dst = parser.next_string(); + uint32_t components = parser.next_uint(); + args.remaps.push_back({ move(src), move(dst), components }); + }); - cbs.add("--pls-in", [&args](CLIParser &parser) { - auto fmt = pls_format(parser.next_string()); - auto name = parser.next_string(); - args.pls_in.push_back({ move(fmt), move(name) }); - }); - cbs.add("--pls-out", [&args](CLIParser &parser) { - auto fmt = pls_format(parser.next_string()); - auto name = parser.next_string(); - args.pls_out.push_back({ move(fmt), move(name) }); - }); + cbs.add("--pls-in", [&args](CLIParser &parser) { + auto fmt = pls_format(parser.next_string()); + auto name = parser.next_string(); + args.pls_in.push_back({ move(fmt), move(name) }); + }); + cbs.add("--pls-out", [&args](CLIParser &parser) { + auto fmt = pls_format(parser.next_string()); + auto name = parser.next_string(); + args.pls_out.push_back({ move(fmt), move(name) }); + }); - cbs.default_handler = [&args](const char *value) { args.input = value; }; - cbs.error_handler = []{ print_help(); }; + cbs.default_handler = [&args](const char *value) { args.input = value; }; + cbs.error_handler = [] { print_help(); }; - CLIParser parser{move(cbs), argc - 1, argv + 1}; - if (!parser.parse()) - { - return EXIT_FAILURE; - } - else if (parser.ended_state) - { - return EXIT_SUCCESS; - } + CLIParser parser{ move(cbs), argc - 1, argv + 1 }; + if (!parser.parse()) + { + return EXIT_FAILURE; + } + else if (parser.ended_state) + { + return EXIT_SUCCESS; + } - if (!args.input) - { - fprintf(stderr, "Didn't specify input file.\n"); - print_help(); - return EXIT_FAILURE; - } + if (!args.input) + { + fprintf(stderr, "Didn't specify input file.\n"); + print_help(); + return EXIT_FAILURE; + } - unique_ptr compiler; + unique_ptr compiler; - if (args.cpp) - { - compiler = unique_ptr(new CompilerCPP(read_spirv_file(args.input))); - if (args.cpp_interface_name) - static_cast(compiler.get())->set_interface_name(args.cpp_interface_name); - } - else if (args.metal) - compiler = unique_ptr(new CompilerMSL(read_spirv_file(args.input))); - else - compiler = unique_ptr(new CompilerGLSL(read_spirv_file(args.input))); + if (args.cpp) + { + compiler = unique_ptr(new CompilerCPP(read_spirv_file(args.input))); + if (args.cpp_interface_name) + static_cast(compiler.get())->set_interface_name(args.cpp_interface_name); + } + else if (args.metal) + compiler = unique_ptr(new CompilerMSL(read_spirv_file(args.input))); + else + compiler = unique_ptr(new CompilerGLSL(read_spirv_file(args.input))); - if (!args.set_version && !compiler->get_options().version) - { - fprintf(stderr, "Didn't specify GLSL version and SPIR-V did not specify language.\n"); - print_help(); - return EXIT_FAILURE; - } + if (!args.set_version && !compiler->get_options().version) + { + fprintf(stderr, "Didn't specify GLSL version and SPIR-V did not specify language.\n"); + print_help(); + return EXIT_FAILURE; + } - CompilerGLSL::Options opts = compiler->get_options(); - if (args.set_version) - opts.version = args.version; - if (args.set_es) - opts.es = args.es; - opts.force_temporary = args.force_temporary; - opts.vulkan_semantics = args.vulkan_semantics; - opts.vertex.fixup_clipspace = args.fixup; - compiler->set_options(opts); + CompilerGLSL::Options opts = compiler->get_options(); + if (args.set_version) + opts.version = args.version; + if (args.set_es) + opts.es = args.es; + opts.force_temporary = args.force_temporary; + opts.vulkan_semantics = args.vulkan_semantics; + opts.vertex.fixup_clipspace = args.fixup; + compiler->set_options(opts); - auto res = compiler->get_shader_resources(); + auto res = compiler->get_shader_resources(); - if (args.flatten_ubo) - for (auto &ubo : res.uniform_buffers) - compiler->flatten_interface_block(ubo.id); + if (args.flatten_ubo) + for (auto &ubo : res.uniform_buffers) + compiler->flatten_interface_block(ubo.id); - auto pls_inputs = remap_pls(args.pls_in, res.stage_inputs, &res.subpass_inputs); - auto pls_outputs = remap_pls(args.pls_out, res.stage_outputs, nullptr); - compiler->remap_pixel_local_storage(move(pls_inputs), move(pls_outputs)); + auto pls_inputs = remap_pls(args.pls_in, res.stage_inputs, &res.subpass_inputs); + auto pls_outputs = remap_pls(args.pls_out, res.stage_outputs, nullptr); + compiler->remap_pixel_local_storage(move(pls_inputs), move(pls_outputs)); - if (args.dump_resources) - { - print_resources(*compiler, res); - print_push_constant_resources(*compiler, res.push_constant_buffers); - } + for (auto &ext : args.extensions) + compiler->require_extension(ext); - string glsl; - for (uint32_t i = 0; i < args.iterations; i++) - glsl = compiler->compile(); + for (auto &remap : args.remaps) + { + if (remap_generic(*compiler, res.stage_inputs, remap)) + continue; + if (remap_generic(*compiler, res.stage_outputs, remap)) + continue; + if (remap_generic(*compiler, res.subpass_inputs, remap)) + continue; + } - if (args.output) - write_string_to_file(args.output, glsl.c_str()); - else - printf("%s", glsl.c_str()); + if (args.dump_resources) + { + print_resources(*compiler, res); + print_push_constant_resources(*compiler, res.push_constant_buffers); + } + + string glsl; + for (uint32_t i = 0; i < args.iterations; i++) + glsl = compiler->compile(); + + if (args.output) + write_string_to_file(args.output, glsl.c_str()); + else + printf("%s", glsl.c_str()); } - diff --git a/spirv_common.hpp b/spirv_common.hpp index f81b5a4a..f7d3f30d 100644 --- a/spirv_common.hpp +++ b/spirv_common.hpp @@ -467,6 +467,7 @@ struct SPIRVariable : IVariant bool deferred_declaration = false; bool phi_variable = false; bool remapped_variable = false; + uint32_t remapped_components = 0; SPIRFunction::Parameter *parameter = nullptr; }; diff --git a/spirv_cross.cpp b/spirv_cross.cpp index 12cbc4fc..f6b1f442 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -2010,3 +2010,13 @@ bool Compiler::get_remapped_variable_state(uint32_t id) const { return get(id).remapped_variable; } + +void Compiler::set_subpass_input_remapped_components(uint32_t id, uint32_t components) +{ + get(id).remapped_components = components; +} + +uint32_t Compiler::get_subpass_input_remapped_components(uint32_t id) const +{ + return get(id).remapped_components; +} diff --git a/spirv_cross.hpp b/spirv_cross.hpp index 29412cd6..06a2aace 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -177,6 +177,12 @@ public: void set_remapped_variable_state(uint32_t id, bool remap_enable); bool get_remapped_variable_state(uint32_t id) const; + // For subpassInput variables which are remapped to plain variables, + // the number of components in the remapped + // variable must be specified as the backing type of subpass inputs are opaque. + void set_subpass_input_remapped_components(uint32_t id, uint32_t components); + uint32_t get_subpass_input_remapped_components(uint32_t id) const; + // Query and modify OpExecutionMode. uint64_t get_execution_mode_mask() const; void unset_execution_mode(spv::ExecutionMode mode); diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 34bad0b9..7e0b4cd5 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -2697,6 +2697,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) } funexpr += ")"; + // Check for function call constraints. + check_function_call_constraints(arg, length); + if (get(result_type).basetype != SPIRType::Void) { // If the function actually writes to an out variable, @@ -3535,18 +3538,26 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) string imgexpr; auto &type = expression_type(ops[2]); - if (var && var->remapped_variable) // PLS input, just read as-is without any op-code + if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code { - // PLS input could have different number of components than what the SPIR expects, swizzle to - // the appropriate vector size. auto itr = find_if(begin(pls_inputs), end(pls_inputs), [var](const PlsRemap &pls) { return pls.id == var->self; }); if (itr == end(pls_inputs)) - throw CompilerError("Found PLS remap for OpImageRead, but ID is not a PLS input ..."); - - uint32_t components = pls_format_to_components(itr->format); - imgexpr = remap_swizzle(result_type, components, ops[2]); + { + // For non-PLS inputs, we rely on subpass type remapping information to get it right + // since ImageRead always returns 4-component vectors and the backing type is opaque. + if (!var->remapped_components) + throw CompilerError("subpassInput was remapped, but remap_components is not set correctly."); + imgexpr = remap_swizzle(result_type, var->remapped_components, ops[2]); + } + else + { + // PLS input could have different number of components than what the SPIR expects, swizzle to + // the appropriate vector size. + uint32_t components = pls_format_to_components(itr->format); + imgexpr = remap_swizzle(result_type, components, ops[2]); + } pure = true; } else if (type.image.dim == DimSubpassData) @@ -4793,3 +4804,26 @@ void CompilerGLSL::end_scope_decl(const string &decl) indent--; statement("} ", decl, ";"); } + +void CompilerGLSL::check_function_call_constraints(const uint32_t *args, uint32_t length) +{ + // If our variable is remapped, and we rely on type-remapping information as + // well, then we cannot pass the variable as a function parameter. + // Fixing this is non-trivial without stamping out variants of the same function, + // so for now warn about this and suggest workarounds instead. + for (uint32_t i = 0; i < length; i++) + { + auto *var = maybe_get(args[i]); + if (!var || !var->remapped_variable) + continue; + + auto &type = get(var->basetype); + if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData) + { + throw CompilerError("Tried passing a remapped subpassInput variable to a function. " + "This will not work correctly because type-remapping information is lost. " + "To workaround, please consider not passing the subpass input as a function parameter, " + "or use in/out variables instead which do not need type remapping information."); + } + } +} diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index c5a75e51..762440ab 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -343,6 +343,8 @@ protected: void remap_pls_variables(); void add_variable(std::unordered_set &variables, uint32_t id); + + void check_function_call_constraints(const uint32_t *args, uint32_t length); }; }