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 {
|
options {
|
||||||
tokenVocab = GhostComputeLexer;
|
tokenVocab = GhostShaderLexer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top-level rule
|
// Top-level rule
|
||||||
@@ -13,7 +13,10 @@ compute:
|
|||||||
RBRACE;
|
RBRACE;
|
||||||
|
|
||||||
computeBody:
|
computeBody:
|
||||||
(definesBlock | includesBlock | keywordsBlock | hlslBlock | computeEntry)*;
|
shaderModel | (definesBlock | includesBlock | keywordsBlock | hlslBlock | computeEntry)*;
|
||||||
|
|
||||||
|
shaderModel:
|
||||||
|
SM IDENTIFIER SEMICOLON;
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
GLOBAL | LOCAL;
|
GLOBAL | LOCAL;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ INCLUDES: 'includes';
|
|||||||
GLOBAL: 'global';
|
GLOBAL: 'global';
|
||||||
LOCAL: 'local';
|
LOCAL: 'local';
|
||||||
HLSL: 'hlsl';
|
HLSL: 'hlsl';
|
||||||
|
SM: 'sm';
|
||||||
|
|
||||||
// Punctuation
|
// Punctuation
|
||||||
LBRACE: '{';
|
LBRACE: '{';
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ shader:
|
|||||||
RBRACE;
|
RBRACE;
|
||||||
|
|
||||||
shaderBody:
|
shaderBody:
|
||||||
(pipelineBlock | passBlock | functionCall)*;
|
shaderModel | (pipelineBlock | passBlock | functionCall)*;
|
||||||
|
|
||||||
|
shaderModel:
|
||||||
|
SM IDENTIFIER SEMICOLON;
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
GLOBAL | LOCAL;
|
GLOBAL | LOCAL;
|
||||||
|
|||||||
@@ -45,14 +45,14 @@ internal static class DSLShaderCompiler
|
|||||||
|
|
||||||
// TODO: Implement shader inheritance resolution, including property and pass merging.
|
// TODO: Implement shader inheritance resolution, including property and pass merging.
|
||||||
// Currently, we just ignore inheritance.
|
// 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,
|
name = semantics.name,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!ShaderPropertiesRegistry.TryGetCode(semantics.name, out var info))
|
if (!ShaderPropertiesRegistry.TryGetInfo(semantics.name, out var info))
|
||||||
{
|
{
|
||||||
info = default;
|
info = default;
|
||||||
}
|
}
|
||||||
@@ -60,6 +60,8 @@ internal static class DSLShaderCompiler
|
|||||||
descriptor.propertiesCode = info.code ?? string.Empty;
|
descriptor.propertiesCode = info.code ?? string.Empty;
|
||||||
descriptor.propertyBufferSize = info.size;
|
descriptor.propertyBufferSize = info.size;
|
||||||
|
|
||||||
|
descriptor.shaderModel = semantics.shaderModel;
|
||||||
|
|
||||||
if (semantics.passes != null)
|
if (semantics.passes != null)
|
||||||
{
|
{
|
||||||
descriptor.passes = new PassDescriptor[semantics.passes.Count];
|
descriptor.passes = new PassDescriptor[semantics.passes.Count];
|
||||||
@@ -91,7 +93,7 @@ internal static class DSLShaderCompiler
|
|||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result<ShaderDescriptor> CompileShader(string shaderPath, string generatedOutputDirectory)
|
public static Result<GraphicsShaderDescriptor> CompileGraphicsShader(string shaderPath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -143,4 +145,82 @@ internal static class DSLShaderCompiler
|
|||||||
return Result.Failure("Failed to compile shader: " + ex.Message);
|
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 class DSLShaderSemantics
|
||||||
{
|
{
|
||||||
public string name = string.Empty;
|
public string name = string.Empty;
|
||||||
|
public ShaderModel shaderModel;
|
||||||
public PipelineSemantic? pipeline;
|
public PipelineSemantic? pipeline;
|
||||||
public List<PassSemantic>? passes;
|
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 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>();
|
errors = new List<DSLShaderError>();
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ public class AntlrShaderCompiler
|
|||||||
|
|
||||||
if (errors.Count > 0)
|
if (errors.Count > 0)
|
||||||
{
|
{
|
||||||
return new List<ShaderModel>();
|
return new List<GraphicsShaderModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var visitor = new ShaderVisitor();
|
var visitor = new ShaderVisitor();
|
||||||
@@ -49,11 +49,165 @@ public class AntlrShaderCompiler
|
|||||||
line = -1,
|
line = -1,
|
||||||
column = -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>();
|
errors = new List<DSLShaderError>();
|
||||||
|
|
||||||
@@ -74,6 +228,31 @@ public class AntlrShaderCompiler
|
|||||||
pipeline = ConvertPipeline(model.Pipeline, errors)
|
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)
|
foreach (var pass in model.Passes)
|
||||||
{
|
{
|
||||||
var passSemantic = ConvertPass(pass, errors);
|
var passSemantic = ConvertPass(pass, errors);
|
||||||
@@ -87,99 +266,6 @@ public class AntlrShaderCompiler
|
|||||||
return semantics;
|
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)
|
private static PipelineSemantic? ConvertPipeline(PipelineBlockModel? pipeline, List<DSLShaderError> errors)
|
||||||
{
|
{
|
||||||
if (pipeline == null || pipeline.Statements.Count == 0)
|
if (pipeline == null || pipeline.Statements.Count == 0)
|
||||||
@@ -275,13 +361,13 @@ public class AntlrShaderCompiler
|
|||||||
|
|
||||||
switch (entryType)
|
switch (entryType)
|
||||||
{
|
{
|
||||||
case "mesh" or "ms":
|
case "ms":
|
||||||
semantic.meshShader = shaderEntry;
|
semantic.meshShader = shaderEntry;
|
||||||
break;
|
break;
|
||||||
case "pixel" or "ps":
|
case "ps":
|
||||||
semantic.pixelShader = shaderEntry;
|
semantic.pixelShader = shaderEntry;
|
||||||
break;
|
break;
|
||||||
case "task" or "ts":
|
case "as":
|
||||||
semantic.taskShader = shaderEntry;
|
semantic.taskShader = shaderEntry;
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
namespace Ghost.DSL.ShaderParser.Model;
|
||||||
|
|
||||||
public class ShaderModel
|
public class GraphicsShaderModel
|
||||||
{
|
{
|
||||||
public string Name { get; set; } = string.Empty;
|
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 PipelineBlockModel? Pipeline { get; set; }
|
||||||
public List<PassBlockModel> Passes { get; set; } = new();
|
public List<PassBlockModel> Passes { get; set; } = new();
|
||||||
public List<FunctionCallModel> FunctionCalls { 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 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
|
public class PipelineBlockModel
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ namespace Ghost.DSL.ShaderParser;
|
|||||||
|
|
||||||
public class ShaderVisitor : GhostShaderParserBaseVisitor<object>
|
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)
|
public override object VisitShaderFile([NotNull] GhostShaderParser.ShaderFileContext context)
|
||||||
{
|
{
|
||||||
foreach (var shaderContext in context.shader())
|
foreach (var shaderContext in context.shader())
|
||||||
{
|
{
|
||||||
var shader = (ShaderModel)VisitShader(shaderContext);
|
var shader = (GraphicsShaderModel)VisitShader(shaderContext);
|
||||||
Shaders.Add(shader);
|
Shaders.Add(shader);
|
||||||
}
|
}
|
||||||
return Shaders;
|
return Shaders;
|
||||||
@@ -19,7 +19,7 @@ public class ShaderVisitor : GhostShaderParserBaseVisitor<object>
|
|||||||
|
|
||||||
public override object VisitShader([NotNull] GhostShaderParser.ShaderContext context)
|
public override object VisitShader([NotNull] GhostShaderParser.ShaderContext context)
|
||||||
{
|
{
|
||||||
var shader = new ShaderModel
|
var shader = new GraphicsShaderModel
|
||||||
{
|
{
|
||||||
Name = StripQuotes(context.STRING_LITERAL().GetText())
|
Name = StripQuotes(context.STRING_LITERAL().GetText())
|
||||||
};
|
};
|
||||||
@@ -27,6 +27,8 @@ public class ShaderVisitor : GhostShaderParserBaseVisitor<object>
|
|||||||
var shaderBody = context.shaderBody();
|
var shaderBody = context.shaderBody();
|
||||||
if (shaderBody != null)
|
if (shaderBody != null)
|
||||||
{
|
{
|
||||||
|
shader.SM = shaderBody.shaderModel()?.GetText() ?? string.Empty;
|
||||||
|
|
||||||
foreach (var pipelineBlock in shaderBody.pipelineBlock())
|
foreach (var pipelineBlock in shaderBody.pipelineBlock())
|
||||||
{
|
{
|
||||||
shader.Pipeline = (PipelineBlockModel)VisitPipelineBlock(pipelineBlock);
|
shader.Pipeline = (PipelineBlockModel)VisitPipelineBlock(pipelineBlock);
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
namespace Ghost.Core.Graphics;
|
namespace Ghost.Core.Graphics;
|
||||||
|
|
||||||
|
public enum ShaderModel
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
SM_6_6,
|
||||||
|
SM_6_7,
|
||||||
|
SM_6_8
|
||||||
|
}
|
||||||
|
|
||||||
public enum KeywordSpace
|
public enum KeywordSpace
|
||||||
{
|
{
|
||||||
Local,
|
Local,
|
||||||
Global,
|
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 struct ShaderEntryPoint
|
||||||
{
|
{
|
||||||
public string entry;
|
public string entry;
|
||||||
@@ -35,7 +30,7 @@ public struct KeywordsGroup
|
|||||||
|
|
||||||
public struct PassDescriptor
|
public struct PassDescriptor
|
||||||
{
|
{
|
||||||
public ShaderDescriptor shader;
|
public GraphicsShaderDescriptor shader;
|
||||||
|
|
||||||
public ulong identifier;
|
public ulong identifier;
|
||||||
public string name;
|
public string name;
|
||||||
@@ -50,21 +45,25 @@ public struct PassDescriptor
|
|||||||
public PipelineState localPipeline;
|
public PipelineState localPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ShaderDescriptor
|
public class GraphicsShaderDescriptor
|
||||||
{
|
{
|
||||||
public string name = string.Empty;
|
public string name = string.Empty;
|
||||||
public string propertiesCode = string.Empty;
|
public string propertiesCode = string.Empty;
|
||||||
public uint propertyBufferSize;
|
public uint propertyBufferSize;
|
||||||
|
public ShaderModel shaderModel;
|
||||||
public PassDescriptor[] passes = Array.Empty<PassDescriptor>();
|
public PassDescriptor[] passes = Array.Empty<PassDescriptor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ComputeShaderDescriptor
|
public class ComputeShaderDescriptor
|
||||||
{
|
{
|
||||||
|
public ulong identifier;
|
||||||
public string name = string.Empty;
|
public string name = string.Empty;
|
||||||
public string propertiesCode = string.Empty;
|
public string propertiesCode = string.Empty;
|
||||||
public uint propertyBufferSize;
|
public uint propertyBufferSize;
|
||||||
public ShaderEntryPoint entryPoint;
|
public string? hlsl;
|
||||||
|
public ShaderModel shaderModel;
|
||||||
public string[] defines = Array.Empty<string>();
|
public string[] defines = Array.Empty<string>();
|
||||||
public string[] includes = Array.Empty<string>();
|
public string[] includes = Array.Empty<string>();
|
||||||
public KeywordsGroup[] keywords = Array.Empty<KeywordsGroup>();
|
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 };
|
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);
|
return s_nameToCode.TryGetValue(name, out info);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -650,7 +650,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
#endif
|
#endif
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var psor = _pipelineLibrary.GetGraphicsPSO(pipelineKey);
|
var psor = _pipelineLibrary.GetPipelineStateObject(pipelineKey);
|
||||||
if (psor.Error != Error.None)
|
if (psor.Error != Error.None)
|
||||||
{
|
{
|
||||||
RecordError(nameof(SetPipelineState), psor.Error);
|
RecordError(nameof(SetPipelineState), psor.Error);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ namespace Ghost.Graphics.D3D12;
|
|||||||
|
|
||||||
internal struct D3D12PipelineState : IDisposable
|
internal struct D3D12PipelineState : IDisposable
|
||||||
{
|
{
|
||||||
public D3DX12_MESH_SHADER_PIPELINE_STATE_DESC psoDesc;
|
|
||||||
public UniquePtr<ID3D12PipelineState> pso;
|
public UniquePtr<ID3D12PipelineState> pso;
|
||||||
public Key64<ShaderVariant> shaderVariant;
|
public Key64<ShaderVariant> shaderVariant;
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
|||||||
|
|
||||||
private UniquePtr<ID3D12RootSignature> _defaultRootSignature;
|
private UniquePtr<ID3D12RootSignature> _defaultRootSignature;
|
||||||
|
|
||||||
private UnsafeHashMap<Key128<GraphicsPipeline>, D3D12PipelineState> _pipelineCache;
|
private UnsafeHashMap<UInt128, D3D12PipelineState> _pipelineCache;
|
||||||
|
|
||||||
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
||||||
|
|
||||||
@@ -58,12 +57,12 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public D3D12PipelineLibrary(D3D12RenderDevice device, D3D12ResourceDatabase resourceDatabase)
|
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;
|
_device = device;
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
|
|
||||||
_pipelineCache = new UnsafeHashMap<Key128<GraphicsPipeline>, D3D12PipelineState>(32, Allocator.Persistent);
|
_pipelineCache = new UnsafeHashMap<UInt128, D3D12PipelineState>(32, Allocator.Persistent);
|
||||||
|
|
||||||
CreateDefaultRootSignature().ThrowIfFailed();
|
CreateDefaultRootSignature().ThrowIfFailed();
|
||||||
}
|
}
|
||||||
@@ -174,7 +173,38 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
|||||||
return D3D12Utility.D3D12_DEPTH_STENCIL_DESC_CREATE(depthEnabled, writeEnabled, cmp);
|
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)
|
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)
|
SizeInBytes = (nuint)sizeof(CD3DX12_PIPELINE_MESH_STATE_STREAM)
|
||||||
};
|
};
|
||||||
|
|
||||||
ID3D12PipelineState* pPipelineState = default;
|
result = CreatePSO(descriptor.VariantKey, pipelineKey, &streamDesc);
|
||||||
|
if (result.IsFailure)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
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;
|
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();
|
AssertNotDisposed();
|
||||||
return _pipelineCache.ContainsKey(key);
|
return _pipelineCache.ContainsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<SharedPtr<ID3D12PipelineState>, Error> GetGraphicsPSO(Key128<GraphicsPipeline> key)
|
public Result<SharedPtr<ID3D12PipelineState>, Error> GetPipelineStateObject(UInt128 key)
|
||||||
{
|
{
|
||||||
AssertNotDisposed();
|
AssertNotDisposed();
|
||||||
if (_pipelineCache.TryGetValue(key, out var cacheEntry))
|
if (_pipelineCache.TryGetValue(key, out var cacheEntry))
|
||||||
|
|||||||
@@ -18,22 +18,22 @@ namespace Ghost.Graphics.Core;
|
|||||||
|
|
||||||
internal sealed partial class DXCShaderCompiler
|
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
|
return (stage, version) switch
|
||||||
{
|
{
|
||||||
(ShaderStage.TaskShader, CompilerTier.Tier0) => "as_6_6",
|
(ShaderStage.TaskShader, ShaderModel.SM_6_6) => "as_6_6",
|
||||||
(ShaderStage.PixelShader, CompilerTier.Tier0) => "ps_6_6",
|
(ShaderStage.PixelShader, ShaderModel.SM_6_6) => "ps_6_6",
|
||||||
(ShaderStage.MeshShader, CompilerTier.Tier0) => "ms_6_6",
|
(ShaderStage.MeshShader, ShaderModel.SM_6_6) => "ms_6_6",
|
||||||
(ShaderStage.ComputeShader, CompilerTier.Tier0) => "cs_6_6",
|
(ShaderStage.ComputeShader, ShaderModel.SM_6_6) => "cs_6_6",
|
||||||
(ShaderStage.TaskShader, CompilerTier.Tier1) => "as_6_7",
|
(ShaderStage.TaskShader, ShaderModel.SM_6_7) => "as_6_7",
|
||||||
(ShaderStage.PixelShader, CompilerTier.Tier1) => "ps_6_7",
|
(ShaderStage.PixelShader, ShaderModel.SM_6_7) => "ps_6_7",
|
||||||
(ShaderStage.MeshShader, CompilerTier.Tier1) => "ms_6_7",
|
(ShaderStage.MeshShader, ShaderModel.SM_6_7) => "ms_6_7",
|
||||||
(ShaderStage.ComputeShader, CompilerTier.Tier1) => "cs_6_7",
|
(ShaderStage.ComputeShader, ShaderModel.SM_6_7) => "cs_6_7",
|
||||||
(ShaderStage.TaskShader, CompilerTier.Tier2) => "as_6_8",
|
(ShaderStage.TaskShader, ShaderModel.SM_6_8) => "as_6_8",
|
||||||
(ShaderStage.PixelShader, CompilerTier.Tier2) => "ps_6_8",
|
(ShaderStage.PixelShader, ShaderModel.SM_6_8) => "ps_6_8",
|
||||||
(ShaderStage.MeshShader, CompilerTier.Tier2) => "ms_6_8",
|
(ShaderStage.MeshShader, ShaderModel.SM_6_8) => "ms_6_8",
|
||||||
(ShaderStage.ComputeShader, CompilerTier.Tier2) => "cs_6_8",
|
(ShaderStage.ComputeShader, ShaderModel.SM_6_8) => "cs_6_8",
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(stage), "Unsupported shader stage or compiler version")
|
_ => 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>
|
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
|
"-E", config.entryPoint, // Entry point
|
||||||
"-HV", "2021", // HLSL version 2021
|
"-HV", "2021", // HLSL version 2021
|
||||||
"-enable-16bit-types", // Enable 16-bit types
|
"-enable-16bit-types", // Enable 16-bit types
|
||||||
@@ -67,6 +67,19 @@ internal sealed partial class DXCShaderCompiler
|
|||||||
argsArray.Add(define);
|
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))
|
if (!config.options.HasFlag(CompilerOption.KeepDebugInfo))
|
||||||
{
|
{
|
||||||
argsArray.Add("-Qstrip_debug");
|
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)
|
public Result<GraphicsCompiledResult> CompilePass(ref readonly PassDescriptor descriptor, ref readonly ShaderCompilationConfig additionalConfig, ref readonly LocalKeywordSet keywords)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var defineCountInDescriptor = descriptor.defines?.Length ?? 0;
|
string[] fullDefines;
|
||||||
var fullDefines = new string[defineCountInDescriptor + additionalConfig.defines.Length];
|
var totalDefineCount = descriptor.defines.Length + additionalConfig.defines.Length;
|
||||||
descriptor.defines?.CopyTo(fullDefines);
|
if (totalDefineCount == 0)
|
||||||
additionalConfig.defines.CopyTo(fullDefines.AsSpan(defineCountInDescriptor));
|
{
|
||||||
|
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();
|
var injectedCodeBuilder = new StringBuilder();
|
||||||
injectedCodeBuilder.AppendLine(descriptor.shader.propertiesCode);
|
injectedCodeBuilder.AppendLine(descriptor.shader.propertiesCode);
|
||||||
@@ -402,13 +421,13 @@ internal sealed unsafe partial class DXCShaderCompiler : IShaderCompiler
|
|||||||
{
|
{
|
||||||
var config = new ShaderCompilationConfig
|
var config = new ShaderCompilationConfig
|
||||||
{
|
{
|
||||||
defines = fullDefines.AsSpan(),
|
defines = fullDefines,
|
||||||
includes = descriptor.includes.AsSpan(),
|
includes = descriptor.includes,
|
||||||
shaderPath = tsEntry.shader,
|
shaderPath = tsEntry.shader,
|
||||||
entryPoint = tsEntry.entry,
|
entryPoint = tsEntry.entry,
|
||||||
injectedCode = injectedCode,
|
injectedCode = injectedCode,
|
||||||
stage = ShaderStage.TaskShader,
|
stage = ShaderStage.TaskShader,
|
||||||
tier = additionalConfig.tier,
|
model = additionalConfig.model,
|
||||||
optimizeLevel = additionalConfig.optimizeLevel,
|
optimizeLevel = additionalConfig.optimizeLevel,
|
||||||
options = additionalConfig.options,
|
options = additionalConfig.options,
|
||||||
};
|
};
|
||||||
@@ -428,13 +447,13 @@ internal sealed unsafe partial class DXCShaderCompiler : IShaderCompiler
|
|||||||
{
|
{
|
||||||
var config = new ShaderCompilationConfig
|
var config = new ShaderCompilationConfig
|
||||||
{
|
{
|
||||||
defines = fullDefines.AsSpan(),
|
defines = fullDefines,
|
||||||
includes = descriptor.includes.AsSpan(),
|
includes = descriptor.includes,
|
||||||
shaderPath = msEntry.shader,
|
shaderPath = msEntry.shader,
|
||||||
entryPoint = msEntry.entry,
|
entryPoint = msEntry.entry,
|
||||||
injectedCode = injectedCode,
|
injectedCode = injectedCode,
|
||||||
stage = ShaderStage.MeshShader,
|
stage = ShaderStage.MeshShader,
|
||||||
tier = additionalConfig.tier,
|
model = additionalConfig.model,
|
||||||
optimizeLevel = additionalConfig.optimizeLevel,
|
optimizeLevel = additionalConfig.optimizeLevel,
|
||||||
options = additionalConfig.options,
|
options = additionalConfig.options,
|
||||||
};
|
};
|
||||||
@@ -458,13 +477,13 @@ internal sealed unsafe partial class DXCShaderCompiler : IShaderCompiler
|
|||||||
{
|
{
|
||||||
var config = new ShaderCompilationConfig
|
var config = new ShaderCompilationConfig
|
||||||
{
|
{
|
||||||
defines = fullDefines.AsSpan(),
|
defines = fullDefines,
|
||||||
includes = descriptor.includes.AsSpan(),
|
includes = descriptor.includes,
|
||||||
shaderPath = psEntry.shader,
|
shaderPath = psEntry.shader,
|
||||||
entryPoint = psEntry.entry,
|
entryPoint = psEntry.entry,
|
||||||
injectedCode = injectedCode,
|
injectedCode = injectedCode,
|
||||||
stage = ShaderStage.PixelShader,
|
stage = ShaderStage.PixelShader,
|
||||||
tier = additionalConfig.tier,
|
model = additionalConfig.model,
|
||||||
optimizeLevel = additionalConfig.optimizeLevel,
|
optimizeLevel = additionalConfig.optimizeLevel,
|
||||||
options = additionalConfig.options,
|
options = additionalConfig.options,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ public struct ResourceRange
|
|||||||
|
|
||||||
public readonly struct ShaderVariant;
|
public readonly struct ShaderVariant;
|
||||||
public readonly struct GraphicsPipeline;
|
public readonly struct GraphicsPipeline;
|
||||||
|
public readonly struct ComputePipeline;
|
||||||
|
|
||||||
public readonly struct ShaderPass
|
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 readonly struct CBufferPropertyInfo
|
||||||
{
|
{
|
||||||
public string Name
|
public string Name
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace Ghost.Graphics.RHI;
|
|||||||
public interface IPipelineLibrary : IDisposable
|
public interface IPipelineLibrary : IDisposable
|
||||||
{
|
{
|
||||||
void SaveLibraryToDisk(string filePath);
|
void SaveLibraryToDisk(string filePath);
|
||||||
bool HasPipeline(Key128<GraphicsPipeline> key);
|
bool HasPipelineStateObject(UInt128 key);
|
||||||
Result<Key128<GraphicsPipeline>> CreatePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled);
|
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 entryPoint;
|
||||||
public string? injectedCode;
|
public string? injectedCode;
|
||||||
public ShaderStage stage;
|
public ShaderStage stage;
|
||||||
public CompilerTier tier;
|
public ShaderModel model;
|
||||||
public CompilerOptimizeLevel optimizeLevel;
|
public CompilerOptimizeLevel optimizeLevel;
|
||||||
public CompilerOption options;
|
public CompilerOption options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CompilerTier
|
|
||||||
{
|
|
||||||
Tier0,
|
|
||||||
Tier1,
|
|
||||||
Tier2
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum CompilerOptimizeLevel
|
public enum CompilerOptimizeLevel
|
||||||
{
|
{
|
||||||
O0,
|
O0,
|
||||||
@@ -92,7 +85,8 @@ public enum ShaderStage
|
|||||||
TaskShader,
|
TaskShader,
|
||||||
MeshShader,
|
MeshShader,
|
||||||
PixelShader,
|
PixelShader,
|
||||||
ComputeShader
|
ComputeShader,
|
||||||
|
Library // For ray tracing shaders or work graph shaders that don't fit into the traditional shader stages
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ShaderInputType
|
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 static class RHIUtility
|
||||||
{
|
{
|
||||||
public const int MAX_RENDER_TARGETS = 8;
|
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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint GetBytesPerPixel(this TextureFormat format)
|
public static uint GetBytesPerPixel(this TextureFormat format)
|
||||||
@@ -180,15 +184,29 @@ public static class RHIUtility
|
|||||||
var pHi = pPasskey[1];
|
var pHi = pPasskey[1];
|
||||||
|
|
||||||
// Distinct constants + cross-feeding to reduce structural collisions.
|
// 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 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)]
|
[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;
|
public const int ROOT_PARAMETER_COUNT = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
[StructLayout(LayoutKind.Explicit, Size = 12)]
|
||||||
public struct PushConstantsData
|
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;
|
public uint frameBuffer;
|
||||||
|
[FieldOffset(4)]
|
||||||
public uint viewBuffer;
|
public uint viewBuffer;
|
||||||
public uint instanceBuffer;
|
[FieldOffset(8)]
|
||||||
public uint instanceIndex;
|
public uint instanceIndex;
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public uint propertyBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct FrameData
|
public struct FrameData
|
||||||
{
|
{
|
||||||
|
public uint instanceBuffer;
|
||||||
public uint userBuffer;
|
public uint userBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Ghost.Core.Utilities;
|
|||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ public partial struct Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial struct Shader : IResourceReleasable
|
public partial struct Shader : IResourceReleasable
|
||||||
{
|
{
|
||||||
private readonly uint _cbufferSize;
|
private readonly uint _propertyBufferSize;
|
||||||
private UnsafeArray<ShaderPass> _shaderPasses;
|
private UnsafeArray<ShaderPass> _shaderPasses;
|
||||||
private UnsafeHashMap<int, int> _passIDToLocal;
|
private UnsafeHashMap<int, int> _passIDToLocal;
|
||||||
private UnsafeHashMap<int, int> _keywordIDToLocal;
|
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.
|
// 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 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);
|
_shaderPasses = new UnsafeArray<ShaderPass>(descriptor.passes.Length, Allocator.Persistent);
|
||||||
_passIDToLocal = new UnsafeHashMap<int, int>(descriptor.passes.Length, Allocator.Persistent);
|
_passIDToLocal = new UnsafeHashMap<int, int>(descriptor.passes.Length, Allocator.Persistent);
|
||||||
_keywordIDToLocal = new UnsafeHashMap<int, int>(32, Allocator.Persistent);
|
_keywordIDToLocal = new UnsafeHashMap<int, int>(32, Allocator.Persistent);
|
||||||
@@ -198,3 +199,31 @@ public partial struct Shader : IResourceReleasable
|
|||||||
_passIDToLocal.Dispose();
|
_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>
|
<IsTrimmable>True</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="TestCompute.gcomp" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Misaki.HighPerformance.Analyzer" Version="1.1.0">
|
<PackageReference Include="Misaki.HighPerformance.Analyzer" Version="1.1.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ public interface IRasterRenderContext : IRenderGraphContext
|
|||||||
void SetScissorRect(ScissorRectDesc desc);
|
void SetScissorRect(ScissorRectDesc desc);
|
||||||
|
|
||||||
void SetGlobalData(uint globalIndex, uint viewIndex);
|
void SetGlobalData(uint globalIndex, uint viewIndex);
|
||||||
void SetInstanceData(uint instanceBuffer);
|
|
||||||
void SetInstanceIndex(uint instanceIndex);
|
void SetInstanceIndex(uint instanceIndex);
|
||||||
|
|
||||||
void SetActiveMaterial(Handle<Material> material);
|
void SetActiveMaterial(Handle<Material> material);
|
||||||
@@ -64,7 +63,6 @@ internal sealed class RenderGraphContext : IUnsafeRenderContext
|
|||||||
|
|
||||||
private uint _activeFrameBuffer;
|
private uint _activeFrameBuffer;
|
||||||
private uint _activeViewBuffer;
|
private uint _activeViewBuffer;
|
||||||
private uint _activeInstanceBuffer;
|
|
||||||
private uint _activeInstanceIndex;
|
private uint _activeInstanceIndex;
|
||||||
|
|
||||||
public ResourceManager ResourceManager => _resourceManager;
|
public ResourceManager ResourceManager => _resourceManager;
|
||||||
@@ -189,7 +187,7 @@ internal sealed class RenderGraphContext : IUnsafeRenderContext
|
|||||||
};
|
};
|
||||||
|
|
||||||
var compiled = compiledCacheResult.Value;
|
var compiled = compiledCacheResult.Value;
|
||||||
_pipelineLibrary.CreatePSO(in psoDes, in compiled).GetValueOrThrow();
|
_pipelineLibrary.CreateGraphicsPipeline(in psoDes, in compiled).GetValueOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
_activePerMaterialData = material._cBufferCache.GpuResource;
|
_activePerMaterialData = material._cBufferCache.GpuResource;
|
||||||
@@ -222,11 +220,6 @@ internal sealed class RenderGraphContext : IUnsafeRenderContext
|
|||||||
_activeViewBuffer = viewBuffer;
|
_activeViewBuffer = viewBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetInstanceData(uint instanceBuffer)
|
|
||||||
{
|
|
||||||
_activeInstanceBuffer = instanceBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetInstanceIndex(uint instanceIndex)
|
public void SetInstanceIndex(uint instanceIndex)
|
||||||
{
|
{
|
||||||
_activeInstanceIndex = instanceIndex;
|
_activeInstanceIndex = instanceIndex;
|
||||||
@@ -238,7 +231,6 @@ internal sealed class RenderGraphContext : IUnsafeRenderContext
|
|||||||
{
|
{
|
||||||
frameBuffer = _activeFrameBuffer,
|
frameBuffer = _activeFrameBuffer,
|
||||||
viewBuffer = _activeViewBuffer,
|
viewBuffer = _activeViewBuffer,
|
||||||
instanceBuffer = _activeInstanceBuffer,
|
|
||||||
instanceIndex = _activeInstanceIndex,
|
instanceIndex = _activeInstanceIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ public sealed partial class ResourceManager : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>An <see cref="Identifier{Shader}"/> representing the newly created shader.</returns>
|
/// <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>
|
/// <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);
|
Debug.Assert(!_disposed);
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,23 @@
|
|||||||
|
|
||||||
// TODO: This should be auto generated to match the c# side.
|
// TODO: This should be auto generated to match the c# side.
|
||||||
|
|
||||||
struct PushConstantData
|
struct GraphicsPushConstantData
|
||||||
{
|
{
|
||||||
BYTE_ADDRESS_BUFFER frameBuffer;
|
BYTE_ADDRESS_BUFFER frameBuffer;
|
||||||
BYTE_ADDRESS_BUFFER viewBuffer;
|
BYTE_ADDRESS_BUFFER viewBuffer;
|
||||||
BYTE_ADDRESS_BUFFER instanceBuffer;
|
|
||||||
uint instanceIndex;
|
uint instanceIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ComputePushConstantData
|
||||||
|
{
|
||||||
|
BYTE_ADDRESS_BUFFER frameBuffer;
|
||||||
|
BYTE_ADDRESS_BUFFER viewBuffer;
|
||||||
|
BYTE_ADDRESS_BUFFER propertiesBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
struct FrameData
|
struct FrameData
|
||||||
{
|
{
|
||||||
|
BYTE_ADDRESS_BUFFER instanceBuffer;
|
||||||
BYTE_ADDRESS_BUFFER userBuffer;
|
BYTE_ADDRESS_BUFFER userBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,6 +55,10 @@ struct MeshData
|
|||||||
BYTE_ADDRESS_BUFFER meshletTrianglesBuffer;
|
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
|
#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)]
|
[numthreads(1, 1, 1)]
|
||||||
void ASMain(uint3 groupID : SV_GroupID)
|
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);
|
MeshData meshData = LoadData<MeshData>(instanceData.meshBuffer, 0);
|
||||||
|
|
||||||
uint meshletIndex = groupID.x;
|
uint meshletIndex = groupID.x;
|
||||||
@@ -100,7 +101,8 @@ shader "MyShader/Standard"
|
|||||||
out vertices PixelInput outVerts[64],
|
out vertices PixelInput outVerts[64],
|
||||||
out indices uint3 outTris[124])
|
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);
|
MeshData meshData = LoadData<MeshData>(instanceData.meshBuffer, 0);
|
||||||
|
|
||||||
ByteAddressBuffer meshletBuffer = GET_BUFFER(meshData.meshletBuffer);
|
ByteAddressBuffer meshletBuffer = GET_BUFFER(meshData.meshletBuffer);
|
||||||
@@ -171,13 +173,14 @@ shader "MyShader/Standard"
|
|||||||
|
|
||||||
return float4(r, g, b, 1.0);
|
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));
|
// return mul(instanceData.localToWorld, float4(input.normal, 1.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task "hlsl_block" : "ASMain";
|
as "hlsl_block" : "ASMain";
|
||||||
mesh "hlsl_block" : "MSMain";
|
ms "hlsl_block" : "MSMain";
|
||||||
pixel "hlsl_block" : "PSMain";
|
ps "hlsl_block" : "PSMain";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.DSL.ShaderCompiler;
|
using Ghost.DSL.ShaderCompiler;
|
||||||
using Ghost.Graphics.Core;
|
using Ghost.Graphics.Core;
|
||||||
using Ghost.Graphics.RenderGraphModule;
|
using Ghost.Graphics.RenderGraphModule;
|
||||||
@@ -43,13 +44,13 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
renderSystem.GraphicsEngine.PipelineLibrary,
|
renderSystem.GraphicsEngine.PipelineLibrary,
|
||||||
renderSystem.GraphicsEngine.ShaderCompiler);
|
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
|
var config = new ShaderCompilationConfig
|
||||||
{
|
{
|
||||||
optimizeLevel = CompilerOptimizeLevel.O3,
|
optimizeLevel = CompilerOptimizeLevel.O3,
|
||||||
options = CompilerOption.KeepReflections,
|
options = CompilerOption.KeepReflections,
|
||||||
tier = CompilerTier.Tier2
|
model = shaderDescriptor.shaderModel
|
||||||
};
|
};
|
||||||
|
|
||||||
ref readonly var pass = ref shaderDescriptor.passes[0];
|
ref readonly var pass = ref shaderDescriptor.passes[0];
|
||||||
@@ -281,14 +282,17 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
HeapType = HeapType.Upload,
|
HeapType = HeapType.Upload,
|
||||||
};
|
};
|
||||||
|
|
||||||
//var frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
var frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
||||||
//var frameBufferResource = frameBufferHandle.AsResource();
|
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.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||||
//ctx.UploadBuffer(frameBufferHandle, new ReadOnlySpan<FrameData>(in frameData));
|
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.AllShading, BarrierAccess.ShaderResource));
|
||||||
|
|
||||||
_renderGraph.Reset();
|
_renderGraph.Reset();
|
||||||
|
|
||||||
@@ -296,8 +300,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
|
|
||||||
MeshletDebugPass(backBuffer, request.opaqueRenderList,
|
MeshletDebugPass(backBuffer, request.opaqueRenderList,
|
||||||
uint.MaxValue,
|
uint.MaxValue,
|
||||||
resourceDatabase.GetBindlessIndex(viewBufferResource),
|
resourceDatabase.GetBindlessIndex(viewBufferResource));
|
||||||
resourceDatabase.GetBindlessIndex(instanceBufferResource));
|
|
||||||
|
|
||||||
var viewState = new ViewState(rtSize.x, rtSize.y, rtSize.x, rtSize.y);
|
var viewState = new ViewState(rtSize.x, rtSize.y, rtSize.x, rtSize.y);
|
||||||
_renderGraph.Compile(viewState);
|
_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))
|
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.renderList = renderList;
|
||||||
passData.globalIndex = globalIndex;
|
passData.globalIndex = globalIndex;
|
||||||
passData.viewIndex = viewIndex;
|
passData.viewIndex = viewIndex;
|
||||||
passData.instanceIndex = instanceBuffer;
|
|
||||||
passData.material = _meshletMaterial;
|
passData.material = _meshletMaterial;
|
||||||
|
|
||||||
builder.SetColorAttachment(backbuffer, 0);
|
builder.SetColorAttachment(backbuffer, 0);
|
||||||
@@ -331,7 +333,6 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx) =>
|
builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx) =>
|
||||||
{
|
{
|
||||||
ctx.SetGlobalData(data.globalIndex, data.viewIndex);
|
ctx.SetGlobalData(data.globalIndex, data.viewIndex);
|
||||||
ctx.SetInstanceData(data.instanceIndex);
|
|
||||||
ctx.SetActiveMaterial(data.material);
|
ctx.SetActiveMaterial(data.material);
|
||||||
|
|
||||||
var instanceIndex = 0u;
|
var instanceIndex = 0u;
|
||||||
|
|||||||
@@ -1,38 +1,19 @@
|
|||||||
using Ghost.DSL.Generator;
|
using Ghost.DSL.Generator;
|
||||||
|
using Ghost.DSL.ShaderCompiler;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using System.Numerics;
|
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;
|
//return;
|
||||||
#if false
|
#if true
|
||||||
var source = File.ReadAllText("F:/csharp/GhostEngine/Ghost.Graphics/test.gshader");
|
var result = DSLShaderCompiler.CompileComputeShader("F:\\csharp\\GhostEngine\\src\\Runtime\\Ghost.Graphics\\TestCompute.gcomp");
|
||||||
|
if (result.IsFailure)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
Console.WriteLine(result.Message);
|
||||||
return;
|
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
|
#endif
|
||||||
|
|
||||||
public struct TestStruct
|
public struct TestStruct
|
||||||
|
|||||||
Reference in New Issue
Block a user