/// <summary>
        /// Binds the geometry stream's buffers to the device in preparation for rendering.
        /// </summary>
        private void BindBuffers(UInt32?program, UInt32?offset)
        {
            unsafe
            {
                var previousBuffer = (uint)OpenGLState.GL_ARRAY_BUFFER_BINDING;

                if (IsUsingVertexArrayObject)
                {
                    using (OpenGLState.ScopedBindVertexArrayObject(vao, glElementArrayBufferBinding ?? 0, force: !gl.IsVertexAttribBindingAvailable))
                    {
                        if (program.HasValue)
                        {
                            DisableVertexAttributesOnCachedProgram();
                        }

                        if (gl.IsVertexAttribBindingAvailable)
                        {
                            for (int i = 0; i < vbuffers.Count; i++)
                            {
                                var binding = vbuffers[i];
                                BindVertexAttributesForBuffer_NewAPI(binding.VertexBuffer,
                                                                     (UInt32)i, (UInt32)binding.InstanceFrequency, program, offset);
                            }
                        }
                        else
                        {
                            for (int i = 0; i < vbuffers.Count; i++)
                            {
                                var binding = vbuffers[i];
                                BindVertexAttributesForBuffer_OldAPI(binding.VertexBuffer,
                                                                     (UInt32)i, (UInt32)binding.InstanceFrequency, program, offset);
                            }
                        }
                    }
                }
                else
                {
                    if (program.HasValue)
                    {
                        DisableVertexAttributesOnCachedProgram();
                    }

                    for (int i = 0; i < vbuffers.Count; i++)
                    {
                        var binding = vbuffers[i];
                        BindVertexAttributesForBuffer_OldAPI(binding.VertexBuffer,
                                                             (UInt32)i, (UInt32)binding.InstanceFrequency, program, offset);
                    }

                    OpenGLState.BindArrayBuffer(previousBuffer);
                }
            }
        }
        /// <summary>
        /// Binds the specified buffer's vertex attributes to the currently cached program using the old API.
        /// </summary>
        private unsafe void BindVertexAttributesForBuffer_OldAPI(OpenGLVertexBuffer vbuffer, UInt32 binding, UInt32 frequency, UInt32?program, UInt32?offset)
        {
            OpenGLState.BindArrayBuffer(vbuffer.OpenGLName);

            var position = offset ?? this.offset;

            foreach (var element in vbuffer.VertexDeclaration)
            {
                var name      = GetVertexAttributeNameFromUsage(element.Usage, element.Index);
                var size      = 0;
                var stride    = 0;
                var normalize = false;
                var type      = GetVertexFormatGL(element.Format, out size, out stride, out normalize);

                var category = OpenGLAttribCategory.Single;
                var location = (UInt32)OpenGLState.CurrentProgram.GetAttribLocation(name, out category);
                if (location >= 0)
                {
                    if (program.HasValue)
                    {
                        if (gl.IsInstancedRenderingAvailable)
                        {
                            gl.VertexAttribDivisor(location, frequency);
                            gl.ThrowIfError();
                        }
                        else
                        {
                            if (frequency != 0)
                            {
                                throw new NotSupportedException(OpenGLStrings.InstancedRenderingNotSupported);
                            }
                        }

                        gl.EnableVertexAttribArray(location);
                        gl.ThrowIfError();
                    }

                    switch (category)
                    {
                    case OpenGLAttribCategory.Single:
                    {
                        gl.VertexAttribPointer(location, size, type, normalize, vbuffer.VertexDeclaration.VertexStride, (void *)(position));
                        gl.ThrowIfError();
                    }
                    break;

                    case OpenGLAttribCategory.Double:
                    {
                        if (!gl.IsDoublePrecisionVertexAttribAvailable)
                        {
                            throw new NotSupportedException(OpenGLStrings.DoublePrecisionVAttribsNotSupported);
                        }

                        gl.VertexAttribLPointer(location, size, type, vbuffer.VertexDeclaration.VertexStride, (void *)(position));
                        gl.ThrowIfError();
                    }
                    break;

                    case OpenGLAttribCategory.Integer:
                    {
                        if (!gl.IsIntegerVertexAttribAvailable)
                        {
                            throw new NotSupportedException(OpenGLStrings.IntegerVAttribsNotSupported);
                        }

                        gl.VertexAttribIPointer(location, size, type, vbuffer.VertexDeclaration.VertexStride, (void *)(position));
                        gl.ThrowIfError();
                    }
                    break;
                    }
                }

                position += (uint)stride;
            }
        }