Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 8 of 8

Thread: Shadow Shader Compilation Error

  1. #1
    Junior Member Newbie
    Join Date
    Mar 2017
    Posts
    12

    Question Shadow Shader Crushes the Application

    Dear Community,

    I have written OpenGL application on c++ that uses variance shadow mapping, and that works greate. But I have implemented the same code for OpenTK on C# and the shadow generator shader seems to make the application crush SOMETIMES at the start and SOMETIMES at the end and sometimes it never crushes, and I do not know what is the reason for that, although I am using the same class for generating 2 other shaders and use them and they did not caused any crush, expect this shadow shader it causes a crush without even use it; (Just Initialize and Dispose) but when I comment the code associated with this shader only everything goes well.

    Vertex Shadow Shader:
    Code :
    #version 330 core
    layout (location = 0) in vec3 vPos;
     
    uniform mat4 lightSpaceMatrix;
    uniform mat4 Model;
     
    void main()
    {
        gl_Position = lightSpaceMatrix * Model * vec4(vPos, 1.0);
    }

    Fragment Shadow Shader:
    Code :
    #version 330 core
     
    out vec4 FragColor;
     
    void main()
    {             
    	float depth = gl_FragCoord.z;
     
    	float dx = dFdx(depth);
    	float dy = dFdy(depth);
    	float moment2 = depth*depth + 0.25*(dx*dx + dy*dy);
     
    	FragColor = vec4(depth, moment2, 0.0, 0.0);
    }

    and here is the usage of the shader class:
    Code :
    public class RenderingEngine  : IDisposable
    {
     
    	private Shader shadowShaderTest;
     
    	private void initializeObjects()
            {
    		//... initialize stuff
    		shadowShaderTest = new Shader(@"res\shaders\vshadow.vs", @"res\shaders\fshadow.frag");
    	}
     
    	public void Dispose()
            {
    		//...dispose stuff
    		shadowShaderTest.Dispose();
    	}
    }

    and here is the shader class:
    Code :
    using OpenTK;
    using OpenTK.Graphics.OpenGL;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
     
    namespace GraphicsHelper.OpenGL
    {
        public class Shader : IDisposable
        {
            private class UniformInfo
            {
                public String name = "";
                public int address = -1;
                public int size = 0;
                public ActiveUniformType type;
            }
     
            private int program_id;
            private int uniformCount = 0;
            private Dictionary<string, UniformInfo> uniforms;
     
            /// <summary>
            /// Gets the program ID.
            /// </summary>
            public int ProgramID { get => program_id; }
     
            /// <summary>
            /// Creates an empty shader program.
            /// </summary>
            private Shader()
            {
                program_id = 0;
            }
     
            /// <summary>
            /// Loads and generate shader program from a given files.
            /// </summary>
            /// <param name="VertexShaderFilePath">Vertex shader file path</param>
            /// <param name="FragmentShaderFilePath">Fragment shader file path</param>
            public Shader(string VertexShaderFilePath, string FragmentShaderFilePath)
            {
                if (!File.Exists(VertexShaderFilePath) || !File.Exists(FragmentShaderFilePath))
                    throw new FileNotFoundException("ONE OR MORE SHADER FILES NOT FOUND");
     
                DuplicateShader(GenerateProgram(File.ReadAllText(VertexShaderFilePath), File.ReadAllText(FragmentShaderFilePath)), this);
            }
     
            private static int CompileShader(string Code, ShaderType Type)
            {
                int success;
     
                int Shader = GL.CreateShader(Type);
                GL.ShaderSource(Shader, Code);
                GL.CompileShader(Shader);
                GL.GetShader(Shader, ShaderParameter.CompileStatus, out success);
     
                if (success == 0)
                {
                    string InfoLog = GL.GetShaderInfoLog(Shader);
                    GL.DeleteShader(Shader);
                    throw new ShaderException("ERROR " + Type.ToString() + " COMPILATION_FAILED" + Environment.NewLine + InfoLog);
                }
                return Shader;
            }
     
            public static Shader GenerateProgram(string VertexShaderCode, string FragmentShaderCode)
            {
                if (VertexShaderCode == null || FragmentShaderCode == null)
                    throw new ArgumentNullException();
     
                int program_id = 0;
     
                if (program_id != 0)
                    GL.DeleteProgram(program_id);
     
                int VertexShader = CompileShader(VertexShaderCode, ShaderType.VertexShader);
                if (VertexShader == 0)
                    throw new ShaderException(ShaderType.VertexShader.ToString() + " COMPILATION FAILED" + Environment.NewLine +
                        GL.GetShaderInfoLog(VertexShader));
                int FragmentShader = CompileShader(FragmentShaderCode, ShaderType.FragmentShader);
                if (FragmentShader == 0)
                    throw new ShaderException(ShaderType.FragmentShader.ToString() + " COMPILATION FAILED" + Environment.NewLine +
                        GL.GetShaderInfoLog(VertexShader));
     
                program_id = GL.CreateProgram();
                GL.AttachShader(program_id, VertexShader);
                GL.AttachShader(program_id, FragmentShader);
                GL.LinkProgram(program_id);
     
                int success;
                GL.GetProgram(program_id, GetProgramParameterName.LinkStatus, out success);
                if (success == 0)
                {
                    string InfoLog = GL.GetProgramInfoLog(program_id);
                    GL.DetachShader(program_id, VertexShader);
                    GL.DetachShader(program_id, FragmentShader);
                    GL.DeleteShader(VertexShader);
                    GL.DeleteShader(FragmentShader);
                    GL.DeleteProgram(program_id);
                    throw new ShaderException("ERROR SHADER PROGRAM LINKING_FAILED" + Environment.NewLine + InfoLog);
                }
     
                GL.DetachShader(program_id, VertexShader);
                GL.DetachShader(program_id, FragmentShader);
                GL.DeleteShader(VertexShader);
                GL.DeleteShader(FragmentShader);
     
                int uniformCount;
                Dictionary<string, UniformInfo> uniforms = new Dictionary<string, UniformInfo>();
     
                GL.GetProgram(program_id, GetProgramParameterName.ActiveUniforms, out uniformCount);
     
                for (int i = 0; i < uniformCount; i++)
                {
                    UniformInfo info = new UniformInfo();
                    int length = 0;
     
                    StringBuilder name = new StringBuilder();
     
                    GL.GetActiveUniform(program_id, i, 256, out length, out info.size, out info.type, name);
     
                    info.name = name.ToString();
                    uniforms.Add(name.ToString(), info);
                    info.address = GL.GetUniformLocation(program_id, info.name);
                }
     
                Shader finalProgram = new Shader();
                finalProgram.program_id = program_id;
                finalProgram.uniformCount = uniformCount;
                finalProgram.uniforms = uniforms;
     
                return finalProgram;
            }
     
            /// <summary>
            /// Make OpenGL use this program object.
            /// </summary>
            public void Use()
            {
                GL.UseProgram(program_id);
            }
     
            private void DuplicateShader(Shader First, Shader Second)
            {
                Second.program_id = First.program_id;
                Second.uniformCount = First.uniformCount;
                Second.uniforms = First.uniforms;
            }
     
            /// <summary>
            /// Gets the location of specific attribute.
            /// </summary>
            /// <param name="AttributeName">Attribute name.</param>
            /// <returns></returns>
            public int GetUniformLocation(string AttributeName)
            {
                return uniforms[AttributeName].address;
            }
     
            private void SetUniform(string UniformName, bool Boolean)
            {
                GL.Uniform1(GetUniformLocation(UniformName), Boolean ? 1 : 0);
            }
     
            private void SetUniform(string UniformName, uint UIntNumber)
            {
                GL.Uniform1(GetUniformLocation(UniformName), UIntNumber);
            }
     
            private void SetUniform(string UniformName, int IntNumber)
            {
                GL.Uniform1(GetUniformLocation(UniformName), IntNumber);
            }
     
            private void SetUniform(string UniformName, float FloatNumber)
            {
                GL.Uniform1(GetUniformLocation(UniformName), FloatNumber);
            }
     
            private void SetUniform(string UniformName, double DoubleNumber)
            {
                GL.Uniform1(GetUniformLocation(UniformName), DoubleNumber);
            }
     
            private void SetUniform(string UniformName, Vector2 Vector2Value)
            {
                GL.Uniform2(GetUniformLocation(UniformName), Vector2Value);
            }
     
            private void SetUniform(string UniformName, float X, float Y)
            {
                GL.Uniform2(GetUniformLocation(UniformName), X, Y);
            }
     
            private void SetUniform(string UniformName, Vector3 Vector3Value)
            {
                GL.Uniform3(GetUniformLocation(UniformName), Vector3Value);
            }
     
            private void SetUniform(string UniformName, float X, float Y, float Z)
            {
                GL.Uniform3(GetUniformLocation(UniformName), X, Y, Z);
            }
     
            private void SetUniform(string UniformName, Vector4 Vector4Value)
            {
                GL.Uniform4(GetUniformLocation(UniformName), Vector4Value);
            }
     
            private void SetUniform(string UniformName, float X, float Y, float Z, float W)
            {
                GL.Uniform4(GetUniformLocation(UniformName), X, Y, Z, W);
            }
     
            private void SetUniform(string UniformName, Matrix2 Matrix2Value, bool Transpose = false)
            {
                GL.UniformMatrix2(GetUniformLocation(UniformName), Transpose, ref Matrix2Value);
            }
     
            private void SetUniform(string UniformName, Matrix3 Matrix3Value, bool Transpose = false)
            {
                GL.UniformMatrix3(GetUniformLocation(UniformName), Transpose, ref Matrix3Value);
            }
     
            private void SetUniform(string UniformName, float M11, float M12, float M13, float M21, float M22, float M23, float M31, float M32, float M33, bool Transpose = false)
            {
                Matrix3 mat = new Matrix3(M11, M12, M13, M21, M22, M23, M31, M32, M33);
                GL.UniformMatrix3(GetUniformLocation(UniformName), Transpose, ref mat);
            }
     
            private void SetUniform(string UniformName, Matrix4 Matrix4Value, bool Transpose = false)
            {
                GL.UniformMatrix4(GetUniformLocation(UniformName), Transpose, ref Matrix4Value);
            }
     
            private void SetUniform(string UniformName, float M11, float M12, float M13, float M14, float M21, float M22, float M23, float M24, float M31, float M32, float M33, float M34, float M41, float M42, float M43, float M44, bool Transpose = false)
            {
                Matrix4 mat = new Matrix4(M11, M12, M13, M14, M21, M22, M23, M24, M31, M32, M33, M34, M41, M42, M43, M44);
                GL.UniformMatrix4(GetUniformLocation(UniformName), Transpose, ref mat);
            }
     
            private void SetUniform(string UniformName, Kernel KernelObject)
            {
                for (int i = 0; i < KernelObject.Length; i++)
                    SetUniform("kernel[" + i + "]", KernelObject[i]);
            }
     
            public object this[string UniformName]
            {
                set
                {
                    if (uniforms.ContainsKey(UniformName))
                    {
                        SetUniform(UniformName, (dynamic)value);
                    }
                }
            }
     
            public void Dispose()
            {
                if (program_id != 0)
                    GL.DeleteProgram(program_id);
                GC.SuppressFinalize(this);
            }
        }
    }
    Last edited by Omar Bsoul; 01-13-2018 at 11:04 AM.

  2. #2
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,511
    Quote Originally Posted by Omar Bsoul View Post
    ...same code for OpenTK on C# and the shadow generator shader seems to make the application crush SOMETIMES at the start and SOMETIMES at the end and sometimes it never crushes
    Please define "crush". That makes no sense in this context. I'm guessing you mean "crash" -- i.e. the program terminates abnormally?

    Since this doesn't happen under C++, it seems that there's something different about how you're doing this in C#.

    What have you tried to debug this? Have you tried Checking for OpenGL Errors? Have you tried producing the crash in a debugger? Do you get a stack trace? Have you tried using a memory checker? Have you tried making changes to your program to help localize the cause of the crash?
    Last edited by Dark Photon; 01-13-2018 at 04:27 PM.

  3. #3
    Junior Member Newbie
    Join Date
    Mar 2017
    Posts
    12
    Yes, a message shown "MyAppName stopped working" and then a window having only one button appears; the button text is "close program".
    It is like an exception begin thrown and not handled, but actually I am surrounding the initialize method with try catch and and printing the exception message, but there is no message printed out.

  4. #4
    Junior Member Newbie
    Join Date
    Mar 2017
    Posts
    12
    Yes I have debuged the code it seemed to work very well and close very well without any crush, and the errors of shader is beeing checked in the shader class above.
    And what made me wondering, is I am already have another 2 shaders that is completely working very well, but this specific shader causes the problem.

  5. #5
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,511
    That's interesting. It sounds like you're suspecting that it's your GPU shader that is causing the crash rather than your CPU C#-based application. If that's true, you should be able to (for testing purposes only) find some change you can make to your GPU shader which will get rid of the crash. As a debugging experiment you might try that. If the shader is the trigger, the mystery would be why you see this with your C# app but not your C++ app.

    What kind of rendering performance are you getting with your C++ and C# applications? Are they comparable? What kind of frame times are you getting? Also, are you using the same GPU and GPU driver in both cases?

    Our of curiosity, what GPU and GPU driver/version are you running on? If you have GPU from another vendor you might try that for comparison.

  6. #6
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,956
    Quote Originally Posted by Omar Bsoul View Post
    I have written OpenGL application on c++ that uses variance shadow mapping, and that works greate. But I have implemented the same code for OpenTK on C# and the shadow generator shader seems to make the application crush SOMETIMES at the start and SOMETIMES at the end and sometimes it never crushes, and I do not know what is the reason for that, although I am using the same class for generating 2 other shaders and use them and they did not caused any crush, expect this shadow shader it causes a crush without even use it; (Just Initialize and Dispose) but when I comment the code associated with this shader only everything goes well.
    Quote Originally Posted by Omar Bsoul View Post
    Code :
            public void Dispose()
            {
                if (program_id != 0)
                    GL.DeleteProgram(program_id);
    You cannot safely call OpenGL functions from destructors in languages with delayed finalisation (where destructors/finalisers are called at some unspecified point after the object is no longer accessible). This definitely includes Java and Python, I suspect that it includes C#, it doesn't include C++ (where destructors are guaranteed to be called as soon as an object ceases to exist). The reason is that OpenGL functions need to have a context bound, and you can't guarantee that this is the case in languages with delayed finalisation.

    In such languages, if you call glDelete*() functions from destructors, it's fairly typical to get errors (or even crashes) at program termination, as the OpenGL context tends to have been unbound and destroyed before the destructors get called.

  7. #7
    Junior Member Newbie
    Join Date
    Mar 2017
    Posts
    12
    Yes that is what I am thinking about, and after experiment I found that, that matrix "lightSapceMatrix" multiplication causes that crush, so if vertex shader becomes like this it will stop crushing:

    Code :
    #version 330 core
    layout(location = 0) in vec3 vPos;
     
    uniform mat4 lightSpaceMatrix;
    uniform mat4 Model;
     
    void main()
    {
        gl_Position = Model * vec4(vPos, 1.0);
    }

    And this maybe a bug in the OpenGL wrapper "OpenTK".

    What kind of rendering performance are you getting with your C++ and C# applications? Are they comparable? What kind of frame times are you getting? Also, are you using the same GPU and GPU driver in both cases?

    Our of curiosity, what GPU and GPU driver/version are you running on? If you have GPU from another vendor you might try that for comparison.
    they are about the same performance and they around 100 fps, and yes they use the same GPU since I do have only dedicated GPU "Intel HD Graphics 3000" and Driver Version is "9.17.10.4459"

  8. #8
    Junior Member Newbie
    Join Date
    Mar 2017
    Posts
    12
    Quote Originally Posted by GClements View Post
    You cannot safely call OpenGL functions from destructors in languages with delayed finalisation (where destructors/finalisers are called at some unspecified point after the object is no longer accessible). This definitely includes Java and Python, I suspect that it includes C#, it doesn't include C++ (where destructors are guaranteed to be called as soon as an object ceases to exist). The reason is that OpenGL functions need to have a context bound, and you can't guarantee that this is the case in languages with delayed finalisation.

    In such languages, if you call glDelete*() functions from destructors, it's fairly typical to get errors (or even crashes) at program termination, as the OpenGL context tends to have been unbound and destroyed before the destructors get called.
    Yes that is true, but I am Disposing 2 other (shaders, vaos, vbos and textures) and that were going very well without any crush.
    And also I have read that, the "GameWindow" class that represent a window in "OpenTK" wrapper; calling the Dispose method before OpenGL context destruction; you can check it here: https://github.com/mono/opentk/blob/.../GameWindow.cs

    Code :
            /// <summary>
            /// Disposes of the GameWindow, releasing all resources consumed by it.
            /// </summary>
            public override void Dispose()
            {
                try
                {
                    Dispose(true);
                }
                finally
                {
                    try
                    {
                        if (glContext != null)
                        {
                            glContext.Dispose();
                            glContext = null;
                        }
                    }
                    finally
                    {
                        base.Dispose();
                    }
                }
                GC.SuppressFinalize(this);
            }

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •