- Major optimization of Ghost.RenderGraph.Concept: pooled resources, zero-allocation hot paths, explicit queue types, and batch barrier APIs. - Migrated Ghost.DSL shader compiler to ANTLR4-based parser; removed hand-written parser, added grammar files and semantic model conversion. - Added CollectionPool/ListPool for pooled list management. - Updated documentation for new architecture and performance. - Removed Ghost.Shader.Concept (material/material system) from repo and solution. - README.md replaced with a brief project statement.
262 lines
7.7 KiB
C#
262 lines
7.7 KiB
C#
using Antlr4.Runtime.Misc;
|
|
using Ghost.DSL.ShaderParser.Model;
|
|
|
|
namespace Ghost.DSL.ShaderParser;
|
|
|
|
public class ShaderVisitor : GhostShaderParserBaseVisitor<object>
|
|
{
|
|
public List<ShaderModel> Shaders { get; } = new();
|
|
|
|
public override object VisitShaderFile([NotNull] GhostShaderParser.ShaderFileContext context)
|
|
{
|
|
foreach (var shaderContext in context.shader())
|
|
{
|
|
var shader = (ShaderModel)VisitShader(shaderContext);
|
|
Shaders.Add(shader);
|
|
}
|
|
return Shaders;
|
|
}
|
|
|
|
public override object VisitShader([NotNull] GhostShaderParser.ShaderContext context)
|
|
{
|
|
var shader = new ShaderModel
|
|
{
|
|
Name = StripQuotes(context.STRING_LITERAL().GetText())
|
|
};
|
|
|
|
var shaderBody = context.shaderBody();
|
|
if (shaderBody != null)
|
|
{
|
|
foreach (var propBlock in shaderBody.propertiesBlock())
|
|
{
|
|
shader.Properties = (PropertiesBlockModel)VisitPropertiesBlock(propBlock);
|
|
}
|
|
|
|
foreach (var pipelineBlock in shaderBody.pipelineBlock())
|
|
{
|
|
shader.Pipeline = (PipelineBlockModel)VisitPipelineBlock(pipelineBlock);
|
|
}
|
|
|
|
foreach (var passBlock in shaderBody.passBlock())
|
|
{
|
|
shader.Passes.Add((PassBlockModel)VisitPassBlock(passBlock));
|
|
}
|
|
|
|
foreach (var funcCall in shaderBody.functionCall())
|
|
{
|
|
shader.FunctionCalls.Add((FunctionCallModel)VisitFunctionCall(funcCall));
|
|
}
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
|
|
public override object VisitPropertiesBlock([NotNull] GhostShaderParser.PropertiesBlockContext context)
|
|
{
|
|
var properties = new PropertiesBlockModel();
|
|
|
|
foreach (var propDecl in context.propertyDeclaration())
|
|
{
|
|
properties.Properties.Add((PropertyDeclarationModel)VisitPropertyDeclaration(propDecl));
|
|
}
|
|
|
|
return properties;
|
|
}
|
|
|
|
public override object VisitPropertyDeclaration([NotNull] GhostShaderParser.PropertyDeclarationContext context)
|
|
{
|
|
var property = new PropertyDeclarationModel
|
|
{
|
|
Type = context.IDENTIFIER(0).GetText(),
|
|
Name = context.IDENTIFIER(1).GetText()
|
|
};
|
|
|
|
if (context.scope() != null)
|
|
{
|
|
property.Scope = context.scope().GetText();
|
|
}
|
|
|
|
if (context.propertyInitializer() != null)
|
|
{
|
|
var init = context.propertyInitializer();
|
|
foreach (var number in init.NUMBER())
|
|
{
|
|
property.Initializer.Add(number.GetText());
|
|
}
|
|
foreach (var identifier in init.IDENTIFIER())
|
|
{
|
|
property.Initializer.Add(identifier.GetText());
|
|
}
|
|
}
|
|
|
|
return property;
|
|
}
|
|
|
|
public override object VisitPipelineBlock([NotNull] GhostShaderParser.PipelineBlockContext context)
|
|
{
|
|
var pipeline = new PipelineBlockModel();
|
|
|
|
foreach (var statement in context.pipelineStatement())
|
|
{
|
|
var key = statement.IDENTIFIER(0).GetText();
|
|
var value = statement.IDENTIFIER(1).GetText();
|
|
pipeline.Statements[key] = value;
|
|
}
|
|
|
|
return pipeline;
|
|
}
|
|
|
|
public override object VisitPassBlock([NotNull] GhostShaderParser.PassBlockContext context)
|
|
{
|
|
var pass = new PassBlockModel
|
|
{
|
|
Name = StripQuotes(context.STRING_LITERAL().GetText())
|
|
};
|
|
|
|
var passBody = context.passBody();
|
|
if (passBody != null)
|
|
{
|
|
foreach (var definesBlock in passBody.definesBlock())
|
|
{
|
|
pass.Defines = (DefinesBlockModel)VisitDefinesBlock(definesBlock);
|
|
}
|
|
|
|
foreach (var includesBlock in passBody.includesBlock())
|
|
{
|
|
pass.Includes = (IncludesBlockModel)VisitIncludesBlock(includesBlock);
|
|
}
|
|
|
|
foreach (var keywordsBlock in passBody.keywordsBlock())
|
|
{
|
|
pass.Keywords = (KeywordsBlockModel)VisitKeywordsBlock(keywordsBlock);
|
|
}
|
|
|
|
foreach (var pipelineBlock in passBody.pipelineBlock())
|
|
{
|
|
pass.LocalPipeline = (PipelineBlockModel)VisitPipelineBlock(pipelineBlock);
|
|
}
|
|
|
|
foreach (var hlslBlock in passBody.hlslBlock())
|
|
{
|
|
pass.Hlsl = (HlslBlockModel)VisitHlslBlock(hlslBlock);
|
|
}
|
|
|
|
foreach (var shaderEntry in passBody.shaderEntry())
|
|
{
|
|
pass.ShaderEntries.Add((ShaderEntryModel)VisitShaderEntry(shaderEntry));
|
|
}
|
|
}
|
|
|
|
return pass;
|
|
}
|
|
|
|
public override object VisitDefinesBlock([NotNull] GhostShaderParser.DefinesBlockContext context)
|
|
{
|
|
var defines = new DefinesBlockModel();
|
|
|
|
foreach (var defineStmt in context.defineStatement())
|
|
{
|
|
defines.Defines.Add(defineStmt.IDENTIFIER().GetText());
|
|
}
|
|
|
|
return defines;
|
|
}
|
|
|
|
public override object VisitIncludesBlock([NotNull] GhostShaderParser.IncludesBlockContext context)
|
|
{
|
|
var includes = new IncludesBlockModel();
|
|
|
|
foreach (var includeStmt in context.includeStatement())
|
|
{
|
|
includes.Includes.Add(StripQuotes(includeStmt.STRING_LITERAL().GetText()));
|
|
}
|
|
|
|
return includes;
|
|
}
|
|
|
|
public override object VisitKeywordsBlock([NotNull] GhostShaderParser.KeywordsBlockContext context)
|
|
{
|
|
var keywords = new KeywordsBlockModel();
|
|
|
|
foreach (var keywordStmt in context.keywordStatement())
|
|
{
|
|
var group = new KeywordGroupModel();
|
|
|
|
if (keywordStmt.scope() != null)
|
|
{
|
|
group.Scope = keywordStmt.scope().GetText();
|
|
}
|
|
|
|
foreach (var identifier in keywordStmt.IDENTIFIER())
|
|
{
|
|
group.Keywords.Add(identifier.GetText());
|
|
}
|
|
|
|
keywords.Groups.Add(group);
|
|
}
|
|
|
|
return keywords;
|
|
}
|
|
|
|
public override object VisitHlslBlock([NotNull] GhostShaderParser.HlslBlockContext context)
|
|
{
|
|
var hlsl = new HlslBlockModel();
|
|
|
|
// Get the text between the braces
|
|
var start = context.LBRACE().Symbol.StopIndex + 1;
|
|
var stop = context.RBRACE().Symbol.StartIndex - 1;
|
|
|
|
if (stop >= start)
|
|
{
|
|
var input = context.Start.InputStream;
|
|
hlsl.Code = input.GetText(new Antlr4.Runtime.Misc.Interval(start, stop));
|
|
}
|
|
|
|
return hlsl;
|
|
}
|
|
|
|
public override object VisitShaderEntry([NotNull] GhostShaderParser.ShaderEntryContext context)
|
|
{
|
|
var entry = new ShaderEntryModel
|
|
{
|
|
EntryType = context.IDENTIFIER().GetText(),
|
|
ShaderPath = StripQuotes(context.STRING_LITERAL(0).GetText()),
|
|
EntryPoint = StripQuotes(context.STRING_LITERAL(1).GetText())
|
|
};
|
|
|
|
return entry;
|
|
}
|
|
|
|
public override object VisitFunctionCall([NotNull] GhostShaderParser.FunctionCallContext context)
|
|
{
|
|
var funcCall = new FunctionCallModel
|
|
{
|
|
Name = context.IDENTIFIER().GetText()
|
|
};
|
|
|
|
if (context.functionArguments() != null)
|
|
{
|
|
foreach (var arg in context.functionArguments().functionArgument())
|
|
{
|
|
var text = arg.GetText();
|
|
if (text.StartsWith('"'))
|
|
{
|
|
text = StripQuotes(text);
|
|
}
|
|
funcCall.Arguments.Add(text);
|
|
}
|
|
}
|
|
|
|
return funcCall;
|
|
}
|
|
|
|
private static string StripQuotes(string text)
|
|
{
|
|
if (text.Length >= 2 && text.StartsWith('"') && text.EndsWith('"'))
|
|
{
|
|
return text.Substring(1, text.Length - 2);
|
|
}
|
|
return text;
|
|
}
|
|
}
|