From 334db5c002b716e914eb78a9c231bd039def432f Mon Sep 17 00:00:00 2001 From: MikiraSora Date: Wed, 30 Oct 2024 04:18:51 +0800 Subject: [PATCH] we needn't switch shader program always --- .../Kernel/Graphics/Base/Shader.cs | 417 +++++++++--------- .../Drawing/Editors/DrawPlayableAreaHelper.cs | 1 + 2 files changed, 217 insertions(+), 201 deletions(-) diff --git a/OngekiFumenEditor/Kernel/Graphics/Base/Shader.cs b/OngekiFumenEditor/Kernel/Graphics/Base/Shader.cs index 4546129c..01b917b9 100644 --- a/OngekiFumenEditor/Kernel/Graphics/Base/Shader.cs +++ b/OngekiFumenEditor/Kernel/Graphics/Base/Shader.cs @@ -7,217 +7,232 @@ namespace OngekiFumenEditor.Kernel.Graphics.Base { - public class Shader : IDisposable - { - private int vertexShader, fragmentShader, program = -1; + public class Shader : IDisposable + { + private int vertexShader, fragmentShader, program = -1; - private bool compiled = false; + private bool compiled = false; - private string vert; + private string vert; - private string frag; + private string frag; - public string VertexProgram { get { return vert; } set { vert = value; } } + public string VertexProgram { get { return vert; } set { vert = value; } } - public string FragmentProgram { get { return frag; } set { frag = value; } } + public string FragmentProgram { get { return frag; } set { frag = value; } } + public string GeometryProgram { get { return geo; } set { geo = value; } } - public string GeometryProgram { get { return geo; } set { geo = value; } } + private Dictionary _uniforms; - private Dictionary _uniforms; + public Dictionary Uniforms { get { return _uniforms; } internal set { _uniforms = value; } } - public Dictionary Uniforms { get { return _uniforms; } internal set { _uniforms = value; } } + private string vertError; + private string fragError; + private string geoError; + public string Error => GenErrorString(); - private string vertError; - private string fragError; - private string geoError; - public string Error => GenErrorString(); + private static int currentUsingProgram = int.MinValue; - private string GenErrorString() - { - string gen(string name, string msg) - { - if (string.IsNullOrWhiteSpace(msg)) - return string.Empty; + private string GenErrorString() + { + string gen(string name, string msg) + { + if (string.IsNullOrWhiteSpace(msg)) + return string.Empty; - return $"{msg} has compile error(s):{msg}\n"; - } - - return gen(nameof(VertexProgram), vertError) + gen(nameof(FragmentProgram), fragError) + gen(nameof(GeometryProgram), geoError); - } - - public void Compile() - { - if (compiled == false) - { - Dispose(); - - Uniforms = new Dictionary(); - - var genShaders = new List(); - - void compileShader(string source, ShaderType shaderType, ref int shader, ref string msg) - { - shader = GL.CreateShader(shaderType); - GL.ShaderSource(shader, source); - - GL.CompileShader(shader); - if (!GL.IsShader(shader)) - throw new Exception($"{shaderType} compile failed."); - msg = GL.GetShaderInfoLog(shader); - if (!string.IsNullOrEmpty(msg)) - Log.LogDebug($"[{shaderType}]:{msg}"); - - genShaders.Add(shader); - } - - compileShader(VertexProgram, ShaderType.VertexShader, ref vertexShader, ref vertError); - compileShader(FragmentProgram, ShaderType.FragmentShader, ref fragmentShader, ref fragError); - if (!string.IsNullOrWhiteSpace(GeometryProgram)) - compileShader(GeometryProgram, ShaderType.GeometryShader, ref geometryShader, ref geoError); - - program = GL.CreateProgram(); - - foreach (var shader in genShaders) - GL.AttachShader(program, shader); - - GL.LinkProgram(program); - - var buildShaderError = GL.GetProgramInfoLog(program); - if (!string.IsNullOrEmpty(buildShaderError)) - Log.LogError(buildShaderError); - - GL.GetProgram(program, GetProgramParameterName.ActiveUniforms, out var total); - - for (int i = 0; i < total; i++) - GL.GetActiveUniform(program, i, 16, out _, out _, out _, out var _); - - compiled = true; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Begin() - { - GL.UseProgram(program); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void End() - { - GL.UseProgram(0); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(string name, Texture tex) - { - if (tex == null) - { - PassNullTexUniform(name); - return; - } - - GL.BindTexture(TextureTarget.Texture2D, tex.ID); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassNullTexUniform(string name) - { - GL.BindTexture(TextureTarget.Texture2D, 0); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(int l, float v) => GL.Uniform1(l, v); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(string name, float val) - { - int l = GetUniformLocation(name); - PassUniform(l, val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(int l, int v) => GL.Uniform1(l, v); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(string name, int val) - { - int l = GetUniformLocation(name); - PassUniform(l, val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(int l, Vector2 v) => GL.Uniform2(l, v); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(string name, Vector2 val) - { - int l = GetUniformLocation(name); - PassUniform(l, val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(int l, Vector4 v) => GL.Uniform4(l, v); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(string name, Vector4 val) - { - int l = GetUniformLocation(name); - PassUniform(l, val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(int l, System.Numerics.Vector2 v) => PassUniform(l, new Vector2(v.X, v.Y)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(string name, System.Numerics.Vector2 val) - { - int l = GetUniformLocation(name); - PassUniform(l, val); - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(int l, Matrix4 v) => GL.UniformMatrix4(l, false, ref v); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PassUniform(string name, Matrix4 matrix4) - { - int l = GetUniformLocation(name); - PassUniform(l, matrix4); - } - - private Dictionary _uniformDictionary = new Dictionary(); - private Dictionary _attrbDictionary = new Dictionary(); - private string geo; - private int geometryShader; - - public int GetUniformLocation(string name) - { - if (!_uniformDictionary.TryGetValue(name, out var l)) - { - l = GL.GetUniformLocation(program, name); - _uniformDictionary[name] = l; - } - - return l; - } - - public int GetAttribLocation(string name) - { - if (!_attrbDictionary.TryGetValue(name, out var l)) - { - l = GL.GetAttribLocation(program, name); - _attrbDictionary[name] = l; - } - - return l; - } - - public void Dispose() - { - if (program < 0) - return; - GL.DeleteShader(vertexShader); - GL.DeleteShader(fragmentShader); - GL.DeleteProgram(program); - program = -1; - } - - public int ShaderProgram => program; - } + return $"{msg} has compile error(s):{msg}\n"; + } + + return gen(nameof(VertexProgram), vertError) + gen(nameof(FragmentProgram), fragError) + gen(nameof(GeometryProgram), geoError); + } + + public void Compile() + { + if (compiled == false) + { + Dispose(); + + Uniforms = new Dictionary(); + + var genShaders = new List(); + + void compileShader(string source, ShaderType shaderType, ref int shader, ref string msg) + { + shader = GL.CreateShader(shaderType); + GL.ShaderSource(shader, source); + + GL.CompileShader(shader); + if (!GL.IsShader(shader)) + throw new Exception($"{shaderType} compile failed."); + msg = GL.GetShaderInfoLog(shader); + if (!string.IsNullOrEmpty(msg)) + Log.LogDebug($"[{shaderType}]:{msg}"); + + genShaders.Add(shader); + } + + compileShader(VertexProgram, ShaderType.VertexShader, ref vertexShader, ref vertError); + compileShader(FragmentProgram, ShaderType.FragmentShader, ref fragmentShader, ref fragError); + if (!string.IsNullOrWhiteSpace(GeometryProgram)) + compileShader(GeometryProgram, ShaderType.GeometryShader, ref geometryShader, ref geoError); + + program = GL.CreateProgram(); + + foreach (var shader in genShaders) + GL.AttachShader(program, shader); + + GL.LinkProgram(program); + + var buildShaderError = GL.GetProgramInfoLog(program); + if (!string.IsNullOrEmpty(buildShaderError)) + Log.LogError(buildShaderError); + + GL.GetProgram(program, GetProgramParameterName.ActiveUniforms, out var total); + + for (int i = 0; i < total; i++) + GL.GetActiveUniform(program, i, 16, out _, out _, out _, out var _); + + compiled = true; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Begin() + { + //假设本项目所有OGL操作都是被我们代码管控之中,因此glUseProgram可以不需要来回切换 +#if DEBUG + /* + 检查是否在我们渲染管控范围外有其他着色器绑定, 好在开发时能及时发现并处理 + */ + GL.GetInteger(GetPName.CurrentProgram, out int curProgram); + if (curProgram != currentUsingProgram && currentUsingProgram != int.MinValue) + throw new Exception("There are other places where shaders are bound."); +#endif + if (currentUsingProgram != program) + { + GL.UseProgram(program); + currentUsingProgram = program; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void End() + { + //不需要解绑 + //GL.UseProgram(0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(string name, Texture tex) + { + if (tex == null) + { + PassNullTexUniform(name); + return; + } + + GL.BindTexture(TextureTarget.Texture2D, tex.ID); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassNullTexUniform(string name) + { + GL.BindTexture(TextureTarget.Texture2D, 0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(int l, float v) => GL.Uniform1(l, v); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(string name, float val) + { + int l = GetUniformLocation(name); + PassUniform(l, val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(int l, int v) => GL.Uniform1(l, v); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(string name, int val) + { + int l = GetUniformLocation(name); + PassUniform(l, val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(int l, Vector2 v) => GL.Uniform2(l, v); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(string name, Vector2 val) + { + int l = GetUniformLocation(name); + PassUniform(l, val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(int l, Vector4 v) => GL.Uniform4(l, v); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(string name, Vector4 val) + { + int l = GetUniformLocation(name); + PassUniform(l, val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(int l, System.Numerics.Vector2 v) => PassUniform(l, new Vector2(v.X, v.Y)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(string name, System.Numerics.Vector2 val) + { + int l = GetUniformLocation(name); + PassUniform(l, val); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(int l, Matrix4 v) => GL.UniformMatrix4(l, false, ref v); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PassUniform(string name, Matrix4 matrix4) + { + int l = GetUniformLocation(name); + PassUniform(l, matrix4); + } + + private Dictionary _uniformDictionary = new Dictionary(); + private Dictionary _attrbDictionary = new Dictionary(); + private string geo; + private int geometryShader; + + public int GetUniformLocation(string name) + { + if (!_uniformDictionary.TryGetValue(name, out var l)) + { + l = GL.GetUniformLocation(program, name); + _uniformDictionary[name] = l; + } + + return l; + } + + public int GetAttribLocation(string name) + { + if (!_attrbDictionary.TryGetValue(name, out var l)) + { + l = GL.GetAttribLocation(program, name); + _attrbDictionary[name] = l; + } + + return l; + } + + public void Dispose() + { + if (program < 0) + return; + GL.DeleteShader(vertexShader); + GL.DeleteShader(fragmentShader); + GL.DeleteProgram(program); + program = -1; + } + + public int ShaderProgram => program; + } } \ No newline at end of file diff --git a/OngekiFumenEditor/Modules/FumenVisualEditor/Graphics/Drawing/Editors/DrawPlayableAreaHelper.cs b/OngekiFumenEditor/Modules/FumenVisualEditor/Graphics/Drawing/Editors/DrawPlayableAreaHelper.cs index aaac7e46..55bf938e 100644 --- a/OngekiFumenEditor/Modules/FumenVisualEditor/Graphics/Drawing/Editors/DrawPlayableAreaHelper.cs +++ b/OngekiFumenEditor/Modules/FumenVisualEditor/Graphics/Drawing/Editors/DrawPlayableAreaHelper.cs @@ -12,6 +12,7 @@ using OngekiFumenEditor.Utils.ObjectPool; using EarcutNet; using System.Drawing; +using System.Runtime.InteropServices; namespace OngekiFumenEditor.Modules.FumenVisualEditor.Graphics.Drawing.Editors {