private void SetVertexAttributes(OpenGLVertexInputLayout inputlayout, VertexBuffer[] vertexBuffers)
        {
            int totalSlotsBound = 0;

            for (int i = 0; i < inputlayout.VBLayoutsBySlot.Length; i++)
            {
                OpenGLVertexInput  input = inputlayout.VBLayoutsBySlot[i];
                OpenGLVertexBuffer vb    = ((OpenGLVertexBuffer)vertexBuffers[i]);
                vb.Apply();
                for (int slot = 0; slot < input.Elements.Length; slot++)
                {
                    ref OpenGLVertexInputElement element = ref input.Elements[slot]; // Large structure -- use by reference.
                    int actualSlot = totalSlotsBound + slot;
                    if (actualSlot >= _vertexAttributesBound)
                    {
                        GL.EnableVertexAttribArray(actualSlot);
                    }
                    GL.VertexAttribPointer(actualSlot, element.ElementCount, element.Type, element.Normalized, vb.Stride, element.Offset);

                    int stepRate = element.InstanceStepRate;
                    if (_vertexAttribDivisors[actualSlot] != stepRate)
                    {
                        GL.VertexAttribDivisor(actualSlot, stepRate);
                        _vertexAttribDivisors[actualSlot] = stepRate;
                    }
                }

                totalSlotsBound += input.Elements.Length;
            }
        public OpenGLShaderSet(
            OpenGLVertexInputLayout inputLayout,
            OpenGLShader vertexShader,
            OpenGLShader tessellationControlShader,
            OpenGLShader tessellationEvaluationShader,
            OpenGLShader geometryShader,
            OpenGLShader fragmentShader)
        {
            InputLayout  = inputLayout;
            VertexShader = vertexShader;
            TessellationControlShader    = tessellationControlShader;
            TessellationEvaluationShader = tessellationEvaluationShader;
            GeometryShader = geometryShader;
            FragmentShader = fragmentShader;

            ProgramID = GL.CreateProgram();
            GL.AttachShader(ProgramID, vertexShader.ShaderID);
            if (tessellationControlShader != null)
            {
                GL.AttachShader(ProgramID, tessellationControlShader.ShaderID);
            }
            if (tessellationEvaluationShader != null)
            {
                GL.AttachShader(ProgramID, tessellationEvaluationShader.ShaderID);
            }
            if (geometryShader != null)
            {
                GL.AttachShader(ProgramID, geometryShader.ShaderID);
            }
            GL.AttachShader(ProgramID, fragmentShader.ShaderID);

            int slot = 0;

            foreach (var input in inputLayout.InputDescriptions)
            {
                for (int i = 0; i < input.Elements.Length; i++)
                {
                    GL.BindAttribLocation(ProgramID, slot, input.Elements[i].Name);
                    slot += 1;
                }
            }

            GL.LinkProgram(ProgramID);

            int linkStatus;

            GL.GetProgram(ProgramID, GetProgramParameterName.LinkStatus, out linkStatus);
            if (linkStatus != 1)
            {
                string log = GL.GetProgramInfoLog(ProgramID);
                throw new VeldridException($"Error linking GL program: {log}");
            }
        }
        public OpenGLShaderSet(
            OpenGLVertexInputLayout inputLayout,
            OpenGLShader vertexShader,
            OpenGLShader tessellationControlShader,
            OpenGLShader tessellationEvaluationShader,
            OpenGLShader geometryShader,
            OpenGLShader fragmentShader)
        {
            InputLayout  = inputLayout;
            VertexShader = vertexShader;
            TessellationControlShader    = tessellationControlShader;
            TessellationEvaluationShader = tessellationEvaluationShader;
            GeometryShader = geometryShader;
            FragmentShader = fragmentShader;

            ProgramID = GL.CreateProgram();
            GL.AttachShader(ProgramID, vertexShader.ShaderID);
            if (tessellationControlShader != null)
            {
                GL.AttachShader(ProgramID, tessellationControlShader.ShaderID);
            }
            if (tessellationEvaluationShader != null)
            {
                GL.AttachShader(ProgramID, tessellationEvaluationShader.ShaderID);
            }
            if (geometryShader != null)
            {
                GL.AttachShader(ProgramID, geometryShader.ShaderID);
            }
            GL.AttachShader(ProgramID, fragmentShader.ShaderID);

            int slot = 0;

            foreach (VertexInputDescription input in inputLayout.InputDescriptions)
            {
                for (int i = 0; i < input.Elements.Length; i++)
                {
                    GL.BindAttribLocation(ProgramID, slot, input.Elements[i].Name);
                    slot += 1;
                }
            }

            GL.LinkProgram(ProgramID);

#if DEBUG && GL_VALIDATE_VERTEX_INPUT_ELEMENTS
            slot = 0;
            foreach (VertexInputDescription input in inputLayout.InputDescriptions)
            {
                for (int i = 0; i < input.Elements.Length; i++)
                {
                    int location = GL.GetAttribLocation(ProgramID, input.Elements[i].Name);
                    if (location == -1)
                    {
                        throw new VeldridException("There was no attribute variable with the name " + input.Elements[i].Name);
                    }
                    slot += 1;
                }
            }
#endif

            int linkStatus;
            GL.GetProgram(ProgramID, GetProgramParameterName.LinkStatus, out linkStatus);
            if (linkStatus != 1)
            {
                string log = GL.GetProgramInfoLog(ProgramID);
                throw new VeldridException($"Error linking GL program: {log}");
            }
        }