OpenGL: How to render 2 simple VAOs on Intel HD Graphics 4000 GPU?

1.1k Views Asked by At

Summary: My original question and observations are followed by an updated working OpenGL code for Intel HD Graphics 4000 GPU.

Original question: Two cubes are shown on Nvidia NVS 4200m GPU and 1 cube shown on Intel HD Graphics 4000 GPU.

  • Using OpenGL 3.2 forward profile and OpenTK to render 2 simple cubes on screen
  • It shows the first cube centered at (0,0,0) on Intel HD Graphics 4000 with the latest GPU driver 7/2/2014 ver 10.18.0010.3621. It should show 2 cubes.
  • We're using a Vertex Array Object (VAO), vertex buffer, index buffer, attributes, normals and GLSL shaders
  • Rebinding the element array buffer just after activating the VAO and before glDrawElements() still shows one cube on Intel and two cubes on Nvidia (VAO and element array buffer state)
  • Shaders
    • The vertex and fragment shaders compile and link OK
    • The vertex and fragment shaders only read from input variables and write only to output variables. They do not read and write to an input/output/uniform. https://communities.intel.com/thread/36284
  • glGetError() calls were done after each OpenGL call and returned no errors.
  • The first cube is centered at (0,0,0), the second one is offset to (4,0,0) and both cubes rotate about (0,0,0)
  • We build the buffers first, attributes next, then create the VAO and hook buffers/attributes to the VAO. Is there a special ordering needed for Intel to work? See: OpenGL, VAOs and multiple buffers
  • Deactivating the VAO after glDrawElements() does not seem to help

Here is the source code based on the OpenTK example program "Open GL 3.0". It should show two cubes, rotating about (0,0,0) with a directional light source.

