157 lines
4.8 KiB
C#
157 lines
4.8 KiB
C#
using System.Text;
|
|
using Dashboard.Drawing;
|
|
using OpenTK.Graphics.OpenGL;
|
|
|
|
namespace Dashboard.OpenGL.Drawing
|
|
{
|
|
public static class KhronosShaderHelper
|
|
{
|
|
public static int CompileStage(ShaderType type, string source, out string? log)
|
|
{
|
|
log = null;
|
|
int shader = GL.CreateShader(type);
|
|
|
|
GL.ShaderSource(shader, source);
|
|
GL.CompileShader(shader);
|
|
|
|
GL.GetShaderi(shader, ShaderParameterName.CompileStatus, out int flag);
|
|
|
|
if (flag != 0)
|
|
return shader;
|
|
|
|
GL.GetShaderInfoLog(shader, out log);
|
|
GL.DeleteShader(shader);
|
|
return 0;
|
|
}
|
|
|
|
public static int LinkStages(ReadOnlySpan<int> stages, out string? log)
|
|
{
|
|
log = null;
|
|
int program = GL.CreateProgram();
|
|
|
|
foreach (int stage in stages)
|
|
{
|
|
GL.AttachShader(program, stage);
|
|
}
|
|
|
|
GL.LinkProgram(program);
|
|
GL.GetProgrami(program, ProgramProperty.LinkStatus, out int flag);
|
|
|
|
if (flag == 0)
|
|
return program;
|
|
|
|
GL.GetProgramInfoLog(program, out log);
|
|
GL.DeleteProgram(program);
|
|
return 0;
|
|
}
|
|
|
|
public static int CreateProgram(this GlslShaderCreateInfo glsl)
|
|
{
|
|
Span<int> stages = stackalloc int[5];
|
|
int failed = 0;
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
int count = 0;
|
|
|
|
Compile(ShaderType.VertexShader, glsl.VertexShader, "Vertex", stages);
|
|
Compile(ShaderType.FragmentShader, glsl.FragmentShader, "Fragment", stages);
|
|
Compile(ShaderType.GeometryShader, glsl.GeometryShader, "Geometry", stages);
|
|
Compile(ShaderType.TessControlShader, glsl.TesselationControl, "Tesselation Control", stages);
|
|
Compile(ShaderType.TessEvaluationShader, glsl.TesselationEvaluation, "Tesselation Evaluation", stages);
|
|
|
|
if (failed > 0)
|
|
{
|
|
throw new Exception($"{failed} shader stage(s) failed to compile. See the exception data for details.")
|
|
{
|
|
Data =
|
|
{
|
|
["Log"] = builder.ToString(),
|
|
},
|
|
};
|
|
}
|
|
|
|
int program = KhronosShaderHelper.LinkStages(stages[..count], out string? log);
|
|
if (program == 0)
|
|
{
|
|
throw new Exception($"Shader program failed to link. See the exception data for details.")
|
|
{
|
|
Data =
|
|
{
|
|
["Log"] = log,
|
|
},
|
|
};
|
|
}
|
|
|
|
return program;
|
|
|
|
void Compile(ShaderType type, string? source, string name, Span<int> stages)
|
|
{
|
|
if (source == null)
|
|
return;
|
|
|
|
int stage = CompileStage(type, source, out string? log);
|
|
if (stage == 0)
|
|
{
|
|
failed++;
|
|
builder.Append($"=== {name} Shader Compile Log Begin ===\n{log}\n=== {name} Shader Compile Log End ===\n\n");
|
|
}
|
|
else
|
|
{
|
|
stages[count++] = stage;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static int CreateProgram(this GlslComputeShaderCreateInfo glsl)
|
|
{
|
|
int compute = CompileStage(ShaderType.ComputeShader, glsl.Source, out string? log);
|
|
if (compute == 0)
|
|
{
|
|
throw new Exception("Failed to compile compute shader. See the exception data for details.")
|
|
{
|
|
Data =
|
|
{
|
|
["Log"] = log,
|
|
},
|
|
};
|
|
}
|
|
|
|
int program = KhronosShaderHelper.LinkStages([compute], out log);
|
|
|
|
if (program != 0)
|
|
return program;
|
|
|
|
throw new Exception("Failed to link compute shader. See the exception data for details.")
|
|
{
|
|
Data =
|
|
{
|
|
["Log"] = log,
|
|
},
|
|
};
|
|
}
|
|
|
|
public static int CreateProgram(this SpirvShaderCreateInfo spirv)
|
|
{
|
|
int program = GL.CreateProgram();
|
|
GL.ProgramBinary(program, (All)spirv.Format, spirv.Binary, spirv.Binary.Length);
|
|
|
|
GL.GetProgrami(program, ProgramProperty.LinkStatus, out int flag);
|
|
if (flag == 0)
|
|
return program;
|
|
|
|
GL.GetProgramInfoLog(program, out string? log);
|
|
GL.DeleteProgram(program);
|
|
|
|
throw new Exception("Failed to load program binary. See the exception data for details.")
|
|
{
|
|
Data =
|
|
{
|
|
["Log"] = log,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
}
|