Files
FlaxEngine/Source/Engine/ShadersCompilation/Parser/ShaderMeta.h
2024-12-13 09:20:01 +01:00

364 lines
9.0 KiB
C++

// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#pragma once
#if COMPILE_WITH_SHADER_COMPILER
#include "Engine/Core/Config.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Math/Math.h"
#include "Engine/Graphics/PixelFormat.h"
#include "Config.h"
struct ShaderPermutationEntry
{
StringAnsi Name;
StringAnsi Value;
};
struct ShaderPermutation
{
// TODO: maybe we could use macro SHADER_PERMUTATIONS_MAX_PARAMS_COUNT and reduce amount of dynamic allocations for permutations
Array<ShaderPermutationEntry> Entries;
Array<char> DebugData;
};
/// <summary>
/// Shader function metadata
/// </summary>
class ShaderFunctionMeta
{
public:
/// <summary>
/// Virtual destructor
/// </summary>
virtual ~ShaderFunctionMeta() = default;
public:
/// <summary>
/// Function name
/// </summary>
StringAnsi Name;
/// <summary>
/// Function flags.
/// </summary>
ShaderFlags Flags;
/// <summary>
/// The minimum graphics platform feature level to support this shader.
/// </summary>
FeatureLevel MinFeatureLevel;
/// <summary>
/// All possible values for the permutations and it's values to generate different permutation of this function
/// </summary>
Array<ShaderPermutation> Permutations;
public:
/// <summary>
/// Checks if definition name has been added to the given permutation
/// </summary>
/// <param name="permutationIndex">Shader permutation index</param>
/// <param name="defineName">Name of the definition to check</param>
/// <returns>True if definition of given name has been registered for the permutations, otherwise false</returns>
bool HasDefinition(int32 permutationIndex, const StringAnsi& defineName) const
{
ASSERT(Math::IsInRange(permutationIndex, 0, Permutations.Count() - 1));
auto& permutation = Permutations[permutationIndex];
for (int32 i = 0; i < permutation.Entries.Count(); i++)
{
if (permutation.Entries[i].Name == defineName)
return true;
}
return false;
}
/// <summary>
/// Checks if definition name has been added to the permutations collection
/// </summary>
/// <param name="defineName">Name of the definition to check</param>
/// <returns>True if definition of given name has been registered for the permutations, otherwise false</returns>
bool HasDefinition(const StringAnsi& defineName) const
{
for (int32 permutationIndex = 0; permutationIndex < Permutations.Count(); permutationIndex++)
{
if (HasDefinition(permutationIndex, defineName))
return true;
}
return false;
}
/// <summary>
/// Gets all macros for given shader permutation
/// </summary>
/// <param name="permutationIndex">Shader permutation index</param>
/// <param name="macros">Output array with permutation macros</param>
void GetDefinitionsForPermutation(int32 permutationIndex, Array<ShaderMacro>& macros) const
{
ASSERT(Math::IsInRange(permutationIndex, 0, Permutations.Count() - 1));
auto& permutation = Permutations[permutationIndex];
for (int32 i = 0; i < permutation.Entries.Count(); i++)
{
auto& e = permutation.Entries[i];
macros.Add({
e.Name.Get(),
e.Value.Get()
});
}
}
public:
/// <summary>
/// Gets shader function meta stage type.
/// </summary>
virtual ShaderStage GetStage() const = 0;
};
/// <summary>
/// Vertex shader function meta
/// </summary>
class VertexShaderMeta : public ShaderFunctionMeta
{
public:
/// <summary>
/// Input element type
/// [Deprecated in v1.10]
/// </summary>
enum class InputType : byte
{
Invalid = 0,
POSITION = 1,
COLOR = 2,
TEXCOORD = 3,
NORMAL = 4,
TANGENT = 5,
BITANGENT = 6,
ATTRIBUTE = 7,
BLENDINDICES = 8,
BLENDWEIGHT = 9,
};
/// <summary>
/// Input element
/// [Deprecated in v1.10]
/// </summary>
struct InputElement
{
/// <summary>
/// Semantic type
/// </summary>
InputType Type;
/// <summary>
/// Semantic index
/// </summary>
byte Index;
/// <summary>
/// Element data format
/// </summary>
PixelFormat Format;
/// <summary>
/// An integer value that identifies the input-assembler
/// </summary>
byte InputSlot;
/// <summary>
/// Optional. Offset (in bytes) between each element. Use INPUT_LAYOUT_ELEMENT_ALIGN for convenience to define the current element directly after the previous one, including any packing if necessary
/// </summary>
uint32 AlignedByteOffset;
/// <summary>
/// Identifies the input data class for a single input slot. INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA or INPUT_LAYOUT_ELEMENT_PER_INSTANCE_DATA
/// </summary>
byte InputSlotClass;
/// <summary>
/// The number of instances to draw using the same per-instance data before advancing in the buffer by one element. This value must be 0 for an element that contains per-vertex data
/// </summary>
uint32 InstanceDataStepRate;
/// <summary>
/// The visible flag expression. Allows to show/hide element from the input layout based on input macros (also from permutation macros). use empty value to skip this feature.
/// </summary>
StringAnsi VisibleFlag;
};
public:
/// <summary>
/// Input layout description
/// [Deprecated in v1.10]
/// </summary>
Array<InputElement> InputLayout;
public:
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
return ShaderStage::Vertex;
}
};
/// <summary>
/// Hull (or tessellation control) shader function meta
/// </summary>
class HullShaderMeta : public ShaderFunctionMeta
{
public:
/// <summary>
/// The input control points count (valid range: 1-32).
/// </summary>
int32 ControlPointsCount;
public:
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
return ShaderStage::Hull;
}
};
/// <summary>
/// Domain (or tessellation evaluation) shader function meta
/// </summary>
class DomainShaderMeta : public ShaderFunctionMeta
{
public:
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
return ShaderStage::Domain;
}
};
/// <summary>
/// Geometry shader function meta
/// </summary>
class GeometryShaderMeta : public ShaderFunctionMeta
{
public:
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
return ShaderStage::Geometry;
}
};
/// <summary>
/// Pixel shader function meta
/// </summary>
class PixelShaderMeta : public ShaderFunctionMeta
{
public:
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
return ShaderStage::Pixel;
}
};
/// <summary>
/// Compute shader function meta
/// </summary>
class ComputeShaderMeta : public ShaderFunctionMeta
{
public:
// [ShaderFunctionMeta]
ShaderStage GetStage() const override
{
return ShaderStage::Compute;
}
};
/// <summary>
/// Constant buffer meta
/// </summary>
struct ConstantBufferMeta
{
/// <summary>
/// Slot index
/// </summary>
byte Slot;
/// <summary>
/// Buffer name
/// </summary>
StringAnsi Name;
};
/// <summary>
/// Shader source metadata
/// </summary>
class ShaderMeta
{
public:
/// <summary>
/// Vertex Shaders
/// </summary>
Array<VertexShaderMeta> VS;
/// <summary>
/// Hull Shaders
/// </summary>
Array<HullShaderMeta> HS;
/// <summary>
/// Domain Shaders
/// </summary>
Array<DomainShaderMeta> DS;
/// <summary>
/// Geometry Shaders
/// </summary>
Array<GeometryShaderMeta> GS;
/// <summary>
/// Pixel Shaders
/// </summary>
Array<PixelShaderMeta> PS;
/// <summary>
/// Compute Shaders
/// </summary>
Array<ComputeShaderMeta> CS;
/// <summary>
/// Constant Buffers
/// </summary>
Array<ConstantBufferMeta> CB;
public:
/// <summary>
/// Gets amount of shaders attached (not counting permutations).
/// </summary>
int32 GetShadersCount() const
{
return VS.Count() + HS.Count() + DS.Count() + GS.Count() + PS.Count() + CS.Count();
}
/// <summary>
/// Gets all shader functions (all types).
/// </summary>
/// <param name="functions">Output collections of functions</param>
void GetShaders(Array<const ShaderFunctionMeta*>& functions) const
{
#define PEEK_SHADERS(collection) for (int32 i = 0; i < collection.Count(); i++) functions.Add(dynamic_cast<const ShaderFunctionMeta*>(&(collection[i])));
PEEK_SHADERS(VS);
PEEK_SHADERS(HS);
PEEK_SHADERS(DS);
PEEK_SHADERS(GS);
PEEK_SHADERS(PS);
PEEK_SHADERS(CS);
#undef PEEK_SHADERS
}
};
#endif