Browse Source

AnyShaderConverter: support validating and converting data as well.

Because it's possible to specify the formats explicitly it doesn't make
sense not to support that. Eventually contents-based detection could be
implemented as well, but I don't want to do that just yet.
pull/495/head
Vladimír Vondruš 5 years ago
parent
commit
20dd2914c5
  1. 215
      src/MagnumPlugins/AnyShaderConverter/AnyConverter.cpp
  2. 7
      src/MagnumPlugins/AnyShaderConverter/AnyConverter.h
  3. 1059
      src/MagnumPlugins/AnyShaderConverter/Test/AnyConverterTest.cpp

215
src/MagnumPlugins/AnyShaderConverter/AnyConverter.cpp

@ -54,7 +54,7 @@ AnyConverter::AnyConverter(PluginManager::AbstractManager& manager, const std::s
AnyConverter::~AnyConverter() = default;
ConverterFeatures AnyConverter::doFeatures() const {
return ConverterFeature::ValidateFile|ConverterFeature::ConvertFile|ConverterFeature::Preprocess|ConverterFeature::DebugInfo|ConverterFeature::Optimize;
return ConverterFeature::ValidateFile|ConverterFeature::ValidateData|ConverterFeature::ConvertFile|ConverterFeature::ConvertData|ConverterFeature::Preprocess|ConverterFeature::DebugInfo|ConverterFeature::Optimize;
}
void AnyConverter::doSetInputFormat(const Format format, const Containers::StringView version) {
@ -228,6 +228,59 @@ std::pair<bool, Containers::String> AnyConverter::doValidateFile(const Stage sta
return converter->validateFile(stage, filename);
}
std::pair<bool, Containers::String> AnyConverter::doValidateData(const Stage stage, const Containers::ArrayView<const char> data) {
CORRADE_INTERNAL_ASSERT(manager());
/* Decide on a plugin name based on the format */
if(_state->inputFormat == Format::Unspecified) {
Error{} << "ShaderTools::AnyConverter::validateData(): no input format specified";
return {};
}
const std::string plugin = Utility::formatString("{}ShaderConverter", stringForFormat(_state->inputFormat));
/* Try to load the plugin */
if(!(manager()->load(plugin) & PluginManager::LoadState::Loaded)) {
Error{} << "ShaderTools::AnyConverter::validateData(): cannot load the" << plugin << "plugin";
return {};
}
PluginManager::PluginMetadata* metadata = manager()->metadata(plugin);
if(flags() & ConverterFlag::Verbose) {
Debug d;
d << "ShaderTools::AnyConverter::validateData(): using" << plugin;
CORRADE_INTERNAL_ASSERT(metadata);
if(plugin != metadata->name())
d << "(provided by" << metadata->name() << Debug::nospace << ")";
}
/* Instantiate the plugin */
Containers::Pointer<AbstractConverter> converter = static_cast<PluginManager::Manager<AbstractConverter>*>(manager())->instantiate(plugin);
/* Check that it can actually validate */
if(!(converter->features() & ConverterFeature::ValidateData)) {
Error{} << "ShaderTools::AnyConverter::validateData():" << metadata->name() << "does not support validation";
return {};
}
/* Check that it can preprocess, in case we were asked to preprocess */
if((!_state->definitionViews.empty() || (flags() & ConverterFlag::PreprocessOnly)) && !(converter->features() & ConverterFeature::Preprocess)) {
Error{} << "ShaderTools::AnyConverter::validateData():" << metadata->name() << "does not support preprocessing";
return {};
}
/* Propagate input/output version and flags */
converter->setFlags(flags());
converter->setInputFormat(_state->inputFormat, _state->inputVersion);
converter->setOutputFormat(_state->outputFormat, _state->outputVersion);
/* Propagate definitions, if any */
if(!_state->definitionViews.empty())
converter->setDefinitions(_state->definitionViews);
/* Try to validate the data (error output should be printed by the plugin
itself) */
return converter->validateData(stage, data);
}
bool AnyConverter::doConvertFileToFile(const Stage stage, const Containers::StringView from, const Containers::StringView to) {
CORRADE_INTERNAL_ASSERT(manager());
@ -308,6 +361,166 @@ bool AnyConverter::doConvertFileToFile(const Stage stage, const Containers::Stri
return converter->convertFileToFile(stage, from, to);
}
Containers::Array<char> AnyConverter::doConvertFileToData(const Stage stage, const Containers::StringView from) {
CORRADE_INTERNAL_ASSERT(manager());
/* Prefer the explicitly set input format. If not set, fall back to
detecting based on input and output extension. */
const Containers::StringView formatFrom = stringForFormat(
_state->inputFormat != Format::Unspecified ? _state->inputFormat : formatForExtension("ShaderTools::AnyConverter::convertFileToData():", from)
);
if(formatFrom.isEmpty()) return {};
if(_state->outputFormat == Format::Unspecified) {
Error{} << "ShaderTools::AnyConverter::convertFileToData(): no output format specified";
return {};
}
const Containers::StringView formatTo = stringForFormat(_state->outputFormat);
/* Decide on a plugin name based on the format. This might result in
invalid combinations such as SpirvToGlslShaderConverter which can't be
really handled yet but I think that's okay for now. */
const std::string plugin = Utility::formatString(
formatFrom == formatTo ? "{}ShaderConverter" : "{}To{}ShaderConverter",
formatFrom, formatTo);
/* Try to load the plugin */
if(!(manager()->load(plugin) & PluginManager::LoadState::Loaded)) {
Error{} << "ShaderTools::AnyConverter::convertFileToData(): cannot load the" << plugin << "plugin";
return {};
}
PluginManager::PluginMetadata* metadata = manager()->metadata(plugin);
if(flags() & ConverterFlag::Verbose) {
Debug d;
d << "ShaderTools::AnyConverter::convertFileToData(): using" << plugin;
CORRADE_INTERNAL_ASSERT(metadata);
if(plugin != metadata->name())
d << "(provided by" << metadata->name() << Debug::nospace << ")";
}
/* Instantiate the plugin */
Containers::Pointer<AbstractConverter> converter = static_cast<PluginManager::Manager<AbstractConverter>*>(manager())->instantiate(plugin);
/* Check that it can actually convert */
if(!(converter->features() & ConverterFeature::ConvertData)) {
Error{} << "ShaderTools::AnyConverter::convertFileToData():" << metadata->name() << "does not support conversion";
return {};
}
/* Check that it can preprocess, in case we were asked to preprocess */
if((!_state->definitionViews.empty() || (flags() & ConverterFlag::PreprocessOnly)) && !(converter->features() & ConverterFeature::Preprocess)) {
Error{} << "ShaderTools::AnyConverter::convertFileToData():" << metadata->name() << "does not support preprocessing";
return {};
}
/* Check that it can output debug info, in case we were asked to */
if(!_state->debugInfoLevel.isEmpty() && !(converter->features() & ConverterFeature::DebugInfo)) {
Error{} << "ShaderTools::AnyConverter::convertFileToData():" << metadata->name() << "does not support controlling debug info output";
return {};
}
/* Check that it can optimize, in case we were asked to */
if(!_state->optimizationLevel.isEmpty() && !(converter->features() & ConverterFeature::Optimize)) {
Error{} << "ShaderTools::AnyConverter::convertFileToData():" << metadata->name() << "does not support optimization";
return {};
}
/* Propagate input/output version and flags */
converter->setFlags(flags());
converter->setInputFormat(_state->inputFormat, _state->inputVersion);
converter->setOutputFormat(_state->outputFormat, _state->outputVersion);
/* Propagate definitions and debug info, if any */
if(!_state->definitionViews.empty())
converter->setDefinitions(_state->definitionViews);
if(!_state->debugInfoLevel.isEmpty())
converter->setDebugInfoLevel(_state->debugInfoLevel);
if(!_state->optimizationLevel.isEmpty())
converter->setOptimizationLevel(_state->optimizationLevel);
/* Try to convert the file (error output should be printed by the plugin
itself) */
return converter->convertFileToData(stage, from);
}
Containers::Array<char> AnyConverter::doConvertDataToData(const Stage stage, const Containers::ArrayView<const char> from) {
CORRADE_INTERNAL_ASSERT(manager());
/* Decide on a plugin name based on the format. This might result in
invalid combinations such as SpirvToGlslShaderConverter which can't be
really handled yet but I think that's okay for now. */
if(_state->inputFormat == Format::Unspecified) {
Error{} << "ShaderTools::AnyConverter::convertDataToData(): no input format specified";
return {};
}
if(_state->outputFormat == Format::Unspecified) {
Error{} << "ShaderTools::AnyConverter::convertDataToData(): no output format specified";
return {};
}
const Containers::StringView formatFrom = stringForFormat(_state->inputFormat);
const Containers::StringView formatTo = stringForFormat(_state->outputFormat);
const std::string plugin = Utility::formatString(
formatFrom == formatTo ? "{}ShaderConverter" : "{}To{}ShaderConverter",
formatFrom, formatTo);
/* Try to load the plugin */
if(!(manager()->load(plugin) & PluginManager::LoadState::Loaded)) {
Error{} << "ShaderTools::AnyConverter::convertDataToData(): cannot load the" << plugin << "plugin";
return {};
}
PluginManager::PluginMetadata* metadata = manager()->metadata(plugin);
if(flags() & ConverterFlag::Verbose) {
Debug d;
d << "ShaderTools::AnyConverter::convertDataToData(): using" << plugin;
CORRADE_INTERNAL_ASSERT(metadata);
if(plugin != metadata->name())
d << "(provided by" << metadata->name() << Debug::nospace << ")";
}
/* Instantiate the plugin */
Containers::Pointer<AbstractConverter> converter = static_cast<PluginManager::Manager<AbstractConverter>*>(manager())->instantiate(plugin);
/* Check that it can actually convert */
if(!(converter->features() & ConverterFeature::ConvertData)) {
Error{} << "ShaderTools::AnyConverter::convertDataToData():" << metadata->name() << "does not support conversion";
return {};
}
/* Check that it can preprocess, in case we were asked to preprocess */
if((!_state->definitionViews.empty() || (flags() & ConverterFlag::PreprocessOnly)) && !(converter->features() & ConverterFeature::Preprocess)) {
Error{} << "ShaderTools::AnyConverter::convertDataToData():" << metadata->name() << "does not support preprocessing";
return {};
}
/* Check that it can output debug info, in case we were asked to */
if(!_state->debugInfoLevel.isEmpty() && !(converter->features() & ConverterFeature::DebugInfo)) {
Error{} << "ShaderTools::AnyConverter::convertDataToData():" << metadata->name() << "does not support controlling debug info output";
return {};
}
/* Check that it can optimize, in case we were asked to */
if(!_state->optimizationLevel.isEmpty() && !(converter->features() & ConverterFeature::Optimize)) {
Error{} << "ShaderTools::AnyConverter::convertDataToData():" << metadata->name() << "does not support optimization";
return {};
}
/* Propagate input/output version and flags */
converter->setFlags(flags());
converter->setInputFormat(_state->inputFormat, _state->inputVersion);
converter->setOutputFormat(_state->outputFormat, _state->outputVersion);
/* Propagate definitions and debug info, if any */
if(!_state->definitionViews.empty())
converter->setDefinitions(_state->definitionViews);
if(!_state->debugInfoLevel.isEmpty())
converter->setDebugInfoLevel(_state->debugInfoLevel);
if(!_state->optimizationLevel.isEmpty())
converter->setOptimizationLevel(_state->optimizationLevel);
/* Try to convert the file (error output should be printed by the plugin
itself) */
return converter->convertDataToData(stage, from);
}
}}
CORRADE_PLUGIN_REGISTER(AnyShaderConverter, Magnum::ShaderTools::AnyConverter,

7
src/MagnumPlugins/AnyShaderConverter/AnyConverter.h

@ -88,7 +88,9 @@ Supported conversion paths:
- SPIR-V Assembly to SPIR-V Assembly, converted with any plugin that provides
`SpirvAssemblyShaderConverter`
Only validating and converting files is supported.
There's format detection based on file contents, so the plugin has to either
operate on files or @ref setInputFormat() / @ref setOutputFormat() has to be
explicitly set.
@section ShaderTools-AnyConverter-usage Usage
@ -140,7 +142,10 @@ class MAGNUM_ANYSHADERCONVERTER_EXPORT AnyConverter: public AbstractConverter {
MAGNUM_ANYSHADERCONVERTER_LOCAL void doSetOptimizationLevel(Containers::StringView level) override;
MAGNUM_ANYSHADERCONVERTER_LOCAL std::pair<bool, Containers::String> doValidateFile(Stage stage, Containers::StringView filename) override;
MAGNUM_ANYSHADERCONVERTER_LOCAL std::pair<bool, Containers::String> doValidateData(Stage stage, Containers::ArrayView<const char> data) override;
MAGNUM_ANYSHADERCONVERTER_LOCAL bool doConvertFileToFile(Stage stage, Containers::StringView from, Containers::StringView to) override;
MAGNUM_ANYSHADERCONVERTER_LOCAL Containers::Array<char> doConvertFileToData(Magnum::ShaderTools::Stage stage, Containers::StringView from) override;
MAGNUM_ANYSHADERCONVERTER_LOCAL Containers::Array<char> doConvertDataToData(Magnum::ShaderTools::Stage stage, Containers::ArrayView<const char> data) override;
struct State;
Containers::Pointer<State> _state;

1059
src/MagnumPlugins/AnyShaderConverter/Test/AnyConverterTest.cpp

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save