Files
GhostEngine/src/Runtime/Ghost.Generator/ComponentRegistrationGenerator.cs
Misaki 68fda03aa9 feat(render): refactor pipeline & shader system for DX12 WG
Major refactor of render pipeline and shader system:
- Replaced legacy shader properties with source generator and attribute-based HLSL struct generation.
- Introduced ShaderPropertiesRegistry for runtime property layout/code registration.
- Added modular IRenderPipeline, IRenderPipelineSettings, and IRenderPayload interfaces.
- Implemented GhostRenderPipeline and ECS-driven GPUScene management.
- Added experimental DirectX 12 Work Graph support.
- Refactored shader compilation, variant hashing, and caching.
- Updated APIs for consistency and improved codegen for registration.

These changes modernize the rendering infrastructure for advanced features like work graphs and dynamic pipelines.

BREAKING CHANGE: Shader DSL, pipeline, and property APIs have changed. Existing shaders and pipeline integrations must be updated.
2026-04-08 23:08:02 +09:00

92 lines
3.0 KiB
C#

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading;
namespace Ghost.Generator
{
// TODO: this should be per assembly, not global
[Generator]
public class ComponentRegistrationGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 1. Pipeline: Find all structs implementing IComponent
var componentCandidates = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (s, _) => s is StructDeclarationSyntax,
transform: GetComponentSymbol)
.Where(symbol => symbol != null)
.Collect();
// 4. Output: Generate the source using both pieces of data at once
context.RegisterSourceOutput(componentCandidates, GenerateRegistrationCode);
}
// Extraction Logic for Components
private static INamedTypeSymbol GetComponentSymbol(GeneratorSyntaxContext ctx, CancellationToken _)
{
var structSyntax = (StructDeclarationSyntax)ctx.Node;
if (!(ctx.SemanticModel.GetDeclaredSymbol(structSyntax) is INamedTypeSymbol symbol))
{
return null;
}
var iComponentSymbol = ctx.SemanticModel.Compilation.GetTypeByMetadataName("Ghost.Entities.IComponent");
if (iComponentSymbol == null)
{
return null;
}
foreach (var iface in symbol.AllInterfaces)
{
if (SymbolEqualityComparer.Default.Equals(iface, iComponentSymbol))
{
return symbol;
}
}
return null;
}
// The Generation Logic (Stateless)
private static void GenerateRegistrationCode(SourceProductionContext context, ImmutableArray<INamedTypeSymbol> components)
{
if (components.IsDefaultOrEmpty)
{
return;
}
var sb = new StringBuilder();
foreach (var symbol in components.Distinct(SymbolEqualityComparer.Default))
{
if (symbol is null)
{
continue;
}
sb.AppendLine($@" global::Ghost.Entities.ComponentRegistry.GetOrRegisterComponentID<{symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>();");
}
var typeName = $"g_component_registration";
var code = $@"// <auto-generated/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static partial class {typeName}
{{
[global::System.Runtime.CompilerServices.ModuleInitializer]
internal static void RegisterIComponentTypes()
{{
{sb}
}}
}}";
context.AddSource($"{typeName}.gen.cs", code);
}
}
}