Browse Source

ShaderTools: ability to control the preprocessor.

For -E, -D and -U magnum-shaderconverter options.
pull/481/head
Vladimír Vondruš 6 years ago
parent
commit
ff7b08a59b
  1. 40
      src/Magnum/ShaderTools/AbstractConverter.cpp
  2. 62
      src/Magnum/ShaderTools/AbstractConverter.h
  3. 124
      src/Magnum/ShaderTools/Test/AbstractConverterTest.cpp

40
src/Magnum/ShaderTools/AbstractConverter.cpp

@ -79,13 +79,16 @@ AbstractConverter::AbstractConverter(PluginManager::AbstractManager& manager, co
ConverterFeatures AbstractConverter::features() const {
const ConverterFeatures features = doFeatures();
CORRADE_ASSERT(features & ~ConverterFeature::InputFileCallback, "ShaderTools::AbstractConverter::features(): implementation reported no features", {});
CORRADE_ASSERT(features & ~(ConverterFeature::InputFileCallback|ConverterFeature::Preprocess),
"ShaderTools::AbstractConverter::features(): implementation reported no features", {});
return features;
}
void AbstractConverter::setFlags(const ConverterFlags flags) {
CORRADE_ASSERT(!(flags & ConverterFlag::Quiet) != !(flags & ConverterFlag::Verbose),
"ShaderTools::AbstractConverter::setFeatures(): can't have both Quiet and Verbose set", );
CORRADE_ASSERT(!(flags >= (ConverterFlag::Quiet|ConverterFlag::Verbose)),
"ShaderTools::AbstractConverter::setFlags(): can't have both Quiet and Verbose set", );
CORRADE_ASSERT((features() & ConverterFeature::Preprocess) || !(flags & ConverterFlag::PreprocessOnly),
"ShaderTools::AbstractConverter::setFlags(): PreprocessOnly not supported by the implementation", );
_flags = flags;
doSetFlags(flags);
}
@ -122,6 +125,20 @@ void AbstractConverter::setOutputFormat(const Format format) {
return setOutputFormat(format, {});
}
void AbstractConverter::setDefinitions(const Containers::ArrayView<const std::pair<Containers::StringView, Containers::StringView>> definitions) {
CORRADE_ASSERT(features() & ConverterFeature::Preprocess,
"ShaderTools::AbstractConverter::setDefinitions(): feature not supported", );
doSetDefinitions(definitions);
}
void AbstractConverter::setDefinitions(std::initializer_list<std::pair<Containers::StringView, Containers::StringView>> definitions) {
return setDefinitions(Containers::arrayView(definitions));
}
void AbstractConverter::doSetDefinitions(Containers::ArrayView<const std::pair<Containers::StringView, Containers::StringView>>) {
CORRADE_ASSERT_UNREACHABLE("ShaderTools::AbstractConverter::setDefinitions(): feature advertised but not implemented", );
}
std::pair<bool, Containers::String> AbstractConverter::validateData(const Stage stage, const Containers::ArrayView<const void> data) {
CORRADE_ASSERT(features() & ConverterFeature::ValidateData,
"ShaderTools::AbstractConverter::validateData(): feature not supported", {});
@ -371,6 +388,8 @@ Containers::Array<char> AbstractConverter::doConvertFileToData(const Stage stage
Containers::Array<char> AbstractConverter::linkDataToData(const Containers::ArrayView<const std::pair<Stage, Containers::ArrayView<const void>>> data) {
CORRADE_ASSERT(features() >= ConverterFeature::LinkData,
"ShaderTools::AbstractConverter::linkDataToData(): feature not supported", {});
CORRADE_ASSERT(!(_flags & ConverterFlag::PreprocessOnly),
"ShaderTools::AbstractConverter::linkDataToData(): PreprocessOnly is not allowed in combination with linking", {});
CORRADE_ASSERT(!data.empty(),
"ShaderTools::AbstractConverter::linkDataToData(): no data passed", {});
@ -392,6 +411,8 @@ Containers::Array<char> AbstractConverter::doLinkDataToData(Containers::ArrayVie
bool AbstractConverter::linkDataToFile(const Containers::ArrayView<const std::pair<Stage, Containers::ArrayView<const void>>> data, const Containers::StringView to) {
CORRADE_ASSERT(features() >= ConverterFeature::LinkData,
"ShaderTools::AbstractConverter::linkDataToFile(): feature not supported", {});
CORRADE_ASSERT(!(_flags & ConverterFlag::PreprocessOnly),
"ShaderTools::AbstractConverter::linkDataToFile(): PreprocessOnly is not allowed in combination with linking", {});
CORRADE_ASSERT(!data.empty(),
"ShaderTools::AbstractConverter::linkDataToFile(): no data passed", {});
@ -451,6 +472,8 @@ Containers::Array<char> AbstractConverter::linkDataToDataUsingInputFileCallbacks
bool AbstractConverter::linkFilesToFile(const Containers::ArrayView<const std::pair<Stage, Containers::StringView>> from, const Containers::StringView to) {
CORRADE_ASSERT(features() & (ConverterFeature::LinkFile|ConverterFeature::LinkData),
"ShaderTools::AbstractConverter::linkFilesToFile(): feature not supported", {});
CORRADE_ASSERT(!(_flags & ConverterFlag::PreprocessOnly),
"ShaderTools::AbstractConverter::linkFilesToFile(): PreprocessOnly is not allowed in combination with linking", {});
CORRADE_ASSERT(!from.empty(),
"ShaderTools::AbstractConverter::linkFilesToFile(): no files passed", {});
@ -539,6 +562,8 @@ bool AbstractConverter::doLinkFilesToFile(const Containers::ArrayView<const std:
Containers::Array<char> AbstractConverter::linkFilesToData(const Containers::ArrayView<const std::pair<Stage, Containers::StringView>> from) {
CORRADE_ASSERT(features() >= ConverterFeature::LinkData,
"ShaderTools::AbstractConverter::linkFilesToData(): feature not supported", {});
CORRADE_ASSERT(!(_flags & ConverterFlag::PreprocessOnly),
"ShaderTools::AbstractConverter::linkFilesToData(): PreprocessOnly is not allowed in combination with linking", {});
CORRADE_ASSERT(!from.empty(),
"ShaderTools::AbstractConverter::linkFilesToData(): no files passed", {});
@ -617,6 +642,7 @@ Debug& operator<<(Debug& debug, const ConverterFeature value) {
_c(LinkData)
_c(LinkFile)
_c(InputFileCallback)
_c(Preprocess)
#undef _c
/* LCOV_EXCL_STOP */
}
@ -635,7 +661,9 @@ Debug& operator<<(Debug& debug, const ConverterFeatures value) {
ConverterFeature::LinkData,
/* Implied by LinkData, has to be after */
ConverterFeature::LinkFile,
ConverterFeature::InputFileCallback});
ConverterFeature::InputFileCallback,
ConverterFeature::Preprocess
});
}
Debug& operator<<(Debug& debug, const ConverterFlag value) {
@ -647,6 +675,7 @@ Debug& operator<<(Debug& debug, const ConverterFlag value) {
_c(Quiet)
_c(Verbose)
_c(WarningAsError)
_c(PreprocessOnly)
#undef _c
/* LCOV_EXCL_STOP */
}
@ -658,7 +687,8 @@ Debug& operator<<(Debug& debug, const ConverterFlags value) {
return Containers::enumSetDebugOutput(debug, value, "ShaderTools::ConverterFlags{}", {
ConverterFlag::Quiet,
ConverterFlag::Verbose,
ConverterFlag::WarningAsError
ConverterFlag::WarningAsError,
ConverterFlag::PreprocessOnly
});
}

62
src/Magnum/ShaderTools/AbstractConverter.h

@ -94,7 +94,13 @@ enum class ConverterFeature: UnsignedInt {
* See @ref ShaderTools-AbstractConverter-usage-callbacks and particular
* converter documentation for more information.
*/
InputFileCallback = 1 << 6
InputFileCallback = 1 << 6,
/**
* Set preprocess definitions using @ref AbstractConverter::setDefinitions()
* and the @ref ConverterFlag::PreprocessOnly flag.
*/
Preprocess = 1 << 7
};
/**
@ -144,7 +150,17 @@ enum class ConverterFlag: UnsignedInt {
* validation or conversion succeeds. With this flag set, it fails.
* @see @ref ConverterFlag::Quiet
*/
WarningAsError = 1 << 2
WarningAsError = 1 << 2,
/**
* Only run the preprocessor. Available only if the converter supports
* @ref ConverterFeature::Preprocess, not allowed in combination with
* @ref AbstractConverter::linkDataToData(),
* @ref AbstractConverter::linkDataToFile(),
* @ref AbstractConverter::linkFilesToFile() or
* @ref AbstractConverter::linkFilesToData().
*/
PreprocessOnly = 1 << 3
};
/**
@ -574,6 +590,24 @@ class MAGNUM_SHADERTOOLS_EXPORT AbstractConverter: public PluginManager::Abstrac
void setOutputFormat(Format format);
#endif
/**
* @brief Set preprocessor definitions
*
* Available only if @ref ConverterFeature::Preprocess is supported.
* First string is macro name, second its value. If the second string
* is empty (but not @cpp nullptr @ce), it's the same as
* @cpp #define @ce without a value; if the second string is
* @cpp nullptr @ce, it's the same as @cpp #undef @ce.
*
* Calling this function replaces the previous set, calling it with an
* empty list will reset the definitions back to initial state.
* @see @ref ConverterFlag::PreprocessOnly
*/
void setDefinitions(Containers::ArrayView<const std::pair<Containers::StringView, Containers::StringView>> definitions);
/** @overload */
void setDefinitions(std::initializer_list<std::pair<Containers::StringView, Containers::StringView>> definitions);
/**
* @brief Validate a shader
*
@ -662,7 +696,9 @@ class MAGNUM_SHADERTOOLS_EXPORT AbstractConverter: public PluginManager::Abstrac
*
* Available only if @ref ConverterFeature::LinkData is supported. On
* failure the function prints an error message and returns
* @cpp nullptr @ce.
* @cpp nullptr @ce. Can't be called if
* @ref ConverterFlag::PreprocessOnly is set --- in that case
* @ref convertDataToData() has to be used instead.
* @see @ref features() @ref linkDataToFile(), @ref linkFilesToFile()
*/
Containers::Array<char> linkDataToData(Containers::ArrayView<const std::pair<Stage, Containers::ArrayView<const void>>> data);
@ -675,7 +711,9 @@ class MAGNUM_SHADERTOOLS_EXPORT AbstractConverter: public PluginManager::Abstrac
*
* Available only if @ref ConverterFeature::LinkData is supported. On
* Returns @cpp true @ce on success, prints an error message and
* returns @cpp false @ce otherwise.
* returns @cpp false @ce otherwise. Can't be called if
* @ref ConverterFlag::PreprocessOnly is set --- in that case
* @ref convertDataToFile() has to be used instead.
* @see @ref features(), @ref linkFilesToFile(),
* @ref linkFilesToData(), @ref linkDataToData()
*/
@ -690,7 +728,9 @@ class MAGNUM_SHADERTOOLS_EXPORT AbstractConverter: public PluginManager::Abstrac
* Available only if @ref ConverterFeature::LinkFile or
* @ref ConverterFeature::LinkData is supported. Returns @cpp true @ce
* on success, prints an error message and returns @cpp false @ce
* otherwise.
* otherwise. Can't be called if @ref ConverterFlag::PreprocessOnly is
* set --- in that case @ref convertFileToFile() has to be used
* instead.
* @see @ref features(), @ref linkFilesToData(), @ref linkDataToFile(),
* @ref linkDataToData()
*/
@ -704,7 +744,9 @@ class MAGNUM_SHADERTOOLS_EXPORT AbstractConverter: public PluginManager::Abstrac
*
* Available only if @ref ConverterFeature::LinkData is supported, On
* failure the function prints an error message and returns
* @cpp nullptr @ce.
* @cpp nullptr @ce. Can't be called if
* @ref ConverterFlag::PreprocessOnly is set --- in that case
* @ref convertFileToData() has to be used instead.
* @see @ref features(), @ref linkFilesToFile(), @ref linkDataToFile(),
* @ref linkDataToData()
*/
@ -862,6 +904,14 @@ class MAGNUM_SHADERTOOLS_EXPORT AbstractConverter: public PluginManager::Abstrac
*/
virtual void doSetOutputFormat(Format format, Containers::StringView version) = 0;
/**
* @brief Implementation for @ref setDefinitions()
*
* Has to be implemented if @ref ConverterFeature::Preprocess is
* supported. This function isn't expected to fail.
*/
virtual void doSetDefinitions(Containers::ArrayView<const std::pair<Containers::StringView, Containers::StringView>> definitions);
/**
* @brief Implementation for @ref validateData()
*

124
src/Magnum/ShaderTools/Test/AbstractConverterTest.cpp

@ -48,10 +48,16 @@ struct AbstractConverterTest: TestSuite::Tester {
void setFlags();
void setFlagsBothQuietAndVerbose();
void setFlagsPreprocessNotSupported();
void setFlagsPreprocessOnlyNotAllowed();
void setFlagsNotImplemented();
void setInputOutputFormat();
void setDefinitions();
void setDefinitionsNotSupported();
void setDefinitionsNotImplemented();
void validateData();
void validateDataNotSupported();
void validateDataNotImplemented();
@ -168,10 +174,16 @@ AbstractConverterTest::AbstractConverterTest() {
&AbstractConverterTest::setFlags,
&AbstractConverterTest::setFlagsBothQuietAndVerbose,
&AbstractConverterTest::setFlagsPreprocessNotSupported,
&AbstractConverterTest::setFlagsPreprocessOnlyNotAllowed,
&AbstractConverterTest::setFlagsNotImplemented,
&AbstractConverterTest::setInputOutputFormat,
&AbstractConverterTest::setDefinitions,
&AbstractConverterTest::setDefinitionsNotSupported,
&AbstractConverterTest::setDefinitionsNotImplemented,
&AbstractConverterTest::validateData,
&AbstractConverterTest::validateDataNotSupported,
&AbstractConverterTest::validateDataNotImplemented,
@ -294,7 +306,7 @@ void AbstractConverterTest::featuresNone() {
struct: AbstractConverter {
ConverterFeatures doFeatures() const override {
/* These aren't real features, so it should still complain */
return ConverterFeature::InputFileCallback;
return ConverterFeature::InputFileCallback|ConverterFeature::Preprocess;
}
void doSetInputFormat(Format, Containers::StringView) override {}
void doSetOutputFormat(Format, Containers::StringView) override {}
@ -347,6 +359,55 @@ void AbstractConverterTest::setFlagsBothQuietAndVerbose() {
CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setFlags(): can't have both Quiet and Verbose set\n");
}
void AbstractConverterTest::setFlagsPreprocessNotSupported() {
#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.setFlags(ConverterFlag::PreprocessOnly);
CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setFlags(): PreprocessOnly not supported by the implementation\n");
}
void AbstractConverterTest::setFlagsPreprocessOnlyNotAllowed() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
struct: AbstractConverter {
ConverterFeatures doFeatures() const override {
/** @todo should Validate/Convert be enforced when Preprocess is
present? */
return ConverterFeature::Preprocess|ConverterFeature::LinkData;
}
void doSetInputFormat(Format, Containers::StringView) override {}
void doSetOutputFormat(Format, Containers::StringView) override {}
} converter;
converter.setFlags(ConverterFlag::PreprocessOnly);
std::ostringstream out;
Error redirectError{&out};
converter.linkDataToData({});
converter.linkDataToFile({}, {});
converter.linkFilesToFile({}, {});
converter.linkFilesToData({});
CORRADE_COMPARE(out.str(),
"ShaderTools::AbstractConverter::linkDataToData(): PreprocessOnly is not allowed in combination with linking\n"
"ShaderTools::AbstractConverter::linkDataToFile(): PreprocessOnly is not allowed in combination with linking\n"
"ShaderTools::AbstractConverter::linkFilesToFile(): PreprocessOnly is not allowed in combination with linking\n"
"ShaderTools::AbstractConverter::linkFilesToData(): PreprocessOnly is not allowed in combination with linking\n");
}
void AbstractConverterTest::setFlagsNotImplemented() {
struct: AbstractConverter {
ConverterFeatures doFeatures() const override {
@ -396,6 +457,67 @@ void AbstractConverterTest::setInputOutputFormat() {
CORRADE_COMPARE(converter.outputVersion, "");
}
void AbstractConverterTest::setDefinitions() {
struct: AbstractConverter {
ConverterFeatures doFeatures() const override {
return ConverterFeature::Preprocess|ConverterFeature::ValidateData;
}
void doSetInputFormat(Format, Containers::StringView) override {}
void doSetOutputFormat(Format, Containers::StringView) override {}
void doSetDefinitions(Containers::ArrayView<const std::pair<Containers::StringView, Containers::StringView>> definitions) override {
howManyIsThere = definitions.size();
}
std::size_t howManyIsThere = 0;
} converter;
converter.setDefinitions({
{"VULKAN", ""},
{"LIGHT_COUNT", "3"},
{"GL_ES", nullptr}
});
CORRADE_COMPARE(converter.howManyIsThere, 3);
}
void AbstractConverterTest::setDefinitionsNotSupported() {
#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.setDefinitions({});
CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setDefinitions(): feature not supported\n");
}
void AbstractConverterTest::setDefinitionsNotImplemented() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
struct: AbstractConverter {
ConverterFeatures doFeatures() const override {
return ConverterFeature::Preprocess|ConverterFeature::ValidateData;
}
void doSetInputFormat(Format, Containers::StringView) override {}
void doSetOutputFormat(Format, Containers::StringView) override {}
} converter;
std::ostringstream out;
Error redirectError{&out};
converter.setDefinitions({});
CORRADE_COMPARE(out.str(), "ShaderTools::AbstractConverter::setDefinitions(): feature advertised but not implemented\n");
}
void AbstractConverterTest::validateData() {
struct: AbstractConverter {
ConverterFeatures doFeatures() const override {

Loading…
Cancel
Save