Refactor asset handler system and catalog for safety

- Introduced AssetHandlerInfo struct for handler registration and lookup, enabling handler caching and decoupling instantiation from extension/type.
- Changed CustomAssetHandlerAttribute to use required named properties; updated source generator.
- Replaced HandlerTypeId with AssetTypeId throughout metadata, catalog, and sub-asset records for clarity.
- Refactored asset catalog to use connection pooling and local command creation for thread safety.
- Updated asset handler interfaces and implementations to align with new registration system and removed redundant properties.
- Migrated mesh import and meshlet building to async JobScheduler jobs; switched to TLSF allocator and improved safety checks.
- Made meshlet/LOD hierarchy building async and job-based with better memory management.
- Updated usages and tests for new APIs; refreshed project references and package versions.
- Improved documentation and code comments for clarity.
This commit is contained in:
2026-05-08 11:50:06 +09:00
parent d052ca848f
commit b42398bbce
23 changed files with 690 additions and 568 deletions

View File

@@ -1,6 +1,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
@@ -22,6 +23,29 @@ internal class AssetHandlerRegistrationGenerator : IIncrementalGenerator
context.RegisterSourceOutput(handerCandidates, GenerateRegistrationCode);
}
private static T GetValueOrDefault<T>(IDictionary<string, TypedConstant> dictionary, string key, T defaultValue = default)
{
if (dictionary.TryGetValue(key, out var value))
{
if (value.Value is T typedValue)
{
return typedValue;
}
}
return defaultValue;
}
private static ImmutableArray<TypedConstant> GetValuesOrDefault(IDictionary<string, TypedConstant> dictionary, string key)
{
if (dictionary.TryGetValue(key, out var value))
{
return value.Values;
}
return default;
}
private void GenerateRegistrationCode(SourceProductionContext context, ImmutableArray<INamedTypeSymbol> array)
{
if (array.IsDefaultOrEmpty)
@@ -39,12 +63,24 @@ internal class AssetHandlerRegistrationGenerator : IIncrementalGenerator
continue;
}
var id = attribute.ConstructorArguments[0].Value as string;
var extensionsTypesConstants = attribute.ConstructorArguments[1].Values;
var extensions = $"new string[] {{ {string.Join(", ", extensionsTypesConstants.Select(v => v.ToCSharpString()))} }}";
var version = (int)attribute.ConstructorArguments[2].Value;
var properties = attribute.NamedArguments.ToDictionary(kv => kv.Key, kv => kv.Value);
sb.AppendLine($" global::Ghost.Editor.Core.Assets.AssetHandlerRegistry.RegisterHandler(new {symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}(), Guid.Parse(\"{id}\"), {extensions}, {version});");
var id = GetValueOrDefault(properties, "AssetTypeId", string.Empty);
var runtimeType = GetValueOrDefault(properties, "RuntimeAssetType", 0);
var version = GetValueOrDefault(properties, "Version", 1);
var allowCaching = GetValueOrDefault(properties, "AllowCaching", false) ? "true" : "false";
var extensionsTypesConstants = GetValuesOrDefault(properties, "Extensions");
var extensions = string.Join(", ", extensionsTypesConstants.Select(v => v.ToCSharpString()));
sb.AppendLine(" global::Ghost.Editor.Core.Assets.AssetHandlerRegistry.RegisterHandler(");
sb.AppendLine($" typeof({symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}),");
sb.AppendLine($" System.Guid.Parse(\"{id}\"),");
sb.AppendLine($" (Ghost.Engine.AssetType){runtimeType},");
sb.AppendLine($" {version},");
sb.AppendLine($" {allowCaching},");
sb.AppendLine($" new string[] {{ {extensions} }});");
sb.AppendLine();
}
var registerTypeName = "g_assethandler_registeration";

View File

@@ -176,6 +176,7 @@ namespace {info.TypeSymbol.ContainingNamespace.ToDisplayString()}
[global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 4)]
{info.TypeSymbol.DeclaredAccessibility.ToString().ToLower()} partial struct {info.TypeSymbol.Name}
{{
#if DEBUG || GHOST_EDITOR
public const string HLSL_SOURCE = @""
# ifndef {definedSymbol}
# define {definedSymbol}
@@ -185,13 +186,14 @@ struct {info.Name}
}};
# endif // {definedSymbol}"";
}}
#endif
}}";
context.AddSource($"{info.TypeSymbol.Name}_HLSL.gen.cs", code);
codeBuilder.Clear();
var typeFullName = info.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
registerBuilder.AppendLine($@" global::Ghost.DSL.ShaderPropertiesRegistry.Register(""{info.ShaderName}"", {typeFullName}.HLSL_SOURCE, (uint)sizeof({typeFullName}));");
registerBuilder.AppendLine($@" global::Ghost.Core.Graphics.ShaderPropertiesRegistry.Register(""{info.ShaderName}"", {typeFullName}.HLSL_SOURCE, (uint)sizeof({typeFullName}));");
}
var registerTypeName = "g_shaderproperty_registeration";