Update: 11/17/2014: The below code works on both Nvidia and Intel HD Graphics 4000 GPU.
Changes:

  • Create VAO before creating buffers for the vertex, index, ... associated with the VAO
  • Move GL.BindAttribLocation() call to just before linking the shader
  • Rebind the element array buffer just before using GL.DrawElements() to render the 3d object
  • Deactivate the buffer and VAO after rendering

    using System;
    using System.Diagnostics;
    using System.IO;
    
    using OpenTK;
    using OpenTK.Graphics;
    using OpenTK.Graphics.OpenGL;
    
    namespace Examples.Tutorial
    {
        [Example("OpenGL 3.0 v2 2 vao works", ExampleCategory.OpenGL, "3.x", Documentation="HelloGL3 - v2 - create vao first")]
        public class HelloGL3v3 : GameWindow
        {
            string vertexShaderSource = @"
    #version 130
    
    precision highp float;
    
    uniform mat4 projection_matrix;
    uniform mat4 modelview_matrix;
    
    in vec3 in_position;
    in vec3 in_normal;
    
    out vec3 normal;
    
    void main(void)
    {
      //works only for orthogonal modelview
      normal = (modelview_matrix * vec4(in_normal, 0)).xyz;
    
      gl_Position = projection_matrix * modelview_matrix * vec4(in_position, 1);
    }";
    
            string fragmentShaderSource = @"
    #version 130
    
    precision highp float;
    
    const vec3 ambient = vec3(0.1, 0.1, 0.1);
    const vec3 lightVecNormalized = normalize(vec3(0.5, 0.5, 20.0));
    //const vec3 lightVecNormalized = normalize(vec3(0.5, 0.5, 2.0));
    const vec3 lightColor = vec3(0.9, 0.9, 0.7);
    
    in vec3 normal;
    
    out vec4 out_frag_color;
    
    void main(void)
    {
      float diffuse = clamp(dot(lightVecNormalized, normalize(normal)), 0.0, 1.0);
      out_frag_color = vec4(ambient + diffuse * lightColor, 1.0);
    }";
    
            int vertexShaderHandle,
                fragmentShaderHandle,
                shaderProgramHandle,
                modelviewMatrixLocation,
                projectionMatrixLocation;
    
    
            Matrix4 projectionMatrix, modelviewMatrix;
    
            public HelloGL3v3() : base(800, 600,
                new GraphicsMode(), "OpenGL 3 Example", 0,
                DisplayDevice.Default, 3, 2,
                GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug)
            { }
    
            protected override void OnLoad (System.EventArgs e)
            {
                VSync = VSyncMode.On;
    
                CreateShaders();
                CreateVaoOne();
                CreateVaoTwo();
    
                // Other state
                GL.Enable(EnableCap.DepthTest);    E();
                GL.ClearColor(System.Drawing.Color.MidnightBlue);  E();
            }
    
            void CreateShaders()
            {
                vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader);            E();
                fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);            E();
    
                GL.ShaderSource(vertexShaderHandle, vertexShaderSource);            E();
                GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource);            E();
    
                GL.CompileShader(vertexShaderHandle);            E();
                GL.CompileShader(fragmentShaderHandle);            E();
    
                Debug.WriteLine(GL.GetShaderInfoLog(vertexShaderHandle));
                Debug.WriteLine(GL.GetShaderInfoLog(fragmentShaderHandle));
    
                // Create program
                shaderProgramHandle = GL.CreateProgram();            E();
    
                GL.AttachShader(shaderProgramHandle, vertexShaderHandle);            E();
                GL.AttachShader(shaderProgramHandle, fragmentShaderHandle);            E();
    
                //BindAttribLocation() for shader needs to be done before linking the shader program
                GL.BindAttribLocation(shaderProgramHandle, 0, "in_position");           E();
                GL.BindAttribLocation(shaderProgramHandle, 1, "in_normal");            E();
    
                GL.LinkProgram(shaderProgramHandle);            E();
    
                Debug.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle));
    
                GL.UseProgram(shaderProgramHandle);           E();
    
                // get uniform locations
                projectionMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "projection_matrix");      E();
                modelviewMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "modelview_matrix");       E();
    
                float aspectRatio = ClientSize.Width / (float)(ClientSize.Height);
                Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, aspectRatio, 1, 100, out projectionMatrix);
                modelviewMatrix = Matrix4.LookAt(new Vector3(0, 13, 15), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
    
                GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix);       E();
                GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelviewMatrix);      E();
            }
    
            int vaoHandle,
                eboHandle;
    
            int[] indicesVboData = new int[]{
                 // front face
                    0, 1, 2, 2, 3, 0,
                    // top face
                    3, 2, 6, 6, 7, 3,
                    // back face
                    7, 6, 5, 5, 4, 7,
                    // left face
                    4, 0, 3, 3, 7, 4,
                    // bottom face
                    0, 1, 5, 5, 4, 0,
                    // right face
                    1, 5, 6, 6, 2, 1, };
    
    
            void CreateVaoOne()
            {
                int positionVboHandle,
                normalVboHandle;
    
                Vector3[] positionVboData = new Vector3[]{
                new Vector3(-1.0f, -1.0f,  1.0f),
                new Vector3( 1.0f, -1.0f,  1.0f),
                new Vector3( 1.0f,  1.0f,  1.0f),
                new Vector3(-1.0f,  2.0f,  1.0f),
                new Vector3(-1.0f, -1.0f, -1.0f),
                new Vector3( 1.0f, -1.0f, -1.0f), 
                new Vector3( 1.0f,  1.0f, -1.0f),
                new Vector3(-1.0f,  1.0f, -1.0f) };
    
    
                // GL3 allows us to store the vertex layout in a "vertex array object" (VAO).
                // This means we do not have to re-issue VertexAttribPointer calls
                // every time we try to use a different vertex layout - these calls are
                // stored in the VAO so we simply need to bind the correct VAO.
                GL.GenVertexArrays(1, out vaoHandle);            E();
                GL.BindVertexArray(vaoHandle);            E();
                //----------------------------------------------------------------------------
                {
                    GL.GenBuffers(1, out positionVboHandle);                E();
                    GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);                E();
                    GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, new IntPtr(positionVboData.Length * Vector3.SizeInBytes), positionVboData, BufferUsageHint.StaticDraw);                E();
    
                    GL.EnableVertexAttribArray(0);                E();
                    GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);                E();
                    GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);                E();
                    //GL.BindAttribLocation(shaderProgramHandle, 0, "in_position");                E();
                }
                //----------------------------------------------------------------------------
                {
                    GL.GenBuffers(1, out normalVboHandle);                E();
    
                    GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle);                E();
                    GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, new IntPtr(positionVboData.Length * Vector3.SizeInBytes), positionVboData, BufferUsageHint.StaticDraw);                E();
    
                    GL.EnableVertexAttribArray(1);                E();
                    GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle);                E();
                    GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);                E();
                    //GL.BindAttribLocation(shaderProgramHandle, 1, "in_normal");                E();
                }
    
                {
                    GL.GenBuffers(1, out eboHandle);                E();
    
                    GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);                E();
    
                    GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(sizeof(uint) * indicesVboData.Length), indicesVboData, BufferUsageHint.StaticDraw);  E();
                    GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);       E();
                }
                //----------------------------------------------------------------------------
                GL.BindBuffer(BufferTarget.ArrayBuffer, 0);    E();
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);    E();
    
                GL.BindVertexArray(0);   E();
            }
    
            int vaoHandle2,
                eboHandle2;
    
            int[] indicesVboData2 = new int[]{
                 // front face
                    0, 1, 2, 2, 3, 0,
                    // top face
                    3, 2, 6, 6, 7, 3,
                    // back face
                    7, 6, 5, 5, 4, 7,
                    // left face
                    4, 0, 3, 3, 7, 4,
                    // bottom face
                    0, 1, 5, 5, 4, 0,
                    // right face
                    1, 5, 6, 6, 2, 1, };
    
            void CreateVaoTwo()
            {
                int positionVboHandle2,
                 normalVboHandle2;
    
                Vector3[] positionVboData2 = new Vector3[]{
                new Vector3(-0.5f, -0.5f,  0.5f),
                new Vector3( 0.5f, -0.5f,  0.5f),
                new Vector3( 0.5f,  0.5f,  0.5f),
                new Vector3(-0.5f,  0.5f,  5.5f),
                new Vector3(-0.5f, -0.5f, -0.5f),
                new Vector3( 0.5f, -0.5f, -0.5f), 
                new Vector3( 0.5f,  0.5f, -0.5f),
                new Vector3(-0.5f,  0.5f, -0.5f) };
    
                Vector3[] normalsVboData2 = new Vector3[]{
                new Vector3(-1.0f, -1.0f,  1.0f),
                new Vector3( 1.0f, -1.0f,  1.0f),
                new Vector3( 1.0f,  1.0f,  1.0f),
                new Vector3(-1.0f,  1.0f,  1.0f),
                new Vector3(-1.0f, -1.0f, -1.0f),
                new Vector3( 1.0f, -1.0f, -1.0f), 
                new Vector3( 1.0f,  1.0f, -1.0f),
                new Vector3(-1.0f,  1.0f, -1.0f) };
    
                //translate the points in the second cube away from the origin
                for (int i = 0; i < positionVboData2.Length; i++)
                    positionVboData2[i] = Vector3.Add(positionVboData2[i], new Vector3(2.0f, 0f, 0f));
    
                GL.GenVertexArrays(1, out vaoHandle2);  E();
                GL.BindVertexArray(vaoHandle2);  E();
    
                //----------------------------------------------------------------------------
                //vertex array
                GL.GenBuffers(1, out positionVboHandle2);            E();
                GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle2);            E();
                GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, new IntPtr(positionVboData2.Length * Vector3.SizeInBytes), positionVboData2, BufferUsageHint.StaticDraw);            E();
    
                GL.EnableVertexAttribArray(0);  E();
                GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle2);  E();
                GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);  E();
                //GL.BindAttribLocation(shaderProgramHandle, 0, "in_position");  E();
    
                //------------------------------------------------------------
                //normals array
                GL.GenBuffers(1, out normalVboHandle2);     E();
                GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle2);     E();
                GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, new IntPtr(normalsVboData2.Length * Vector3.SizeInBytes), normalsVboData2, BufferUsageHint.StaticDraw);     E();
    
                GL.EnableVertexAttribArray(1);   E();
                GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle2);   E();
                GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);  E();
                //GL.BindAttribLocation(shaderProgramHandle, 1, "in_normal");  E();
    
                //------------------------------------------------------------
                //element (index) array
                GL.GenBuffers(1, out eboHandle2);       E();
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle2);      E();
                GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(sizeof(uint) * indicesVboData2.Length), indicesVboData2, BufferUsageHint.StaticDraw);      E();
    
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle2); E();
    
                //------------------------------------------------------------
                GL.BindBuffer(BufferTarget.ArrayBuffer, 0); E();
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);   E();
    
                GL.BindVertexArray(0);   E();
            }
    
            protected override void OnUpdateFrame(FrameEventArgs e)
            {
                if ((Keyboard[OpenTK.Input.Key.ControlLeft]) || (Keyboard[OpenTK.Input.Key.ControlRight]))
                    return;
    
                Matrix4 rotation = Matrix4.CreateRotationY((float)e.Time);
                Matrix4.Mult(ref rotation, ref modelviewMatrix, out modelviewMatrix);
                GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelviewMatrix);
    
                if (Keyboard[OpenTK.Input.Key.Escape])
                    Exit();
            }
    
            protected override void OnRenderFrame(FrameEventArgs e)
            {
                GL.Viewport(0, 0, Width, Height);  E();
    
                GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);  E();
    
                //GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
    
                GL.BindVertexArray(vaoHandle);  E();
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);    E();
                GL.DrawElements(BeginMode.Triangles, indicesVboData.Length, DrawElementsType.UnsignedInt, IntPtr.Zero); E();
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
                GL.BindVertexArray(0);
    
                //-----------------------------------------------------------------------
                GL.BindVertexArray(vaoHandle2); E();
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle2);   E();
                GL.DrawElements(BeginMode.Triangles, indicesVboData2.Length, DrawElementsType.UnsignedInt, IntPtr.Zero);  E();
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);     E();
                GL.BindVertexArray(0);   E();
    
                SwapBuffers(); E();
            }
    
            [STAThread]
            public static void Main()
            {
                using (HelloGL3v3 example = new HelloGL3v3())
                {
                    Utilities.SetWindowTitle(example);
                    example.Run(30);
                }
            }
    
            private void E()
            {
                ErrorCode errorCode = GL.GetError();
                if (errorCode == ErrorCode.NoError)
                    return;
    
                throw new Exception("Error code - " + errorCode.ToString()); // some open GL Error
            }
        }
    }
    
0

There are 0 best solutions below