0 Replies Latest reply on Jun 2, 2014 12:16 AM by aybe

    Wrong GLSL uniform returned when using an explicit layout, bug ?

    aybe

      Environment : Windows 8.1 x64, HD7850 with 2Gb, Visual Studio 2013, OpenGL 4, C#, Catalyst 14.4

       

      I have come to the conclusion that there seems to be a bug when trying to retrieve the value of a uniform matrix in a GLSL vertex shader

      that is explicitly laid out in a location, while setting the uniform value works, the value returned is in fact of another uniform.

       

      Here is the vertex shader part used, declarations without explicit location have been commented out as they do produce the order 0, 2, 1

      which surprisingly does not produce this incorrect behavior.

      #version 440
      precision highp float;
      
      //uniform mat4 Model;
      //uniform mat4 View;
      //uniform mat4 Projection;
      
      layout (location = 0) uniform mat4 Model;
      layout (location = 1) uniform mat4 View;
      layout (location = 2) uniform mat4 Projection;
      
      layout (location = 0) in vec3 in_position;
      layout (location = 1) in vec4 in_color;
      out vec4 out_color;
      void main(void)
      {
          out_color = in_color;
          gl_Position = Projection * View * Model * vec4(in_position, 1.0);
      }
      
      
      
      
      
      

      It seems that the driver sorts uniforms according their name as trying to change the name to be consecutive in an alphabetical order fools the system.

      The second source confirming this is CodeXL where there are also sorted alphabetically, View and Projection being inverted:

       

      snap0307.png

      Below is the result when explicit locations are not used (behavior is correct)

      snap0306.png

       

      Here is an example project in C# with OpenTK, create a Console Application and install OpenTK Nuget package (Install-Package OpenTK)

       

      At the very end of the second code block is commented where the incorrect value is being returned.

       

      The fragment shader associated with the former vertex shader.

      #version 440
      precision highp float;
      in vec4 out_color;
      out vec4 out_frag_color;
      void main(void)
      {
          out_frag_color = out_color;
      }
      
      
      
      
      

       

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using ConsoleApplication1.Examples;
      using OpenTK;
      
      namespace ConsoleApplication1 {
          internal static class MyProgram {
      
              private static void Main(string[] args) {
                      using (var gameWindow = new BareExampleGame()) {
                          gameWindow.Run(60, 60);
                      }
              }
          }
      }
      
      
      
      

       

      using System.Runtime.InteropServices;
      using OpenTK;
      
      namespace ConsoleApplication1 {
          [StructLayout(LayoutKind.Sequential)]
          public struct VP3C4 {
              public readonly Vector3 Position;
              public readonly Vector4 Color;
      
              public VP3C4(Vector3 position, Vector4 color) {
                  Position = position;
                  Color = color;
              }
          }
      }
      
      
      
      


      using System;
      using System.Drawing;
      using System.IO;
      using System.Runtime.InteropServices;
      using ConsoleApplication1.Types;
      using OpenTK;
      using OpenTK.Graphics;
      using OpenTK.Graphics.OpenGL4;
      using OpenTK.Input;
      
      namespace ConsoleApplication1.Examples {
          internal class BareExampleGame : GameWindow {
              private int _program;
              private double _time;
              private int _vao;
      
              public BareExampleGame()
                  : base(
                      640, 480, new GraphicsMode(new ColorFormat(32), 24, GraphicsMode.Default.Stencil, 4), "",
                      GameWindowFlags.Default, DisplayDevice.Default,
                      4, 4, GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug) {
              }
      
              protected override unsafe void OnLoad(EventArgs e) {
                  VSync = VSyncMode.On;
                  GL.Enable(EnableCap.DepthTest);
                  GL.Enable(EnableCap.Blend);
                  GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
      
                  int vs = GL.CreateShader(ShaderType.VertexShader);
                  string vsText = File.ReadAllText(Combine("Geometry.vert.glsl"));
                  GL.ShaderSource(vs, vsText);
                  GL.CompileShader(vs);
                  string vsLog = GL.GetShaderInfoLog(vs);
      
                  int fs = GL.CreateShader(ShaderType.FragmentShader);
                  string fsText = File.ReadAllText(Combine("Geometry.frag.glsl"));
                  GL.ShaderSource(fs, fsText);
                  GL.CompileShader(fs);
                  string fsLog = GL.GetShaderInfoLog(fs);
      
                  int program = GL.CreateProgram();
                  GL.AttachShader(program, vs);
                  GL.AttachShader(program, fs);
                  GL.LinkProgram(program);
                  string programInfoLog = GL.GetProgramInfoLog(program);
      
                  GL.UseProgram(program);
                  _program = program;
      
                  int stride = sizeof (VP3C4);
                  VP3C4[] data = {
                      new VP3C4(new Vector3(0, 0, 0), new Vector4(1, 0, 0, 1)),
                      new VP3C4(new Vector3(256, 0, 0), new Vector4(0, 1, 0, 1)),
                      new VP3C4(new Vector3(256, 256, 0), new Vector4(0, 0, 1, 1)),
                      new VP3C4(new Vector3(0, 0, 0), new Vector4(1, 0, 0, 1)),
                      new VP3C4(new Vector3(256, 256, 0), new Vector4(0, 0, 1, 1)),
                      new VP3C4(new Vector3(0, 256, 0), new Vector4(1, 1, 1, 1))
                  };
      
                  int vbo = GL.GenBuffer();
                  GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
                  GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr) (stride*data.Length), data, BufferUsageHint.StaticDraw);
      
                  var indices = new uint[] {0, 1, 2, 3, 4, 5};
                  int ibo = GL.GenBuffer();
                  GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo);
                  GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr) (sizeof (uint)*indices.Length), indices,
                      BufferUsageHint.StaticDraw);
      
                  _vao = GL.GenVertexArray();
                  GL.BindVertexArray(_vao);
      
                  GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
                  GL.EnableVertexAttribArray(0);
                  GL.EnableVertexAttribArray(1);
      
                  GL.BindVertexBuffer(0, vbo, new IntPtr(0), stride);
                  GL.VertexAttribFormat(0, 3, VertexAttribType.Float, false, 0);
                  GL.VertexAttribBinding(0, 0);
                  GL.VertexAttribFormat(1, 4, VertexAttribType.Float, false, 12);
                  GL.VertexAttribBinding(1, 0);
      
                  GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo);
                  base.OnLoad(e);
              }
      
              private static string Combine(string geometryVertGlsl) {
                  string commandLine = Environment.CommandLine;
                  string trim = commandLine.Trim().Trim('"');
                  string directoryName = Path.GetDirectoryName(trim);
                  if (directoryName != null) {
                      string combine = Path.Combine(directoryName, geometryVertGlsl);
                      return combine;
                  }
                  throw new InvalidOperationException();
              }
      
              private static void Callback(DebugSource source, DebugType type, int id, DebugSeverity severity, int length,
                  IntPtr message, IntPtr userparam) {
                  string ptrToStringAnsi = Marshal.PtrToStringAnsi(message);
                  Console.WriteLine(ptrToStringAnsi);
              }
      
              protected override void OnUpdateFrame(FrameEventArgs e) {
                  GL.Viewport(0, 0, Width, Height);
                  GL.CullFace(CullFaceMode.FrontAndBack);
                  if (Keyboard[Key.Escape]) {
                      Exit();
                  }
                  double time = e.Time;
                  double d = (_time*50)%360.0d;
                  _time += time;
                  Matrix4 matrixModel =
                      Matrix4.Identity
                      *Matrix4.CreateScale(1, 1, 1)
      
                          // rotate with origin defined
                      *Matrix4.CreateTranslation(-128, -128, 0)
                      *Matrix4.CreateRotationZ((float) MathHelper.DegreesToRadians(d))
                      *Matrix4.CreateTranslation(128, 128, 0)
      
                      *Matrix4.CreateTranslation(256, 256, 0)
                      ;
                  Matrix4 matrixView = Matrix4.Identity;
                  Matrix4 matrixProjection = Matrix4.CreateOrthographicOffCenter(0, Width, Height, 0, 0, 1);
                  int program = _program;
                  int location1 = GL.GetUniformLocation(program, "Model");
                  int location2 = GL.GetUniformLocation(program, "View");
                  int location3 = GL.GetUniformLocation(program, "Projection");
                  GL.UniformMatrix4(location1, false, ref matrixModel);
                  GL.UniformMatrix4(location2, false, ref matrixView);
                  GL.UniformMatrix4(location3, false, ref matrixProjection);
      
                  var f1 = new float[16];
                  var f2 = new float[16];
                  var f3 = new float[16];
                  GL.GetUniform(program, location1, f1);
                  GL.GetUniform(program, location2, f2); // BUG
                  GL.GetUniform(program, location3, f3); // BUG
                  Matrix4 matrix1 = f1.ToMatrix4();
                  Matrix4 matrix2 = f2.ToMatrix4();
                  Matrix4 matrix3 = f3.ToMatrix4();
      
                  Title = string.Format("Model: {0}, View: {1}, Projection: {2}", location1, location2, location3);
                  base.OnUpdateFrame(e);
              }
      
              protected override void OnRenderFrame(FrameEventArgs e) {
                  GL.ClearColor(Color.Black);
                  GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
                  GL.BindVertexArray(_vao);
                  GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
      
                  SwapBuffers();
                  base.OnRenderFrame(e);
              }
          }
      }
      
      
      
      

       

      EDIT : I have checked against an Intel HD4600, the problem does not occur.

       

      Thank you.