From b9ef6b4a024bdbe4988626df2c614a313aa1073b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Oct 2020 21:37:58 +0200 Subject: [PATCH] ShaderTools: ability to control optimizations and debug level. So the -O and -g options in magnum-sceneconverter can be implemented in a generic way. --- src/Magnum/ShaderTools/AbstractConverter.cpp | 28 +++- src/Magnum/ShaderTools/AbstractConverter.h | 66 ++++++++- .../Test/AbstractConverterTest.cpp | 132 +++++++++++++++++- 3 files changed, 222 insertions(+), 4 deletions(-) diff --git a/src/Magnum/ShaderTools/AbstractConverter.cpp b/src/Magnum/ShaderTools/AbstractConverter.cpp index fd063cfa2..4458b695b 100644 --- a/src/Magnum/ShaderTools/AbstractConverter.cpp +++ b/src/Magnum/ShaderTools/AbstractConverter.cpp @@ -79,7 +79,7 @@ AbstractConverter::AbstractConverter(PluginManager::AbstractManager& manager, co ConverterFeatures AbstractConverter::features() const { const ConverterFeatures features = doFeatures(); - CORRADE_ASSERT(features & ~(ConverterFeature::InputFileCallback|ConverterFeature::Preprocess), + CORRADE_ASSERT(features & ~(ConverterFeature::InputFileCallback|ConverterFeature::Preprocess|ConverterFeature::Optimize|ConverterFeature::DebugInfo), "ShaderTools::AbstractConverter::features(): implementation reported no features", {}); return features; } @@ -139,6 +139,26 @@ void AbstractConverter::doSetDefinitions(Containers::ArrayView AbstractConverter::validateData(const Stage stage, const Containers::ArrayView data) { CORRADE_ASSERT(features() & ConverterFeature::ValidateData, "ShaderTools::AbstractConverter::validateData(): feature not supported", {}); @@ -643,6 +663,8 @@ Debug& operator<<(Debug& debug, const ConverterFeature value) { _c(LinkFile) _c(InputFileCallback) _c(Preprocess) + _c(Optimize) + _c(DebugInfo) #undef _c /* LCOV_EXCL_STOP */ } @@ -662,7 +684,9 @@ Debug& operator<<(Debug& debug, const ConverterFeatures value) { /* Implied by LinkData, has to be after */ ConverterFeature::LinkFile, ConverterFeature::InputFileCallback, - ConverterFeature::Preprocess + ConverterFeature::Preprocess, + ConverterFeature::Optimize, + ConverterFeature::DebugInfo }); } diff --git a/src/Magnum/ShaderTools/AbstractConverter.h b/src/Magnum/ShaderTools/AbstractConverter.h index 002d5dd04..75c330ddb 100644 --- a/src/Magnum/ShaderTools/AbstractConverter.h +++ b/src/Magnum/ShaderTools/AbstractConverter.h @@ -100,7 +100,19 @@ enum class ConverterFeature: UnsignedInt { * Set preprocess definitions using @ref AbstractConverter::setDefinitions() * and the @ref ConverterFlag::PreprocessOnly flag. */ - Preprocess = 1 << 7 + Preprocess = 1 << 7, + + /** + * Control code optimization using + * @ref AbstractConverter::setOptimizationLevel() + */ + Optimize = 1 << 8, + + /** + * Control amount of debug info present in the output using + * @ref AbstractConverter::setDebugInfoLevel() + */ + DebugInfo = 1 << 9 }; /** @@ -608,6 +620,32 @@ class MAGNUM_SHADERTOOLS_EXPORT AbstractConverter: public PluginManager::Abstrac /** @overload */ void setDefinitions(std::initializer_list> definitions); + /** + * @brief Set optimization level + * + * Available only if @ref ConverterFeature::Optimize is supported. + * Interpreted in a plugin-specific way, if it's not recognized the + * following @ref convertDataToData(), @ref convertDataToFile(), + * @ref convertFileToFile(), @ref convertFileToData(), + * @ref linkDataToData(), @ref linkDataToFile(), @ref linkFilesToFile() + * or @ref linkFilesToData() call will fail. + * @see @ref setDebugInfoLevel() + */ + void setOptimizationLevel(Containers::StringView level); + + /** + * @brief Set debug info level + * + * Available only if @ref ConverterFeature::DebugInfo is supported. + * Interpreted in a plugin-specific way, if it's not recognized the + * following @ref convertDataToData(), @ref convertDataToFile(), + * @ref convertFileToFile(), @ref convertFileToData(), + * @ref linkDataToData(), @ref linkDataToFile(), @ref linkFilesToFile() + * or @ref linkFilesToData() call will fail. + * @see @ref setOptimizationLevel() + */ + void setDebugInfoLevel(Containers::StringView level); + /** * @brief Validate a shader * @@ -912,6 +950,32 @@ class MAGNUM_SHADERTOOLS_EXPORT AbstractConverter: public PluginManager::Abstrac */ virtual void doSetDefinitions(Containers::ArrayView> definitions); + /** + * @brief Implementation for @ref setOptimizationLevel() + * + * Has to be implemented if @ref ConverterFeature::Optimize is + * supported. To simplify error handling on user side, this function + * isn't expected to fail --- if the level isn't recognized, the + * following @ref convertDataToData(), @ref convertDataToFile(), + * @ref convertFileToFile(), @ref convertFileToData(), + * @ref linkDataToData(), @ref linkDataToFile(), @ref linkFilesToFile() + * or @ref linkFilesToData() should fail instead. + */ + virtual void doSetOptimizationLevel(Containers::StringView level); + + /** + * @brief Implementation for @ref setDebugInfoLevel() + * + * Has to be implemented if @ref ConverterFeature::DebugInfo is + * supported. To simplify error handling on user side, this function + * isn't expected to fail --- if the level isn't recognized, the + * following @ref convertDataToData(), @ref convertDataToFile(), + * @ref convertFileToFile(), @ref convertFileToData(), + * @ref linkDataToData(), @ref linkDataToFile(), @ref linkFilesToFile() + * or @ref linkFilesToData() should fail instead. + */ + virtual void doSetDebugInfoLevel(Containers::StringView level); + /** * @brief Implementation for @ref validateData() * diff --git a/src/Magnum/ShaderTools/Test/AbstractConverterTest.cpp b/src/Magnum/ShaderTools/Test/AbstractConverterTest.cpp index a3cabc464..6c1357990 100644 --- a/src/Magnum/ShaderTools/Test/AbstractConverterTest.cpp +++ b/src/Magnum/ShaderTools/Test/AbstractConverterTest.cpp @@ -58,6 +58,14 @@ struct AbstractConverterTest: TestSuite::Tester { void setDefinitionsNotSupported(); void setDefinitionsNotImplemented(); + void setOptimizationLevel(); + void setOptimizationLevelNotSupported(); + void setOptimizationLevelNotImplemented(); + + void setDebugInfoLevel(); + void setDebugInfoLevelNotSupported(); + void setDebugInfoLevelNotImplemented(); + void validateData(); void validateDataNotSupported(); void validateDataNotImplemented(); @@ -184,6 +192,14 @@ AbstractConverterTest::AbstractConverterTest() { &AbstractConverterTest::setDefinitionsNotSupported, &AbstractConverterTest::setDefinitionsNotImplemented, + &AbstractConverterTest::setOptimizationLevel, + &AbstractConverterTest::setOptimizationLevelNotSupported, + &AbstractConverterTest::setOptimizationLevelNotImplemented, + + &AbstractConverterTest::setDebugInfoLevel, + &AbstractConverterTest::setDebugInfoLevelNotSupported, + &AbstractConverterTest::setDebugInfoLevelNotImplemented, + &AbstractConverterTest::validateData, &AbstractConverterTest::validateDataNotSupported, &AbstractConverterTest::validateDataNotImplemented, @@ -306,7 +322,7 @@ void AbstractConverterTest::featuresNone() { struct: AbstractConverter { ConverterFeatures doFeatures() const override { /* These aren't real features, so it should still complain */ - return ConverterFeature::InputFileCallback|ConverterFeature::Preprocess; + return ConverterFeature::InputFileCallback|ConverterFeature::Preprocess|ConverterFeature::Optimize|ConverterFeature::DebugInfo; } void doSetInputFormat(Format, Containers::StringView) override {} void doSetOutputFormat(Format, Containers::StringView) override {} @@ -518,6 +534,120 @@ void AbstractConverterTest::setDefinitionsNotImplemented() { CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setDefinitions(): feature advertised but not implemented\n"); } +void AbstractConverterTest::setOptimizationLevel() { + struct: AbstractConverter { + ConverterFeatures doFeatures() const override { + return ConverterFeature::Optimize|ConverterFeature::ValidateData; + } + void doSetInputFormat(Format, Containers::StringView) override {} + void doSetOutputFormat(Format, Containers::StringView) override {} + + void doSetOptimizationLevel(Containers::StringView level) override { + optimization = level; + } + + Containers::StringView optimization; + } converter; + + converter.setOptimizationLevel("2"); + CORRADE_COMPARE(converter.optimization, "2"); +} + +void AbstractConverterTest::setOptimizationLevelNotSupported() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractConverter { + ConverterFeatures doFeatures() const override { + return ConverterFeature::ValidateData; + } + void doSetInputFormat(Format, Containers::StringView) override {} + void doSetOutputFormat(Format, Containers::StringView) override {} + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.setOptimizationLevel({}); + CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setOptimizationLevel(): feature not supported\n"); +} + +void AbstractConverterTest::setOptimizationLevelNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractConverter { + ConverterFeatures doFeatures() const override { + return ConverterFeature::Optimize|ConverterFeature::ValidateData; + } + void doSetInputFormat(Format, Containers::StringView) override {} + void doSetOutputFormat(Format, Containers::StringView) override {} + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.setOptimizationLevel({}); + CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setOptimizationLevel(): feature advertised but not implemented\n"); +} + +void AbstractConverterTest::setDebugInfoLevel() { + struct: AbstractConverter { + ConverterFeatures doFeatures() const override { + return ConverterFeature::DebugInfo|ConverterFeature::ValidateData; + } + void doSetInputFormat(Format, Containers::StringView) override {} + void doSetOutputFormat(Format, Containers::StringView) override {} + + void doSetDebugInfoLevel(Containers::StringView level) override { + debugInfo = level; + } + + Containers::StringView debugInfo; + } converter; + + converter.setDebugInfoLevel("0"); + CORRADE_COMPARE(converter.debugInfo, "0"); +} + +void AbstractConverterTest::setDebugInfoLevelNotSupported() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractConverter { + ConverterFeatures doFeatures() const override { + return ConverterFeature::ValidateData; + } + void doSetInputFormat(Format, Containers::StringView) override {} + void doSetOutputFormat(Format, Containers::StringView) override {} + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.setDebugInfoLevel({}); + CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setDebugInfoLevel(): feature not supported\n"); +} + +void AbstractConverterTest::setDebugInfoLevelNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractConverter { + ConverterFeatures doFeatures() const override { + return ConverterFeature::DebugInfo|ConverterFeature::ValidateData; + } + void doSetInputFormat(Format, Containers::StringView) override {} + void doSetOutputFormat(Format, Containers::StringView) override {} + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.setDebugInfoLevel({}); + CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setDebugInfoLevel(): feature advertised but not implemented\n"); +} + void AbstractConverterTest::validateData() { struct: AbstractConverter { ConverterFeatures doFeatures() const override {