diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp index 79b7352cd..3042f66da 100644 --- a/Source/Engine/Content/Assets/Material.cpp +++ b/Source/Engine/Content/Assets/Material.cpp @@ -467,10 +467,6 @@ void Material::OnDependencyModified(BinaryAsset* asset) Reload(); } -#endif - -#if USE_EDITOR - void Material::InitCompilationOptions(ShaderCompilationOptions& options) { // Base @@ -488,7 +484,7 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options) const bool useForward = ((info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable) && !isOpaque) || info.Domain == MaterialDomain::Particle; const bool useTess = info.TessellationMode != TessellationMethod::None && - RenderTools::CanSupportTessellation(options.Profile) && isSurfaceOrTerrainOrDeformable; + EnumHasAllFlags(RenderTools::GetShaderProfileFeatures(options.Profile), ShaderProfileFeatures::TessellationShaders) && isSurfaceOrTerrainOrDeformable; const bool useDistortion = (info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable || info.Domain == MaterialDomain::Particle) && !isOpaque && diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h index b45ebdf32..0e174c67e 100644 --- a/Source/Engine/Graphics/Enums.h +++ b/Source/Engine/Graphics/Enums.h @@ -147,6 +147,37 @@ API_ENUM() enum class ShaderProfile const Char* ToString(ShaderProfile value); +/// +/// Shader profile feature flags. Defines a set of features supported by a shader profile. +/// +API_ENUM() enum class ShaderProfileFeatures +{ + /// + /// Nothing. + /// + None = 0, + + /// + /// Compute shaders are supported. + /// + ComputeShaders = 1, + + /// + /// Geometry shaders are supported. + /// + GeometryShaders = 2, + + /// + /// Tessellation shaders are supported (Hull and Domain). + /// + TessellationShaders = 4, + + API_ENUM(Attributes = "HideInEditor") + MAX +}; + +DECLARE_ENUM_OPERATORS(ShaderProfileFeatures); + /// /// Graphics feature levels indicates what level of support can be relied upon. /// They are named after the graphics API to indicate the minimum level of the features set to support. diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp index 0d10380a2..d658b902c 100644 --- a/Source/Engine/Graphics/RenderTools.cpp +++ b/Source/Engine/Graphics/RenderTools.cpp @@ -9,7 +9,6 @@ #include "RenderTask.h" #include "Engine/Content/Assets/Model.h" #include "Engine/Content/Assets/SkinnedModel.h" -#include "Engine/Core/Log.h" #include "Engine/Core/Math/Packed.h" #include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Engine/Time.h" @@ -281,6 +280,24 @@ FeatureLevel RenderTools::GetFeatureLevel(ShaderProfile profile) } } +ShaderProfileFeatures RenderTools::GetShaderProfileFeatures(ShaderProfile profile) +{ + switch (profile) + { + case ShaderProfile::DirectX_SM6: + case ShaderProfile::DirectX_SM5: + case ShaderProfile::Vulkan_SM5: + return ShaderProfileFeatures::ComputeShaders | ShaderProfileFeatures::GeometryShaders | ShaderProfileFeatures::TessellationShaders; + case ShaderProfile::PS4: + case ShaderProfile::PS5: + return ShaderProfileFeatures::ComputeShaders | ShaderProfileFeatures::GeometryShaders; + case ShaderProfile::DirectX_SM4: + return ShaderProfileFeatures::GeometryShaders; + default: + return ShaderProfileFeatures::None; + } +} + bool RenderTools::CanSupportTessellation(ShaderProfile profile) { switch (profile) diff --git a/Source/Engine/Graphics/RenderTools.h b/Source/Engine/Graphics/RenderTools.h index 2a2bc6357..92790c288 100644 --- a/Source/Engine/Graphics/RenderTools.h +++ b/Source/Engine/Graphics/RenderTools.h @@ -47,12 +47,20 @@ public: /// The feature level matching the given shader profile. static FeatureLevel GetFeatureLevel(ShaderProfile profile); + /// + /// Gets the features for the given shader profile. Runtime device might not support all of them. + /// + /// The shader profile. + /// The feature flags for the given shader profile. + static ShaderProfileFeatures GetShaderProfileFeatures(ShaderProfile profile); + /// /// Check if the given shader profile supports the tessellation. Runtime can reject tessellation support but it defines if given shader profile CAN support tessellation. + /// [Deprecated in v1.12] /// /// The profile. /// True if can support tessellation shaders, otherwise false. - static bool CanSupportTessellation(ShaderProfile profile); + DEPRECATED("Use GetShaderProfileFeatures instead") static bool CanSupportTessellation(ShaderProfile profile); /// /// Computes the image row pitch in bytes, and the slice pitch (size in bytes of the image) based on format, width, and height. diff --git a/Source/Engine/ShadersCompilation/Parser/IShaderParser.h b/Source/Engine/ShadersCompilation/Parser/IShaderParser.h index 72d4b85d1..8c1f0c81b 100644 --- a/Source/Engine/ShadersCompilation/Parser/IShaderParser.h +++ b/Source/Engine/ShadersCompilation/Parser/IShaderParser.h @@ -55,6 +55,12 @@ namespace ShaderProcessing /// The graphics feature level virtual FeatureLevel GetFeatureLevel() const = 0; + /// + /// Gets the parser feature flags for the Shader Profile of the target platform graphics backend. + /// + /// The shader profile features mask. + virtual ShaderProfileFeatures GetFeatures() const = 0; + /// /// Gets the parser macros. /// diff --git a/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.h b/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.h index 1727f9f4c..da821b716 100644 --- a/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.h +++ b/Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.h @@ -354,10 +354,7 @@ namespace ShaderProcessing // Clear current meta auto& current = ShaderMetaReaderType::_current; - current.Name.Clear(); - current.Permutations.Clear(); - current.Flags = ShaderFlags::Default; - current.MinFeatureLevel = FeatureLevel::ES2; + current = MetaType(); _permutationReader->Clear(); // Here we read '(x, y)\n' where 'x' is a shader function 'visible' flag, and 'y' is mini feature level @@ -388,6 +385,7 @@ namespace ShaderProcessing }; MinFeatureLevel levels[] = { + { FeatureLevel::ES2, "AUTO" }, { FeatureLevel::ES2, "FEATURE_LEVEL_ES2" }, { FeatureLevel::ES3, "FEATURE_LEVEL_ES3" }, { FeatureLevel::ES3_1, "FEATURE_LEVEL_ES3_1" }, @@ -406,7 +404,7 @@ namespace ShaderProcessing } if (missing) { - parser->OnError(TEXT("Invalid shader function \'minFeatureLevel\' option value.")); + parser->OnError(TEXT("Invalid shader function \'minFeatures\' option value.")); return; } @@ -433,7 +431,9 @@ namespace ShaderProcessing } // Check if use this shader program - if ((current.Flags & ShaderFlags::Hidden) == (ShaderFlags)0 && current.MinFeatureLevel <= parser->GetFeatureLevel()) + if ((current.Flags & ShaderFlags::Hidden) == (ShaderFlags)0 && + current.MinFeatureLevel <= parser->GetFeatureLevel() && + EnumHasAllFlags(parser->GetFeatures(), current.MinFeatures)) { // Cache read function ShaderMetaReaderType::_cache.Add(current); diff --git a/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h b/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h index c10488812..cb1bcd869 100644 --- a/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h +++ b/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h @@ -44,12 +44,17 @@ public: /// /// Function flags. /// - ShaderFlags Flags; + ShaderFlags Flags = ShaderFlags::Default; /// - /// The minimum graphics platform feature level to support this shader. + /// The minimum graphics platform feature level to support for this shader. /// - FeatureLevel MinFeatureLevel; + FeatureLevel MinFeatureLevel = FeatureLevel::ES2; + + /// + /// The minimum shader profile feature to support for this shader. + /// + ShaderProfileFeatures MinFeatures = ShaderProfileFeatures::None; /// /// All possible values for the permutations and it's values to generate different permutation of this function @@ -220,6 +225,11 @@ public: int32 ControlPointsCount; public: + HullShaderMeta() + { + MinFeatures = ShaderProfileFeatures::TessellationShaders; + } + // [ShaderFunctionMeta] ShaderStage GetStage() const override { @@ -233,6 +243,11 @@ public: class DomainShaderMeta : public ShaderFunctionMeta { public: + DomainShaderMeta() + { + MinFeatures = ShaderProfileFeatures::TessellationShaders; + } + // [ShaderFunctionMeta] ShaderStage GetStage() const override { @@ -246,6 +261,11 @@ public: class GeometryShaderMeta : public ShaderFunctionMeta { public: + GeometryShaderMeta() + { + MinFeatures = ShaderProfileFeatures::GeometryShaders; + } + // [ShaderFunctionMeta] ShaderStage GetStage() const override { @@ -272,6 +292,11 @@ public: class ComputeShaderMeta : public ShaderFunctionMeta { public: + ComputeShaderMeta() + { + MinFeatures = ShaderProfileFeatures::ComputeShaders; + } + // [ShaderFunctionMeta] ShaderStage GetStage() const override { diff --git a/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.cpp b/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.cpp index 3176906ab..7ea79a3b8 100644 --- a/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.cpp +++ b/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.cpp @@ -4,10 +4,11 @@ #if COMPILE_WITH_SHADER_COMPILER +#include "Engine/Core/Log.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Utilities/TextProcessing.h" #include "Engine/Profiler/ProfilerCPU.h" -#include "Engine/Core/Log.h" +#include "Engine/Graphics/RenderTools.h" #include "ShaderFunctionReader.CB.h" #include "ShaderFunctionReader.VS.h" #include "ShaderFunctionReader.HS.h" @@ -17,12 +18,13 @@ #include "ShaderFunctionReader.CS.h" #include "Config.h" -ShaderProcessing::Parser::Parser(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, FeatureLevel featureLevel) +ShaderProcessing::Parser::Parser(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, ShaderProfile profile) : failed(false) , targetName(targetName) , text(source, sourceLength) , _macros(macros) - , _featureLevel(featureLevel) + , _featureLevel(RenderTools::GetFeatureLevel(profile)) + , _features(RenderTools::GetShaderProfileFeatures(profile)) { } @@ -30,10 +32,10 @@ ShaderProcessing::Parser::~Parser() { } -bool ShaderProcessing::Parser::Process(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, FeatureLevel featureLevel, ShaderMeta* result) +bool ShaderProcessing::Parser::Process(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, ShaderProfile profile, ShaderMeta* result) { PROFILE_CPU_NAMED("Shader.Parse"); - Parser parser(targetName, source, sourceLength, macros, featureLevel); + Parser parser(targetName, source, sourceLength, macros, profile); parser.Process(result); return parser.Failed(); } diff --git a/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.h b/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.h index 884ff76c1..f0d9afb5f 100644 --- a/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.h +++ b/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.h @@ -22,20 +22,18 @@ namespace ShaderProcessing class Parser : public IShaderParser, public ITokenReadersContainerBase { private: - bool failed; String targetName; Reader text; ParserMacros _macros; FeatureLevel _featureLevel; + ShaderProfileFeatures _features; private: - - Parser(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, FeatureLevel featureLevel); + Parser(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, ShaderProfile profile); ~Parser(); public: - /// /// Process shader source code and generate metadata /// @@ -43,13 +41,12 @@ namespace ShaderProcessing /// ANSI source code /// Amount of characters in the source code /// The input macros. - /// The target feature level. + /// The target shader profile. /// Output result with metadata /// True if cannot process the file (too many errors), otherwise false - static bool Process(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, FeatureLevel featureLevel, ShaderMeta* result); + static bool Process(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, ShaderProfile profile, ShaderMeta* result); public: - /// /// Process shader source code and generate metadata /// @@ -57,34 +54,32 @@ namespace ShaderProcessing void Process(ShaderMeta* result); private: - void init(); bool process(); bool collectResults(ShaderMeta* result); public: - // [IShaderParser] FeatureLevel GetFeatureLevel() const override { return _featureLevel; } - + ShaderProfileFeatures GetFeatures() const override + { + return _features; + } bool Failed() const override { return failed; } - Reader& GetReader() override { return text; } - ParserMacros GetMacros() const override { return _macros; } - void OnError(const String& message) override; void OnWarning(const String& message) override; }; diff --git a/Source/Engine/ShadersCompilation/ShadersCompilation.cpp b/Source/Engine/ShadersCompilation/ShadersCompilation.cpp index d3e16c98d..c8f68f007 100644 --- a/Source/Engine/ShadersCompilation/ShadersCompilation.cpp +++ b/Source/Engine/ShadersCompilation/ShadersCompilation.cpp @@ -152,20 +152,14 @@ bool ShadersCompilation::Compile(ShaderCompilationOptions& options) options.SourceLength--; const DateTime startTime = DateTime::NowUTC(); - const FeatureLevel featureLevel = RenderTools::GetFeatureLevel(options.Profile); // Process shader source to collect metadata ShaderMeta meta; - if (ShaderProcessing::Parser::Process(options.TargetName, options.Source, options.SourceLength, options.Macros, featureLevel, &meta)) + if (ShaderProcessing::Parser::Process(options.TargetName, options.Source, options.SourceLength, options.Macros, options.Profile, &meta)) { LOG(Warning, "Failed to parse source code."); return true; } - const int32 shadersCount = meta.GetShadersCount(); - if (shadersCount == 0 && featureLevel > FeatureLevel::ES2) - { - LOG(Warning, "Shader has no valid functions."); - } // Perform actual compilation bool result; diff --git a/Source/Engine/Utilities/TextProcessing.cpp b/Source/Engine/Utilities/TextProcessing.cpp index a78185002..2ac0fc2ad 100644 --- a/Source/Engine/Utilities/TextProcessing.cpp +++ b/Source/Engine/Utilities/TextProcessing.cpp @@ -9,8 +9,6 @@ TextProcessing::TextProcessing(const char* input, int32 length) , _cursor(const_cast(input)) , _position(0) , _line(1) - , Separators(32) - , Whitespaces(8) { } diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index eaf4793e5..c678259d1 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -32,14 +32,14 @@ #endif // Meta macros used by shaders parser -#define META_VS(isVisible, minFeatureLevel) +#define META_VS(isVisible, minFeatures) #define META_VS_IN_ELEMENT(type, index, format, slot, offset, slotClass, stepRate, isVisible) // [Deprecated in v1.10] -#define META_HS(isVisible, minFeatureLevel) +#define META_HS(isVisible, minFeatures) #define META_HS_PATCH(inControlPoints) -#define META_DS(isVisible, minFeatureLevel) -#define META_GS(isVisible, minFeatureLevel) -#define META_PS(isVisible, minFeatureLevel) -#define META_CS(isVisible, minFeatureLevel) +#define META_DS(isVisible, minFeatures) +#define META_GS(isVisible, minFeatures) +#define META_PS(isVisible, minFeatures) +#define META_CS(isVisible, minFeatures) #define META_FLAG(flag) #define META_PERMUTATION_1(param0) #define META_PERMUTATION_2(param0, param1)