Add ShaderProfileFeatures for more expendable shader feature sets

This commit is contained in:
2026-03-04 16:55:04 +01:00
parent aff8090adb
commit ceebc68d18
12 changed files with 121 additions and 49 deletions
+1 -5
View File
@@ -467,10 +467,6 @@ void Material::OnDependencyModified(BinaryAsset* asset)
Reload(); Reload();
} }
#endif
#if USE_EDITOR
void Material::InitCompilationOptions(ShaderCompilationOptions& options) void Material::InitCompilationOptions(ShaderCompilationOptions& options)
{ {
// Base // 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 useForward = ((info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable) && !isOpaque) || info.Domain == MaterialDomain::Particle;
const bool useTess = const bool useTess =
info.TessellationMode != TessellationMethod::None && info.TessellationMode != TessellationMethod::None &&
RenderTools::CanSupportTessellation(options.Profile) && isSurfaceOrTerrainOrDeformable; EnumHasAllFlags(RenderTools::GetShaderProfileFeatures(options.Profile), ShaderProfileFeatures::TessellationShaders) && isSurfaceOrTerrainOrDeformable;
const bool useDistortion = const bool useDistortion =
(info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable || info.Domain == MaterialDomain::Particle) && (info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable || info.Domain == MaterialDomain::Particle) &&
!isOpaque && !isOpaque &&
+31
View File
@@ -147,6 +147,37 @@ API_ENUM() enum class ShaderProfile
const Char* ToString(ShaderProfile value); const Char* ToString(ShaderProfile value);
/// <summary>
/// Shader profile feature flags. Defines a set of features supported by a shader profile.
/// </summary>
API_ENUM() enum class ShaderProfileFeatures
{
/// <summary>
/// Nothing.
/// </summary>
None = 0,
/// <summary>
/// Compute shaders are supported.
/// </summary>
ComputeShaders = 1,
/// <summary>
/// Geometry shaders are supported.
/// </summary>
GeometryShaders = 2,
/// <summary>
/// Tessellation shaders are supported (Hull and Domain).
/// </summary>
TessellationShaders = 4,
API_ENUM(Attributes = "HideInEditor")
MAX
};
DECLARE_ENUM_OPERATORS(ShaderProfileFeatures);
/// <summary> /// <summary>
/// Graphics feature levels indicates what level of support can be relied upon. /// 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. /// They are named after the graphics API to indicate the minimum level of the features set to support.
+18 -1
View File
@@ -9,7 +9,6 @@
#include "RenderTask.h" #include "RenderTask.h"
#include "Engine/Content/Assets/Model.h" #include "Engine/Content/Assets/Model.h"
#include "Engine/Content/Assets/SkinnedModel.h" #include "Engine/Content/Assets/SkinnedModel.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Math/Packed.h" #include "Engine/Core/Math/Packed.h"
#include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Core/Math/OrientedBoundingBox.h"
#include "Engine/Engine/Time.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) bool RenderTools::CanSupportTessellation(ShaderProfile profile)
{ {
switch (profile) switch (profile)
+9 -1
View File
@@ -47,12 +47,20 @@ public:
/// <returns>The feature level matching the given shader profile.</returns> /// <returns>The feature level matching the given shader profile.</returns>
static FeatureLevel GetFeatureLevel(ShaderProfile profile); static FeatureLevel GetFeatureLevel(ShaderProfile profile);
/// <summary>
/// Gets the features for the given shader profile. Runtime device might not support all of them.
/// </summary>
/// <param name="profile">The shader profile.</param>
/// <returns>The feature flags for the given shader profile.</returns>
static ShaderProfileFeatures GetShaderProfileFeatures(ShaderProfile profile);
/// <summary> /// <summary>
/// Check if the given shader profile supports the tessellation. Runtime can reject tessellation support but it defines if given shader profile CAN support tessellation. /// 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]
/// </summary> /// </summary>
/// <param name="profile">The profile.</param> /// <param name="profile">The profile.</param>
/// <returns>True if can support tessellation shaders, otherwise false.</returns> /// <returns>True if can support tessellation shaders, otherwise false.</returns>
static bool CanSupportTessellation(ShaderProfile profile); DEPRECATED("Use GetShaderProfileFeatures instead") static bool CanSupportTessellation(ShaderProfile profile);
/// <summary> /// <summary>
/// Computes the image row pitch in bytes, and the slice pitch (size in bytes of the image) based on format, width, and height. /// Computes the image row pitch in bytes, and the slice pitch (size in bytes of the image) based on format, width, and height.
@@ -55,6 +55,12 @@ namespace ShaderProcessing
/// <returns>The graphics feature level</returns> /// <returns>The graphics feature level</returns>
virtual FeatureLevel GetFeatureLevel() const = 0; virtual FeatureLevel GetFeatureLevel() const = 0;
/// <summary>
/// Gets the parser feature flags for the Shader Profile of the target platform graphics backend.
/// </summary>
/// <returns>The shader profile features mask.</returns>
virtual ShaderProfileFeatures GetFeatures() const = 0;
/// <summary> /// <summary>
/// Gets the parser macros. /// Gets the parser macros.
/// </summary> /// </summary>
@@ -354,10 +354,7 @@ namespace ShaderProcessing
// Clear current meta // Clear current meta
auto& current = ShaderMetaReaderType::_current; auto& current = ShaderMetaReaderType::_current;
current.Name.Clear(); current = MetaType();
current.Permutations.Clear();
current.Flags = ShaderFlags::Default;
current.MinFeatureLevel = FeatureLevel::ES2;
_permutationReader->Clear(); _permutationReader->Clear();
// Here we read '(x, y)\n' where 'x' is a shader function 'visible' flag, and 'y' is mini feature level // 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[] = MinFeatureLevel levels[] =
{ {
{ FeatureLevel::ES2, "AUTO" },
{ FeatureLevel::ES2, "FEATURE_LEVEL_ES2" }, { FeatureLevel::ES2, "FEATURE_LEVEL_ES2" },
{ FeatureLevel::ES3, "FEATURE_LEVEL_ES3" }, { FeatureLevel::ES3, "FEATURE_LEVEL_ES3" },
{ FeatureLevel::ES3_1, "FEATURE_LEVEL_ES3_1" }, { FeatureLevel::ES3_1, "FEATURE_LEVEL_ES3_1" },
@@ -406,7 +404,7 @@ namespace ShaderProcessing
} }
if (missing) if (missing)
{ {
parser->OnError(TEXT("Invalid shader function \'minFeatureLevel\' option value.")); parser->OnError(TEXT("Invalid shader function \'minFeatures\' option value."));
return; return;
} }
@@ -433,7 +431,9 @@ namespace ShaderProcessing
} }
// Check if use this shader program // 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 // Cache read function
ShaderMetaReaderType::_cache.Add(current); ShaderMetaReaderType::_cache.Add(current);
@@ -44,12 +44,17 @@ public:
/// <summary> /// <summary>
/// Function flags. /// Function flags.
/// </summary> /// </summary>
ShaderFlags Flags; ShaderFlags Flags = ShaderFlags::Default;
/// <summary> /// <summary>
/// The minimum graphics platform feature level to support this shader. /// The minimum graphics platform feature level to support for this shader.
/// </summary> /// </summary>
FeatureLevel MinFeatureLevel; FeatureLevel MinFeatureLevel = FeatureLevel::ES2;
/// <summary>
/// The minimum shader profile feature to support for this shader.
/// </summary>
ShaderProfileFeatures MinFeatures = ShaderProfileFeatures::None;
/// <summary> /// <summary>
/// All possible values for the permutations and it's values to generate different permutation of this function /// All possible values for the permutations and it's values to generate different permutation of this function
@@ -220,6 +225,11 @@ public:
int32 ControlPointsCount; int32 ControlPointsCount;
public: public:
HullShaderMeta()
{
MinFeatures = ShaderProfileFeatures::TessellationShaders;
}
// [ShaderFunctionMeta] // [ShaderFunctionMeta]
ShaderStage GetStage() const override ShaderStage GetStage() const override
{ {
@@ -233,6 +243,11 @@ public:
class DomainShaderMeta : public ShaderFunctionMeta class DomainShaderMeta : public ShaderFunctionMeta
{ {
public: public:
DomainShaderMeta()
{
MinFeatures = ShaderProfileFeatures::TessellationShaders;
}
// [ShaderFunctionMeta] // [ShaderFunctionMeta]
ShaderStage GetStage() const override ShaderStage GetStage() const override
{ {
@@ -246,6 +261,11 @@ public:
class GeometryShaderMeta : public ShaderFunctionMeta class GeometryShaderMeta : public ShaderFunctionMeta
{ {
public: public:
GeometryShaderMeta()
{
MinFeatures = ShaderProfileFeatures::GeometryShaders;
}
// [ShaderFunctionMeta] // [ShaderFunctionMeta]
ShaderStage GetStage() const override ShaderStage GetStage() const override
{ {
@@ -272,6 +292,11 @@ public:
class ComputeShaderMeta : public ShaderFunctionMeta class ComputeShaderMeta : public ShaderFunctionMeta
{ {
public: public:
ComputeShaderMeta()
{
MinFeatures = ShaderProfileFeatures::ComputeShaders;
}
// [ShaderFunctionMeta] // [ShaderFunctionMeta]
ShaderStage GetStage() const override ShaderStage GetStage() const override
{ {
@@ -4,10 +4,11 @@
#if COMPILE_WITH_SHADER_COMPILER #if COMPILE_WITH_SHADER_COMPILER
#include "Engine/Core/Log.h"
#include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Array.h"
#include "Engine/Utilities/TextProcessing.h" #include "Engine/Utilities/TextProcessing.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Core/Log.h" #include "Engine/Graphics/RenderTools.h"
#include "ShaderFunctionReader.CB.h" #include "ShaderFunctionReader.CB.h"
#include "ShaderFunctionReader.VS.h" #include "ShaderFunctionReader.VS.h"
#include "ShaderFunctionReader.HS.h" #include "ShaderFunctionReader.HS.h"
@@ -17,12 +18,13 @@
#include "ShaderFunctionReader.CS.h" #include "ShaderFunctionReader.CS.h"
#include "Config.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) : failed(false)
, targetName(targetName) , targetName(targetName)
, text(source, sourceLength) , text(source, sourceLength)
, _macros(macros) , _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"); PROFILE_CPU_NAMED("Shader.Parse");
Parser parser(targetName, source, sourceLength, macros, featureLevel); Parser parser(targetName, source, sourceLength, macros, profile);
parser.Process(result); parser.Process(result);
return parser.Failed(); return parser.Failed();
} }
@@ -22,20 +22,18 @@ namespace ShaderProcessing
class Parser : public IShaderParser, public ITokenReadersContainerBase<IShaderFunctionReader> class Parser : public IShaderParser, public ITokenReadersContainerBase<IShaderFunctionReader>
{ {
private: private:
bool failed; bool failed;
String targetName; String targetName;
Reader text; Reader text;
ParserMacros _macros; ParserMacros _macros;
FeatureLevel _featureLevel; FeatureLevel _featureLevel;
ShaderProfileFeatures _features;
private: private:
Parser(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, ShaderProfile profile);
Parser(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, FeatureLevel featureLevel);
~Parser(); ~Parser();
public: public:
/// <summary> /// <summary>
/// Process shader source code and generate metadata /// Process shader source code and generate metadata
/// </summary> /// </summary>
@@ -43,13 +41,12 @@ namespace ShaderProcessing
/// <param name="source">ANSI source code</param> /// <param name="source">ANSI source code</param>
/// <param name="sourceLength">Amount of characters in the source code</param> /// <param name="sourceLength">Amount of characters in the source code</param>
/// <param name="macros">The input macros.</param> /// <param name="macros">The input macros.</param>
/// <param name="featureLevel">The target feature level.</param> /// <param name="profile">The target shader profile.</param>
/// <param name="result">Output result with metadata</param> /// <param name="result">Output result with metadata</param>
/// <returns>True if cannot process the file (too many errors), otherwise false</returns> /// <returns>True if cannot process the file (too many errors), otherwise false</returns>
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: public:
/// <summary> /// <summary>
/// Process shader source code and generate metadata /// Process shader source code and generate metadata
/// </summary> /// </summary>
@@ -57,34 +54,32 @@ namespace ShaderProcessing
void Process(ShaderMeta* result); void Process(ShaderMeta* result);
private: private:
void init(); void init();
bool process(); bool process();
bool collectResults(ShaderMeta* result); bool collectResults(ShaderMeta* result);
public: public:
// [IShaderParser] // [IShaderParser]
FeatureLevel GetFeatureLevel() const override FeatureLevel GetFeatureLevel() const override
{ {
return _featureLevel; return _featureLevel;
} }
ShaderProfileFeatures GetFeatures() const override
{
return _features;
}
bool Failed() const override bool Failed() const override
{ {
return failed; return failed;
} }
Reader& GetReader() override Reader& GetReader() override
{ {
return text; return text;
} }
ParserMacros GetMacros() const override ParserMacros GetMacros() const override
{ {
return _macros; return _macros;
} }
void OnError(const String& message) override; void OnError(const String& message) override;
void OnWarning(const String& message) override; void OnWarning(const String& message) override;
}; };
@@ -152,20 +152,14 @@ bool ShadersCompilation::Compile(ShaderCompilationOptions& options)
options.SourceLength--; options.SourceLength--;
const DateTime startTime = DateTime::NowUTC(); const DateTime startTime = DateTime::NowUTC();
const FeatureLevel featureLevel = RenderTools::GetFeatureLevel(options.Profile);
// Process shader source to collect metadata // Process shader source to collect metadata
ShaderMeta meta; 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."); LOG(Warning, "Failed to parse source code.");
return true; return true;
} }
const int32 shadersCount = meta.GetShadersCount();
if (shadersCount == 0 && featureLevel > FeatureLevel::ES2)
{
LOG(Warning, "Shader has no valid functions.");
}
// Perform actual compilation // Perform actual compilation
bool result; bool result;
@@ -9,8 +9,6 @@ TextProcessing::TextProcessing(const char* input, int32 length)
, _cursor(const_cast<char*>(input)) , _cursor(const_cast<char*>(input))
, _position(0) , _position(0)
, _line(1) , _line(1)
, Separators(32)
, Whitespaces(8)
{ {
} }
+6 -6
View File
@@ -32,14 +32,14 @@
#endif #endif
// Meta macros used by shaders parser // 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_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_HS_PATCH(inControlPoints)
#define META_DS(isVisible, minFeatureLevel) #define META_DS(isVisible, minFeatures)
#define META_GS(isVisible, minFeatureLevel) #define META_GS(isVisible, minFeatures)
#define META_PS(isVisible, minFeatureLevel) #define META_PS(isVisible, minFeatures)
#define META_CS(isVisible, minFeatureLevel) #define META_CS(isVisible, minFeatures)
#define META_FLAG(flag) #define META_FLAG(flag)
#define META_PERMUTATION_1(param0) #define META_PERMUTATION_1(param0)
#define META_PERMUTATION_2(param0, param1) #define META_PERMUTATION_2(param0, param1)