feat(shader): add compute shader support and refactor pipeline
Refactored shader system to support both graphics and compute shaders. - Updated ANTLR grammars and parser logic for explicit shader model and compute shader entry points. - Split shader models and descriptors for graphics and compute. - Refactored pipeline key generation and D3D12 pipeline library for compute support. - Updated push constant layouts and HLSL includes for both shader types. - Improved error handling and test coverage with new example files. BREAKING CHANGE: Shader model, descriptor, and pipeline APIs have changed. Existing shader and pipeline code must be updated to use the new types and conventions.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
parser grammar GhostComputeParser;
|
||||
parser grammar GhostComputeShaderParser;
|
||||
|
||||
options {
|
||||
tokenVocab = GhostComputeLexer;
|
||||
tokenVocab = GhostShaderLexer;
|
||||
}
|
||||
|
||||
// Top-level rule
|
||||
@@ -13,7 +13,10 @@ compute:
|
||||
RBRACE;
|
||||
|
||||
computeBody:
|
||||
(definesBlock | includesBlock | keywordsBlock | hlslBlock | computeEntry)*;
|
||||
shaderModel | (definesBlock | includesBlock | keywordsBlock | hlslBlock | computeEntry)*;
|
||||
|
||||
shaderModel:
|
||||
SM IDENTIFIER SEMICOLON;
|
||||
|
||||
scope:
|
||||
GLOBAL | LOCAL;
|
||||
|
||||
@@ -11,6 +11,7 @@ INCLUDES: 'includes';
|
||||
GLOBAL: 'global';
|
||||
LOCAL: 'local';
|
||||
HLSL: 'hlsl';
|
||||
SM: 'sm';
|
||||
|
||||
// Punctuation
|
||||
LBRACE: '{';
|
||||
|
||||
@@ -13,7 +13,10 @@ shader:
|
||||
RBRACE;
|
||||
|
||||
shaderBody:
|
||||
(pipelineBlock | passBlock | functionCall)*;
|
||||
shaderModel | (pipelineBlock | passBlock | functionCall)*;
|
||||
|
||||
shaderModel:
|
||||
SM IDENTIFIER SEMICOLON;
|
||||
|
||||
scope:
|
||||
GLOBAL | LOCAL;
|
||||
|
||||
@@ -45,14 +45,14 @@ internal static class DSLShaderCompiler
|
||||
|
||||
// TODO: Implement shader inheritance resolution, including property and pass merging.
|
||||
// Currently, we just ignore inheritance.
|
||||
public static Result<ShaderDescriptor> ResolveShader(DSLShaderSemantics semantics)
|
||||
public static Result<GraphicsShaderDescriptor> ResolveShader(DSLShaderSemantics semantics)
|
||||
{
|
||||
var descriptor = new ShaderDescriptor
|
||||
var descriptor = new GraphicsShaderDescriptor
|
||||
{
|
||||
name = semantics.name,
|
||||
};
|
||||
|
||||
if (!ShaderPropertiesRegistry.TryGetCode(semantics.name, out var info))
|
||||
if (!ShaderPropertiesRegistry.TryGetInfo(semantics.name, out var info))
|
||||
{
|
||||
info = default;
|
||||
}
|
||||
@@ -60,6 +60,8 @@ internal static class DSLShaderCompiler
|
||||
descriptor.propertiesCode = info.code ?? string.Empty;
|
||||
descriptor.propertyBufferSize = info.size;
|
||||
|
||||
descriptor.shaderModel = semantics.shaderModel;
|
||||
|
||||
if (semantics.passes != null)
|
||||
{
|
||||
descriptor.passes = new PassDescriptor[semantics.passes.Count];
|
||||
@@ -91,7 +93,7 @@ internal static class DSLShaderCompiler
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public static Result<ShaderDescriptor> CompileShader(string shaderPath, string generatedOutputDirectory)
|
||||
public static Result<GraphicsShaderDescriptor> CompileGraphicsShader(string shaderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -143,4 +145,82 @@ internal static class DSLShaderCompiler
|
||||
return Result.Failure("Failed to compile shader: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static Result<ComputeShaderDescriptor> CompileComputeShader(string shaderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var source = File.ReadAllText(shaderPath);
|
||||
|
||||
var shaderModels = AntlrShaderCompiler.ParseComputeShaders(source, out var parseErrors);
|
||||
|
||||
if (parseErrors.Count != 0)
|
||||
{
|
||||
var errorMessages = new StringBuilder();
|
||||
foreach (var error in parseErrors)
|
||||
{
|
||||
errorMessages.AppendLine(error.ToString());
|
||||
}
|
||||
|
||||
return Result.Failure("Failed to parse compute shader due to errors:\n" + errorMessages.ToString());
|
||||
}
|
||||
|
||||
if (shaderModels.Count == 0)
|
||||
{
|
||||
return Result.Failure("No compute shader found in the provided file.");
|
||||
}
|
||||
|
||||
var model = AntlrShaderCompiler.ConvertToComputeSemantics(shaderModels[0], out var errors);
|
||||
|
||||
if (errors.Count != 0 || model == null)
|
||||
{
|
||||
var errorMessages = new StringBuilder();
|
||||
foreach (var error in errors)
|
||||
{
|
||||
errorMessages.AppendLine(error.ToString());
|
||||
}
|
||||
|
||||
return Result.Failure("Failed to compile compute shader due to errors:\n" + errorMessages.ToString());
|
||||
}
|
||||
|
||||
var result = ResolveComputeShader(model);
|
||||
if (result.IsFailure)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Failure("Failed to compile compute shader: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static Result<ComputeShaderDescriptor> ResolveComputeShader(DSLComputeShaderSemantics semantics)
|
||||
{
|
||||
var descriptor = new ComputeShaderDescriptor
|
||||
{
|
||||
identifier = XxHash64.HashToUInt64(MemoryMarshal.AsBytes(semantics.name.AsSpan())),
|
||||
name = semantics.name,
|
||||
};
|
||||
|
||||
if (!ShaderPropertiesRegistry.TryGetInfo(semantics.name, out var info))
|
||||
{
|
||||
info = default;
|
||||
}
|
||||
|
||||
descriptor.propertiesCode = info.code ?? string.Empty;
|
||||
descriptor.propertyBufferSize = info.size;
|
||||
|
||||
descriptor.shaderModel = semantics.shaderModel;
|
||||
|
||||
descriptor.hlsl = semantics.hlsl;
|
||||
descriptor.defines = semantics.defines?.ToArray() ?? Array.Empty<string>();
|
||||
descriptor.includes = semantics.includes?.ToArray() ?? Array.Empty<string>();
|
||||
descriptor.keywords = semantics.keywords?.ToArray() ?? Array.Empty<KeywordsGroup>();
|
||||
descriptor.entryPoints = semantics.entryPoints?.ToArray() ?? Array.Empty<ShaderEntryPoint>();
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,18 @@ public class PassSemantic
|
||||
public class DSLShaderSemantics
|
||||
{
|
||||
public string name = string.Empty;
|
||||
public ShaderModel shaderModel;
|
||||
public PipelineSemantic? pipeline;
|
||||
public List<PassSemantic>? passes;
|
||||
}
|
||||
|
||||
public class DSLComputeShaderSemantics
|
||||
{
|
||||
public string name = string.Empty;
|
||||
public string? hlsl;
|
||||
public ShaderModel shaderModel;
|
||||
public List<string>? defines;
|
||||
public List<string>? includes;
|
||||
public List<KeywordsGroup>? keywords;
|
||||
public List<ShaderEntryPoint>? entryPoints;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace Ghost.DSL.ShaderParser;
|
||||
|
||||
public class AntlrShaderCompiler
|
||||
{
|
||||
public static List<ShaderModel> ParseShaders(string source, out List<DSLShaderError> errors)
|
||||
public static List<GraphicsShaderModel> ParseShaders(string source, out List<DSLShaderError> errors)
|
||||
{
|
||||
errors = new List<DSLShaderError>();
|
||||
|
||||
@@ -33,7 +33,7 @@ public class AntlrShaderCompiler
|
||||
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
return new List<ShaderModel>();
|
||||
return new List<GraphicsShaderModel>();
|
||||
}
|
||||
|
||||
var visitor = new ShaderVisitor();
|
||||
@@ -49,11 +49,165 @@ public class AntlrShaderCompiler
|
||||
line = -1,
|
||||
column = -1
|
||||
});
|
||||
return new List<ShaderModel>();
|
||||
return new List<GraphicsShaderModel>();
|
||||
}
|
||||
}
|
||||
|
||||
public static DSLShaderSemantics? ConvertToSemantics(ShaderModel model, out List<DSLShaderError> errors)
|
||||
public static List<ComputeShaderModel> ParseComputeShaders(string source, out List<DSLShaderError> errors)
|
||||
{
|
||||
errors = new List<DSLShaderError>();
|
||||
|
||||
try
|
||||
{
|
||||
var inputStream = new AntlrInputStream(source);
|
||||
var lexer = new GhostShaderLexer(inputStream);
|
||||
|
||||
// Capture lexer errors
|
||||
lexer.RemoveErrorListeners();
|
||||
var lexerErrorListener = new ErrorListener(errors);
|
||||
lexer.AddErrorListener(lexerErrorListener);
|
||||
|
||||
var tokenStream = new CommonTokenStream(lexer);
|
||||
var parser = new GhostComputeShaderParser(tokenStream);
|
||||
|
||||
// Capture parser errors
|
||||
parser.RemoveErrorListeners();
|
||||
var parserErrorListener = new ErrorListener(errors);
|
||||
parser.AddErrorListener(parserErrorListener);
|
||||
|
||||
var tree = parser.computeFile();
|
||||
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
return new List<ComputeShaderModel>();
|
||||
}
|
||||
|
||||
var visitor = new ComputeShaderVisitor();
|
||||
visitor.Visit(tree);
|
||||
|
||||
return visitor.ComputeShaders;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errors.Add(new DSLShaderError
|
||||
{
|
||||
message = $"Unexpected error during parsing: {ex.Message}",
|
||||
line = -1,
|
||||
column = -1
|
||||
});
|
||||
return new List<ComputeShaderModel>();
|
||||
}
|
||||
}
|
||||
|
||||
public static DSLComputeShaderSemantics? ConvertToComputeSemantics(ComputeShaderModel model, out List<DSLShaderError> errors)
|
||||
{
|
||||
errors = new List<DSLShaderError>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(model.Name))
|
||||
{
|
||||
errors.Add(new DSLShaderError
|
||||
{
|
||||
message = "Compute shader name cannot be empty.",
|
||||
line = 0,
|
||||
column = 0
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
var semantics = new DSLComputeShaderSemantics
|
||||
{
|
||||
name = model.Name,
|
||||
defines = model.Defines?.Defines,
|
||||
includes = model.Includes?.Includes,
|
||||
hlsl = model.Hlsl?.Code
|
||||
};
|
||||
|
||||
if (string.IsNullOrEmpty(model.SM))
|
||||
{
|
||||
semantics.shaderModel = ShaderModel.SM_6_8; // Default to highest supported shader model
|
||||
}
|
||||
else
|
||||
{
|
||||
semantics.shaderModel = model.SM.ToLower() switch
|
||||
{
|
||||
"6_6" => ShaderModel.SM_6_6,
|
||||
"6_7" => ShaderModel.SM_6_7,
|
||||
"6_8" => ShaderModel.SM_6_8,
|
||||
_ => ShaderModel.Invalid
|
||||
};
|
||||
|
||||
if (semantics.shaderModel == ShaderModel.Invalid)
|
||||
{
|
||||
errors.Add(new DSLShaderError
|
||||
{
|
||||
message = $"Unknown shader model '{model.SM}'.",
|
||||
line = 0,
|
||||
column = 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (model.Keywords != null)
|
||||
{
|
||||
semantics.keywords = new List<KeywordsGroup>();
|
||||
foreach (var group in model.Keywords.Groups)
|
||||
{
|
||||
var keywordGroup = new KeywordsGroup
|
||||
{
|
||||
space = group.Scope?.ToLower() == "global" ? KeywordSpace.Global : KeywordSpace.Local,
|
||||
keywords = group.Keywords
|
||||
};
|
||||
semantics.keywords.Add(keywordGroup);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entry in model.ShaderEntries)
|
||||
{
|
||||
var entryType = entry.EntryType.ToLower();
|
||||
if (entryType == "cs")
|
||||
{
|
||||
semantics.entryPoints ??= new List<ShaderEntryPoint>();
|
||||
semantics.entryPoints.Add(new ShaderEntryPoint
|
||||
{
|
||||
shader = entry.ShaderPath,
|
||||
entry = entry.EntryPoint
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
errors.Add(new DSLShaderError
|
||||
{
|
||||
message = $"Unknown compute shader entry type '{entry.EntryType}'. Expected 'compute' or 'cs'.",
|
||||
line = 0,
|
||||
column = 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (semantics.entryPoints == null)
|
||||
{
|
||||
errors.Add(new DSLShaderError
|
||||
{
|
||||
message = $"Compute shader '{model.Name}' must contain a compute/cs entry declaration.",
|
||||
line = 0,
|
||||
column = 0
|
||||
});
|
||||
}
|
||||
|
||||
if (semantics.entryPoints != null && semantics.entryPoints.Count > 8)
|
||||
{
|
||||
errors.Add(new DSLShaderError
|
||||
{
|
||||
message = $"Compute shader '{model.Name}' cannot have more than 8 entry points.",
|
||||
line = 0,
|
||||
column = 0
|
||||
});
|
||||
}
|
||||
|
||||
return semantics;
|
||||
}
|
||||
|
||||
public static DSLShaderSemantics? ConvertToSemantics(GraphicsShaderModel model, out List<DSLShaderError> errors)
|
||||
{
|
||||
errors = new List<DSLShaderError>();
|
||||
|
||||
@@ -74,6 +228,31 @@ public class AntlrShaderCompiler
|
||||
pipeline = ConvertPipeline(model.Pipeline, errors)
|
||||
};
|
||||
|
||||
if (string.IsNullOrEmpty(model.SM))
|
||||
{
|
||||
semantics.shaderModel = ShaderModel.SM_6_8; // Default to highest supported shader model
|
||||
}
|
||||
else
|
||||
{
|
||||
semantics.shaderModel = model.SM.ToLower() switch
|
||||
{
|
||||
"6_6" => ShaderModel.SM_6_6,
|
||||
"6_7" => ShaderModel.SM_6_7,
|
||||
"6_8" => ShaderModel.SM_6_8,
|
||||
_ => ShaderModel.Invalid
|
||||
};
|
||||
|
||||
if (semantics.shaderModel == ShaderModel.Invalid)
|
||||
{
|
||||
errors.Add(new DSLShaderError
|
||||
{
|
||||
message = $"Unknown shader model '{model.SM}'.",
|
||||
line = 0,
|
||||
column = 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var pass in model.Passes)
|
||||
{
|
||||
var passSemantic = ConvertPass(pass, errors);
|
||||
@@ -87,99 +266,6 @@ public class AntlrShaderCompiler
|
||||
return semantics;
|
||||
}
|
||||
|
||||
private static ShaderPropertyType ParsePropertyType(string type, List<DSLShaderError> errors)
|
||||
{
|
||||
return type.ToLower() switch
|
||||
{
|
||||
"float" => ShaderPropertyType.Float,
|
||||
"float2" => ShaderPropertyType.Float2,
|
||||
"float3" => ShaderPropertyType.Float3,
|
||||
"float4" => ShaderPropertyType.Float4,
|
||||
"float4x4" => ShaderPropertyType.Float4x4,
|
||||
"int" => ShaderPropertyType.Int,
|
||||
"int2" => ShaderPropertyType.Int2,
|
||||
"int3" => ShaderPropertyType.Int3,
|
||||
"int4" => ShaderPropertyType.Int4,
|
||||
"uint" => ShaderPropertyType.UInt,
|
||||
"uint2" => ShaderPropertyType.UInt2,
|
||||
"uint3" => ShaderPropertyType.UInt3,
|
||||
"uint4" => ShaderPropertyType.UInt4,
|
||||
"bool" => ShaderPropertyType.Bool,
|
||||
"bool2" => ShaderPropertyType.Bool2,
|
||||
"bool3" => ShaderPropertyType.Bool3,
|
||||
"bool4" => ShaderPropertyType.Bool4,
|
||||
"tex2d" => ShaderPropertyType.Texture2D,
|
||||
"tex3d" => ShaderPropertyType.Texture3D,
|
||||
"texcube" => ShaderPropertyType.TextureCube,
|
||||
"texcube_arr" => ShaderPropertyType.TextureCubeArray,
|
||||
"tex2d_arr" => ShaderPropertyType.Texture2DArray,
|
||||
"sampler" => ShaderPropertyType.Sampler,
|
||||
_ => ShaderPropertyType.None
|
||||
};
|
||||
}
|
||||
|
||||
private static object? ParsePropertyValue(ShaderPropertyType type, List<string> values, List<DSLShaderError> errors)
|
||||
{
|
||||
// For textures, the value is an identifier (e.g., "white", "black")
|
||||
if (type is ShaderPropertyType.Texture2D or ShaderPropertyType.Texture3D or ShaderPropertyType.TextureCube)
|
||||
{
|
||||
return values.Count > 0 ? values[0] : null;
|
||||
}
|
||||
|
||||
// For samplers, no default value
|
||||
if (type == ShaderPropertyType.Sampler)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// For numeric types, parse the values
|
||||
try
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ShaderPropertyType.Float => values.Count > 0 ? float.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture) : 0f,
|
||||
ShaderPropertyType.Float2 => values.Count >= 2 ? new Misaki.HighPerformance.Mathematics.float2(
|
||||
float.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture),
|
||||
float.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture)) : default,
|
||||
ShaderPropertyType.Float3 => values.Count >= 3 ? new Misaki.HighPerformance.Mathematics.float3(
|
||||
float.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture),
|
||||
float.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture),
|
||||
float.Parse(values[2], System.Globalization.CultureInfo.InvariantCulture)) : default,
|
||||
ShaderPropertyType.Float4 => values.Count >= 4 ? new Misaki.HighPerformance.Mathematics.float4(
|
||||
float.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture),
|
||||
float.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture),
|
||||
float.Parse(values[2], System.Globalization.CultureInfo.InvariantCulture),
|
||||
float.Parse(values[3], System.Globalization.CultureInfo.InvariantCulture)) : default,
|
||||
ShaderPropertyType.Int => values.Count > 0 ? int.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture) : 0,
|
||||
ShaderPropertyType.Int2 => values.Count >= 2 ? new Misaki.HighPerformance.Mathematics.int2(
|
||||
int.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture),
|
||||
int.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture)) : default,
|
||||
ShaderPropertyType.Int3 => values.Count >= 3 ? new Misaki.HighPerformance.Mathematics.int3(
|
||||
int.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture),
|
||||
int.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture),
|
||||
int.Parse(values[2], System.Globalization.CultureInfo.InvariantCulture)) : default,
|
||||
ShaderPropertyType.Int4 => values.Count >= 4 ? new Misaki.HighPerformance.Mathematics.int4(
|
||||
int.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture),
|
||||
int.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture),
|
||||
int.Parse(values[2], System.Globalization.CultureInfo.InvariantCulture),
|
||||
int.Parse(values[3], System.Globalization.CultureInfo.InvariantCulture)) : default,
|
||||
ShaderPropertyType.UInt => values.Count > 0 ? uint.Parse(values[0], System.Globalization.CultureInfo.InvariantCulture) : 0u,
|
||||
ShaderPropertyType.Bool => values.Count > 0 && (values[0] == "1" || values[0].ToLower() == "true"),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errors.Add(new DSLShaderError
|
||||
{
|
||||
message = $"Failed to parse property value: {ex.Message}",
|
||||
line = 0,
|
||||
column = 0
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static PipelineSemantic? ConvertPipeline(PipelineBlockModel? pipeline, List<DSLShaderError> errors)
|
||||
{
|
||||
if (pipeline == null || pipeline.Statements.Count == 0)
|
||||
@@ -275,13 +361,13 @@ public class AntlrShaderCompiler
|
||||
|
||||
switch (entryType)
|
||||
{
|
||||
case "mesh" or "ms":
|
||||
case "ms":
|
||||
semantic.meshShader = shaderEntry;
|
||||
break;
|
||||
case "pixel" or "ps":
|
||||
case "ps":
|
||||
semantic.pixelShader = shaderEntry;
|
||||
break;
|
||||
case "task" or "ts":
|
||||
case "as":
|
||||
semantic.taskShader = shaderEntry;
|
||||
break;
|
||||
default:
|
||||
|
||||
149
src/Editor/Ghost.DSL/ShaderParser/ComputeShaderVisitor.cs
Normal file
149
src/Editor/Ghost.DSL/ShaderParser/ComputeShaderVisitor.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using Antlr4.Runtime.Misc;
|
||||
using Ghost.DSL.ShaderParser.Model;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Ghost.DSL.ShaderParser;
|
||||
|
||||
internal class ComputeShaderVisitor : GhostComputeShaderParserBaseVisitor<object>
|
||||
{
|
||||
public List<ComputeShaderModel> ComputeShaders { get; } = new();
|
||||
|
||||
public override object VisitComputeFile([NotNull] GhostComputeShaderParser.ComputeFileContext context)
|
||||
{
|
||||
foreach (var shaderContext in context.compute())
|
||||
{
|
||||
var shader = (ComputeShaderModel)VisitCompute(shaderContext);
|
||||
ComputeShaders.Add(shader);
|
||||
}
|
||||
|
||||
return ComputeShaders;
|
||||
}
|
||||
|
||||
private static string StripQuotes(string text)
|
||||
{
|
||||
if (text.Length >= 2 && text.StartsWith('"') && text.EndsWith('"'))
|
||||
{
|
||||
return text.Substring(1, text.Length - 2);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public override object VisitCompute([NotNull] GhostComputeShaderParser.ComputeContext context)
|
||||
{
|
||||
var compute = new ComputeShaderModel
|
||||
{
|
||||
Name = StripQuotes(context.STRING_LITERAL().GetText())
|
||||
};
|
||||
|
||||
var computeBody = context.computeBody();
|
||||
if (computeBody != null)
|
||||
{
|
||||
compute.SM = computeBody.shaderModel()?.GetText() ?? string.Empty;
|
||||
|
||||
foreach (var definesBlock in computeBody.definesBlock())
|
||||
{
|
||||
compute.Defines = (DefinesBlockModel)VisitDefinesBlock(definesBlock);
|
||||
}
|
||||
|
||||
foreach (var includesBlock in computeBody.includesBlock())
|
||||
{
|
||||
compute.Includes = (IncludesBlockModel)VisitIncludesBlock(includesBlock);
|
||||
}
|
||||
|
||||
foreach (var keywordsBlock in computeBody.keywordsBlock())
|
||||
{
|
||||
compute.Keywords = (KeywordsBlockModel)VisitKeywordsBlock(keywordsBlock);
|
||||
}
|
||||
|
||||
var hlslBlock = computeBody.hlslBlock().FirstOrDefault();
|
||||
if (hlslBlock != null)
|
||||
{
|
||||
compute.Hlsl = (HlslBlockModel)VisitHlslBlock(hlslBlock);
|
||||
}
|
||||
|
||||
foreach (var computeEntry in computeBody.computeEntry())
|
||||
{
|
||||
compute.ShaderEntries.Add((ShaderEntryModel)VisitComputeEntry(computeEntry));
|
||||
}
|
||||
}
|
||||
|
||||
return compute;
|
||||
}
|
||||
|
||||
public override object VisitDefinesBlock([NotNull] GhostComputeShaderParser.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] GhostComputeShaderParser.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] GhostComputeShaderParser.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] GhostComputeShaderParser.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 Interval(start, stop));
|
||||
}
|
||||
|
||||
return hlsl;
|
||||
}
|
||||
|
||||
public override object VisitComputeEntry([NotNull] GhostComputeShaderParser.ComputeEntryContext 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;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,24 @@
|
||||
namespace Ghost.DSL.ShaderParser.Model;
|
||||
|
||||
public class ShaderModel
|
||||
public class GraphicsShaderModel
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public PropertiesBlockModel? Properties { get; set; }
|
||||
public string SM { get; set; } = string.Empty;
|
||||
public PipelineBlockModel? Pipeline { get; set; }
|
||||
public List<PassBlockModel> Passes { get; set; } = new();
|
||||
public List<FunctionCallModel> FunctionCalls { get; set; } = new();
|
||||
}
|
||||
|
||||
public class PropertiesBlockModel
|
||||
public class ComputeShaderModel
|
||||
{
|
||||
public List<PropertyDeclarationModel> Properties { get; set; } = new();
|
||||
}
|
||||
|
||||
public class PropertyDeclarationModel
|
||||
{
|
||||
public string? Scope { get; set; }
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public List<string> Initializer { get; set; } = new();
|
||||
public string SM { get; set; } = string.Empty;
|
||||
public DefinesBlockModel? Defines { get; set; }
|
||||
public IncludesBlockModel? Includes { get; set; }
|
||||
public KeywordsBlockModel? Keywords { get; set; }
|
||||
public HlslBlockModel? Hlsl { get; set; }
|
||||
public List<FunctionCallModel> FunctionCalls { get; set; } = new();
|
||||
public List<ShaderEntryModel> ShaderEntries { get; set; } = new();
|
||||
}
|
||||
|
||||
public class PipelineBlockModel
|
||||
|
||||
@@ -5,13 +5,13 @@ namespace Ghost.DSL.ShaderParser;
|
||||
|
||||
public class ShaderVisitor : GhostShaderParserBaseVisitor<object>
|
||||
{
|
||||
public List<ShaderModel> Shaders { get; } = new();
|
||||
public List<GraphicsShaderModel> Shaders { get; } = new();
|
||||
|
||||
public override object VisitShaderFile([NotNull] GhostShaderParser.ShaderFileContext context)
|
||||
{
|
||||
foreach (var shaderContext in context.shader())
|
||||
{
|
||||
var shader = (ShaderModel)VisitShader(shaderContext);
|
||||
var shader = (GraphicsShaderModel)VisitShader(shaderContext);
|
||||
Shaders.Add(shader);
|
||||
}
|
||||
return Shaders;
|
||||
@@ -19,7 +19,7 @@ public class ShaderVisitor : GhostShaderParserBaseVisitor<object>
|
||||
|
||||
public override object VisitShader([NotNull] GhostShaderParser.ShaderContext context)
|
||||
{
|
||||
var shader = new ShaderModel
|
||||
var shader = new GraphicsShaderModel
|
||||
{
|
||||
Name = StripQuotes(context.STRING_LITERAL().GetText())
|
||||
};
|
||||
@@ -27,6 +27,8 @@ public class ShaderVisitor : GhostShaderParserBaseVisitor<object>
|
||||
var shaderBody = context.shaderBody();
|
||||
if (shaderBody != null)
|
||||
{
|
||||
shader.SM = shaderBody.shaderModel()?.GetText() ?? string.Empty;
|
||||
|
||||
foreach (var pipelineBlock in shaderBody.pipelineBlock())
|
||||
{
|
||||
shader.Pipeline = (PipelineBlockModel)VisitPipelineBlock(pipelineBlock);
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
namespace Ghost.Core.Graphics;
|
||||
|
||||
public enum ShaderModel
|
||||
{
|
||||
Invalid,
|
||||
SM_6_6,
|
||||
SM_6_7,
|
||||
SM_6_8
|
||||
}
|
||||
|
||||
public enum KeywordSpace
|
||||
{
|
||||
Local,
|
||||
Global,
|
||||
}
|
||||
|
||||
public enum ShaderPropertyType
|
||||
{
|
||||
None,
|
||||
Float, Float2, Float3, Float4,
|
||||
Float4x4,
|
||||
Int, Int2, Int3, Int4,
|
||||
UInt, UInt2, UInt3, UInt4,
|
||||
Bool, Bool2, Bool3, Bool4,
|
||||
Texture2D, Texture3D, TextureCube,
|
||||
Texture2DArray, TextureCubeArray,
|
||||
Sampler
|
||||
}
|
||||
|
||||
public struct ShaderEntryPoint
|
||||
{
|
||||
public string entry;
|
||||
@@ -35,7 +30,7 @@ public struct KeywordsGroup
|
||||
|
||||
public struct PassDescriptor
|
||||
{
|
||||
public ShaderDescriptor shader;
|
||||
public GraphicsShaderDescriptor shader;
|
||||
|
||||
public ulong identifier;
|
||||
public string name;
|
||||
@@ -50,21 +45,25 @@ public struct PassDescriptor
|
||||
public PipelineState localPipeline;
|
||||
}
|
||||
|
||||
public class ShaderDescriptor
|
||||
public class GraphicsShaderDescriptor
|
||||
{
|
||||
public string name = string.Empty;
|
||||
public string propertiesCode = string.Empty;
|
||||
public uint propertyBufferSize;
|
||||
public ShaderModel shaderModel;
|
||||
public PassDescriptor[] passes = Array.Empty<PassDescriptor>();
|
||||
}
|
||||
|
||||
public class ComputeShaderDescriptor
|
||||
{
|
||||
public ulong identifier;
|
||||
public string name = string.Empty;
|
||||
public string propertiesCode = string.Empty;
|
||||
public uint propertyBufferSize;
|
||||
public ShaderEntryPoint entryPoint;
|
||||
public string? hlsl;
|
||||
public ShaderModel shaderModel;
|
||||
public string[] defines = Array.Empty<string>();
|
||||
public string[] includes = Array.Empty<string>();
|
||||
public KeywordsGroup[] keywords = Array.Empty<KeywordsGroup>();
|
||||
public ShaderEntryPoint[] entryPoints = Array.Empty<ShaderEntryPoint>();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public static class ShaderPropertiesRegistry
|
||||
s_nameToCode[name] = new ShaderPropertyInfo { shaderName = name, code = code, size = size };
|
||||
}
|
||||
|
||||
public static bool TryGetCode(string name, out ShaderPropertyInfo info)
|
||||
public static bool TryGetInfo(string name, out ShaderPropertyInfo info)
|
||||
{
|
||||
return s_nameToCode.TryGetValue(name, out info);
|
||||
}
|
||||
|
||||
@@ -650,7 +650,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
#endif
|
||||
IncrementCommandCount();
|
||||
|
||||
var psor = _pipelineLibrary.GetGraphicsPSO(pipelineKey);
|
||||
var psor = _pipelineLibrary.GetPipelineStateObject(pipelineKey);
|
||||
if (psor.Error != Error.None)
|
||||
{
|
||||
RecordError(nameof(SetPipelineState), psor.Error);
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace Ghost.Graphics.D3D12;
|
||||
|
||||
internal struct D3D12PipelineState : IDisposable
|
||||
{
|
||||
public D3DX12_MESH_SHADER_PIPELINE_STATE_DESC psoDesc;
|
||||
public UniquePtr<ID3D12PipelineState> pso;
|
||||
public Key64<ShaderVariant> shaderVariant;
|
||||
|
||||
@@ -33,7 +32,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
|
||||
private UniquePtr<ID3D12RootSignature> _defaultRootSignature;
|
||||
|
||||
private UnsafeHashMap<Key128<GraphicsPipeline>, D3D12PipelineState> _pipelineCache;
|
||||
private UnsafeHashMap<UInt128, D3D12PipelineState> _pipelineCache;
|
||||
|
||||
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
||||
|
||||
@@ -58,12 +57,12 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
}
|
||||
|
||||
public D3D12PipelineLibrary(D3D12RenderDevice device, D3D12ResourceDatabase resourceDatabase)
|
||||
:base(CreateLibrary(device, null)) // TODO: we need to path to load the existing library from disk.
|
||||
: base(CreateLibrary(device, null)) // TODO: we need to path to load the existing library from disk.
|
||||
{
|
||||
_device = device;
|
||||
_resourceDatabase = resourceDatabase;
|
||||
|
||||
_pipelineCache = new UnsafeHashMap<Key128<GraphicsPipeline>, D3D12PipelineState>(32, Allocator.Persistent);
|
||||
_pipelineCache = new UnsafeHashMap<UInt128, D3D12PipelineState>(32, Allocator.Persistent);
|
||||
|
||||
CreateDefaultRootSignature().ThrowIfFailed();
|
||||
}
|
||||
@@ -174,7 +173,38 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
return D3D12Utility.D3D12_DEPTH_STENCIL_DESC_CREATE(depthEnabled, writeEnabled, cmp);
|
||||
}
|
||||
|
||||
public Result<Key128<GraphicsPipeline>> CreatePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled)
|
||||
private Result CreatePSO(Key64<ShaderVariant> shaderVariantKey, UInt128 pipelineKey, D3D12_PIPELINE_STATE_STREAM_DESC* pStreamDesc)
|
||||
{
|
||||
ID3D12PipelineState* pPipelineState = default;
|
||||
|
||||
var pKeyStr = stackalloc char[33]; // 32 for 128 bits key + 1 for null terminator
|
||||
var keySpan = new Span<char>(pKeyStr, 33);
|
||||
if (!RHIUtility.TryGetStringFromHash(pipelineKey, keySpan))
|
||||
{
|
||||
return Result.Failure("Failed to convert pipeline key to string.");
|
||||
}
|
||||
|
||||
var hr = pNativeObject->LoadPipeline(pKeyStr, pStreamDesc, __uuidof(pPipelineState), (void**)&pPipelineState);
|
||||
if (hr == E.E_INVALIDARG)
|
||||
{
|
||||
// Pipeline not found in the library, create a new one.
|
||||
ThrowIfFailed(_device.NativeObject.Get()->CreatePipelineState(pStreamDesc, __uuidof(pPipelineState), (void**)&pPipelineState));
|
||||
ThrowIfFailed(pNativeObject->StorePipeline(pKeyStr, pPipelineState));
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowIfFailed(hr);
|
||||
}
|
||||
|
||||
D3D12PipelineState pso = default;
|
||||
pso.shaderVariant = shaderVariantKey;
|
||||
pso.pso.Attach(pPipelineState);
|
||||
|
||||
_pipelineCache[pipelineKey] = pso;
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
public Result<Key128<GraphicsPipeline>> CreateGraphicsPipeline(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled)
|
||||
{
|
||||
static Result ValidatePassReflectionData(ref readonly GraphicsCompiledResult compiled)
|
||||
{
|
||||
@@ -270,45 +300,55 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
SizeInBytes = (nuint)sizeof(CD3DX12_PIPELINE_MESH_STATE_STREAM)
|
||||
};
|
||||
|
||||
ID3D12PipelineState* pPipelineState = default;
|
||||
|
||||
var pKeyStr = stackalloc char[33]; // 32 for 128 bits key + 1 for null terminator
|
||||
var keySpan = new Span<char>(pKeyStr, 33);
|
||||
if (!pipelineKey.TryGetString(keySpan))
|
||||
result = CreatePSO(descriptor.VariantKey, pipelineKey, &streamDesc);
|
||||
if (result.IsFailure)
|
||||
{
|
||||
return Result.Failure("Failed to convert pipeline key to string.");
|
||||
return result;
|
||||
}
|
||||
|
||||
var hr = pNativeObject->LoadPipeline(pKeyStr, &streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState);
|
||||
if (hr == E.E_INVALIDARG)
|
||||
{
|
||||
// Pipeline not found in the library, create a new one.
|
||||
ThrowIfFailed(_device.NativeObject.Get()->CreatePipelineState(&streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState));
|
||||
ThrowIfFailed(pNativeObject->StorePipeline(pKeyStr, pPipelineState));
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowIfFailed(hr);
|
||||
}
|
||||
|
||||
D3D12PipelineState pso = default;
|
||||
pso.shaderVariant = descriptor.VariantKey;
|
||||
pso.psoDesc = desc;
|
||||
pso.pso.Attach(pPipelineState);
|
||||
|
||||
_pipelineCache[pipelineKey] = pso;
|
||||
}
|
||||
|
||||
return pipelineKey;
|
||||
}
|
||||
|
||||
public bool HasPipeline(Key128<GraphicsPipeline> key)
|
||||
public Result<Key128<ComputePipeline>> CreateComputePipeline(ref readonly ComputePSODescriptor descriptor, ref readonly ShaderCompileResult compiled)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
|
||||
var pipelineKey = RHIUtility.CreateComputePipelineKey(descriptor.VariantKey, compiled.hashCode);
|
||||
if (!_pipelineCache.ContainsKey(pipelineKey))
|
||||
{
|
||||
var result = ValidateReflectionData(compiled.reflectionData);
|
||||
if (result.IsFailure)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var byteCode = new D3D12_SHADER_BYTECODE(compiled.bytecode.GetUnsafePtr(), (nuint)compiled.bytecode.Length);
|
||||
var desc = new CD3DX12_PIPELINE_STATE_STREAM_CS(in byteCode);
|
||||
|
||||
var streamDesc = new D3D12_PIPELINE_STATE_STREAM_DESC
|
||||
{
|
||||
pPipelineStateSubobjectStream = &desc,
|
||||
SizeInBytes = (nuint)sizeof(CD3DX12_PIPELINE_STATE_STREAM_CS)
|
||||
};
|
||||
|
||||
result = CreatePSO(descriptor.VariantKey, pipelineKey, &streamDesc);
|
||||
if (result.IsFailure)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return pipelineKey;
|
||||
}
|
||||
|
||||
public bool HasPipelineStateObject(UInt128 key)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
return _pipelineCache.ContainsKey(key);
|
||||
}
|
||||
|
||||
public Result<SharedPtr<ID3D12PipelineState>, Error> GetGraphicsPSO(Key128<GraphicsPipeline> key)
|
||||
public Result<SharedPtr<ID3D12PipelineState>, Error> GetPipelineStateObject(UInt128 key)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
if (_pipelineCache.TryGetValue(key, out var cacheEntry))
|
||||
|
||||
@@ -18,22 +18,22 @@ namespace Ghost.Graphics.Core;
|
||||
|
||||
internal sealed partial class DXCShaderCompiler
|
||||
{
|
||||
private static string GetProfileString(ShaderStage stage, CompilerTier version)
|
||||
private static string GetProfileString(ShaderStage stage, ShaderModel version)
|
||||
{
|
||||
return (stage, version) switch
|
||||
{
|
||||
(ShaderStage.TaskShader, CompilerTier.Tier0) => "as_6_6",
|
||||
(ShaderStage.PixelShader, CompilerTier.Tier0) => "ps_6_6",
|
||||
(ShaderStage.MeshShader, CompilerTier.Tier0) => "ms_6_6",
|
||||
(ShaderStage.ComputeShader, CompilerTier.Tier0) => "cs_6_6",
|
||||
(ShaderStage.TaskShader, CompilerTier.Tier1) => "as_6_7",
|
||||
(ShaderStage.PixelShader, CompilerTier.Tier1) => "ps_6_7",
|
||||
(ShaderStage.MeshShader, CompilerTier.Tier1) => "ms_6_7",
|
||||
(ShaderStage.ComputeShader, CompilerTier.Tier1) => "cs_6_7",
|
||||
(ShaderStage.TaskShader, CompilerTier.Tier2) => "as_6_8",
|
||||
(ShaderStage.PixelShader, CompilerTier.Tier2) => "ps_6_8",
|
||||
(ShaderStage.MeshShader, CompilerTier.Tier2) => "ms_6_8",
|
||||
(ShaderStage.ComputeShader, CompilerTier.Tier2) => "cs_6_8",
|
||||
(ShaderStage.TaskShader, ShaderModel.SM_6_6) => "as_6_6",
|
||||
(ShaderStage.PixelShader, ShaderModel.SM_6_6) => "ps_6_6",
|
||||
(ShaderStage.MeshShader, ShaderModel.SM_6_6) => "ms_6_6",
|
||||
(ShaderStage.ComputeShader, ShaderModel.SM_6_6) => "cs_6_6",
|
||||
(ShaderStage.TaskShader, ShaderModel.SM_6_7) => "as_6_7",
|
||||
(ShaderStage.PixelShader, ShaderModel.SM_6_7) => "ps_6_7",
|
||||
(ShaderStage.MeshShader, ShaderModel.SM_6_7) => "ms_6_7",
|
||||
(ShaderStage.ComputeShader, ShaderModel.SM_6_7) => "cs_6_7",
|
||||
(ShaderStage.TaskShader, ShaderModel.SM_6_8) => "as_6_8",
|
||||
(ShaderStage.PixelShader, ShaderModel.SM_6_8) => "ps_6_8",
|
||||
(ShaderStage.MeshShader, ShaderModel.SM_6_8) => "ms_6_8",
|
||||
(ShaderStage.ComputeShader, ShaderModel.SM_6_8) => "cs_6_8",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(stage), "Unsupported shader stage or compiler version")
|
||||
};
|
||||
}
|
||||
@@ -54,7 +54,7 @@ internal sealed partial class DXCShaderCompiler
|
||||
{
|
||||
var argsArray = new List<string>
|
||||
{
|
||||
"-T", GetProfileString(config.stage, config.tier), // Target profile (ms_6_6, ps_6_6)
|
||||
"-T", GetProfileString(config.stage, config.model), // Target profile (ms_6_6, ps_6_6)
|
||||
"-E", config.entryPoint, // Entry point
|
||||
"-HV", "2021", // HLSL version 2021
|
||||
"-enable-16bit-types", // Enable 16-bit types
|
||||
@@ -67,6 +67,19 @@ internal sealed partial class DXCShaderCompiler
|
||||
argsArray.Add(define);
|
||||
}
|
||||
|
||||
if (config.stage == ShaderStage.TaskShader
|
||||
|| config.stage == ShaderStage.MeshShader
|
||||
|| config.stage == ShaderStage.PixelShader)
|
||||
{
|
||||
argsArray.Add("-D");
|
||||
argsArray.Add("__GRAPHICS__");
|
||||
}
|
||||
else if (config.stage == ShaderStage.ComputeShader)
|
||||
{
|
||||
argsArray.Add("-D");
|
||||
argsArray.Add("__COMPUTE__");
|
||||
}
|
||||
|
||||
if (!config.options.HasFlag(CompilerOption.KeepDebugInfo))
|
||||
{
|
||||
argsArray.Add("-Qstrip_debug");
|
||||
@@ -378,16 +391,22 @@ internal sealed unsafe partial class DXCShaderCompiler : IShaderCompiler
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should be shader variant specific compile instead of pass specific.
|
||||
// TODO: Build final shader code in memory before compiling.
|
||||
public Result<GraphicsCompiledResult> CompilePass(ref readonly PassDescriptor descriptor, ref readonly ShaderCompilationConfig additionalConfig, ref readonly LocalKeywordSet keywords)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var defineCountInDescriptor = descriptor.defines?.Length ?? 0;
|
||||
var fullDefines = new string[defineCountInDescriptor + additionalConfig.defines.Length];
|
||||
descriptor.defines?.CopyTo(fullDefines);
|
||||
additionalConfig.defines.CopyTo(fullDefines.AsSpan(defineCountInDescriptor));
|
||||
string[] fullDefines;
|
||||
var totalDefineCount = descriptor.defines.Length + additionalConfig.defines.Length;
|
||||
if (totalDefineCount == 0)
|
||||
{
|
||||
fullDefines = Array.Empty<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
fullDefines = new string[totalDefineCount];
|
||||
descriptor.defines.CopyTo(fullDefines);
|
||||
additionalConfig.defines.CopyTo(fullDefines.AsSpan(descriptor.defines.Length));
|
||||
}
|
||||
|
||||
var injectedCodeBuilder = new StringBuilder();
|
||||
injectedCodeBuilder.AppendLine(descriptor.shader.propertiesCode);
|
||||
@@ -402,13 +421,13 @@ internal sealed unsafe partial class DXCShaderCompiler : IShaderCompiler
|
||||
{
|
||||
var config = new ShaderCompilationConfig
|
||||
{
|
||||
defines = fullDefines.AsSpan(),
|
||||
includes = descriptor.includes.AsSpan(),
|
||||
defines = fullDefines,
|
||||
includes = descriptor.includes,
|
||||
shaderPath = tsEntry.shader,
|
||||
entryPoint = tsEntry.entry,
|
||||
injectedCode = injectedCode,
|
||||
stage = ShaderStage.TaskShader,
|
||||
tier = additionalConfig.tier,
|
||||
model = additionalConfig.model,
|
||||
optimizeLevel = additionalConfig.optimizeLevel,
|
||||
options = additionalConfig.options,
|
||||
};
|
||||
@@ -428,13 +447,13 @@ internal sealed unsafe partial class DXCShaderCompiler : IShaderCompiler
|
||||
{
|
||||
var config = new ShaderCompilationConfig
|
||||
{
|
||||
defines = fullDefines.AsSpan(),
|
||||
includes = descriptor.includes.AsSpan(),
|
||||
defines = fullDefines,
|
||||
includes = descriptor.includes,
|
||||
shaderPath = msEntry.shader,
|
||||
entryPoint = msEntry.entry,
|
||||
injectedCode = injectedCode,
|
||||
stage = ShaderStage.MeshShader,
|
||||
tier = additionalConfig.tier,
|
||||
model = additionalConfig.model,
|
||||
optimizeLevel = additionalConfig.optimizeLevel,
|
||||
options = additionalConfig.options,
|
||||
};
|
||||
@@ -458,13 +477,13 @@ internal sealed unsafe partial class DXCShaderCompiler : IShaderCompiler
|
||||
{
|
||||
var config = new ShaderCompilationConfig
|
||||
{
|
||||
defines = fullDefines.AsSpan(),
|
||||
includes = descriptor.includes.AsSpan(),
|
||||
defines = fullDefines,
|
||||
includes = descriptor.includes,
|
||||
shaderPath = psEntry.shader,
|
||||
entryPoint = psEntry.entry,
|
||||
injectedCode = injectedCode,
|
||||
stage = ShaderStage.PixelShader,
|
||||
tier = additionalConfig.tier,
|
||||
model = additionalConfig.model,
|
||||
optimizeLevel = additionalConfig.optimizeLevel,
|
||||
options = additionalConfig.options,
|
||||
};
|
||||
|
||||
@@ -167,6 +167,7 @@ public struct ResourceRange
|
||||
|
||||
public readonly struct ShaderVariant;
|
||||
public readonly struct GraphicsPipeline;
|
||||
public readonly struct ComputePipeline;
|
||||
|
||||
public readonly struct ShaderPass
|
||||
{
|
||||
@@ -241,6 +242,14 @@ public ref struct GraphicsPSODescriptor
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct ComputePSODescriptor
|
||||
{
|
||||
public Key64<ShaderVariant> VariantKey
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct CBufferPropertyInfo
|
||||
{
|
||||
public string Name
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Ghost.Graphics.RHI;
|
||||
public interface IPipelineLibrary : IDisposable
|
||||
{
|
||||
void SaveLibraryToDisk(string filePath);
|
||||
bool HasPipeline(Key128<GraphicsPipeline> key);
|
||||
Result<Key128<GraphicsPipeline>> CreatePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled);
|
||||
bool HasPipelineStateObject(UInt128 key);
|
||||
Result<Key128<GraphicsPipeline>> CreateGraphicsPipeline(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled);
|
||||
Result<Key128<ComputePipeline>> CreateComputePipeline(ref readonly ComputePSODescriptor descriptor, ref readonly ShaderCompileResult compiled);
|
||||
}
|
||||
|
||||
@@ -57,18 +57,11 @@ public ref struct ShaderCompilationConfig
|
||||
public string entryPoint;
|
||||
public string? injectedCode;
|
||||
public ShaderStage stage;
|
||||
public CompilerTier tier;
|
||||
public ShaderModel model;
|
||||
public CompilerOptimizeLevel optimizeLevel;
|
||||
public CompilerOption options;
|
||||
}
|
||||
|
||||
public enum CompilerTier
|
||||
{
|
||||
Tier0,
|
||||
Tier1,
|
||||
Tier2
|
||||
}
|
||||
|
||||
public enum CompilerOptimizeLevel
|
||||
{
|
||||
O0,
|
||||
@@ -92,7 +85,8 @@ public enum ShaderStage
|
||||
TaskShader,
|
||||
MeshShader,
|
||||
PixelShader,
|
||||
ComputeShader
|
||||
ComputeShader,
|
||||
Library // For ray tracing shaders or work graph shaders that don't fit into the traditional shader stages
|
||||
}
|
||||
|
||||
public enum ShaderInputType
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ghost.Graphics.RHI;
|
||||
|
||||
public interface IWorkGraphPipeline
|
||||
{
|
||||
}
|
||||
@@ -10,6 +10,10 @@ namespace Ghost.Graphics.RHI;
|
||||
public static class RHIUtility
|
||||
{
|
||||
public const int MAX_RENDER_TARGETS = 8;
|
||||
public const ulong PIPELINE_KEY_MASK = 0xFFFFFFFFFFFFFFF0ul;
|
||||
public const ulong GRAPHICS_PIPELINE_KEY_FLAG = 0x1ul;
|
||||
public const ulong COMPUTE_PIPELINE_KEY_FLAG = 0x2ul;
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint GetBytesPerPixel(this TextureFormat format)
|
||||
@@ -180,15 +184,29 @@ public static class RHIUtility
|
||||
var pHi = pPasskey[1];
|
||||
|
||||
// Distinct constants + cross-feeding to reduce structural collisions.
|
||||
var lo = Mix64(mLo ^ (pLo + 0x9E3779B97F4A7C15ul) ^ (mHi * 0xD6E8FEB86659FD93ul));
|
||||
var hi = Mix64(mHi ^ (pHi + 0xC2B2AE3D27D4EB4Ful) ^ (pLo * 0x165667B19E3779F9ul));
|
||||
var lo = Mix64(mLo ^ (pLo + 0x9E3779B97F4A7C15ul) ^ (mHi * 0xD6E8FEB86659FD93ul));
|
||||
|
||||
return new Key128<GraphicsPipeline>(new UInt128(lo, hi));
|
||||
lo = lo & PIPELINE_KEY_MASK | GRAPHICS_PIPELINE_KEY_FLAG; // Ensure graphics pipeline keys are distinguishable from compute pipeline keys.
|
||||
|
||||
return new Key128<GraphicsPipeline>(new UInt128(hi, lo));
|
||||
}
|
||||
|
||||
public static Key128<ComputePipeline> CreateComputePipelineKey(Key64<ShaderVariant> shaderVariantKey, ulong compiledHash)
|
||||
{
|
||||
var shaderHash = shaderVariantKey.Value;
|
||||
var stateHash = compiledHash;
|
||||
// Simple XOR mix. Not as robust as the graphics pipeline key, but sufficient for compute shaders which have fewer variants.
|
||||
var hi = shaderHash ^ (stateHash + 0x9E3779B97F4A7C15ul) ^ (shaderHash * 0xD6E8FEB86659FD93ul);
|
||||
var lo = stateHash ^ (shaderHash + 0xC2B2AE3D27D4EB4Ful) ^ (stateHash * 0x165667B19E3779F9ul);
|
||||
lo = lo & PIPELINE_KEY_MASK | COMPUTE_PIPELINE_KEY_FLAG; // Ensure compute pipeline keys are distinguishable from graphics pipeline keys.
|
||||
|
||||
return new Key128<ComputePipeline>(new UInt128(hi, lo));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryGetString(this Key128<GraphicsPipeline> key, Span<char> destination)
|
||||
public static bool TryGetStringFromHash(UInt128 key, Span<char> destination)
|
||||
{
|
||||
return key.Value.TryFormat(destination, out var _, "X16");
|
||||
return key.TryFormat(destination, out var _, "X16");
|
||||
}
|
||||
}
|
||||
@@ -10,20 +10,25 @@ public static class RootSignatureLayout
|
||||
public const int ROOT_PARAMETER_COUNT = 1;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
[StructLayout(LayoutKind.Explicit, Size = 12)]
|
||||
public struct PushConstantsData
|
||||
{
|
||||
public const uint NUM_32BITS_VALUE = 16u / sizeof(uint);
|
||||
|
||||
public const uint NUM_32BITS_VALUE = 12u / sizeof(uint);
|
||||
|
||||
[FieldOffset(0)]
|
||||
public uint frameBuffer;
|
||||
[FieldOffset(4)]
|
||||
public uint viewBuffer;
|
||||
public uint instanceBuffer;
|
||||
[FieldOffset(8)]
|
||||
public uint instanceIndex;
|
||||
[FieldOffset(8)]
|
||||
public uint propertyBuffer;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FrameData
|
||||
{
|
||||
public uint instanceBuffer;
|
||||
public uint userBuffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using Ghost.Core.Utilities;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -75,7 +76,7 @@ public partial struct Shader
|
||||
/// </summary>
|
||||
public partial struct Shader : IResourceReleasable
|
||||
{
|
||||
private readonly uint _cbufferSize;
|
||||
private readonly uint _propertyBufferSize;
|
||||
private UnsafeArray<ShaderPass> _shaderPasses;
|
||||
private UnsafeHashMap<int, int> _passIDToLocal;
|
||||
private UnsafeHashMap<int, int> _keywordIDToLocal;
|
||||
@@ -84,11 +85,11 @@ public partial struct Shader : IResourceReleasable
|
||||
// We can use a int array since the number and index of tags are fixed at compile time.
|
||||
|
||||
public readonly int PassCount => _shaderPasses.Count;
|
||||
public readonly uint PropertyBufferSize => _cbufferSize;
|
||||
public readonly uint PropertyBufferSize => _propertyBufferSize;
|
||||
|
||||
internal Shader(ShaderDescriptor descriptor, ref readonly GraphicsCompiledResult compiledResult)
|
||||
internal Shader(GraphicsShaderDescriptor descriptor, ref readonly GraphicsCompiledResult compiledResult)
|
||||
{
|
||||
_cbufferSize = descriptor.propertyBufferSize;
|
||||
_propertyBufferSize = descriptor.propertyBufferSize;
|
||||
_shaderPasses = new UnsafeArray<ShaderPass>(descriptor.passes.Length, Allocator.Persistent);
|
||||
_passIDToLocal = new UnsafeHashMap<int, int>(descriptor.passes.Length, Allocator.Persistent);
|
||||
_keywordIDToLocal = new UnsafeHashMap<int, int>(32, Allocator.Persistent);
|
||||
@@ -198,3 +199,31 @@ public partial struct Shader : IResourceReleasable
|
||||
_passIDToLocal.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public unsafe partial struct ComputeShader
|
||||
{
|
||||
private fixed ulong _entryHash[8];
|
||||
private readonly int _entryPointCount;
|
||||
private readonly uint _propertyBufferSize;
|
||||
|
||||
public readonly uint PropertyBufferSize => _propertyBufferSize;
|
||||
|
||||
internal ComputeShader(ComputeShaderDescriptor descriptor, ReadOnlySpan<ShaderCompileResult> compiledResults)
|
||||
{
|
||||
Debug.Assert(descriptor.entryPoints.Length == compiledResults.Length);
|
||||
|
||||
_propertyBufferSize = descriptor.propertyBufferSize;
|
||||
_entryPointCount = descriptor.entryPoints.Length;
|
||||
for (var i = 0; i < descriptor.entryPoints.Length; i++)
|
||||
{
|
||||
_entryHash[i] = Hash.Combine64(descriptor.identifier, compiledResults[i].hashCode);
|
||||
}
|
||||
}
|
||||
|
||||
public ulong GetEntryHash(int entryPointIndex)
|
||||
{
|
||||
Debug.Assert(entryPointIndex >= 0 && entryPointIndex < _entryPointCount);
|
||||
return _entryHash[entryPointIndex];
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
<IsTrimmable>True</IsTrimmable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="TestCompute.gcomp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Misaki.HighPerformance.Analyzer" Version="1.1.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -25,7 +25,6 @@ public interface IRasterRenderContext : IRenderGraphContext
|
||||
void SetScissorRect(ScissorRectDesc desc);
|
||||
|
||||
void SetGlobalData(uint globalIndex, uint viewIndex);
|
||||
void SetInstanceData(uint instanceBuffer);
|
||||
void SetInstanceIndex(uint instanceIndex);
|
||||
|
||||
void SetActiveMaterial(Handle<Material> material);
|
||||
@@ -64,7 +63,6 @@ internal sealed class RenderGraphContext : IUnsafeRenderContext
|
||||
|
||||
private uint _activeFrameBuffer;
|
||||
private uint _activeViewBuffer;
|
||||
private uint _activeInstanceBuffer;
|
||||
private uint _activeInstanceIndex;
|
||||
|
||||
public ResourceManager ResourceManager => _resourceManager;
|
||||
@@ -189,7 +187,7 @@ internal sealed class RenderGraphContext : IUnsafeRenderContext
|
||||
};
|
||||
|
||||
var compiled = compiledCacheResult.Value;
|
||||
_pipelineLibrary.CreatePSO(in psoDes, in compiled).GetValueOrThrow();
|
||||
_pipelineLibrary.CreateGraphicsPipeline(in psoDes, in compiled).GetValueOrThrow();
|
||||
}
|
||||
|
||||
_activePerMaterialData = material._cBufferCache.GpuResource;
|
||||
@@ -222,11 +220,6 @@ internal sealed class RenderGraphContext : IUnsafeRenderContext
|
||||
_activeViewBuffer = viewBuffer;
|
||||
}
|
||||
|
||||
public void SetInstanceData(uint instanceBuffer)
|
||||
{
|
||||
_activeInstanceBuffer = instanceBuffer;
|
||||
}
|
||||
|
||||
public void SetInstanceIndex(uint instanceIndex)
|
||||
{
|
||||
_activeInstanceIndex = instanceIndex;
|
||||
@@ -238,7 +231,6 @@ internal sealed class RenderGraphContext : IUnsafeRenderContext
|
||||
{
|
||||
frameBuffer = _activeFrameBuffer,
|
||||
viewBuffer = _activeViewBuffer,
|
||||
instanceBuffer = _activeInstanceBuffer,
|
||||
instanceIndex = _activeInstanceIndex,
|
||||
};
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ public sealed partial class ResourceManager : IDisposable
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="Identifier{Shader}"/> representing the newly created shader.</returns>
|
||||
/// <param name="descriptor">The viewGroup containing the shader's properties and passes.</param>
|
||||
public Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor, ref readonly GraphicsCompiledResult compiledResult)
|
||||
public Identifier<Shader> CreateGraphicsShader(GraphicsShaderDescriptor descriptor, ref readonly GraphicsCompiledResult compiledResult)
|
||||
{
|
||||
Debug.Assert(!_disposed);
|
||||
|
||||
|
||||
@@ -5,16 +5,23 @@
|
||||
|
||||
// TODO: This should be auto generated to match the c# side.
|
||||
|
||||
struct PushConstantData
|
||||
struct GraphicsPushConstantData
|
||||
{
|
||||
BYTE_ADDRESS_BUFFER frameBuffer;
|
||||
BYTE_ADDRESS_BUFFER viewBuffer;
|
||||
BYTE_ADDRESS_BUFFER instanceBuffer;
|
||||
uint instanceIndex;
|
||||
};
|
||||
|
||||
struct ComputePushConstantData
|
||||
{
|
||||
BYTE_ADDRESS_BUFFER frameBuffer;
|
||||
BYTE_ADDRESS_BUFFER viewBuffer;
|
||||
BYTE_ADDRESS_BUFFER propertiesBuffer;
|
||||
};
|
||||
|
||||
struct FrameData
|
||||
{
|
||||
BYTE_ADDRESS_BUFFER instanceBuffer;
|
||||
BYTE_ADDRESS_BUFFER userBuffer;
|
||||
};
|
||||
|
||||
@@ -48,6 +55,10 @@ struct MeshData
|
||||
BYTE_ADDRESS_BUFFER meshletTrianglesBuffer;
|
||||
};
|
||||
|
||||
PushConstantData g_PushConstantData : register(b0);
|
||||
#if define(__GRAPHICS__)
|
||||
GraphicsPushConstantData g_PushConstantData : register(b0);
|
||||
#elif defined(__COMPUTE__)
|
||||
ComputePushConstantData g_PushConstantData : register(b0);
|
||||
#endif
|
||||
|
||||
#endif // GHOST_PROPERTIES_HLSL
|
||||
|
||||
20
src/Runtime/Ghost.Graphics/TestCompute.gcomp
Normal file
20
src/Runtime/Ghost.Graphics/TestCompute.gcomp
Normal file
@@ -0,0 +1,20 @@
|
||||
compute "TestComputeShader"
|
||||
{
|
||||
hlsl
|
||||
{
|
||||
RWTexture2D<float4> OutputTexture : register(u0);
|
||||
[numthreads(8, 8, 1)]
|
||||
void CSMain(uint3 DTid : SV_DispatchThreadID)
|
||||
{
|
||||
OutputTexture[DTid.xy] = float4(DTid.x / 512.0f, DTid.y / 512.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void CSMain2(uint3 DTid : SV_DispatchThreadID)
|
||||
{
|
||||
OutputTexture[DTid.xy] = float4(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
cs "hlsl_block" : "CSMain";
|
||||
cs "hlsl_block" : "CSMain2";
|
||||
}
|
||||
@@ -46,7 +46,8 @@ shader "MyShader/Standard"
|
||||
[numthreads(1, 1, 1)]
|
||||
void ASMain(uint3 groupID : SV_GroupID)
|
||||
{
|
||||
InstanceData instanceData = LoadData<InstanceData>(g_PushConstantData.instanceBuffer, g_PushConstantData.instanceIndex);
|
||||
FrameData frameData = LoadData<FrameData>(g_PushConstantData.frameBuffer, 0);
|
||||
InstanceData instanceData = LoadData<InstanceData>(frameData.instanceBuffer, g_PushConstantData.instanceIndex);
|
||||
MeshData meshData = LoadData<MeshData>(instanceData.meshBuffer, 0);
|
||||
|
||||
uint meshletIndex = groupID.x;
|
||||
@@ -100,7 +101,8 @@ shader "MyShader/Standard"
|
||||
out vertices PixelInput outVerts[64],
|
||||
out indices uint3 outTris[124])
|
||||
{
|
||||
InstanceData instanceData = LoadData<InstanceData>(g_PushConstantData.instanceBuffer, g_PushConstantData.instanceIndex);
|
||||
FrameData frameData = LoadData<FrameData>(g_PushConstantData.frameBuffer, 0);
|
||||
InstanceData instanceData = LoadData<InstanceData>(frameData.instanceBuffer, g_PushConstantData.instanceIndex);
|
||||
MeshData meshData = LoadData<MeshData>(instanceData.meshBuffer, 0);
|
||||
|
||||
ByteAddressBuffer meshletBuffer = GET_BUFFER(meshData.meshletBuffer);
|
||||
@@ -171,13 +173,14 @@ shader "MyShader/Standard"
|
||||
|
||||
return float4(r, g, b, 1.0);
|
||||
|
||||
// InstanceData instanceData = LoadData<InstanceData>(g_PushConstantData.instanceBuffer, g_PushConstantData.instanceIndex);
|
||||
// FrameData frameData = LoadData<FrameData>(g_PushConstantData.frameBuffer, 0);
|
||||
// InstanceData instanceData = LoadData<InstanceData>(frameData.instanceBuffer, g_PushConstantData.instanceIndex);
|
||||
// return mul(instanceData.localToWorld, float4(input.normal, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
task "hlsl_block" : "ASMain";
|
||||
mesh "hlsl_block" : "MSMain";
|
||||
pixel "hlsl_block" : "PSMain";
|
||||
as "hlsl_block" : "ASMain";
|
||||
ms "hlsl_block" : "MSMain";
|
||||
ps "hlsl_block" : "PSMain";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Core.Graphics;
|
||||
using Ghost.DSL.ShaderCompiler;
|
||||
using Ghost.Graphics.Core;
|
||||
using Ghost.Graphics.RenderGraphModule;
|
||||
@@ -43,13 +44,13 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
renderSystem.GraphicsEngine.PipelineLibrary,
|
||||
renderSystem.GraphicsEngine.ShaderCompiler);
|
||||
|
||||
var shaderDescriptor = DSLShaderCompiler.CompileShader("F:/csharp/GhostEngine/src/Runtime/Ghost.Graphics/test.gshdr", "C:/Users/Misaki/Downloads/Archive").GetValueOrThrow();
|
||||
var shaderDescriptor = DSLShaderCompiler.CompileGraphicsShader("F:/csharp/GhostEngine/src/Runtime/Ghost.Graphics/test.gshdr").GetValueOrThrow();
|
||||
|
||||
var config = new ShaderCompilationConfig
|
||||
{
|
||||
optimizeLevel = CompilerOptimizeLevel.O3,
|
||||
options = CompilerOption.KeepReflections,
|
||||
tier = CompilerTier.Tier2
|
||||
model = shaderDescriptor.shaderModel
|
||||
};
|
||||
|
||||
ref readonly var pass = ref shaderDescriptor.passes[0];
|
||||
@@ -281,14 +282,17 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
HeapType = HeapType.Upload,
|
||||
};
|
||||
|
||||
//var frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
||||
//var frameBufferResource = frameBufferHandle.AsResource();
|
||||
var frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
||||
var frameBufferResource = frameBufferHandle.AsResource();
|
||||
|
||||
//var frameData = new FrameData();
|
||||
var frameData = new FrameData
|
||||
{
|
||||
instanceBuffer = resourceDatabase.GetBindlessIndex(instanceBufferResource)
|
||||
};
|
||||
|
||||
//ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||
//ctx.UploadBuffer(frameBufferHandle, new ReadOnlySpan<FrameData>(in frameData));
|
||||
//ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.AllShading, BarrierAccess.ShaderResource));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||
ctx.UploadBuffer(frameBufferHandle, new ReadOnlySpan<FrameData>(in frameData));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.AllShading, BarrierAccess.ShaderResource));
|
||||
|
||||
_renderGraph.Reset();
|
||||
|
||||
@@ -296,8 +300,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
|
||||
MeshletDebugPass(backBuffer, request.opaqueRenderList,
|
||||
uint.MaxValue,
|
||||
resourceDatabase.GetBindlessIndex(viewBufferResource),
|
||||
resourceDatabase.GetBindlessIndex(instanceBufferResource));
|
||||
resourceDatabase.GetBindlessIndex(viewBufferResource));
|
||||
|
||||
var viewState = new ViewState(rtSize.x, rtSize.y, rtSize.x, rtSize.y);
|
||||
_renderGraph.Compile(viewState);
|
||||
@@ -313,7 +316,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
}
|
||||
}
|
||||
|
||||
private void MeshletDebugPass(Identifier<RGTexture> backbuffer, RenderList renderList, uint globalIndex, uint viewIndex, uint instanceBuffer)
|
||||
private void MeshletDebugPass(Identifier<RGTexture> backbuffer, RenderList renderList, uint globalIndex, uint viewIndex)
|
||||
{
|
||||
using (var builder = _renderGraph.AddRasterRenderPass<MeshletDebugPassData>("Meshlet Debug Pass", out var passData))
|
||||
{
|
||||
@@ -322,7 +325,6 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
passData.renderList = renderList;
|
||||
passData.globalIndex = globalIndex;
|
||||
passData.viewIndex = viewIndex;
|
||||
passData.instanceIndex = instanceBuffer;
|
||||
passData.material = _meshletMaterial;
|
||||
|
||||
builder.SetColorAttachment(backbuffer, 0);
|
||||
@@ -331,7 +333,6 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx) =>
|
||||
{
|
||||
ctx.SetGlobalData(data.globalIndex, data.viewIndex);
|
||||
ctx.SetInstanceData(data.instanceIndex);
|
||||
ctx.SetActiveMaterial(data.material);
|
||||
|
||||
var instanceIndex = 0u;
|
||||
|
||||
@@ -1,38 +1,19 @@
|
||||
using Ghost.DSL.Generator;
|
||||
using Ghost.DSL.ShaderCompiler;
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
using System.Numerics;
|
||||
|
||||
ShaderStructGenerator.GenerateHLSL([typeof(TestStruct), typeof(TestEnum), typeof(TestEnumFlags)], PackingRules.Exact, "C:/Users/Misaki/Downloads/Archive/Test.cs.hlsl");
|
||||
//ShaderStructGenerator.GenerateHLSL([typeof(TestStruct), typeof(TestEnum), typeof(TestEnumFlags)], PackingRules.Exact, "C:/Users/Misaki/Downloads/Archive/Test.cs.hlsl");
|
||||
|
||||
//return;
|
||||
#if false
|
||||
var source = File.ReadAllText("F:/csharp/GhostEngine/Ghost.Graphics/test.gshader");
|
||||
|
||||
var lexer = new Lexer(source);
|
||||
var stream = new TokenStream(lexer.Tokenize());
|
||||
var shaderInfo = SDLCompiler.ParseShaders(stream);
|
||||
var model = SDLCompiler.SemanticAnalysis(shaderInfo[0], out var errors);
|
||||
|
||||
foreach (var error in errors)
|
||||
{
|
||||
Console.WriteLine(error);
|
||||
}
|
||||
|
||||
if (errors.Count != 0)
|
||||
#if true
|
||||
var result = DSLShaderCompiler.CompileComputeShader("F:\\csharp\\GhostEngine\\src\\Runtime\\Ghost.Graphics\\TestCompute.gcomp");
|
||||
if (result.IsFailure)
|
||||
{
|
||||
Console.WriteLine(result.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
Console.WriteLine("Failed to compile shader due to errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
var descriptor = SDLCompiler.ResolveShader(model);
|
||||
SDLCompiler.GenerateShaderCode(descriptor, "C:/Users/Misaki/Downloads/Archive");
|
||||
|
||||
Console.WriteLine("Shader compiled successfully:");
|
||||
#endif
|
||||
|
||||
public struct TestStruct
|
||||
|
||||
Reference in New Issue
Block a user