-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathHotReloadShaderExample.cs
More file actions
155 lines (133 loc) · 4.36 KB
/
Copy pathHotReloadShaderExample.cs
File metadata and controls
155 lines (133 loc) · 4.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using System;
using System.IO;
using System.Numerics;
using MoonWorks;
using MoonWorks.Graphics;
using MoonWorks.Input;
namespace MoonWorksGraphicsTests;
record struct Uniforms(Vector2 Resolution, float Time);
class HotReloadShaderExample : Example
{
GraphicsPipeline Pipeline;
Shader VertexShader;
Shader FragmentShader;
float Time;
FileSystemWatcher Watcher;
bool NeedReload;
public override void Init()
{
Window.SetTitle("HotReloadShader");
VertexShader = ShaderCross.Create(
GraphicsDevice,
RootTitleStorage,
TestUtils.GetHLSLPath("Fullscreen.vert"),
"main",
ShaderCross.ShaderFormat.HLSL,
ShaderStage.Vertex
);
LoadPipeline();
Logger.LogInfo("Edit HotReload.frag.hlsl in the Content directory to reload the shader!");
Watcher = new FileSystemWatcher(Path.Combine(SDL3.SDL.SDL_GetBasePath(), "Content", "Shaders", "HLSL"));
Watcher.Filter = "HotReload.frag.hlsl";
Watcher.NotifyFilter = NotifyFilters.LastWrite;
Watcher.EnableRaisingEvents = true;
Watcher.Changed += OnChanged;
}
public override void Update(TimeSpan delta)
{
Time += (float) delta.TotalSeconds;
if (NeedReload)
{
Logger.LogInfo("File change detected, reloading pipeline...");
LoadPipeline();
Logger.LogInfo("Done!");
NeedReload = false;
}
}
public override void Draw(double alpha)
{
CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer();
Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window);
if (swapchainTexture != null)
{
var renderPass = cmdbuf.BeginRenderPass(
new ColorTargetInfo(swapchainTexture, LoadOp.DontCare)
);
renderPass.BindGraphicsPipeline(Pipeline);
cmdbuf.PushFragmentUniformData(
new Uniforms(
new Vector2(swapchainTexture.Width, swapchainTexture.Height),
Time
)
);
renderPass.DrawPrimitives(3, 1, 0, 0);
cmdbuf.EndRenderPass(renderPass);
}
GraphicsDevice.Submit(cmdbuf);
}
public override void Destroy()
{
Pipeline.Dispose();
VertexShader.Dispose();
FragmentShader.Dispose();
}
private void LoadPipeline()
{
var fragmentShader = ShaderCross.Create(
GraphicsDevice,
RootTitleStorage,
TestUtils.GetHLSLPath("HotReload.frag"),
"main",
ShaderCross.ShaderFormat.HLSL,
ShaderStage.Fragment
);
if (fragmentShader == null)
{
Logger.LogError("Failed to compile fragment shader!");
Logger.LogError(SDL3.SDL.SDL_GetError());
return;
}
var pipeline = GraphicsPipeline.Create(
GraphicsDevice,
new GraphicsPipelineCreateInfo
{
TargetInfo = new GraphicsPipelineTargetInfo
{
ColorTargetDescriptions =
[
new ColorTargetDescription
{
Format = Window.SwapchainFormat,
BlendState = ColorTargetBlendState.NoBlend
}
]
},
DepthStencilState = DepthStencilState.Disable,
VertexShader = VertexShader,
FragmentShader = fragmentShader,
VertexInputState = VertexInputState.Empty,
RasterizerState = RasterizerState.CCW_CullNone,
PrimitiveType = PrimitiveType.TriangleList,
MultisampleState = MultisampleState.None
}
);
if (pipeline == null)
{
Logger.LogError("Failed to compile pipeline!");
Logger.LogError(SDL3.SDL.SDL_GetError());
return;
}
Pipeline?.Dispose();
FragmentShader?.Dispose();
FragmentShader = fragmentShader;
Pipeline = pipeline;
}
private void OnChanged(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
NeedReload = true;
}
}