// Copyright (c) 2012-2023 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 Entries; Array DebugData; }; /// /// Shader function metadata /// class ShaderFunctionMeta { public: /// /// Virtual destructor /// virtual ~ShaderFunctionMeta() = default; public: /// /// Function name /// StringAnsi Name; /// /// Function flags. /// ShaderFlags Flags; /// /// The minimum graphics platform feature level to support this shader. /// FeatureLevel MinFeatureLevel; /// /// All possible values for the permutations and it's values to generate different permutation of this function /// Array Permutations; public: /// /// Checks if definition name has been added to the given permutation /// /// Shader permutation index /// Name of the definition to check /// True if definition of given name has been registered for the permutations, otherwise false 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; } /// /// Checks if definition name has been added to the permutations collection /// /// Name of the definition to check /// True if definition of given name has been registered for the permutations, otherwise false bool HasDefinition(const StringAnsi& defineName) const { for (int32 permutationIndex = 0; permutationIndex < Permutations.Count(); permutationIndex++) { if (HasDefinition(permutationIndex, defineName)) return true; } return false; } /// /// Gets all macros for given shader permutation /// /// Shader permutation index /// Output array with permutation macros void GetDefinitionsForPermutation(int32 permutationIndex, Array& 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: /// /// Gets shader function meta stage type. /// virtual ShaderStage GetStage() const = 0; }; /// /// Vertex shader function meta /// class VertexShaderMeta : public ShaderFunctionMeta { public: /// /// Input element type /// enum class InputType : byte { Invalid = 0, POSITION = 1, COLOR = 2, TEXCOORD = 3, NORMAL = 4, TANGENT = 5, BITANGENT = 6, ATTRIBUTE = 7, BLENDINDICES = 8, BLENDWEIGHT = 9, }; /// /// Input element /// struct InputElement { /// /// Semantic type /// InputType Type; /// /// Semantic index /// byte Index; /// /// Element data format /// PixelFormat Format; /// /// An integer value that identifies the input-assembler /// byte InputSlot; /// /// 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 /// uint32 AlignedByteOffset; /// /// Identifies the input data class for a single input slot. INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA or INPUT_LAYOUT_ELEMENT_PER_INSTANCE_DATA /// byte InputSlotClass; /// /// 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 /// uint32 InstanceDataStepRate; /// /// 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. /// StringAnsi VisibleFlag; }; public: /// /// Input layout description /// Array InputLayout; public: // [ShaderFunctionMeta] ShaderStage GetStage() const override { return ShaderStage::Vertex; } }; /// /// Hull (or tessellation control) shader function meta /// class HullShaderMeta : public ShaderFunctionMeta { public: /// /// The input control points count (valid range: 1-32). /// int32 ControlPointsCount; public: // [ShaderFunctionMeta] ShaderStage GetStage() const override { return ShaderStage::Hull; } }; /// /// Domain (or tessellation evaluation) shader function meta /// class DomainShaderMeta : public ShaderFunctionMeta { public: // [ShaderFunctionMeta] ShaderStage GetStage() const override { return ShaderStage::Domain; } }; /// /// Geometry shader function meta /// class GeometryShaderMeta : public ShaderFunctionMeta { public: // [ShaderFunctionMeta] ShaderStage GetStage() const override { return ShaderStage::Geometry; } }; /// /// Pixel shader function meta /// class PixelShaderMeta : public ShaderFunctionMeta { public: // [ShaderFunctionMeta] ShaderStage GetStage() const override { return ShaderStage::Pixel; } }; /// /// Compute shader function meta /// class ComputeShaderMeta : public ShaderFunctionMeta { public: // [ShaderFunctionMeta] ShaderStage GetStage() const override { return ShaderStage::Compute; } }; /// /// Constant buffer meta /// struct ConstantBufferMeta { /// /// Slot index /// byte Slot; /// /// Buffer name /// StringAnsi Name; }; /// /// Shader source metadata /// class ShaderMeta { public: /// /// Vertex Shaders /// Array VS; /// /// Hull Shaders /// Array HS; /// /// Domain Shaders /// Array DS; /// /// Geometry Shaders /// Array GS; /// /// Pixel Shaders /// Array PS; /// /// Compute Shaders /// Array CS; /// /// Constant Buffers /// Array CB; public: /// /// Gets amount of shaders attached (not counting permutations) /// /// Amount of all shader programs uint32 GetShadersCount() const { return VS.Count() + HS.Count() + DS.Count() + GS.Count() + PS.Count() + CS.Count(); } /// /// Gets all shader functions (all types) /// /// Output collections of functions void GetShaders(Array& functions) const { #define PEEK_SHADERS(collection) for (int32 i = 0; i < collection.Count(); i++) functions.Add(dynamic_cast(&(collection[i]))); PEEK_SHADERS(VS); PEEK_SHADERS(HS); PEEK_SHADERS(DS); PEEK_SHADERS(GS); PEEK_SHADERS(PS); PEEK_SHADERS(CS); #undef PEEK_SHADERS } }; #endif