Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a rather strange exception on my application using OpenTK on Linux (ArchLinux with Mono 3.2.8) with GL.UseProgram(). I wrote a class to combine multiple files to one program:

public sealed class Shader : IContent
{
    public string Name
    {
        get { return name; }
    }

    readonly string name;
    readonly ShaderElement[] elements;
    int programId;

    public Shader(string name, params ShaderElement[] elements)
    {
        this.name = name;
        this.elements = elements;
        this.programId = -1;
    }

    public void Compile()
    {
        programId = GL.CreateProgram();
        for (int i = 0; i < elements.Length; i++)
        {
            var info = new FileInfo(elements[i].File);
            if (info.Exists)
            {
                int shaderId = GL.CreateShader(elements[i].Type);
                using (var reader = info.OpenText())
                    GL.ShaderSource(shaderId, reader.ReadToEnd());
                GL.AttachShader(programId, shaderId);
            }
            else
                throw new FileNotFoundException("Shader file not found.", info.Name);
        }
        GL.LinkProgram(programId);
    }

    public void Apply()
    {
        if (programId == -1)
            throw new InvalidOperationException("Compile() has to be called before Apply()");
        GL.UseProgram(programId);
    }
    public void Unapply()
    {
        GL.UseProgram(0);
    }

    public void Dispose()
    {
        GL.DeleteProgram(programId);
    }
}

My sample shader is very short because I try to understand how OpenGL works:
Vertex:

precision highp float;

void main()
{
    gl_FrontColor = gl_Color;
    gl_Position = ftransform();
}

Fragment:

precision highp float;

void main()
{
    gl_FragColor = gl_Color * (1-clamp(gl_FragCoord.z - 0.05, 0, 1));
    gl_FragColor.w = 1;
}

A sample call for Apply():

public override void Draw(double interpolation)
{
    GL.MatrixMode(MatrixMode.Modelview);
    GL.LoadMatrix(ref translate);
    GL.MatrixMode(MatrixMode.Projection);
    GL.LoadMatrix(ref projection);
    GL.Color3(Color.Red);
    simpleShader.Apply();
    sphere.Draw();
    simpleShader.Unapply();
}

Running the application under Windows does not generate any exception.
The following is crashing running under Linux:

First call of Draw()
 -> First call of Shader.Apply()
 -> Draws geometry for first frame
 -> First call of Shader.Unapply()
Second call of Draw()
 -> Second call of Shader.Apply()
    -> GL throws InvalidOperation Error.

Any ideas why Windows behaves different to Linux and how this can be resolved?

share|improve this question
    
......and what graphics card have you got? The OS isn't really relevant, the graphics card and it's drivers is. –  Darth Melkor Apr 28 '14 at 12:02

2 Answers 2

I have been using OpenTK with mono on Fedora and have not seen that error. Your example uses some C# features I'm not familiar with, and I don't know what is in your draw sphere, so I have created a simple example that works on Linux below.

Although only a triangle is drawn, it uses the shaders, and I enabled and disabled the shader programs as you have in your example above.

I assume you already have a GLControl you can pass into this function. My program sets up a 512 x 512 GLControl like this before calling the test function:

