Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
Shader.cs
浏览该文件的文档.
1#if DIRECT3D11
2using System.Runtime.InteropServices;
3using SharpDX.D3DCompiler;
4using SharpDX.Direct3D11;
5#else
6using Silk.NET.OpenGLES;
7using System.Xml.Linq;
8#endif
9
10namespace Engine.Graphics {
11 public class Shader : GraphicsResource {
12 public Dictionary<string, ShaderParameter> m_parametersByName;
14 public string m_vertexShaderCode;
15 public string m_pixelShaderCode;
17#if DIRECT3D11
18 public VertexShader m_vertexShader;
19 public PixelShader m_pixelShader;
20 public SharpDX.Direct3D11.Buffer[] m_allConstantBuffers;
21 public int[] m_allConstantBuffersSizes;
22 public IntPtr[] m_allConstantBuffersCpu;
23 public SharpDX.Direct3D11.Buffer[] m_vertexShaderConstantBuffers;
24 public SharpDX.Direct3D11.Buffer[] m_pixelShaderConstantBuffers;
25 public byte[] m_pixelShaderBytecode;
26 public byte[] m_vertexShaderBytecode;
27 public Dictionary<VertexDeclaration, InputLayout> m_inputLayouts = new();
28 public VertexDeclaration m_lastVertexDeclaration;
29 public InputLayout m_lastInputLayout;
30#else
31 public struct ShaderAttributeData {
32 public string Semantic;
33
34 public int Location;
35 }
36
37 public struct VertexAttributeData {
38 public int Size;
39
40 public VertexAttribPointerType Type;
41
42 public bool Normalize;
43
44 public int Offset;
45 }
46
47 public int m_program;
48 public int m_vertexShader;
49 public int m_pixelShader;
50 public Dictionary<VertexDeclaration, VertexAttributeData[]> m_vertexAttributeDataByDeclaration = [];
51 public List<ShaderAttributeData> m_shaderAttributeData = [];
53#endif
54
55 public string DebugName {
56 get {
57#if DIRECT3D11
58 return m_vertexShader.DebugName;
59#else
60 return string.Empty;
61#endif
62 }
63 // ReSharper disable ValueParameterNotUsed
64 set
65 // ReSharper restore ValueParameterNotUsed
66 {
67#if DIRECT3D11
68 m_vertexShader.DebugName = value;
69 m_pixelShader.DebugName = value;
70#endif
71 }
72 }
73
74 public virtual ShaderParameter GetParameter(string name, bool allowNull = false) =>
75 m_parametersByName.TryGetValue(name, out ShaderParameter value) ? value :
76 allowNull ? new ShaderParameter("null", ShaderParameterType.Null) :
77 throw new InvalidOperationException($"Parameter \"{name}\" not found.");
78
79 public override int GetGpuMemoryUsage() => 16384;
80
81 public virtual void PrepareForDrawingOverride() { }
82
83 public virtual void InitializeShader(string vertexShaderCode, string pixelShaderCode, ShaderMacro[] shaderMacros) {
84 ArgumentNullException.ThrowIfNull(vertexShaderCode);
85 ArgumentNullException.ThrowIfNull(pixelShaderCode);
86 ArgumentNullException.ThrowIfNull(shaderMacros);
87 m_vertexShaderCode = vertexShaderCode;
88 m_pixelShaderCode = pixelShaderCode;
89 m_shaderMacros = (ShaderMacro[])shaderMacros.Clone();
90 }
91
92 public object Tag { get; set; }
93
94 public ReadOnlyList<ShaderParameter> Parameters => new(m_parameters);
95
96 public virtual void Construct(string vertexShaderCode, string pixelShaderCode, params ShaderMacro[] shaderMacros) {
97 try {
98 InitializeShader(vertexShaderCode, pixelShaderCode, shaderMacros);
100 }
101 catch {
102 Dispose();
103 throw;
104 }
105 }
106
107 public Shader(string vertexShaderCode, string pixelShaderCode, params ShaderMacro[] shaderMacros) {
108 Construct(vertexShaderCode, pixelShaderCode, shaderMacros);
109 }
110
111 public override void Dispose() {
112 base.Dispose();
114 }
115
116 public virtual void PrepareForDrawing() {
117#if !DIRECT3D11
118 m_glymulParameter.SetValue(Display.RenderTarget != null ? -1f : 1f);
119#endif
121 }
122
123#if !DIRECT3D11
124 public virtual VertexAttributeData[] GetVertexAttribData(VertexDeclaration vertexDeclaration) {
125 if (!m_vertexAttributeDataByDeclaration.TryGetValue(vertexDeclaration, out VertexAttributeData[] value)) {
126 value = new VertexAttributeData[8];
127 foreach (ShaderAttributeData shaderAttributeDatum in m_shaderAttributeData) {
128 VertexElement vertexElement = null;
129 for (int i = 0; i < vertexDeclaration.m_elements.Length; i++) {
130 if (vertexDeclaration.m_elements[i].Semantic == shaderAttributeDatum.Semantic) {
131 vertexElement = vertexDeclaration.m_elements[i];
132 break;
133 }
134 }
135 if (!(vertexElement != null)) {
136 throw new InvalidOperationException($"VertexElement not found for shader attribute \"{shaderAttributeDatum.Semantic}\".");
137 }
138 value[shaderAttributeDatum.Location] = new VertexAttributeData {
139 Size = vertexElement.Format.GetElementsCount(), Offset = vertexElement.Offset
140 };
142 vertexElement.Format,
143 out value[shaderAttributeDatum.Location].Type,
144 out value[shaderAttributeDatum.Location].Normalize
145 );
146 }
147 m_vertexAttributeDataByDeclaration.Add(vertexDeclaration, value);
148 }
149 return value;
150 }
151
152 public static void ParseShaderMetadata(string shaderCode,
153 Dictionary<string, string> semanticsByAttribute,
154 Dictionary<string, string> samplersByTexture) {
155 string[] array = shaderCode.Split('\n');
156 for (int i = 0; i < array.Length; i++) {
157 try {
158 string text = array[i];
159 text = text.Trim();
160 if (text.StartsWith("//")) {
161 text = text.Substring(2).TrimStart();
162 if (text.StartsWith('<')
163 && text.EndsWith("/>")) {
164 XElement xElement = XElement.Parse(text);
165 if (xElement.Name == "Semantic") {
166 XAttribute attribute = xElement.Attribute("Attribute");
167 if (attribute == null) {
168 throw new InvalidOperationException("Missing \"Attribute\" attribute in shader metadata.");
169 }
170 XAttribute name = xElement.Attribute("Name");
171 if (name == null) {
172 throw new InvalidOperationException("Missing \"Name\" attribute in shader metadata.");
173 }
174 semanticsByAttribute.Add(attribute.Value, name.Value);
175 }
176 else {
177 if (!(xElement.Name == "Sampler")) {
178 throw new InvalidOperationException("Unrecognized shader metadata node.");
179 }
180 XAttribute texture = xElement.Attribute("Texture");
181 if (texture == null) {
182 throw new InvalidOperationException("Missing \"Texture\" attribute in shader metadata.");
183 }
184 XAttribute name = xElement.Attribute("Name");
185 if (name == null) {
186 throw new InvalidOperationException("Missing \"Name\" attribute in shader metadata.");
187 }
188 samplersByTexture.Add(texture.Value, name.Value);
189 }
190 }
191 }
192 }
193 catch (Exception ex) {
194 throw new InvalidOperationException($"Error in shader metadata, line {i + 1}. {ex.Message}");
195 }
196 }
197 }
198
199 public virtual string PrependShaderMacros(string shaderCode, ShaderMacro[] shaderMacros, bool isVertexShader) {
200 string str = "";
201 if (shaderCode.StartsWith("#version ")) {
202 string versioncode = shaderCode.Split(new[] { '\n' })[0];
203 string versionnum = versioncode.Split(new[] { ' ' })[1];
204 if (int.Parse(versionnum) >= 300
205 || versioncode.EndsWith("es")) {
206 str += $"#version {versionnum} es{Environment.NewLine}";
207 }
208 else {
209 str += $"#version {versionnum}{Environment.NewLine}";
210 }
211 shaderCode = $"//{shaderCode}";
212 }
213 else {
214 //[WARN] 未指定版本时,会主动加上最低的版本号
215 str += $"#version 100{Environment.NewLine}";
216 }
217 str = $"{str}#define GLSL{Environment.NewLine}";
218 if (isVertexShader) {
219 str = !Display.UseReducedZRange
220 ? $"{str}#define OPENGL_POSITION_FIX gl_Position.y *= u_glymul; gl_Position.z = 2.0 * gl_Position.z - gl_Position.w;{Environment.NewLine}"
221 : $"{str}#define OPENGL_POSITION_FIX gl_Position.y *= u_glymul;{Environment.NewLine}";
222 str = $"{str}uniform float u_glymul;{Environment.NewLine}";
223 }
224 foreach (ShaderMacro shaderMacro in shaderMacros) {
225 str = $"{str}#define {shaderMacro.Name} {shaderMacro.Value}{Environment.NewLine}";
226 }
227 str = $"{str}#line 1{Environment.NewLine}";
228 return str + shaderCode;
229 }
230#endif
231
232 public override void HandleDeviceLost() {
234 }
235
236 public override void HandleDeviceReset() {
238 }
239
240 public virtual void CompileShaders() {
241#if DIRECT3D11
242 m_parametersByName = new Dictionary<string, ShaderParameter>();
243 List<SharpDX.Direct3D11.Buffer> list = new();
244 List<int> list2 = new();
245 List<IntPtr> list3 = new();
246 List<SharpDX.Direct3D11.Buffer> list4 = new();
247 List<SharpDX.Direct3D11.Buffer> list5 = new();
248 m_vertexShaderBytecode = CompileShader(m_vertexShaderCode, true, list, list2, list3, list4);
249 m_pixelShaderBytecode = CompileShader(m_pixelShaderCode, false, list, list2, list3, list5);
250 if (m_parameters == null) {
251 m_parameters = m_parametersByName.Values.ToArray();
252 }
253 else {
254 ShaderParameter[] parameters = m_parameters;
255 foreach (ShaderParameter t in parameters) {
256 t.IsChanged = true;
257 }
258 }
259 m_vertexShaderConstantBuffers = list4.ToArray();
260 m_pixelShaderConstantBuffers = list5.ToArray();
261 m_allConstantBuffers = list.ToArray();
262 m_allConstantBuffersSizes = list2.ToArray();
263 m_allConstantBuffersCpu = list3.ToArray();
264 m_vertexShader = new VertexShader(DXWrapper.Device, m_vertexShaderBytecode);
265 m_pixelShader = new PixelShader(DXWrapper.Device, m_pixelShaderBytecode);
266#else
268 Dictionary<string, string> dictionary = [];
269 Dictionary<string, string> dictionary2 = [];
270 ParseShaderMetadata(m_vertexShaderCode, dictionary, dictionary2);
271 ParseShaderMetadata(m_pixelShaderCode, dictionary, dictionary2);
273 string string2 = PrependShaderMacros(m_pixelShaderCode, m_shaderMacros, false);
274 uint vertexShader = GLWrapper.GL.CreateShader(ShaderType.VertexShader);
275 m_vertexShader = (int)vertexShader;
276 GLWrapper.GL.ShaderSource(vertexShader, @string);
277 GLWrapper.GL.CompileShader(vertexShader);
278 GLWrapper.GL.GetShader(vertexShader, ShaderParameterName.CompileStatus, out int @params);
279 if (@params != 1) {
280 string shaderInfoLog = GLWrapper.GL.GetShaderInfoLog(vertexShader);
281 throw new InvalidOperationException($"Error compiling vertex shader.\n{shaderInfoLog}");
282 }
283 uint pixelShader = GLWrapper.GL.CreateShader(ShaderType.FragmentShader);
284 m_pixelShader = (int)pixelShader;
285 GLWrapper.GL.ShaderSource(pixelShader, string2);
286 GLWrapper.GL.CompileShader(pixelShader);
287 GLWrapper.GL.GetShader(pixelShader, ShaderParameterName.CompileStatus, out int params2);
288 if (params2 != 1) {
289 string shaderInfoLog2 = GLWrapper.GL.GetShaderInfoLog(pixelShader);
290 throw new InvalidOperationException($"Error compiling pixel shader.\n{shaderInfoLog2}");
291 }
292 uint program = GLWrapper.GL.CreateProgram();
293 m_program = (int)program;
294 GLWrapper.GL.AttachShader(program, vertexShader);
295 GLWrapper.GL.AttachShader(program, pixelShader);
296 GLWrapper.GL.LinkProgram(program);
297 GLWrapper.GL.GetProgram(program, ProgramPropertyARB.LinkStatus, out int params3);
298 if (params3 != 1) {
299 string programInfoLog = GLWrapper.GL.GetProgramInfoLog(program);
300 throw new InvalidOperationException($"Error linking program.\n{programInfoLog}");
301 }
302 GLWrapper.GL.GetProgram(program, ProgramPropertyARB.ActiveAttributes, out int params4);
303 for (int i = 0; i < params4; i++) {
304 GLWrapper.GL.GetActiveAttrib(
305 program,
306 (uint)i,
307 256u,
308 out uint _,
309 out int _,
310 out AttributeType _,
311 out string stringBuilder
312 );
313 int attribLocation = GLWrapper.GL.GetAttribLocation(program, stringBuilder);
314 if (!dictionary.TryGetValue(stringBuilder, out string value)) {
315 throw new InvalidOperationException($"Attribute \"{stringBuilder}\" has no semantic defined in shader metadata.");
316 }
317 m_shaderAttributeData.Add(new ShaderAttributeData { Location = attribLocation, Semantic = value });
318 }
319 GLWrapper.GL.GetProgram(program, ProgramPropertyARB.ActiveUniforms, out int params5);
320 List<ShaderParameter> list = [];
321 Dictionary<string, ShaderParameter> dictionary3 = [];
322 for (int j = 0; j < params5; j++) {
323 GLWrapper.GL.GetActiveUniform(
324 program,
325 (uint)j,
326 256u,
327 out uint _,
328 out int size2,
329 out UniformType type2,
330 out string stringBuilder2
331 );
332 int uniformLocation = GLWrapper.GL.GetUniformLocation(program, stringBuilder2);
333 ShaderParameterType shaderParameterType = GLWrapper.TranslateActiveUniformType(type2);
334 int num = stringBuilder2.IndexOf('[');
335 if (num >= 0) {
336 stringBuilder2 = stringBuilder2.Remove(num, stringBuilder2.Length - num);
337 }
338 ShaderParameter shaderParameter = new(this, stringBuilder2, shaderParameterType, size2) { Location = uniformLocation };
339 dictionary3.Add(shaderParameter.Name, shaderParameter);
340 list.Add(shaderParameter);
341 if (shaderParameterType == ShaderParameterType.Texture2D) {
342 if (!dictionary2.TryGetValue(shaderParameter.Name, out string value2)) {
343 throw new InvalidOperationException($"Texture \"{shaderParameter.Name}\" has no sampler defined in shader metadata.");
344 }
345 ShaderParameter shaderParameter2 = new(this, value2, ShaderParameterType.Sampler2D, 1) { Location = int.MaxValue };
346 dictionary3.Add(value2, shaderParameter2);
347 list.Add(shaderParameter2);
348 }
349 }
350 if (m_parameters != null) {
351 foreach (KeyValuePair<string, ShaderParameter> item in dictionary3) {
352 if (m_parametersByName.TryGetValue(item.Key, out ShaderParameter value3)) {
353 value3.Location = item.Value.Location;
354 }
355 }
356 ShaderParameter[] parameters = m_parameters;
357 for (int k = 0; k < parameters.Length; k++) {
358 parameters[k].IsChanged = true;
359 }
360 }
361 else {
362 m_parameters = list.ToArray();
363 m_parametersByName = dictionary3;
364 }
365 m_glymulParameter = GetParameter("u_glymul");
366 if (m_glymulParameter.Type != 0) {
367 throw new InvalidOperationException("u_glymul parameter has invalid type.");
368 }
369#endif
370 }
371
372#if DIRECT3D11
373 public virtual byte[] CompileShader(string code,
374 bool isVertexShader,
375 List<SharpDX.Direct3D11.Buffer> allConstantBuffers,
376 List<int> allConstantBuffersSizes,
377 List<IntPtr> allConstantBuffersCpu,
378 List<SharpDX.Direct3D11.Buffer> shaderConstantBuffers) {
379 string text = isVertexShader ? "vs_4_0_level_9_1" : "ps_4_0_level_9_1";
380 List<SharpDX.Direct3D.ShaderMacro> list = new();
381 list.Add(new SharpDX.Direct3D.ShaderMacro("HLSL", string.Empty));
382 list.AddRange(m_shaderMacros.Select(s => new SharpDX.Direct3D.ShaderMacro(s.Name, s.Value)));
383 ShaderFlags shaderFlags = ShaderFlags.OptimizationLevel1;
384 byte[] array;
385 using (CompilationResult compilationResult = ShaderBytecode.Compile(
386 code,
387 "main",
388 text,
389 shaderFlags,
390 EffectFlags.None,
391 list.ToArray(),
392 null,
393 string.Empty
394 )) {
395 if (compilationResult.HasErrors) {
396 throw new InvalidOperationException(compilationResult.Message);
397 }
398 if (!string.IsNullOrWhiteSpace(compilationResult.Message)) {
399 Log.Warning(compilationResult.Message);
400 }
401 array = compilationResult.Bytecode;
402 }
403 using (ShaderReflection shaderReflection = new(array)) {
404 for (int i = 0; i < shaderReflection.Description.ConstantBuffers; i++) {
405 int count = allConstantBuffers.Count;
406 ConstantBuffer constantBuffer = shaderReflection.GetConstantBuffer(i);
407 SharpDX.Direct3D11.Buffer buffer = new(
408 DXWrapper.Device,
409 constantBuffer.Description.Size,
410 ResourceUsage.Dynamic,
411 BindFlags.ConstantBuffer,
412 CpuAccessFlags.Write,
413 ResourceOptionFlags.None,
414 0
415 );
416 allConstantBuffers.Add(buffer);
417 allConstantBuffersSizes.Add(buffer.Description.SizeInBytes);
418 shaderConstantBuffers.Add(buffer);
419 allConstantBuffersCpu.Add(Marshal.AllocHGlobal(constantBuffer.Description.Size));
420 for (int j = 0; j < constantBuffer.Description.VariableCount; j++) {
421 ShaderReflectionVariable variable = constantBuffer.GetVariable(j);
422 ShaderReflectionType variableType = variable.GetVariableType();
423 ShaderParameterType shaderParameterType = DXWrapper.TranslateShaderTypeDescription(variableType.Description);
424 if (!m_parametersByName.TryGetValue(variable.Description.Name, out ShaderParameter shaderParameter)) {
425 shaderParameter = new ShaderParameter(
426 this,
427 variable.Description.Name,
428 shaderParameterType,
429 MathUtils.Max(variableType.Description.ElementCount, 1)
430 );
431 m_parametersByName.Add(shaderParameter.Name, shaderParameter);
432 }
433 if (isVertexShader) {
434 shaderParameter.VsBufferIndex = count;
435 shaderParameter.VsBufferPtr = allConstantBuffersCpu[count] + variable.Description.StartOffset;
436 }
437 else {
438 shaderParameter.PsBufferIndex = count;
439 shaderParameter.PsBufferPtr = allConstantBuffersCpu[count] + variable.Description.StartOffset;
440 }
441 }
442 }
443 for (int k = 0; k < shaderReflection.Description.BoundResources; k++) {
444 InputBindingDescription resourceBindingDescription = shaderReflection.GetResourceBindingDescription(k);
445 if (resourceBindingDescription.Type != ShaderInputType.ConstantBuffer) {
446 ShaderParameterType shaderParameterType2 = DXWrapper.TranslateInputBindingDescription(resourceBindingDescription);
447 if (!m_parametersByName.TryGetValue(resourceBindingDescription.Name, out ShaderParameter shaderParameter2)) {
448 shaderParameter2 = new ShaderParameter(this, resourceBindingDescription.Name, shaderParameterType2, 1);
449 m_parametersByName.Add(shaderParameter2.Name, shaderParameter2);
450 }
451 if (isVertexShader) {
452 shaderParameter2.VsResourceBindingSlot = resourceBindingDescription.BindPoint;
453 }
454 else {
455 shaderParameter2.PsResourceBindingSlot = resourceBindingDescription.BindPoint;
456 }
457 }
458 }
459 }
460 return array;
461 }
462#endif
463
464 public virtual void DeleteShaders() {
465#if DIRECT3D11
466 Utilities.Dispose(ref m_vertexShader);
467 Utilities.Dispose(ref m_pixelShader);
468 if (m_allConstantBuffers != null) {
469 Utilities.DisposeCollection(m_allConstantBuffers);
470 m_allConstantBuffers = null;
471 }
472 if (m_inputLayouts != null) {
473 Utilities.DisposeCollection(m_inputLayouts.Values);
474 m_inputLayouts = null;
475 }
476 if (m_allConstantBuffersCpu != null) {
477 IntPtr[] allConstantBuffersCpu = m_allConstantBuffersCpu;
478 foreach (IntPtr t in allConstantBuffersCpu) {
479 Marshal.FreeHGlobal(t);
480 }
481 m_allConstantBuffersCpu = null;
482 }
483#else
484 uint vertexShader = (uint)m_vertexShader;
485 uint pixelShader = (uint)m_pixelShader;
486 if (m_program != 0) {
487 uint program = (uint)m_program;
488 if (m_vertexShader != 0) {
489 GLWrapper.GL.DetachShader(program, vertexShader);
490 }
491 if (m_pixelShader != 0) {
492 GLWrapper.GL.DetachShader(program, pixelShader);
493 }
495 m_program = 0;
496 }
497 if (m_vertexShader != 0) {
498 GLWrapper.GL.DeleteShader(vertexShader);
499 m_vertexShader = 0;
500 }
501 if (m_pixelShader != 0) {
502 GLWrapper.GL.DeleteShader(pixelShader);
503 m_pixelShader = 0;
504 }
505#endif
506 }
507 }
508}
static RenderTarget2D RenderTarget
static void TranslateVertexElementFormat(VertexElementFormat vertexElementFormat, out VertexAttribPointerType type, out bool normalize)
static void DeleteProgram(int program)
static ShaderParameterType TranslateActiveUniformType(UniformType type)
override void HandleDeviceReset()
override int GetGpuMemoryUsage()
virtual VertexAttributeData[] GetVertexAttribData(VertexDeclaration vertexDeclaration)
static void ParseShaderMetadata(string shaderCode, Dictionary< string, string > semanticsByAttribute, Dictionary< string, string > samplersByTexture)
virtual string PrependShaderMacros(string shaderCode, ShaderMacro[] shaderMacros, bool isVertexShader)
override void HandleDeviceLost()
ReadOnlyList< ShaderParameter > Parameters
List< ShaderAttributeData > m_shaderAttributeData
virtual void DeleteShaders()
virtual ShaderParameter GetParameter(string name, bool allowNull=false)
virtual void InitializeShader(string vertexShaderCode, string pixelShaderCode, ShaderMacro[] shaderMacros)
ShaderParameter[] m_parameters
Shader(string vertexShaderCode, string pixelShaderCode, params ShaderMacro[] shaderMacros)
virtual void CompileShaders()
virtual void Construct(string vertexShaderCode, string pixelShaderCode, params ShaderMacro[] shaderMacros)
virtual void PrepareForDrawing()
ShaderParameter m_glymulParameter
Dictionary< VertexDeclaration, VertexAttributeData[]> m_vertexAttributeDataByDeclaration
Dictionary< string, ShaderParameter > m_parametersByName
virtual void PrepareForDrawingOverride()
ShaderMacro[] m_shaderMacros
override void Dispose()
static void Warning(object message)
定义 Log.cs:68