Files
FlaxEngine/Source/Engine/ShadersCompilation/Parser/ShaderProcessing.cpp
2021-10-14 11:46:02 +02:00

149 lines
4.0 KiB
C++

// Copyright (c) 2012-2021 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/Profiler/ProfilerCPU.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)
{
PROFILE_CPU("Shader.Parse");
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