You're breathtaking!
This commit is contained in:
21
Source/Engine/ShadersCompilation/Parser/Config.h
Normal file
21
Source/Engine/ShadersCompilation/Parser/Config.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Config.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
#include "Engine/Utilities/TextProcessing.h"
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
typedef TextProcessing Reader;
|
||||
typedef Reader::Token Token;
|
||||
typedef Reader::SeparatorData Separator;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Don't count ending '\0' character
|
||||
#define MACRO_LENGTH(macro) (ARRAY_COUNT(macro) - 1)
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ITokenReader.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for shader functions readers like Pixel Shader readers or Constant Buffer readers
|
||||
/// </summary>
|
||||
class IShaderFunctionReader : public ITokenReader
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Virtual destructor
|
||||
/// </summary>
|
||||
virtual ~IShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Collects shader function reader results to the final Shader Meta
|
||||
/// </summary>
|
||||
/// <param name="parser">Parser object</param>
|
||||
/// <param name="result">Parsing result</param>
|
||||
virtual void CollectResults(IShaderParser* parser, ShaderMeta* result) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
90
Source/Engine/ShadersCompilation/Parser/IShaderParser.h
Normal file
90
Source/Engine/ShadersCompilation/Parser/IShaderParser.h
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
struct ParserMacros
|
||||
{
|
||||
const Array<ShaderMacro>* Data;
|
||||
|
||||
ParserMacros(const Array<ShaderMacro>& data)
|
||||
{
|
||||
Data = &data;
|
||||
}
|
||||
|
||||
Token GetValue(Token& token) const
|
||||
{
|
||||
for (int32 i = 0; i < Data->Count(); i++)
|
||||
{
|
||||
if (token == Data->At(i).Name)
|
||||
{
|
||||
// Use macro value
|
||||
return Token(Data->At(i).Definition);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to token
|
||||
return token;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Interface describing shader source code parser
|
||||
/// </summary>
|
||||
class IShaderParser
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Virtual destructor
|
||||
/// </summary>
|
||||
virtual ~IShaderParser()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parser feature level of the target platform graphics backend.
|
||||
/// </summary>
|
||||
/// <returns>The graphics feature level</returns>
|
||||
virtual FeatureLevel GetFeatureLevel() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parser macros.
|
||||
/// </summary>
|
||||
/// <returns>The macros</returns>
|
||||
virtual ParserMacros GetMacros() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets value indicating that shader processing operation failed
|
||||
/// </summary>
|
||||
/// <returns>True if shader processing failed, otherwise false</returns>
|
||||
virtual bool Failed() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets source code reader
|
||||
/// </summary>
|
||||
/// <returns>Source code reader</returns>
|
||||
virtual Reader& GetReader() = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Event send to the parser on reading shader source code error
|
||||
/// </summary>
|
||||
/// <param name="message">Message to send</param>
|
||||
virtual void OnError(const String& message) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Event send to the parser on reading shader source code warning
|
||||
/// </summary>
|
||||
/// <param name="message">Message to send</param>
|
||||
virtual void OnWarning(const String& message) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
44
Source/Engine/ShadersCompilation/Parser/ITokenReader.h
Normal file
44
Source/Engine/ShadersCompilation/Parser/ITokenReader.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "IShaderParser.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for objects that can read shader source code tokens
|
||||
/// </summary>
|
||||
class ITokenReader
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Virtual destructor
|
||||
/// </summary>
|
||||
virtual ~ITokenReader()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Checks if given token can be processed by this reader
|
||||
/// </summary>
|
||||
/// <param name="token">Starting token to check</param>
|
||||
/// <returns>True if given token is valid starting token, otherwise false</returns>
|
||||
virtual bool CheckStartToken(const Token& token) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Start processing source after reading start token
|
||||
/// </summary>
|
||||
/// <param name="parser">Parser object</param>
|
||||
/// <param name="text">Source code reader</param>
|
||||
virtual void Process(IShaderParser* parser, Reader& text) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "ITokenReader.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for objects that can have child token readers
|
||||
/// </summary>
|
||||
template<typename Type>
|
||||
class ITokenReadersContainerBase
|
||||
{
|
||||
protected:
|
||||
|
||||
Array<Type*> _childReaders;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Virtual destructor
|
||||
/// </summary>
|
||||
virtual ~ITokenReadersContainerBase()
|
||||
{
|
||||
// Cleanup
|
||||
_childReaders.ClearDelete();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// <summary>
|
||||
/// Try to process given token by any child reader
|
||||
/// </summary>
|
||||
/// <param name="token">Starting token to check</param>
|
||||
/// <param name="parser">Parser object</param>
|
||||
/// <returns>True if no token processing has been done, otherwise false</returns>
|
||||
virtual bool ProcessChildren(const Token& token, IShaderParser* parser)
|
||||
{
|
||||
for (int32 i = 0; i < _childReaders.Count(); i++)
|
||||
{
|
||||
if (_childReaders[i]->CheckStartToken(token))
|
||||
{
|
||||
_childReaders[i]->Process(parser, parser->GetReader());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Interface for objects that can have child ITokenReader objects
|
||||
/// </summary>
|
||||
class ITokenReadersContainer : public ITokenReadersContainerBase<ITokenReader>
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Virtual destructor
|
||||
/// </summary>
|
||||
virtual ~ITokenReadersContainer()
|
||||
{
|
||||
// Cleanup
|
||||
_childReaders.ClearDelete();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShaderFunctionReader.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant Buffers reader
|
||||
/// </summary>
|
||||
class ConstantBufferReader : public ShaderMetaReader<ConstantBufferMeta>
|
||||
{
|
||||
private:
|
||||
|
||||
Token _endToken;
|
||||
|
||||
DECLARE_SHADER_META_READER_HEADER("META_CB_BEGIN", CB);
|
||||
|
||||
ConstantBufferReader()
|
||||
: _endToken("META_CB_END")
|
||||
{
|
||||
}
|
||||
|
||||
~ConstantBufferReader()
|
||||
{
|
||||
}
|
||||
|
||||
// [ShaderMetaReader]
|
||||
void OnParseBefore(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
Token token;
|
||||
|
||||
// Clear current meta
|
||||
_current.Name.Clear();
|
||||
|
||||
// Here we read '(x)\n' where 'x' is a shader function slot
|
||||
text.ReadToken(&token);
|
||||
if (StringUtils::Parse(token.Start, token.Length, &_current.Slot))
|
||||
{
|
||||
parser->OnError(TEXT("Invalid constant buffer slot index."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Read buffer name
|
||||
text.ReadToken(&token);
|
||||
_current.Name = token.ToString();
|
||||
|
||||
// Check if name is unique
|
||||
for (int32 i = 0; i < _cache.Count(); i++)
|
||||
{
|
||||
if (_cache[i].Name == _current.Name)
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Duplicated constant buffer \'{0}\'. Buffer with that name already exists."), String(_current.Name)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Read rest of the line
|
||||
text.ReadLine();
|
||||
}
|
||||
|
||||
void OnParse(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
Token token;
|
||||
|
||||
// Read function properties
|
||||
bool foundEnd = false;
|
||||
while (text.CanRead())
|
||||
{
|
||||
text.ReadToken(&token);
|
||||
|
||||
// Try to find the ending
|
||||
if (token == _endToken)
|
||||
{
|
||||
foundEnd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if end has not been found
|
||||
if (!foundEnd)
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Missing constant buffer \'{0}\' ending."), String(_current.Name)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void OnParseAfter(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
// Cache buffer
|
||||
_cache.Add(_current);
|
||||
}
|
||||
|
||||
void CollectResults(IShaderParser* parser, ShaderMeta* result) override
|
||||
{
|
||||
// Validate constant buffer slots overlapping
|
||||
for (int32 i = 0; i < _cache.Count(); i++)
|
||||
{
|
||||
auto& first = _cache[i];
|
||||
for (int32 j = i + 1; j < _cache.Count(); j++)
|
||||
{
|
||||
auto& second = _cache[j];
|
||||
if (first.Slot == second.Slot)
|
||||
{
|
||||
parser->OnError(TEXT("Constant buffers slots are overlapping."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate amount of used constant buffers
|
||||
for (int32 i = 0; i < _cache.Count(); i++)
|
||||
{
|
||||
auto& f = _cache[i];
|
||||
if (f.Slot >= MAX_CONSTANT_BUFFER_SLOTS)
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Constant buffer {0} is using invalid slot {1}. Maximum supported slot is {2}."), String(f.Name), f.Slot, MAX_CONSTANT_BUFFER_SLOTS - 1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Base
|
||||
ShaderMetaReader::CollectResults(parser, result);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShaderFunctionReader.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Compute Shaders reader
|
||||
/// </summary>
|
||||
class ComputeShaderFunctionReader : public ShaderFunctionReader<ComputeShaderMeta>
|
||||
{
|
||||
DECLARE_SHADER_META_READER_HEADER("META_CS", CS);
|
||||
|
||||
ComputeShaderFunctionReader()
|
||||
{
|
||||
_childReaders.Add(New<StripLineReader>("numthreads"));
|
||||
}
|
||||
|
||||
~ComputeShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShaderFunctionReader.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Domain Shaders reader
|
||||
/// </summary>
|
||||
class DomainShaderFunctionReader : public ShaderFunctionReader<DomainShaderMeta>
|
||||
{
|
||||
DECLARE_SHADER_META_READER_HEADER("META_DS", DS);
|
||||
|
||||
DomainShaderFunctionReader()
|
||||
{
|
||||
_childReaders.Add(New<StripLineReader>("domain"));
|
||||
}
|
||||
|
||||
~DomainShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShaderFunctionReader.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Geometry Shaders reader
|
||||
/// </summary>
|
||||
class GeometryShaderFunctionReader : public ShaderFunctionReader<GeometryShaderMeta>
|
||||
{
|
||||
class MaxVertexCountReader : public ITokenReader
|
||||
{
|
||||
private:
|
||||
|
||||
Token _startToken;
|
||||
|
||||
public:
|
||||
|
||||
MaxVertexCountReader()
|
||||
: _startToken("maxvertexcount")
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [ITokenReader]
|
||||
bool CheckStartToken(const Token& token) override
|
||||
{
|
||||
return token == _startToken;
|
||||
}
|
||||
|
||||
void Process(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
// Read line to end
|
||||
text.ReadLine();
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_SHADER_META_READER_HEADER("META_GS", GS);
|
||||
|
||||
GeometryShaderFunctionReader()
|
||||
{
|
||||
_childReaders.Add(New<MaxVertexCountReader>());
|
||||
}
|
||||
|
||||
~GeometryShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShaderFunctionReader.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Hull Shaders reader
|
||||
/// </summary>
|
||||
class HullShaderFunctionReader : public ShaderFunctionReader<HullShaderMeta>
|
||||
{
|
||||
class PatchSizeReader : public ITokenReader
|
||||
{
|
||||
protected:
|
||||
|
||||
HullShaderFunctionReader* _parent;
|
||||
Token _startToken;
|
||||
|
||||
public:
|
||||
|
||||
PatchSizeReader(HullShaderFunctionReader* parent)
|
||||
: _parent(parent)
|
||||
, _startToken("META_HS_PATCH")
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [ITokenReader]
|
||||
bool CheckStartToken(const Token& token) override
|
||||
{
|
||||
return token == _startToken;
|
||||
}
|
||||
|
||||
void Process(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
Token token;
|
||||
auto& current = _parent->_current;
|
||||
|
||||
// Input control points count
|
||||
text.ReadToken(&token);
|
||||
token = parser->GetMacros().GetValue(token);
|
||||
int32 controlPointsCount;
|
||||
if (StringUtils::Parse(token.Start, token.Length, &controlPointsCount))
|
||||
{
|
||||
parser->OnError(TEXT("Cannot parse Hull shader input control points count."));
|
||||
return;
|
||||
}
|
||||
if (Math::IsNotInRange(controlPointsCount, 1, 32))
|
||||
{
|
||||
parser->OnError(TEXT("Invalid amount of control points. Valid range is [1-32]."));
|
||||
return;
|
||||
}
|
||||
current.ControlPointsCount = controlPointsCount;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_SHADER_META_READER_HEADER("META_HS", HS);
|
||||
|
||||
HullShaderFunctionReader()
|
||||
{
|
||||
_childReaders.Add(New<PatchSizeReader>(this));
|
||||
_childReaders.Add(New<StripLineReader>("domain"));
|
||||
_childReaders.Add(New<StripLineReader>("partitioning"));
|
||||
_childReaders.Add(New<StripLineReader>("outputtopology"));
|
||||
_childReaders.Add(New<StripLineReader>("maxtessfactor"));
|
||||
_childReaders.Add(New<StripLineReader>("outputcontrolpoints"));
|
||||
_childReaders.Add(New<StripLineReader>("patchconstantfunc"));
|
||||
}
|
||||
|
||||
~HullShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
|
||||
void OnParseBefore(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
// Clear current meta
|
||||
_current.ControlPointsCount = 0;
|
||||
|
||||
// Base
|
||||
ShaderFunctionReader::OnParseBefore(parser, text);
|
||||
}
|
||||
|
||||
void OnParseAfter(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
// Check if errors in parsed data
|
||||
if (_current.ControlPointsCount == 0)
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Hull Shader \'{0}\' has missing META_HS_PATCH macro that defines the amount of the input control points from the Input Assembler."), String(_current.Name)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Base
|
||||
ShaderFunctionReader::OnParseAfter(parser, text);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShaderFunctionReader.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Pixel Shaders reader
|
||||
/// </summary>
|
||||
class PixelShaderFunctionReader : public ShaderFunctionReader<PixelShaderMeta>
|
||||
{
|
||||
DECLARE_SHADER_META_READER_HEADER("META_PS", PS);
|
||||
|
||||
PixelShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
|
||||
~PixelShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShaderFunctionReader.h"
|
||||
#include "ShaderProcessing.h"
|
||||
#include "Engine/Graphics/Shaders/Config.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Vertex Shaders reader
|
||||
/// </summary>
|
||||
class VertexShaderFunctionReader : public ShaderFunctionReader<VertexShaderMeta>
|
||||
{
|
||||
class InputLayoutReader : public ITokenReader
|
||||
{
|
||||
protected:
|
||||
|
||||
VertexShaderFunctionReader* _parent;
|
||||
Token _startToken;
|
||||
|
||||
public:
|
||||
|
||||
InputLayoutReader(VertexShaderFunctionReader* parent)
|
||||
: _parent(parent)
|
||||
, _startToken("META_VS_IN_ELEMENT")
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [ITokenReader]
|
||||
bool CheckStartToken(const Token& token) override
|
||||
{
|
||||
return token == _startToken;
|
||||
}
|
||||
|
||||
void Process(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
VertexShaderMeta::InputElement element;
|
||||
Token token;
|
||||
auto& current = _parent->_current;
|
||||
|
||||
// Semantic type
|
||||
text.ReadToken(&token);
|
||||
element.Type = ParseInputType(token);
|
||||
|
||||
// Semantic index
|
||||
text.ReadToken(&token);
|
||||
if (StringUtils::Parse(token.Start, token.Length, &element.Index))
|
||||
{
|
||||
parser->OnError(TEXT("Cannot parse token."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Element format
|
||||
text.ReadToken(&token);
|
||||
element.Format = ParsePixelFormat(token);
|
||||
if (element.Format == PixelFormat::Unknown)
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Unknown input data format \'{0}\' for the Vertex Shader."), String(token.ToString())));
|
||||
return;
|
||||
}
|
||||
|
||||
// Input slot
|
||||
text.ReadToken(&token);
|
||||
if (StringUtils::Parse(token.Start, token.Length, &element.InputSlot))
|
||||
{
|
||||
parser->OnError(TEXT("Cannot parse token."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Aligned byte offset
|
||||
text.ReadToken(&token);
|
||||
if (token == "ALIGN")
|
||||
{
|
||||
element.AlignedByteOffset = INPUT_LAYOUT_ELEMENT_ALIGN;
|
||||
}
|
||||
else if (StringUtils::Parse(token.Start, token.Length, &element.AlignedByteOffset))
|
||||
{
|
||||
parser->OnError(TEXT("Cannot parse token."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Input slot class
|
||||
text.ReadToken(&token);
|
||||
if (token == "PER_VERTEX")
|
||||
{
|
||||
element.InputSlotClass = INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA;
|
||||
}
|
||||
else if (token == "PER_INSTANCE")
|
||||
{
|
||||
element.InputSlotClass = INPUT_LAYOUT_ELEMENT_PER_INSTANCE_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Invalid input slot class type \'{0}\'."), String(token.ToString())));
|
||||
return;
|
||||
}
|
||||
|
||||
// Instance data step rate
|
||||
text.ReadToken(&token);
|
||||
if (StringUtils::Parse(token.Start, token.Length, &element.InstanceDataStepRate))
|
||||
{
|
||||
parser->OnError(TEXT("Cannot parse token."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Visible state
|
||||
text.ReadToken(&token);
|
||||
element.VisibleFlag = token.ToString();
|
||||
|
||||
current.InputLayout.Add(element);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_SHADER_META_READER_HEADER("META_VS", VS);
|
||||
|
||||
VertexShaderFunctionReader()
|
||||
{
|
||||
_childReaders.Add(New<InputLayoutReader>(this));
|
||||
}
|
||||
|
||||
~VertexShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
|
||||
void OnParseBefore(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
// Clear current meta
|
||||
_current.InputLayout.Clear();
|
||||
|
||||
// Base
|
||||
ShaderFunctionReader::OnParseBefore(parser, text);
|
||||
}
|
||||
|
||||
void OnParseAfter(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
// Check if errors in specified input layout
|
||||
if (_current.InputLayout.Count() > VERTEX_SHADER_MAX_INPUT_ELEMENTS)
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Vertex Shader \'{0}\' has too many input layout elements specified. Maximum allowed amount is {1}."), String(_current.Name), VERTEX_SHADER_MAX_INPUT_ELEMENTS));
|
||||
return;
|
||||
}
|
||||
|
||||
// Base
|
||||
ShaderFunctionReader::OnParseAfter(parser, text);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
446
Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.h
Normal file
446
Source/Engine/ShadersCompilation/Parser/ShaderFunctionReader.h
Normal file
@@ -0,0 +1,446 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IShaderFunctionReader.h"
|
||||
#include "ShaderMeta.h"
|
||||
#include "Config.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of shader meta functions reader
|
||||
/// </summary>
|
||||
template<typename MetaType>
|
||||
class ShaderMetaReader : public IShaderFunctionReader, public ITokenReadersContainer
|
||||
{
|
||||
protected:
|
||||
|
||||
Array<MetaType> _cache;
|
||||
MetaType _current;
|
||||
|
||||
ShaderMetaReader()
|
||||
{
|
||||
}
|
||||
|
||||
~ShaderMetaReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// <summary>
|
||||
/// Event called before parsing shader function
|
||||
/// </summary>
|
||||
/// <param name="parser">Parser object</param>
|
||||
/// <param name="text">Source code reader</param>
|
||||
virtual void OnParseBefore(IShaderParser* parser, Reader& text) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Event called for parsing shader function
|
||||
/// </summary>
|
||||
/// <param name="parser">Parser object</param>
|
||||
/// <param name="text">Source code reader</param>
|
||||
virtual void OnParse(IShaderParser* parser, Reader& text)
|
||||
{
|
||||
Token token;
|
||||
|
||||
// Read function properties
|
||||
while (text.CanRead())
|
||||
{
|
||||
text.ReadToken(&token);
|
||||
|
||||
// Call children
|
||||
if (ProcessChildren(token, parser))
|
||||
break;
|
||||
}
|
||||
|
||||
// Token should contain function output type, now read function name
|
||||
text.ReadToken(&token);
|
||||
_current.Name = token.ToString();
|
||||
|
||||
// Check if name is unique
|
||||
for (int32 i = 0; i < _cache.Count(); i++)
|
||||
{
|
||||
if (_cache[i].Name == _current.Name)
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Duplicated function \'{0}\'. Function with that name already exists."), String(_current.Name)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event called after parsing shader function
|
||||
/// </summary>
|
||||
/// <param name="parser">Parser object</param>
|
||||
/// <param name="text">Source code reader</param>
|
||||
virtual void OnParseAfter(IShaderParser* parser, Reader& text) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Process final results and send them to the Shader Meta object
|
||||
/// </summary>
|
||||
/// <param name="parser">Parser object</param>
|
||||
/// <param name="result">Output shader meta</param>
|
||||
virtual void FlushCache(IShaderParser* parser, ShaderMeta* result) = 0;
|
||||
|
||||
public:
|
||||
|
||||
// [IShaderFunctionReader]
|
||||
void Process(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
OnParseBefore(parser, text);
|
||||
if (parser->Failed())
|
||||
return;
|
||||
|
||||
OnParse(parser, text);
|
||||
if (parser->Failed())
|
||||
return;
|
||||
|
||||
OnParseAfter(parser, text);
|
||||
}
|
||||
|
||||
void CollectResults(IShaderParser* parser, ShaderMeta* result) override
|
||||
{
|
||||
// Validate function names
|
||||
for (int32 i = 0; i < _cache.Count(); i++)
|
||||
{
|
||||
auto& first = _cache[i];
|
||||
for (int32 j = i + 1; j < _cache.Count(); j++)
|
||||
{
|
||||
auto& second = _cache[j];
|
||||
if (first.Name == second.Name)
|
||||
{
|
||||
parser->OnError(TEXT("Duplicated shader function names."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlushCache(parser, result);
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of shader functions reader
|
||||
/// </summary>
|
||||
template<typename MetaType>
|
||||
class ShaderFunctionReader : public ShaderMetaReader<MetaType>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef ShaderMetaReader<MetaType> ShaderMetaReaderType;
|
||||
|
||||
protected:
|
||||
|
||||
class StripLineReader : public ITokenReader
|
||||
{
|
||||
private:
|
||||
|
||||
Token _startToken;
|
||||
|
||||
public:
|
||||
|
||||
explicit StripLineReader(const char* token)
|
||||
: _startToken(token)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [ITokenReader]
|
||||
bool CheckStartToken(const Token& token) override
|
||||
{
|
||||
return token == _startToken;
|
||||
}
|
||||
|
||||
void Process(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
// Read line to end
|
||||
text.ReadLine();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Shader function permutations reader
|
||||
/// </summary>
|
||||
class PermutationReader : public ITokenReader
|
||||
{
|
||||
protected:
|
||||
|
||||
ShaderFunctionReader* _parent;
|
||||
int32 _startTokenPermutationSize;
|
||||
|
||||
const char* PermutationTokens[SHADER_PERMUTATIONS_MAX_PARAMS_COUNT] =
|
||||
{
|
||||
"META_PERMUTATION_1",
|
||||
"META_PERMUTATION_2",
|
||||
"META_PERMUTATION_3",
|
||||
"META_PERMUTATION_4",
|
||||
};
|
||||
static_assert(SHADER_PERMUTATIONS_MAX_PARAMS_COUNT == 4, "Invalid maximum amount of shader permutations.");
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent shader function reader object</param>
|
||||
PermutationReader(ShaderFunctionReader* parent)
|
||||
: _parent(parent)
|
||||
, _startTokenPermutationSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Clear cache
|
||||
/// </summary>
|
||||
void Clear()
|
||||
{
|
||||
_startTokenPermutationSize = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [ITokenReader]
|
||||
bool CheckStartToken(const Token& token) override
|
||||
{
|
||||
for (int32 i = 0; i < ARRAY_COUNT(PermutationTokens); i++)
|
||||
{
|
||||
if (token == PermutationTokens[i])
|
||||
{
|
||||
_startTokenPermutationSize = i + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Process(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
Token token;
|
||||
auto& current = _parent->_current;
|
||||
|
||||
// Add permutation
|
||||
int32 permutationIndex = current.Permutations.Count();
|
||||
auto& permutation = current.Permutations.AddOne();
|
||||
|
||||
// Read all parameters for the permutation
|
||||
ASSERT(_startTokenPermutationSize > 0);
|
||||
for (int32 paramIndex = 0; paramIndex < _startTokenPermutationSize; paramIndex++)
|
||||
{
|
||||
// Check for missing end
|
||||
if (!text.CanRead())
|
||||
{
|
||||
parser->OnError(TEXT("Missing ending of shader function permutation."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Read definition name
|
||||
text.ReadToken(&token);
|
||||
if (token.Length == 0)
|
||||
{
|
||||
parser->OnError(TEXT("Incorrect shader permutation. Definition name is empty."));
|
||||
return;
|
||||
}
|
||||
StringAnsi name = token.ToString();
|
||||
|
||||
// Read '=' character
|
||||
if (token.Separator != Separator('='))
|
||||
{
|
||||
if (token.Separator.IsWhiteSpace())
|
||||
text.EatWhiteSpaces();
|
||||
if (text.PeekChar() != '=')
|
||||
{
|
||||
parser->OnError(TEXT("Incorrect shader permutation. Missing \'='\' character for definition value."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Read definition value
|
||||
text.ReadToken(&token);
|
||||
if (token.Length == 0)
|
||||
{
|
||||
parser->OnError(TEXT("Incorrect shader permutation. Definition value is empty."));
|
||||
return;
|
||||
}
|
||||
StringAnsi value = token.ToString();
|
||||
|
||||
// Read ',' or ')' character (depends on parameter index)
|
||||
char checkChar = (paramIndex == _startTokenPermutationSize - 1) ? ')' : ',';
|
||||
if (token.Separator != Separator(checkChar))
|
||||
{
|
||||
parser->OnError(TEXT("Incorrect shader permutation declaration."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if hasn't been already defined in that permutation
|
||||
if (current.HasDefinition(permutationIndex, name))
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Incorrect shader function permutation definition. Already defined \'{0}\'."), String(name)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Add entry to the meta
|
||||
permutation.Entries.Add({ name, value });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Shader function flag reader
|
||||
/// </summary>
|
||||
class FlagReader : public ITokenReader
|
||||
{
|
||||
protected:
|
||||
|
||||
ShaderFunctionReader* _parent;
|
||||
Token _startToken;
|
||||
|
||||
public:
|
||||
|
||||
FlagReader(ShaderFunctionReader* parent)
|
||||
: _parent(parent)
|
||||
, _startToken("META_FLAG")
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// [ITokenReader]
|
||||
bool CheckStartToken(const Token& token) override
|
||||
{
|
||||
return token == _startToken;
|
||||
}
|
||||
|
||||
void Process(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
Token token;
|
||||
auto& current = _parent->_current;
|
||||
|
||||
// Shader Flag type
|
||||
text.ReadToken(&token);
|
||||
current.Flags |= ParseShaderFlags(token);
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
PermutationReader* _permutationReader;
|
||||
|
||||
ShaderFunctionReader()
|
||||
{
|
||||
_childReaders.Add(_permutationReader = New<PermutationReader>(this));
|
||||
_childReaders.Add(New<FlagReader>(this));
|
||||
}
|
||||
|
||||
~ShaderFunctionReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// [ShaderMetaReader]
|
||||
void OnParseBefore(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
Token token;
|
||||
|
||||
// Clear current meta
|
||||
_current.Name.Clear();
|
||||
_current.Permutations.Clear();
|
||||
_current.Flags = ShaderFlags::Default;
|
||||
_current.MinFeatureLevel = FeatureLevel::ES2;
|
||||
_permutationReader->Clear();
|
||||
|
||||
// Here we read '(x, y)\n' where 'x' is a shader function 'visible' flag, and 'y' is mini feature level
|
||||
text.ReadToken(&token);
|
||||
token = parser->GetMacros().GetValue(token);
|
||||
if (token == "true" || token == "1")
|
||||
{
|
||||
// Visible shader
|
||||
}
|
||||
else if (token == "false" || token == "0")
|
||||
{
|
||||
// Hidden shader
|
||||
_current.Flags = ShaderFlags::Hidden;
|
||||
}
|
||||
else
|
||||
{
|
||||
parser->OnError(TEXT("Invalid shader function \'isVisible\' option value."));
|
||||
return;
|
||||
}
|
||||
text.ReadToken(&token);
|
||||
token = parser->GetMacros().GetValue(token);
|
||||
struct MinFeatureLevel
|
||||
{
|
||||
FeatureLevel Level;
|
||||
const char* Token;
|
||||
};
|
||||
MinFeatureLevel levels[] =
|
||||
{
|
||||
{ FeatureLevel::ES2, "FEATURE_LEVEL_ES2" },
|
||||
{ FeatureLevel::ES3, "FEATURE_LEVEL_ES3" },
|
||||
{ FeatureLevel::ES3_1, "FEATURE_LEVEL_ES3_1" },
|
||||
{ FeatureLevel::SM4, "FEATURE_LEVEL_SM4" },
|
||||
{ FeatureLevel::SM5, "FEATURE_LEVEL_SM5" },
|
||||
};
|
||||
bool missing = true;
|
||||
for (int32 i = 0; i < ARRAY_COUNT(levels); i++)
|
||||
{
|
||||
if (token == levels[i].Token)
|
||||
{
|
||||
_current.MinFeatureLevel = levels[i].Level;
|
||||
missing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (missing)
|
||||
{
|
||||
parser->OnError(TEXT("Invalid shader function \'minFeatureLevel\' option value."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Read rest of the line
|
||||
text.ReadLine();
|
||||
}
|
||||
|
||||
void OnParseAfter(IShaderParser* parser, Reader& text) override
|
||||
{
|
||||
// Validate amount of permutations
|
||||
if (_current.Permutations.Count() > SHADER_PERMUTATIONS_MAX_COUNT)
|
||||
{
|
||||
parser->OnError(String::Format(TEXT("Function \'{0}\' uses too many permutations. Maximum allowed amount is {1}."), String(_current.Name), SHADER_PERMUTATIONS_MAX_COUNT));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if shader has no permutations
|
||||
if (_current.Permutations.IsEmpty())
|
||||
{
|
||||
// Just add blank permutation (rest of the code will work without any hacks for empty permutations list)
|
||||
_current.Permutations.Add(ShaderPermutation());
|
||||
}
|
||||
|
||||
// Check if use this shader program
|
||||
if ((_current.Flags & ShaderFlags::Hidden) == false && _current.MinFeatureLevel <= parser->GetFeatureLevel())
|
||||
{
|
||||
// Cache read function
|
||||
_cache.Add(_current);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#define DECLARE_SHADER_META_READER_HEADER(tokenName, shaderMetaMemberCollection) public: \
|
||||
bool CheckStartToken(const Token& token) override \
|
||||
{ return token == tokenName; } \
|
||||
void FlushCache(IShaderParser* parser, ShaderMeta* result) \
|
||||
{ result->shaderMetaMemberCollection.Add(_cache); }
|
||||
|
||||
#endif
|
||||
377
Source/Engine/ShadersCompilation/Parser/ShaderMeta.h
Normal file
377
Source/Engine/ShadersCompilation/Parser/ShaderMeta.h
Normal file
@@ -0,0 +1,377 @@
|
||||
// Copyright (c) 2012-2020 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>
|
||||
/// <returns>Shader Stage type</returns>
|
||||
virtual ShaderStage GetStage() const = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Vertex shader function meta
|
||||
/// </summary>
|
||||
class VertexShaderMeta : public ShaderFunctionMeta
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Input element type
|
||||
/// </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
|
||||
/// </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
|
||||
/// </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>
|
||||
/// <returns>Amount of all shader programs</returns>
|
||||
uint32 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
|
||||
@@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ShaderProcessing.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
#include "Engine/Core/Log.h"
|
||||
|
||||
VertexShaderMeta::InputType ShaderProcessing::ParseInputType(const Token& token)
|
||||
{
|
||||
struct InputDesc
|
||||
{
|
||||
VertexShaderMeta::InputType e;
|
||||
const char* s;
|
||||
};
|
||||
|
||||
#define _PARSE_ENTRY(x) { VertexShaderMeta::InputType::x, #x }
|
||||
const InputDesc formats[] =
|
||||
{
|
||||
_PARSE_ENTRY(Invalid),
|
||||
_PARSE_ENTRY(POSITION),
|
||||
_PARSE_ENTRY(COLOR),
|
||||
_PARSE_ENTRY(TEXCOORD),
|
||||
_PARSE_ENTRY(NORMAL),
|
||||
_PARSE_ENTRY(TANGENT),
|
||||
_PARSE_ENTRY(BITANGENT),
|
||||
_PARSE_ENTRY(ATTRIBUTE),
|
||||
_PARSE_ENTRY(BLENDINDICES),
|
||||
_PARSE_ENTRY(BLENDWEIGHT),
|
||||
};
|
||||
#undef _PARSE_ENTRY
|
||||
|
||||
for (int32 i = 0; i < ARRAY_COUNT(formats); i++)
|
||||
{
|
||||
if (token == formats[i].s)
|
||||
return formats[i].e;
|
||||
}
|
||||
|
||||
return VertexShaderMeta::InputType::Invalid;
|
||||
}
|
||||
|
||||
PixelFormat ShaderProcessing::ParsePixelFormat(const Token& token)
|
||||
{
|
||||
struct DataDesc
|
||||
{
|
||||
PixelFormat e;
|
||||
const char* s;
|
||||
};
|
||||
|
||||
#define _PARSE_ENTRY(x) { PixelFormat::x, #x }
|
||||
const DataDesc formats[] =
|
||||
{
|
||||
_PARSE_ENTRY(Unknown),
|
||||
_PARSE_ENTRY(R32G32B32A32_Float),
|
||||
_PARSE_ENTRY(R32G32B32A32_UInt),
|
||||
_PARSE_ENTRY(R32G32B32A32_SInt),
|
||||
_PARSE_ENTRY(R32G32B32_Float),
|
||||
_PARSE_ENTRY(R32G32B32_UInt),
|
||||
_PARSE_ENTRY(R32G32B32_SInt),
|
||||
_PARSE_ENTRY(R16G16B16A16_Float),
|
||||
_PARSE_ENTRY(R16G16B16A16_UNorm),
|
||||
_PARSE_ENTRY(R16G16B16A16_UInt),
|
||||
_PARSE_ENTRY(R16G16B16A16_SNorm),
|
||||
_PARSE_ENTRY(R16G16B16A16_SInt),
|
||||
_PARSE_ENTRY(R32G32_Float),
|
||||
_PARSE_ENTRY(R32G32_UInt),
|
||||
_PARSE_ENTRY(R32G32_SInt),
|
||||
_PARSE_ENTRY(R10G10B10A2_UNorm),
|
||||
_PARSE_ENTRY(R10G10B10A2_UInt),
|
||||
_PARSE_ENTRY(R11G11B10_Float),
|
||||
_PARSE_ENTRY(R8G8B8A8_UNorm),
|
||||
_PARSE_ENTRY(R8G8B8A8_UNorm_sRGB),
|
||||
_PARSE_ENTRY(R8G8B8A8_UInt),
|
||||
_PARSE_ENTRY(R8G8B8A8_SNorm),
|
||||
_PARSE_ENTRY(R8G8B8A8_SInt),
|
||||
_PARSE_ENTRY(R16G16_Float),
|
||||
_PARSE_ENTRY(R16G16_UNorm),
|
||||
_PARSE_ENTRY(R16G16_UInt),
|
||||
_PARSE_ENTRY(R16G16_SNorm),
|
||||
_PARSE_ENTRY(R16G16_SInt),
|
||||
_PARSE_ENTRY(R32_Float),
|
||||
_PARSE_ENTRY(R32_UInt),
|
||||
_PARSE_ENTRY(R32_SInt),
|
||||
_PARSE_ENTRY(R8G8_UNorm),
|
||||
_PARSE_ENTRY(R8G8_UInt),
|
||||
_PARSE_ENTRY(R8G8_SNorm),
|
||||
_PARSE_ENTRY(R8G8_SInt),
|
||||
_PARSE_ENTRY(R16_Float),
|
||||
_PARSE_ENTRY(R16_UNorm),
|
||||
_PARSE_ENTRY(R16_UInt),
|
||||
_PARSE_ENTRY(R16_SNorm),
|
||||
_PARSE_ENTRY(R16_SInt),
|
||||
_PARSE_ENTRY(R8_UNorm),
|
||||
_PARSE_ENTRY(R8_UInt),
|
||||
_PARSE_ENTRY(R8_SNorm),
|
||||
_PARSE_ENTRY(R8_SInt),
|
||||
_PARSE_ENTRY(A8_UNorm),
|
||||
_PARSE_ENTRY(R1_UNorm),
|
||||
_PARSE_ENTRY(R8G8_B8G8_UNorm),
|
||||
_PARSE_ENTRY(G8R8_G8B8_UNorm),
|
||||
_PARSE_ENTRY(BC1_UNorm),
|
||||
_PARSE_ENTRY(BC1_UNorm_sRGB),
|
||||
_PARSE_ENTRY(BC2_UNorm),
|
||||
_PARSE_ENTRY(BC2_UNorm_sRGB),
|
||||
_PARSE_ENTRY(BC3_UNorm),
|
||||
_PARSE_ENTRY(BC3_UNorm_sRGB),
|
||||
_PARSE_ENTRY(BC4_UNorm),
|
||||
_PARSE_ENTRY(BC4_SNorm),
|
||||
_PARSE_ENTRY(BC5_UNorm),
|
||||
_PARSE_ENTRY(BC5_SNorm),
|
||||
_PARSE_ENTRY(B5G6R5_UNorm),
|
||||
_PARSE_ENTRY(B5G5R5A1_UNorm),
|
||||
_PARSE_ENTRY(B8G8R8A8_UNorm),
|
||||
_PARSE_ENTRY(B8G8R8X8_UNorm),
|
||||
_PARSE_ENTRY(B8G8R8A8_UNorm_sRGB),
|
||||
_PARSE_ENTRY(B8G8R8X8_UNorm_sRGB),
|
||||
_PARSE_ENTRY(BC6H_Uf16),
|
||||
_PARSE_ENTRY(BC6H_Sf16),
|
||||
_PARSE_ENTRY(BC7_UNorm),
|
||||
_PARSE_ENTRY(BC7_UNorm_sRGB),
|
||||
};
|
||||
#undef _PARSE_ENTRY
|
||||
|
||||
for (int32 i = 0; i < ARRAY_COUNT(formats); i++)
|
||||
{
|
||||
if (token.EqualsIgnoreCase(formats[i].s))
|
||||
return formats[i].e;
|
||||
}
|
||||
|
||||
return PixelFormat::Unknown;
|
||||
}
|
||||
|
||||
ShaderFlags ShaderProcessing::ParseShaderFlags(const Token& token)
|
||||
{
|
||||
struct DataDesc
|
||||
{
|
||||
ShaderFlags e;
|
||||
const char* s;
|
||||
};
|
||||
|
||||
#define _PARSE_ENTRY(x) { ShaderFlags::x, #x }
|
||||
const DataDesc data[] =
|
||||
{
|
||||
_PARSE_ENTRY(Default),
|
||||
_PARSE_ENTRY(Hidden),
|
||||
_PARSE_ENTRY(NoFastMath),
|
||||
_PARSE_ENTRY(VertexToGeometryShader),
|
||||
};
|
||||
static_assert(ARRAY_COUNT(data) == 4, "Invalid amount of Shader Flag data entries.");
|
||||
#undef _PARSE_ENTRY
|
||||
|
||||
for (int32 i = 0; i < ARRAY_COUNT(data); i++)
|
||||
{
|
||||
if (token.EqualsIgnoreCase(data[i].s))
|
||||
return data[i].e;
|
||||
}
|
||||
|
||||
return ShaderFlags::Default;
|
||||
}
|
||||
|
||||
#endif
|
||||
146
Source/Engine/ShadersCompilation/Parser/ShaderProcessing.cpp
Normal file
146
Source/Engine/ShadersCompilation/Parser/ShaderProcessing.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ShaderProcessing.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Utilities/TextProcessing.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "ShaderFunctionReader.CB.h"
|
||||
#include "ShaderFunctionReader.VS.h"
|
||||
#include "ShaderFunctionReader.HS.h"
|
||||
#include "ShaderFunctionReader.DS.h"
|
||||
#include "ShaderFunctionReader.GS.h"
|
||||
#include "ShaderFunctionReader.PS.h"
|
||||
#include "ShaderFunctionReader.CS.h"
|
||||
#include "Config.h"
|
||||
|
||||
ShaderProcessing::Parser::Parser(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, FeatureLevel featureLevel)
|
||||
: failed(false)
|
||||
, targetName(targetName)
|
||||
, text(source, sourceLength)
|
||||
, _macros(macros)
|
||||
, _featureLevel(featureLevel)
|
||||
{
|
||||
}
|
||||
|
||||
ShaderProcessing::Parser::~Parser()
|
||||
{
|
||||
}
|
||||
|
||||
bool ShaderProcessing::Parser::Process(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, FeatureLevel featureLevel, ShaderMeta* result)
|
||||
{
|
||||
Parser parser(targetName, source, sourceLength, macros, featureLevel);
|
||||
parser.Process(result);
|
||||
return parser.Failed();
|
||||
}
|
||||
|
||||
void ShaderProcessing::Parser::Process(ShaderMeta* result)
|
||||
{
|
||||
init();
|
||||
|
||||
failed = process();
|
||||
|
||||
if (!failed)
|
||||
failed = collectResults(result);
|
||||
}
|
||||
|
||||
void ShaderProcessing::Parser::init()
|
||||
{
|
||||
// Init text processing tokens for hlsl language
|
||||
text.Setup_HLSL();
|
||||
|
||||
// Init shader functions readers
|
||||
_childReaders.Add(New<ConstantBufferReader>());
|
||||
_childReaders.Add(New<VertexShaderFunctionReader>());
|
||||
_childReaders.Add(New<HullShaderFunctionReader>());
|
||||
_childReaders.Add(New<DomainShaderFunctionReader>());
|
||||
_childReaders.Add(New<GeometryShaderFunctionReader>());
|
||||
_childReaders.Add(New<PixelShaderFunctionReader>());
|
||||
_childReaders.Add(New<ComputeShaderFunctionReader>());
|
||||
}
|
||||
|
||||
bool ShaderProcessing::Parser::process()
|
||||
{
|
||||
const Token defineToken("#define");
|
||||
const Separator singleLineCommentSeparator('/', '/');
|
||||
const Separator multiLineCommentSeparator('/', '*');
|
||||
|
||||
// TODO: split parsing into two phrases: comments preprocessing and parsing
|
||||
|
||||
// Read whole source code
|
||||
Token token;
|
||||
while (text.CanRead())
|
||||
{
|
||||
text.ReadToken(&token);
|
||||
|
||||
// Single line comment
|
||||
if (token.Separator == singleLineCommentSeparator)
|
||||
{
|
||||
// Read whole line
|
||||
text.ReadLine();
|
||||
}
|
||||
// Multi line comment
|
||||
else if (token.Separator == multiLineCommentSeparator)
|
||||
{
|
||||
// Read tokens until end sequence
|
||||
char prev = ' ';
|
||||
char c;
|
||||
while (text.CanRead())
|
||||
{
|
||||
c = text.ReadChar();
|
||||
if (prev == '*' && c == '/')
|
||||
{
|
||||
break;
|
||||
}
|
||||
prev = c;
|
||||
}
|
||||
|
||||
// Check if comment is valid (has end before file end)
|
||||
if (!text.CanRead())
|
||||
{
|
||||
OnWarning(TEXT("Missing multiline comment ending"));
|
||||
}
|
||||
}
|
||||
// Preprocessor definition
|
||||
else if (token == defineToken)
|
||||
{
|
||||
// Skip
|
||||
text.ReadLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call children
|
||||
ProcessChildren(token, this);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShaderProcessing::Parser::collectResults(ShaderMeta* result)
|
||||
{
|
||||
// Collect results from all the readers
|
||||
for (int32 i = 0; i < _childReaders.Count(); i++)
|
||||
_childReaders[i]->CollectResults(this, result);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShaderProcessing::Parser::OnError(const String& message)
|
||||
{
|
||||
// Set flag
|
||||
failed = true;
|
||||
|
||||
// Send event
|
||||
LOG(Error, "Processing shader '{0}' error at line {1}. {2}", targetName, text.GetLine(), message);
|
||||
}
|
||||
|
||||
void ShaderProcessing::Parser::OnWarning(const String& message)
|
||||
{
|
||||
// Send event
|
||||
LOG(Warning, "Processing shader '{0}' warning at line {1}. {2}", targetName, text.GetLine(), message);
|
||||
}
|
||||
|
||||
#endif
|
||||
93
Source/Engine/ShadersCompilation/Parser/ShaderProcessing.h
Normal file
93
Source/Engine/ShadersCompilation/Parser/ShaderProcessing.h
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShaderMeta.h"
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "IShaderFunctionReader.h"
|
||||
#include "ITokenReadersContainer.h"
|
||||
|
||||
namespace ShaderProcessing
|
||||
{
|
||||
extern VertexShaderMeta::InputType ParseInputType(const Token& token);
|
||||
extern PixelFormat ParsePixelFormat(const Token& token);
|
||||
extern ShaderFlags ParseShaderFlags(const Token& token);
|
||||
|
||||
/// <summary>
|
||||
/// Shader files meta data processing tool
|
||||
/// </summary>
|
||||
class Parser : public IShaderParser, public ITokenReadersContainerBase<IShaderFunctionReader>
|
||||
{
|
||||
private:
|
||||
|
||||
bool failed;
|
||||
String targetName;
|
||||
Reader text;
|
||||
ParserMacros _macros;
|
||||
FeatureLevel _featureLevel;
|
||||
|
||||
private:
|
||||
|
||||
Parser(const String& targetName, const char* source, int32 sourceLength, ParserMacros macros, FeatureLevel featureLevel);
|
||||
~Parser();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Process shader source code and generate metadata
|
||||
/// </summary>
|
||||
/// <param name="targetName">Calling object name (used for warnings/errors logging)</param>
|
||||
/// <param name="source">ANSI source code</param>
|
||||
/// <param name="sourceLength">Amount of characters in the source code</param>
|
||||
/// <param name="macros">The input macros.</param>
|
||||
/// <param name="featureLevel">The target feature level.</param>
|
||||
/// <param name="result">Output result with metadata</param>
|
||||
/// <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);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Process shader source code and generate metadata
|
||||
/// </summary>
|
||||
/// <param name="result">Output result with metadata</param>
|
||||
void Process(ShaderMeta* result);
|
||||
|
||||
private:
|
||||
|
||||
void init();
|
||||
bool process();
|
||||
bool collectResults(ShaderMeta* result);
|
||||
|
||||
public:
|
||||
|
||||
// [IShaderParser]
|
||||
FeatureLevel GetFeatureLevel() const override
|
||||
{
|
||||
return _featureLevel;
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user