Files
Fishing2/Packages/com.waveharmonic.crest/Editor/Scripts/Utility/Shared/ShaderGeneratorUtility.cs
2026-01-01 22:00:33 +08:00

80 lines
3.4 KiB
C#

// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// Exposes a customized version of Unity's shader generator task to only generate
// our source files.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Rendering;
using UnityEngine.Rendering;
namespace WaveHarmonic.Crest.Editor
{
static class ShaderGeneratorUtility
{
static MethodInfo s_GenerateAsync;
static MethodInfo GenerateAsync => s_GenerateAsync ??= typeof(CSharpToHLSL)
.GetMethod("GenerateAsync", BindingFlags.Static | BindingFlags.NonPublic);
static async Task InvokeAsync(this MethodInfo methodInfo, object obj, params object[] parameters)
{
dynamic awaitable = methodInfo.Invoke(obj, parameters);
await awaitable;
}
// Adapted from:
// https://github.com/Unity-Technologies/Graphics/blob/96ba978a240e96adcb2abceb21e90b24caa484a3/Packages/com.unity.render-pipelines.core/Editor/ShaderGenerator/CSharpToHLSL.cs#L18L53
internal static async Task GenerateAll()
{
Dictionary<string, List<ShaderTypeGenerator>> sourceGenerators = null;
try
{
// Store per source file path the generator definitions
sourceGenerators = DictionaryPool<string, List<ShaderTypeGenerator>>.Get();
// Extract all types with the GenerateHLSL tag
foreach (var type in TypeCache.GetTypesWithAttribute<GenerateHLSL>())
{
// Only generate our sources as Unity's will trigger a package refresh.
if (!type.FullName.StartsWith("WaveHarmonic.Crest")) continue;
var attr = type.GetCustomAttributes(typeof(GenerateHLSL), false).First() as GenerateHLSL;
if (!sourceGenerators.TryGetValue(attr.sourcePath, out var generators))
{
generators = ListPool<ShaderTypeGenerator>.Get();
sourceGenerators.Add(attr.sourcePath, generators);
}
generators.Add(new(type, attr));
}
// We need to force the culture to invariant, otherwise generated code can replace characters.
// For example, Turkish will replace "I" with "İ". This is a bug with GenerateAsync.
var culture = System.Globalization.CultureInfo.CurrentCulture;
System.Globalization.CultureInfo.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
// Generate all files
await Task.WhenAll(sourceGenerators.Select(async it => await GenerateAsync
.InvokeAsync(null, new object[] { $"{it.Key}.hlsl", $"{Path.ChangeExtension(it.Key, "custom")}.hlsl", it.Value })));
System.Globalization.CultureInfo.CurrentCulture = culture;
}
finally
{
// Make sure we always release pooled resources
if (sourceGenerators != null)
{
foreach (var pair in sourceGenerators)
ListPool<ShaderTypeGenerator>.Release(pair.Value);
DictionaryPool<string, List<ShaderTypeGenerator>>.Release(sourceGenerators);
}
}
}
}
}