Browse Source

shaderconverter: allow specifying input/output format as well.

To make it convenient, the format equals to the usual file extension.
Currently skipping WGSL and DXIL however because I have no idea what
extension should they have, not even the DirectXShaderCompiler repo
tests show anything useful, there it's either generic LLVM *.ll or *.bc.

Come on, did people in 2020 also forget how to design file formats?!
pull/484/head
Vladimír Vondruš 6 years ago
parent
commit
38172d41b2
  1. 108
      src/Magnum/ShaderTools/shaderconverter.cpp

108
src/Magnum/ShaderTools/shaderconverter.cpp

@ -24,6 +24,7 @@
*/ */
#include <Corrade/Containers/GrowableArray.h> #include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Utility/Arguments.h> #include <Corrade/Utility/Arguments.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
@ -64,6 +65,8 @@ magnum-shaderconverter [-h|--help] [--validate] [--link]
[-c|--converter-options key=val,key2=val2,]... [-q|--quiet] [-v|--verbose] [-c|--converter-options key=val,key2=val2,]... [-q|--quiet] [-v|--verbose]
[--warning-as-error] [-E|--preprocess-only] [-D|--define name=value]... [--warning-as-error] [-E|--preprocess-only] [-D|--define name=value]...
[-U|--undefine name]... [-O|--optimize LEVEL] [-g|--debug-info LEVEL] [-U|--undefine name]... [-O|--optimize LEVEL] [-g|--debug-info LEVEL]
[--input-format glsl|spv|spvasm|hlsl|metal]...
[--output-format glsl|spv|spvasm|hlsl|metal]...
[--input-version VERSION]... [--output-version VERSION]... [--input-version VERSION]... [--output-version VERSION]...
[--] input... output [--] input... output
@endcode @endcode
@ -99,6 +102,10 @@ Arguments:
@ref ShaderTools::AbstractConverter::setOptimizationLevel() function. @ref ShaderTools::AbstractConverter::setOptimizationLevel() function.
- `-g`, `--debug-info LEVEL` --- debug info level to use. Corresponds to the - `-g`, `--debug-info LEVEL` --- debug info level to use. Corresponds to the
@ref ShaderTools::AbstractConverter::setDebugInfoLevel() function. @ref ShaderTools::AbstractConverter::setDebugInfoLevel() function.
- `--input-format glsl|spv|spvasm|hlsl|metal` --- input format for each
converter
- `--output-format glsl|spv|spvasm|hlsl|metal` --- output format for each
converter
- `--input-version VERSION` --- input format version for each converter - `--input-version VERSION` --- input format version for each converter
- `--output-version VERSION` --- output format version for each converter - `--output-version VERSION` --- output format version for each converter
@ -118,10 +125,10 @@ key/value pairs to set in the converter plugin configuration. If the `=`
character is omitted, it's equivalent to saying `key=true`; configuration character is omitted, it's equivalent to saying `key=true`; configuration
subgroups are delimited with `/`. It's possible to specify the `-C` / subgroups are delimited with `/`. It's possible to specify the `-C` /
`--converter` option (and correspondingly also `-c` / `--converter-options`, `--converter` option (and correspondingly also `-c` / `--converter-options`,
`--input-version` and `--output-version`) multiple times in order to chain more `--input-format`, `--output-format`, `--input-version` and `--output-version`)
converters together. All converters in the chain have to support the multiple times in order to chain more converters together. All converters in
@ref ShaderTools::ConverterFeature::ConvertData feature, if there's just one the chain have to support the @ref ShaderTools::ConverterFeature::ConvertData
converter it's enough for it to support feature, if there's just one converter it's enough for it to support
@ref ShaderTools::ConverterFeature::ConvertFile. If no `-C` / `--converter` is @ref ShaderTools::ConverterFeature::ConvertFile. If no `-C` / `--converter` is
specified, @ref ShaderTools::AnyConverter "AnyShaderConverter" is used. specified, @ref ShaderTools::AnyConverter "AnyShaderConverter" is used.
@ -130,9 +137,10 @@ The `-D` / `--define`, `-U` / `--undefine`, `-O` / `--optimize`, `-g` /
converter. Split the conversion to multiple passes if you need to pass those to converter. Split the conversion to multiple passes if you need to pass those to
converters later in the chain. converters later in the chain.
Values accepted by `-O` / `--optimize`, `-g` / `--debug-info`, `--input-version` Values accepted by `-O` / `--optimize`, `-g` / `--debug-info`, `--input-format`,
and `--output-version` are converter-specific, see documentation of a `--output-format`, `--input-version` and `--output-version` are
particular converter for more information. converter-specific, see documentation of a particular converter for more
information.
@section magnum-shaderconverter-example Example usage @section magnum-shaderconverter-example Example usage
@ -158,6 +166,7 @@ magnum-shaderconverter phong.frag -DDIFFUSE_TEXTURE -DNORMAL_TEXTURE --input-ver
} }
using namespace Corrade::Containers::Literals;
using namespace Magnum; using namespace Magnum;
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -177,6 +186,9 @@ int main(int argc, char** argv) {
.addArrayOption('U', "undefine").setHelp("undefine", "undefine a preprocessor macro", "name") .addArrayOption('U', "undefine").setHelp("undefine", "undefine a preprocessor macro", "name")
.addOption('O', "optimize").setHelp("optimize", "optimization level to use", "LEVEL") .addOption('O', "optimize").setHelp("optimize", "optimization level to use", "LEVEL")
.addOption('g', "debug-info").setHelp("debug-info", "debug info level to use", "LEVEL") .addOption('g', "debug-info").setHelp("debug-info", "debug info level to use", "LEVEL")
/** @todo what the heck is the extension for wgsl and dxil?! */
.addArrayOption("input-format").setHelp("input-format", "input format for each converter", "glsl|spv|spvasm|hlsl|metal")
.addArrayOption("output-format").setHelp("output-format", "output format for each converter", "glsl|spv|spvasm|hlsl|metal")
.addArrayOption("input-version").setHelp("input-version", "input format version for each converter", "VERSION") .addArrayOption("input-version").setHelp("input-version", "input format version for each converter", "VERSION")
.addArrayOption("output-version").setHelp("output-version", "output format version for each converter", "VERSION") .addArrayOption("output-version").setHelp("output-version", "output format version for each converter", "VERSION")
.setParseErrorCallback([](const Utility::Arguments& args, Utility::Arguments::ParseError error, const std::string& key) { .setParseErrorCallback([](const Utility::Arguments& args, Utility::Arguments::ParseError error, const std::string& key) {
@ -201,20 +213,21 @@ The -c / --converter-options argument accept a comma-separated list of
key/value pairs to set in the converter plugin configuration. If the = key/value pairs to set in the converter plugin configuration. If the =
character is omitted, it's equivalent to saying key=true; configuration character is omitted, it's equivalent to saying key=true; configuration
subgroups are delimited with /. It's possible to specify the -C / --converter subgroups are delimited with /. It's possible to specify the -C / --converter
option (and correspondingly also -c / --converter-options, --input-version and option (and correspondingly also -c / --converter-options, --input-format,
--output-version) multiple times in order to chain more converters together. --output-format, --input-version and --output-version) multiple times in order
All converters in the chain have to support the ConvertData feature, if there's to chain more converters together. All converters in the chain have to support
just one converter it's enough for it to support ConvertFile. If no -C / the ConvertData feature, if there's just one converter it's enough for it to
--converter is specified, AnyShaderConverter is used. support ConvertFile. If no -C / --converter is specified, AnyShaderConverter is
used.
The -D / --define, -U / --undefine, -O / --optimize, -g / --debug-info, -E / The -D / --define, -U / --undefine, -O / --optimize, -g / --debug-info, -E /
--preprocess-only arguments apply only to the first converter. Split the --preprocess-only arguments apply only to the first converter. Split the
conversion to multiple passes if you need to pass those to converters later in conversion to multiple passes if you need to pass those to converters later in
the chain. the chain.
Values accepted by -O / --optimize, -g / --debug-info, --input-version and Values accepted by -O / --optimize, -g / --debug-info, --input-format,
--output-version are converter-specific, see documentation of a particular --output-format, --input-version and --output-version are converter-specific,
converter for more information.)") see documentation of a particular converter for more information.)")
.parse(argc, argv); .parse(argc, argv);
/* Generic checks */ /* Generic checks */
@ -268,13 +281,46 @@ converter for more information.)")
return 7; return 7;
} }
/* Set options and versions, if passed */ /* Set options if passed */
if(i < args.arrayValueCount("converter-options")) if(i < args.arrayValueCount("converter-options"))
Implementation::setOptions(*converter, args.arrayValue("converter-options", i)); Implementation::setOptions(*converter, args.arrayValue("converter-options", i));
/* Parse format, if passed */
ShaderTools::Format inputFormat{}, outputFormat{};
auto parseFormat = [](Containers::StringView format) -> Containers::Optional<ShaderTools::Format> {
if(format == ""_s) return ShaderTools::Format::Unspecified;
if(format == "glsl"_s) return ShaderTools::Format::Glsl;
if(format == "spv"_s) return ShaderTools::Format::Spirv;
if(format == "spvasm"_s) return ShaderTools::Format::SpirvAssembly;
if(format == "hlsl"_s) return ShaderTools::Format::Hlsl;
if(format == "metal"_s) return ShaderTools::Format::Msl;
/** @todo wgsl and dxil once i figure out the extensions */
Error{} << "Unrecognized format" << format << Debug::nospace << ", expected glsl, spv, spvasm, hlsl or metal";
return {};
};
if(i < args.arrayValueCount("input-format")) {
if(const Containers::Optional<ShaderTools::Format> format = parseFormat(args.arrayValue<Containers::StringView>("input-format", i)))
inputFormat = *format;
else return 8;
}
if(i < args.arrayValueCount("output-format")) {
if(const Containers::Optional<ShaderTools::Format> format = parseFormat(args.arrayValue<Containers::StringView>("output-format", i)))
outputFormat = *format;
else return 9;
}
/* Get version, if passed */
Containers::StringView inputVersion{}, outputVersion{};
if(i < args.arrayValueCount("input-version")) if(i < args.arrayValueCount("input-version"))
converter->setInputFormat({}, args.arrayValue("input-version", i)); inputVersion = args.arrayValue("input-version", i);
if(i < args.arrayValueCount("output-version")) if(i < args.arrayValueCount("output-version"))
converter->setOutputFormat({}, args.arrayValue("output-version", i)); outputVersion = args.arrayValue("output-version", i);
/* If not passed, these are set to Unspecified and "", which is the
default */
converter->setInputFormat(inputFormat, inputVersion);
converter->setOutputFormat(outputFormat, outputVersion);
ShaderTools::ConverterFlags flags; ShaderTools::ConverterFlags flags;
@ -290,7 +336,7 @@ converter for more information.)")
if((args.isSet("preprocess-only") || args.arrayValueCount("define") || args.arrayValueCount("undefine"))) { if((args.isSet("preprocess-only") || args.arrayValueCount("define") || args.arrayValueCount("undefine"))) {
if(!(converter->features() & ShaderTools::ConverterFeature::Preprocess)) { if(!(converter->features() & ShaderTools::ConverterFeature::Preprocess)) {
Error{} << "The -E / -D / -U options are set, but" << converterName << "doesn't support preprocessing"; Error{} << "The -E / -D / -U options are set, but" << converterName << "doesn't support preprocessing";
return 8; return 10;
} }
if(args.isSet("preprocess-only")) if(args.isSet("preprocess-only"))
@ -315,7 +361,7 @@ converter for more information.)")
if(!args.value("optimize").empty()) { if(!args.value("optimize").empty()) {
if(!(converter->features() & ShaderTools::ConverterFeature::Optimize)) { if(!(converter->features() & ShaderTools::ConverterFeature::Optimize)) {
Error{} << "The -O option is set, but" << converterName << "doesn't support optimization"; Error{} << "The -O option is set, but" << converterName << "doesn't support optimization";
return 9; return 11;
} }
converter->setOptimizationLevel(args.value("optimize")); converter->setOptimizationLevel(args.value("optimize"));
@ -324,7 +370,7 @@ converter for more information.)")
if(!args.value("debug-info").empty()) { if(!args.value("debug-info").empty()) {
if(!(converter->features() & ShaderTools::ConverterFeature::DebugInfo)) { if(!(converter->features() & ShaderTools::ConverterFeature::DebugInfo)) {
Error{} << "The -g option is set, but" << converterName << "doesn't support debug info"; Error{} << "The -g option is set, but" << converterName << "doesn't support debug info";
return 10; return 12;
} }
converter->setDebugInfoLevel(args.value("debug-info")); converter->setDebugInfoLevel(args.value("debug-info"));
@ -349,7 +395,7 @@ converter for more information.)")
if(!(converter->features() & ShaderTools::ConverterFeature::ValidateFile)) { if(!(converter->features() & ShaderTools::ConverterFeature::ValidateFile)) {
Error{} << converterName << "doesn't support file validation"; Error{} << converterName << "doesn't support file validation";
return 11; return 13;
} }
std::pair<bool, Containers::String> out = converter->validateFile(ShaderTools::Stage::Unspecified, args.arrayValue("input", 0)); std::pair<bool, Containers::String> out = converter->validateFile(ShaderTools::Stage::Unspecified, args.arrayValue("input", 0));
@ -363,7 +409,7 @@ converter for more information.)")
if(!out.second.isEmpty()) Warning{} << out.second; if(!out.second.isEmpty()) Warning{} << out.second;
} else if(args.isSet("verbose")) } else if(args.isSet("verbose"))
Debug{} << "Validation passed"; Debug{} << "Validation passed";
return out.first ? 0 : 12; return out.first ? 0 : 14;
} }
/** @todo ability to specify the stage (need a configurationvalue parser for this) */ /** @todo ability to specify the stage (need a configurationvalue parser for this) */
@ -372,7 +418,7 @@ converter for more information.)")
if(i == 0 && converterCount <= 1) { if(i == 0 && converterCount <= 1) {
if(!(converter->features() & ShaderTools::ConverterFeature::ConvertFile)) { if(!(converter->features() & ShaderTools::ConverterFeature::ConvertFile)) {
Error{} << converterName << "doesn't support file conversion"; Error{} << converterName << "doesn't support file conversion";
return 13; return 15;
} }
/* No verbose output for just one converter */ /* No verbose output for just one converter */
@ -381,14 +427,14 @@ converter for more information.)")
if(args.isSet("link")) { if(args.isSet("link")) {
if(!converter->linkFilesToFile(linkInputs, args.value("output"))) { if(!converter->linkFilesToFile(linkInputs, args.value("output"))) {
Error{} << "Cannot link" << args.arrayValue("input", 0) << "and others to" << args.value("output"); Error{} << "Cannot link" << args.arrayValue("input", 0) << "and others to" << args.value("output");
return 14; return 16;
} }
/* Converting */ /* Converting */
} else { } else {
if(!converter->convertFileToFile(ShaderTools::Stage::Unspecified, args.arrayValue("input", 0), args.value("output"))) { if(!converter->convertFileToFile(ShaderTools::Stage::Unspecified, args.arrayValue("input", 0), args.value("output"))) {
Error{} << "Cannot convert" << args.arrayValue("input", 0) << "to" << args.value("output"); Error{} << "Cannot convert" << args.arrayValue("input", 0) << "to" << args.value("output");
return 15; return 17;
} }
} }
@ -396,7 +442,7 @@ converter for more information.)")
} else { } else {
if(!(converter->features() & ShaderTools::ConverterFeature::ConvertData)) { if(!(converter->features() & ShaderTools::ConverterFeature::ConvertData)) {
Error{} << converterName << "doesn't support data conversion"; Error{} << converterName << "doesn't support data conversion";
return 16; return 18;
} }
/* This is the first --converter and there are more, go from a file /* This is the first --converter and there are more, go from a file
@ -409,14 +455,14 @@ converter for more information.)")
if(args.isSet("link")) { if(args.isSet("link")) {
if(!(data = converter->linkFilesToData(linkInputs))) { if(!(data = converter->linkFilesToData(linkInputs))) {
Error{} << "Cannot link" << args.arrayValue("input", 0) << "and others to" << args.value("output"); Error{} << "Cannot link" << args.arrayValue("input", 0) << "and others to" << args.value("output");
return 17; return 19;
} }
/* Converting */ /* Converting */
} else { } else {
if(!(data = converter->convertFileToData(ShaderTools::Stage::Unspecified, args.arrayValue("input", 0)))) { if(!(data = converter->convertFileToData(ShaderTools::Stage::Unspecified, args.arrayValue("input", 0)))) {
Error{} << "Cannot convert" << args.arrayValue("input", 0); Error{} << "Cannot convert" << args.arrayValue("input", 0);
return 18; return 20;
} }
} }
@ -431,7 +477,7 @@ converter for more information.)")
/* Subsequent operations are always a conversion, not link */ /* Subsequent operations are always a conversion, not link */
if(!(data = converter->convertDataToData(ShaderTools::Stage::Unspecified, data))) { if(!(data = converter->convertDataToData(ShaderTools::Stage::Unspecified, data))) {
Error{} << "Cannot convert shader data"; Error{} << "Cannot convert shader data";
return 19; return 21;
} }
/* This is the last --converter, output to a file and exit the /* This is the last --converter, output to a file and exit the
@ -445,7 +491,7 @@ converter for more information.)")
/* Subsequent operations are always a conversion, not link */ /* Subsequent operations are always a conversion, not link */
if(!converter->convertDataToFile(ShaderTools::Stage::Unspecified, data, args.value("output"))) { if(!converter->convertDataToFile(ShaderTools::Stage::Unspecified, data, args.value("output"))) {
Error{} << "Cannot save file" << args.value("output"); Error{} << "Cannot save file" << args.value("output");
return 20; return 22;
} }
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE();

Loading…
Cancel
Save