int w = GlControl1.Width;
int h = GlControl1.Height;
GL.MatrixMode (MatrixMode.Projection);
GL.LoadIdentity ();
GL.Ortho (0, w, 0, h, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
GL.Viewport (0, 0, w, h); // Use all of the glControl painting area



using System;
using System.Text;
using System.Drawing;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System.Windows.Forms;

namespace OpenTkTestNamespace
{
    public class StackExchangeTestsClass
    {
        public StackExchangeTestsClass()
        {
        }

        static string VertexShader = 
        "float;" +
        "attribute vec4 vPosition;" +
        "void main()" +
        "{" +
            "gl_Position = vPosition;" +
        "}";    

        static string FragmentShader = 
        "float;" +
        "uniform vec4 vColor;" +
        "void main()" +

        "{" +
            "gl_FragColor = vColor * 1.0 / 256.0 + 1.0 / 256.0 * vec4(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z, 1);" + // (1-clamp(gl_FragCoord.z - 0.05, 0, 1));" +
        "}";        

        static int programId;

        static OpenTK.GLControl GlControl;

        static bool setup_complete = false;

        public static StringBuilder Test(OpenTK.GLControl GlControl_in)
        {
            StringBuilder result = new StringBuilder();
            if (setup_complete == false)
            {               
                GlControl = GlControl_in;
                Compile();
                result.AppendLine("Compile Complete");
                setup_complete = true;              
            }

            Apply();
            result.AppendLine("Apply Complete");
            DrawSomething();
            Unapply();
            result.AppendLine("UnApply Complete");
            Apply();
            result.AppendLine("Apply Complete");
            DrawSomething();
            Unapply();
            result.AppendLine("UnApply Complete");
            return result;
        }

        public static int loadShader(ShaderType type, String shaderCode)
        {
            int shader_ok;
            // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
            // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
            int shader = GL.CreateShader(type);

            // add the source code to the shader and compile it
            GL.ShaderSource(shader, shaderCode);
            GL.CompileShader(shader);
            GL.GetShader(shader, ShaderParameter.CompileStatus, out shader_ok);
            if (shader_ok == 0) {
                MessageBox.Show("Failed to compile " + shaderCode);
                //fprintf(stderr, "Failed to compile %s:\n", filename);
                //show_info_log(shader, glGetShaderiv, glGetShaderInfoLog);
                //glDeleteShader(shader);
                return 0;
            }

            return shader;
        }

        public static void Compile()
        {   
            int VshaderId = loadShader(ShaderType.VertexShader, VertexShader);
            int FshaderId = loadShader(ShaderType.FragmentShader, FragmentShader);
            programId = GL.CreateProgram();
            GL.AttachShader(programId, VshaderId);
            GL.AttachShader(programId, FshaderId);
            GL.LinkProgram(programId);
            int program_ok;
            GL.GetProgram(programId, ProgramParameter.LinkStatus, out program_ok);
            if (program_ok == 0)
            {
                MessageBox.Show("Failed to link " + program_ok.ToString());
            }
        }

        public static void Apply()
        {
            if (programId == -1)
                throw new InvalidOperationException("Compile() has to be called before Apply()");
            GL.UseProgram(programId);
        }

        public static void Unapply()
        {
            GL.UseProgram(0);
        }

        static int mColorHandle;

        // Set color with red, green, blue and alpha (opacity) values
        static OpenTK.Graphics.Color4 color = new OpenTK.Graphics.Color4(0.5f, 0.5f, 0.5f, 1.0f);

        private static void DrawTriangle()
        {
            //GL.MatrixMode(MatrixMode.Modelview);
            //GL.LoadIdentity();
            GL.Color3(Color.Yellow);
            GL.Begin(BeginMode.Triangles);
            GL.Vertex3(0.0, 1, -1);
            GL.Vertex3(-1, -1, 0);
            GL.Vertex3(1, -1, 1);
            GL.End();
        }

        public static void DrawSomething()
        {           
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            // get handle to fragment shader's vColor member
            mColorHandle = GL.GetUniformLocation(programId, "vColor");

            // Set color for drawing the triangle
            GL.Uniform4(mColorHandle, color);

            DrawTriangle();

            GlControl.SwapBuffers();
        }
    }
}

Hope that helps.

share|improve this answer

After you compile and link the shader program you should validate and check the compile and link status'. Anyway, you don't even seem to be compiling the shader sources. Do that and make the checks and it should work.

The Compile() function should look more like this:

public void Compile()
{
    programId = GL.CreateProgram();
    for (int i = 0; i < elements.Length; i++)
    {
        var info = new FileInfo(elements[i].File);
        if (info.Exists)
        {
            int shaderId = GL.CreateShader(elements[i].Type);
            using (var reader = info.OpenText())
                GL.ShaderSource(shaderId, reader.ReadToEnd());
            GL.CompileShader(shaderID);
            //get compile status with glGetShaderiv(shaderID, GL_COMPILE_STATUS, &status);
            GL.AttachShader(programId, shaderId);
        }
        else
            throw new FileNotFoundException("Shader file not found.", info.Name);
    }
    GL.LinkProgram(programId);
    GL.ValidateProgram(programID);
    //get link status with glGetProgramiv(programID, GL_LINK_STATUS, &status);
    //get validate status with glGetProgramiv(programID, GL_VALIDATE_STATUS, &status);
}

And if an error occurs get the error logs and print them somewhere. You can get the logs by calling

glGetShaderInfoLog(shaderID, maxLen, &len, &log);

or respectively

glGetProgramInfoLog(programID, maxlen, &len, &log);

References:

glCompileShader()

glGetShaderInfoLog()

glGetProgramInfoLog()

glGetShaderiv()

glGetProgramiv()

glValidateProgram()

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.