diff --git a/src/Fuse/FuseEffectInstance.cs b/src/Fuse/FuseEffectInstance.cs
new file mode 100644
index 00000000..430347d2
--- /dev/null
+++ b/src/Fuse/FuseEffectInstance.cs
@@ -0,0 +1,98 @@
+using Stride.Core;
+using Stride.Core.Diagnostics;
+using Stride.Engine.Design;
+using Stride.Games;
+using Stride.Graphics;
+using Stride.Rendering;
+using Stride.Shaders;
+using Stride.Shaders.Compiler;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Fuse
+{
+ public class FuseEffectInstance : EffectInstance
+ {
+ private readonly ShaderSource shaderSource;
+ private readonly IDisposable subscriptions;
+ private EffectSystem effectSystem;
+
+ public FuseEffectInstance(ShaderSource shaderSource, ParameterCollection parameters, IDisposable subscriptions) : base(null, parameters)
+ {
+ this.shaderSource = shaderSource;
+ this.subscriptions = subscriptions;
+ }
+
+ protected override void Destroy()
+ {
+ subscriptions.Dispose();
+ base.Destroy();
+ }
+
+ ///
+ /// Defines the effect parameters used when compiling this effect.
+ ///
+ public EffectCompilerParameters EffectCompilerParameters = EffectCompilerParameters.Default;
+
+ public void Initialize(IServiceRegistry services)
+ {
+ this.effectSystem = services.GetSafeServiceAs();
+
+ var gameSettings = services.GetSafeServiceAs().Settings;
+ EffectCompilerParameters.ApplyCompilationMode(gameSettings.CompilationMode);
+
+ var graphicsDevice = services.GetSafeServiceAs().GraphicsDevice;
+ EffectCompilerParameters.Platform = GraphicsDevice.Platform;
+ EffectCompilerParameters.Profile = graphicsDevice.Features.RequestedProfile;
+ }
+
+ protected override void ChooseEffect(GraphicsDevice graphicsDevice)
+ {
+ var watch = Stopwatch.StartNew();
+
+ // Setup compilation parameters
+ var compilerParameters = new CompilerParameters
+ {
+ EffectParameters = EffectCompilerParameters,
+ };
+
+ foreach (var effectParameterKey in Parameters.ParameterKeyInfos)
+ {
+ if (effectParameterKey.Key.Type == ParameterKeyType.Permutation)
+ {
+ compilerParameters.SetObject(effectParameterKey.Key, Parameters.ObjectValues[effectParameterKey.BindingSlot]);
+ }
+ }
+
+ var compiler = effectSystem.Compiler;
+
+ // Workaround for Stride effect compiler cache bug
+ ShaderNodesUtil.MakeInMemoryShadersAvailableToTheSourceManager(compiler, shaderSource);
+
+ // Compile the shader
+ var compilerResult = compiler.Compile(shaderSource, compilerParameters);
+ CheckResult(compilerResult);
+
+ var bytecodeResult = compilerResult.Bytecode.WaitForResult();
+
+ CheckResult(bytecodeResult.CompilationLog);
+
+ if (bytecodeResult.Bytecode is null)
+ throw new InvalidOperationException("EffectCompiler returned no shader and no compilation error.");
+
+ effect = new Effect(graphicsDevice, bytecodeResult.Bytecode);
+
+ Console.WriteLine($"Compile Time: {watch.ElapsedMilliseconds} ms for Shader {shaderSource}");
+ }
+
+ private static void CheckResult(LoggerResult compilerResult)
+ {
+ // Check errors
+ if (compilerResult.HasErrors)
+ {
+ throw new InvalidOperationException("Could not compile shader. See error messages." + compilerResult.ToText());
+ }
+ }
+ }
+}
diff --git a/src/Fuse/Inputs.cs b/src/Fuse/Inputs.cs
index 49a4e41c..5529e989 100644
--- a/src/Fuse/Inputs.cs
+++ b/src/Fuse/Inputs.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Text;
using Fuse.compute;
using Stride.Graphics;
using Stride.Rendering;
@@ -101,7 +102,9 @@ public override string ToString()
public bool IsResource { get; }
}
- public abstract class AbstractInput : ShaderNode, IGpuInput where TParameterKeyType : ParameterKey where TParameterUpdaterType : ParameterUpdater
+ public abstract class AbstractInput : ShaderNode, IGpuInput
+ where TParameterKeyType : ParameterKey
+ where TParameterUpdaterType : ParameterUpdater
{
protected readonly TParameterUpdaterType Updater;// = new ValueParameterUpdater();
@@ -408,30 +411,4 @@ public override void OnUpdateName()
SetFieldDeclaration(TypeHelpers.GetGpuType());
}
}
- /*
- public class CompositionInput : AbstractInput, PermutationParameterUpdater> where T : IComputeNode
- {
-
- public CompositionInput(SetVar value): base("input", false, value)
- {
- }
-
- protected override PermutationParameterUpdater CreateUpdater()
- {
- return new PermutationParameterUpdater();
- }
-
- protected override void OnPassContext(ShaderGeneratorContext nodeContext)
- {
- Updater.Track(nodeContext, ParameterKey);
- }
-
- protected override void OnGenerateCode(ShaderGeneratorContext nodeContext)
- {
- ParameterKey = new PermutationParameterKey(ID);
- SetFieldDeclaration(TypeHelpers.GetGpuTypeForType());
- }
-
-
- }*/
}
\ No newline at end of file
diff --git a/src/Fuse/Properties/launchSettings.json b/src/Fuse/Properties/launchSettings.json
index 0dbbaf3c..b8a1d596 100644
--- a/src/Fuse/Properties/launchSettings.json
+++ b/src/Fuse/Properties/launchSettings.json
@@ -2,12 +2,12 @@
"profiles": {
"Normal startup": {
"commandName": "Executable",
- "executablePath": "C:\\Program Files\\vvvv\\vvvv_gamma_5.3-0251-gc882d50ce8\\vvvv.exe",
+ "executablePath": "C:\\Program Files\\vvvv\\vvvv_gamma_5.3-0346-g0a53f6c531\\vvvv.exe",
"commandLineArgs": "--package-repositories $(PackageRepositories)"
},
"Work on Fuse patches": {
"commandName": "Executable",
- "executablePath": "C:\\Program Files\\vvvv\\vvvv_gamma_5.3-0251-gc882d50ce8\\vvvv.exe",
+ "executablePath": "C:\\Program Files\\vvvv\\vvvv_gamma_5.3-0346-g0a53f6c531\\vvvv.exe",
"commandLineArgs": "--package-repositories $(PackageRepositories) --editable-packages VL.Fuse"
}
}
diff --git a/src/Fuse/ShaderFX/AbstractToShaderFX.cs b/src/Fuse/ShaderFX/AbstractToShaderFX.cs
index a84bcdb1..561d05fe 100644
--- a/src/Fuse/ShaderFX/AbstractToShaderFX.cs
+++ b/src/Fuse/ShaderFX/AbstractToShaderFX.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Text;
using JetBrains.Profiler.Api;
+using Stride.Core.Yaml.Tokens;
using Stride.Rendering.Materials;
using Stride.Rendering.Materials.ComputeColors;
using Stride.Shaders;
@@ -58,7 +59,7 @@ public abstract class AbstractToShaderFX : IComputeValue
private readonly HashSet_constantArrays = new();
private readonly HashSet_streams = new();
private readonly HashSet_mixins = new();
- private readonly HashSet_compositions = new();
+ private readonly HashSet_compositions = new();
private readonly Dictionary _functionMap = new();
private readonly string _sourceTemplate;
@@ -148,7 +149,7 @@ private Dictionary BuildTemplateMap()
_mixins.ForEach(mixin => mixinBuilder.Append(", " + mixin));
var compositionBuilder = new StringBuilder();
- _compositions.ForEach(composition => compositionBuilder.AppendLine(composition));
+ _compositions.ForEach(composition => compositionBuilder.AppendLine(composition.Declaration));
var functionBuilder = new StringBuilder();
_functionMap?.ForEach(kv => functionBuilder.AppendLine(kv.Value));
@@ -212,11 +213,11 @@ private void HandleShader(bool theIsComputeShader, AbstractShaderNode theShaderI
_stopwatch.Restart();
theShaderInput.MixinList().ForEach(value => _mixins.Add(value));
if(ShaderNodesUtil.TimeShaderGeneration)Console.WriteLine($" Mixins: {_stopwatch.ElapsedMilliseconds} ms");
- /*
+
_stopwatch.Restart();
theShaderInput.CompositionList().ForEach(value => _compositions.Add(value));
if(ShaderNodesUtil.TimeShaderGeneration)Console.WriteLine($" Compositions: {_stopwatch.ElapsedMilliseconds} ms");
- */
+
_stopwatch.Restart();
theShaderInput.FunctionMap().ForEach(HandleFunction);
if(ShaderNodesUtil.TimeShaderGeneration)Console.WriteLine($" Functions: {_stopwatch.ElapsedMilliseconds} ms");
@@ -291,18 +292,32 @@ public ShaderSource GenerateShaderSource(ShaderGeneratorContext theContext, Mate
}
if(ShaderNodesUtil.TimeShaderGeneration)Console.WriteLine($"-> Evaluate: {_stopwatch.ElapsedMilliseconds} ms");
- _stopwatch.Restart();
- ShaderNodesUtil.AddShaderSource( ShaderName, ShaderCode, "shaders\\" + ShaderName + ".sdsl");
- if(ShaderNodesUtil.TimeShaderGeneration)Console.WriteLine($"-> AddShaderSource: {_stopwatch.ElapsedMilliseconds} ms");
- // _parameters = theContext.Parameters;
-
- // _input.InputList().ForEach(input => input.AddParameters(_parameters));
- var result = new ShaderClassSource(ShaderName);
- _stopwatch.Stop();
+ var shaderSource = new ShaderMixinSource()
+ {
+ Name = ShaderName,
+ Mixins =
+ {
+ new ShaderClassString(ShaderName, ShaderCode)
+ }
+ };
+
+ foreach (var composition in _compositions)
+ {
+ var compositionSource = composition.ComputeNode.GenerateShaderSource(theContext, baseKeys);
+ shaderSource.AddComposition(composition.CompositionName, compositionSource);
+ }
+
+ // _parameters = theContext.Parameters;
+
+ // _input.InputList().ForEach(input => input.AddParameters(_parameters));
+ //var result = new ShaderClassSource(ShaderName);
+ _stopwatch.Stop();
if(ShaderNodesUtil.TimeShaderGeneration)Console.WriteLine($"-> Execution Time: {watch.ElapsedMilliseconds} ms for Shader {ShaderName}");
//MeasureProfiler.SaveData(ShaderName);
- return result;
+ //return result;
+
+ return shaderSource;
}
}
}
\ No newline at end of file
diff --git a/src/Fuse/ShaderFX/CompositionInput.cs b/src/Fuse/ShaderFX/CompositionInput.cs
index 4bcfbf9e..1ce63d54 100644
--- a/src/Fuse/ShaderFX/CompositionInput.cs
+++ b/src/Fuse/ShaderFX/CompositionInput.cs
@@ -1,47 +1,48 @@
using System.Collections.Generic;
-using NuGet;
using Stride.Rendering.Materials;
using VL.Core;
using VL.Stride.Shaders.ShaderFX;
namespace Fuse.ShaderFX
{
+ public interface IComposition
+ {
+ string Declaration { get; }
+ string CompositionName { get; }
+ IComputeNode ComputeNode { get; }
+ }
- public class CompositionInput : ShaderNode
+ public class CompositionInput : ShaderNode, IComposition
+ where T : unmanaged
{
- protected const string DeclarationTemplate = @"
- compose Compute${compositionType} ${compositionName};";
-
- public CompositionInput(NodeContext nodeContext, string theId, IComputeValue theComposition) : base(nodeContext, theId, null)
+ IComputeValue _value;
+
+ public CompositionInput(NodeContext nodeContext, SetVar value /* Should just be IComputeValue */)
+ : base(nodeContext, "compositionInput")
{
-
- AddProperty(Compositions, this);
+ _value = value?.Value ?? new VL.Stride.Shaders.ShaderFX.ComputeNode();
+
+ SetProperty(Compositions, this);
}
-
- protected override Dictionary CreateTemplateMap()
- {
- var result = new Dictionary
- {
- {"compositionType", TypeHelpers.GetSignature()},
- {"compositionName", ID}
- };
- foreach (var template in base.CreateTemplateMap())
+ public string Declaration => ShaderNodesUtil.Evaluate("compose ${compositionType} ${compositionId};",
+ new Dictionary()
{
- result.Add(template.Key, template.Value);
- }
+ { "compositionType", TypeHelpers.GetCompositionType() },
+ { "compositionId", CompositionName }
+ });
+
+ public IComputeNode ComputeNode => _value;
+
+ public string CompositionName => $"composition{ID}";
- return result;
- }
-
protected override string SourceTemplate()
{
- return "${resultType} ${resultName} = ${compositionName}.Compute();";
- }
-
- public override void OnPassContext(ShaderGeneratorContext theContext)
- {
- ShaderNodesUtil.Evaluate(DeclarationTemplate,CreateTemplateMap());
+ return ShaderNodesUtil.Evaluate("${resultType} ${resultName} = ${compositionId}.Compute();",
+ new Dictionary
+ {
+ {"compositionId", CompositionName},
+ });
}
}
}
\ No newline at end of file
diff --git a/src/Fuse/ShaderNode.cs b/src/Fuse/ShaderNode.cs
index 9ca6c612..d560dffa 100644
--- a/src/Fuse/ShaderNode.cs
+++ b/src/Fuse/ShaderNode.cs
@@ -605,9 +605,9 @@ public List InputList()
return PropertyForTree(Inputs);
}
- public List CompositionList()
+ public List CompositionList()
{
- return PropertyForTree(Compositions);
+ return PropertyForTree(Compositions);
}
public List DeclarationList()
diff --git a/src/Fuse/ShaderNodesUtil.cs b/src/Fuse/ShaderNodesUtil.cs
index 4d263501..f38cea46 100644
--- a/src/Fuse/ShaderNodesUtil.cs
+++ b/src/Fuse/ShaderNodesUtil.cs
@@ -10,12 +10,16 @@
using Fuse.ShaderFX;
using Stride.Core;
using Stride.Core.Mathematics;
+using Stride.Graphics;
using Stride.Rendering;
using Stride.Rendering.Materials;
+using Stride.Shaders;
using Stride.Shaders.Compiler;
using Stride.Shaders.Parser;
+using Stride.Shaders.Parser.Mixins;
using VL.Core;
using VL.Stride;
+using VL.Stride.Effects;
using VL.Stride.Rendering;
using VL.Stride.Rendering.ComputeEffect;
using VL.Stride.Shaders.ShaderFX;
@@ -223,19 +227,8 @@ public static void AddShaderSource(string type, string sourceCode, string source
var game = ServiceRegistry.Current.GetGameProvider().GetHandle().Resource;
if (game == null) return;
- var effectSystem = game.EffectSystem;
- var compiler = effectSystem.Compiler as EffectCompiler;
- if (compiler is null && effectSystem.Compiler is EffectCompilerCache effectCompilerCache)
- compiler = typeof(EffectCompilerChain)
- .GetProperty("Compiler", BindingFlags.Instance | BindingFlags.NonPublic)
- ?.GetValue(effectCompilerCache) as EffectCompiler;
-
- if (compiler == null) return;
-
- var getParserMethod =
- typeof(EffectCompiler).GetMethod("GetMixinParser", BindingFlags.Instance | BindingFlags.NonPublic);
- if (getParserMethod == null) return;
- if (!(getParserMethod.Invoke(compiler, null) is ShaderMixinParser parser)) return;
+ var parser = game.EffectSystem.Compiler.GetShaderMixinParser();
+ if (parser is null) return;
var sourceManager = parser.SourceManager;
sourceManager.AddShaderSource(type, sourceCode, sourcePath);
@@ -246,6 +239,49 @@ public static void AddShaderSource(string type, string sourceCode, string source
}
}
+ public static ShaderMixinParser GetShaderMixinParser(this IEffectCompiler compiler)
+ {
+ var effectCompiler = compiler as EffectCompiler;
+ if (effectCompiler is null && compiler is EffectCompilerCache effectCompilerCache)
+ effectCompiler = typeof(EffectCompilerChain)
+ .GetProperty("Compiler", BindingFlags.Instance | BindingFlags.NonPublic)
+ ?.GetValue(effectCompilerCache) as EffectCompiler;
+
+ if (effectCompiler is null)
+ return null;
+
+ var getParserMethod = typeof(EffectCompiler).GetMethod("GetMixinParser", BindingFlags.Instance | BindingFlags.NonPublic);
+ if (getParserMethod is null)
+ return null;
+
+ return (ShaderMixinParser)getParserMethod.Invoke(effectCompiler, null);
+ }
+
+ // Workaround for compiler cache: it assumes that all shaders are known to the source manager
+ public static void MakeInMemoryShadersAvailableToTheSourceManager(IEffectCompiler compiler, ShaderSource shaderSource)
+ {
+ var parser = compiler.GetShaderMixinParser();
+ if (parser is null)
+ return;
+
+ var sourceManager = parser.SourceManager;
+ if (sourceManager is null)
+ return;
+
+ Scan(sourceManager, shaderSource);
+
+ static void Scan(ShaderSourceManager sourceManager, ShaderSource shaderSource)
+ {
+ if (shaderSource is ShaderClassString shaderClassString)
+ sourceManager.AddShaderSource(shaderClassString.ClassName, shaderClassString.ShaderSourceCode, null);
+ else if (shaderSource is ShaderMixinSource shaderMixinSource)
+ {
+ foreach (var s in shaderMixinSource.Mixins)
+ Scan(sourceManager, s);
+ }
+ }
+ }
+
// ReSharper disable once UnusedMember.Global
// accessed from vl
public static VLComputeEffectShader RegisterComputeShader( ToComputeFx theComputeFx)
@@ -273,7 +309,7 @@ protected override void Destroy()
}
- public static DynamicEffectInstance RegisterDrawShader(ToDrawFX theDrawShader)
+ public static FuseEffectInstance RegisterDrawShader(ToDrawFX theDrawShader)
{
var watch = new Stopwatch();
@@ -281,16 +317,16 @@ public static DynamicEffectInstance RegisterDrawShader(ToDrawFX theDrawShader)
var game = ServiceRegistry.Current.GetGameProvider().GetHandle().Resource;
if (game == null) return null;
- var effectImageShader = new DynamicDrawEffectInstance("ShaderFXGraphEffect");
+ var parameters = new ParameterCollection();
+ var subscriptions = new CompositeDisposable();
var method = typeof(ShaderGraph).GetMethod("NewShaderGeneratorContext", BindingFlags.Static | BindingFlags.NonPublic);
- var context = method?.Invoke(null, new object[]{game.GraphicsDevice, effectImageShader.Parameters, effectImageShader.Subscriptions});
+ var context = (ShaderGeneratorContext)method?.Invoke(null, new object[]{game.GraphicsDevice, parameters, subscriptions});
//var context = ShaderGraph.NewShaderGeneratorContext(game.GraphicsDevice, effectImageShader.Parameters, effectImageShader.Subscriptions);
var key = new MaterialComputeColorKeys(MaterialKeys.DiffuseMap, MaterialKeys.DiffuseValue, Stride.Core.Mathematics.Color.White);
- theDrawShader.GenerateShaderSource((ShaderGeneratorContext) context,key);
- effectImageShader.EffectName = theDrawShader.ShaderName;
- Console.WriteLine($"Register Time: {watch.ElapsedMilliseconds} ms for Shader {theDrawShader.ShaderName}");
- return effectImageShader;
+ var shaderSource = theDrawShader.GenerateShaderSource(context,key);
+
+ return new FuseEffectInstance(shaderSource, parameters, subscriptions);
}
// ReSharper disable once UnusedMember.Global
diff --git a/vl/Fuse.Core.vl b/vl/Fuse.Core.vl
index 83ac5218..5ccba1ec 100644
--- a/vl/Fuse.Core.vl
+++ b/vl/Fuse.Core.vl
@@ -1,6 +1,6 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
11
@@ -87710,14 +87781,14 @@
-
-
+
+
-
+
-
+
@@ -87860,10 +87931,10 @@
-
-
-
+
+
+
@@ -88244,6 +88315,394 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -88255,7 +88714,6 @@
-
@@ -88345,6 +88803,7 @@
+