Inheritance: Axiom.Graphics.HardwareBufferManager
        protected void InitGL()
        {
            // intialize GL extensions and check capabilites
            glSupport.InitializeExtensions();

            // log hardware info
            LogManager.Instance.Write("Vendor: {0}", glSupport.Vendor);
            LogManager.Instance.Write("Video Board: {0}", glSupport.VideoCard);
            LogManager.Instance.Write("Version: {0}", glSupport.Version);

            LogManager.Instance.Write("Extensions supported:");

            foreach(string ext in glSupport.Extensions) {
                LogManager.Instance.Write(ext);
            }

            // create our special program manager
            gpuProgramMgr = new GLGpuProgramManager();

            // query hardware capabilites
            CheckCaps();

            // create a specialized instance, which registers itself as the singleton instance of HardwareBufferManager
            // use software buffers as a fallback, which operate as regular vertex arrays
            if(caps.CheckCap(Capabilities.VertexBuffer)) {
                hardwareBufferManager = new GLHardwareBufferManager();
            }
            else {
                hardwareBufferManager = new GLSoftwareBufferManager();
            }

            // by creating our texture manager, singleton TextureManager will hold our implementation
            textureMgr = new GLTextureManager();

            isGLInitialized = true;
        }
        protected void BindVertexElementToGpu(VertexElement elem, HardwareVertexBuffer vertexBuffer, int vertexStart,
                                              IList <int> attribsBound, IList <int> instanceAttribsBound)
        {
            IntPtr pBufferData;
            var    hwGlBuffer = (GLHardwareVertexBuffer)vertexBuffer;

            if (currentCapabilities.HasCapability(Graphics.Capabilities.VertexBuffer))
            {
                Gl.glBindBufferARB(Gl.GL_ARRAY_BUFFER_ARB, hwGlBuffer.GLBufferID);
                pBufferData = BUFFER_OFFSET(elem.Offset);
            }
            else
            {
                // ReSharper disable PossibleInvalidCastException
                pBufferData = ((GLDefaultHardwareVertexBuffer)(vertexBuffer)).DataPtr(elem.Offset);
                // ReSharper restore PossibleInvalidCastException
            }
            if (vertexStart != 0)
            {
                pBufferData = pBufferData.Offset(vertexStart * vertexBuffer.VertexSize);
            }

            var sem            = elem.Semantic;
            var multitexturing = Capabilities.TextureUnitCount > 1;

            var isCustomAttrib = false;

            if (this.currentVertexProgram != null)
            {
                isCustomAttrib = this.currentVertexProgram.IsAttributeValid(sem, (uint)elem.Index);

                if (hwGlBuffer.IsInstanceData)
                {
                    var attrib = this.currentVertexProgram.AttributeIndex(sem, (uint)elem.Index);
                    glVertexAttribDivisor((int)attrib, hwGlBuffer.InstanceDataStepRate);
                    instanceAttribsBound.Add((int)attrib);
                }
            }


            // Custom attribute support
            // tangents, binormals, blendweights etc always via this route
            // builtins may be done this way too
            if (isCustomAttrib)
            {
                var attrib     = this.currentVertexProgram.AttributeIndex(sem, (uint)elem.Index);
                var typeCount  = VertexElement.GetTypeCount(elem.Type);
                var normalised = Gl.GL_FALSE;
                switch (elem.Type)
                {
                case VertexElementType.Color:
                case VertexElementType.Color_ABGR:
                case VertexElementType.Color_ARGB:
                    // Because GL takes these as a sequence of single unsigned bytes, count needs to be 4
                    // VertexElement::getTypeCount treats them as 1 (RGBA)
                    // Also need to normalise the fixed-point data
                    typeCount  = 4;
                    normalised = Gl.GL_TRUE;
                    break;

                default:
                    break;
                }

                Gl.glVertexAttribPointerARB(attrib, typeCount, GLHardwareBufferManager.GetGLType(elem.Type), normalised,
                                            vertexBuffer.VertexSize, pBufferData);
                Gl.glEnableVertexAttribArrayARB(attrib);

                attribsBound.Add((int)attrib);
            }
            else
            {
                // fixed-function & builtin attribute support
                switch (sem)
                {
                case VertexElementSemantic.Position:
                    Gl.glVertexPointer(VertexElement.GetTypeCount(elem.Type), GLHardwareBufferManager.GetGLType(elem.Type),
                                       vertexBuffer.VertexSize, pBufferData);
                    Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
                    break;

                case VertexElementSemantic.Normal:
                    Gl.glNormalPointer(GLHardwareBufferManager.GetGLType(elem.Type), vertexBuffer.VertexSize, pBufferData);
                    Gl.glEnableClientState(Gl.GL_NORMAL_ARRAY);
                    break;

                case VertexElementSemantic.Diffuse:
                    Gl.glColorPointer(4, GLHardwareBufferManager.GetGLType(elem.Type), vertexBuffer.VertexSize, pBufferData);
                    Gl.glEnableClientState(Gl.GL_COLOR_ARRAY);
                    break;

                case VertexElementSemantic.Specular:
                    if (this.GLEW_EXT_secondary_color)
                    {
                        Gl.glSecondaryColorPointerEXT(4, GLHardwareBufferManager.GetGLType(elem.Type), vertexBuffer.VertexSize,
                                                      pBufferData);
                        Gl.glEnableClientState(Gl.GL_SECONDARY_COLOR_ARRAY);
                    }
                    break;

                case VertexElementSemantic.TexCoords:

                    if (this.currentVertexProgram != null)
                    {
                        // Programmable pipeline - direct UV assignment
                        Gl.glClientActiveTextureARB(Gl.GL_TEXTURE0 + elem.Index);
                        Gl.glTexCoordPointer(VertexElement.GetTypeCount(elem.Type), GLHardwareBufferManager.GetGLType(elem.Type),
                                             vertexBuffer.VertexSize, pBufferData);
                        Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
                    }
                    else
                    {
                        // fixed function matching to units based on tex_coord_set
                        for (var i = 0; i < disabledTexUnitsFrom; i++)
                        {
                            // Only set this texture unit's texcoord pointer if it
                            // is supposed to be using this element's index
                            if (this.texCoordIndex[i] != elem.Index || i >= this._fixedFunctionTextureUnits)
                            {
                                continue;
                            }

                            if (multitexturing)
                            {
                                Gl.glClientActiveTextureARB(Gl.GL_TEXTURE0 + i);
                            }
                            Gl.glTexCoordPointer(VertexElement.GetTypeCount(elem.Type), GLHardwareBufferManager.GetGLType(elem.Type),
                                                 vertexBuffer.VertexSize, pBufferData);
                            Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
                        }
                    }
                    break;

                default:
                    break;
                }
            } // isCustomAttrib
        }
        public override void InitializeFromRenderSystemCapabilities(
            RenderSystemCapabilities caps, RenderTarget primary )
        {
            if ( caps.RendersystemName != Name )
            {
                throw new AxiomException(
                    "Trying to initialize GLRenderSystem from RenderSystemCapabilities that do not support OpenGL" );
            }

            // set texture the number of texture units
            _fixedFunctionTextureUnits = caps.TextureUnitCount;

            //In GL there can be less fixed function texture units than general
            //texture units. Get the minimum of the two.
            if ( caps.HasCapability( Graphics.Capabilities.FragmentPrograms ) )
            {
                int maxTexCoords;
                Gl.glGetIntegerv( Gl.GL_MAX_TEXTURE_COORDS_ARB, out maxTexCoords );
                if ( _fixedFunctionTextureUnits > maxTexCoords )
                {
                    _fixedFunctionTextureUnits = maxTexCoords;
                }
            }

            /* Axiom: assume that OpenTK/Tao does this already
             * otherwise we will need to use delegates for these gl calls ..
             * 
            if (caps.HasCapability(Graphics.Capabilities.GL15NoVbo))
            {
                // Assign ARB functions same to GL 1.5 version since
                // interface identical

                Gl.glBindBufferARB = Gl.glBindBuffer;
                Gl.glBufferDataARB = Gl.glBufferData;
                Gl.glBufferSubDataARB = Gl.glBufferSubData;
                Gl.glDeleteBuffersARB = Gl.glDeleteBuffers;
                Gl.glGenBuffersARB = Gl.glGenBuffers;
                Gl.glGetBufferParameterivARB = Gl.glGetBufferParameteriv;
                Gl.glGetBufferPointervARB = Gl.glGetBufferPointerv;
                Gl.glGetBufferSubDataARB = Gl.glGetBufferSubData;
                Gl.glIsBufferARB = Gl.glIsBuffer;
                Gl.glMapBufferARB = Gl.glMapBuffer;
                Gl.glUnmapBufferARB = Gl.glUnmapBuffer;
            }
             */

            if ( caps.HasCapability( Graphics.Capabilities.VertexBuffer ) )
            {

                _hardwareBufferManager = new GLHardwareBufferManager();
            }
            else
            {
                _hardwareBufferManager = new GLDefaultHardwareBufferManager();
            }

            // XXX Need to check for nv2 support and make a program manager for it
            // XXX Probably nv1 as well for older cards
            // GPU Program Manager setup
            gpuProgramMgr = new GLGpuProgramManager();

            if ( caps.HasCapability( Graphics.Capabilities.VertexPrograms ) )
            {
                if ( caps.IsShaderProfileSupported( "arbvp1" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "arbvp1", new ARBGpuProgramFactory() );
                }

                if ( caps.IsShaderProfileSupported( "vp30" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "vp30", new ARBGpuProgramFactory() );
                }

                if ( caps.IsShaderProfileSupported( "vp40" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "vp40", new ARBGpuProgramFactory() );
                }

                if ( caps.IsShaderProfileSupported( "gp4vp" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "gp4vp", new ARBGpuProgramFactory() );
                }

                if ( caps.IsShaderProfileSupported( "gpu_vp" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "gpu_vp", new ARBGpuProgramFactory() );
                }
            }

            if ( caps.HasCapability( Graphics.Capabilities.GeometryPrograms ) )
            {
                //TODO : Should these be createGLArbGpuProgram or createGLGpuNVparseProgram?
                if ( caps.IsShaderProfileSupported( "nvgp4" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "nvgp4", new ARBGpuProgramFactory() );
                }
                if ( caps.IsShaderProfileSupported( "gp4gp" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "gp4gp", new ARBGpuProgramFactory() );
                }
                if ( caps.IsShaderProfileSupported( "gpu_gp" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "gpu_gp", new ARBGpuProgramFactory() );
                }
            }

            if ( caps.HasCapability( Graphics.Capabilities.FragmentPrograms ) )
            {

                if ( caps.IsShaderProfileSupported( "fp20" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "fp20", new Nvidia.NvparseProgramFactory() );
                }

                if ( caps.IsShaderProfileSupported( "ps_1_4" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "ps_1_4", new ATI.ATIFragmentShaderFactory() );
                }

                if ( caps.IsShaderProfileSupported( "ps_1_3" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "ps_1_3", new ATI.ATIFragmentShaderFactory() );
                }

                if ( caps.IsShaderProfileSupported( "ps_1_2" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "ps_1_2", new ATI.ATIFragmentShaderFactory() );
                }

                if ( caps.IsShaderProfileSupported( "ps_1_1" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "ps_1_1", new ATI.ATIFragmentShaderFactory() );
                }

                if ( caps.IsShaderProfileSupported( "arbfp1" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "arbfp1", new ARBGpuProgramFactory() );
                }

                if ( caps.IsShaderProfileSupported( "fp40" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "fp40", new ARBGpuProgramFactory() );
                }

                if ( caps.IsShaderProfileSupported( "fp30" ) )
                {
                    gpuProgramMgr.RegisterProgramFactory( "fp30", new ARBGpuProgramFactory() );
                }

            }

            if ( caps.IsShaderProfileSupported( "glsl" ) )
            {
                // NFZ - check for GLSL vertex and fragment shader support successful
                _GLSLProgramFactory = new GLSL.GLSLProgramFactory();
                HighLevelGpuProgramManager.Instance.AddFactory( _GLSLProgramFactory );
                LogManager.Instance.Write( "GLSL support detected" );
            }

            /* Axiom: assume that OpenTK/Tao does this already
             * otherwise we will need to use delegates for these gl calls ..
             * 
            if ( caps.HasCapability( Graphics.Capabilities.HardwareOcculusion ) )
            {
                if ( caps.HasCapability( Graphics.Capabilities.GL15NoHardwareOcclusion ) )
                {
                    // Assign ARB functions same to GL 1.5 version since
                    // interface identical
                    Gl.glBeginQueryARB = Gl.glBeginQuery;
                    Gl.glDeleteQueriesARB = Gl.glDeleteQueries;
                    Gl.glEndQueryARB = Gl.glEndQuery;
                    Gl.glGenQueriesARB = Gl.glGenQueries;
                    Gl.glGetQueryObjectivARB = Gl.glGetQueryObjectiv;
                    Gl.glGetQueryObjectuivARB = Gl.glGetQueryObjectuiv;
                    Gl.glGetQueryivARB = Gl.glGetQueryiv;
                    Gl.glIsQueryARB = Gl.glIsQuery;
                }
            }
             */

            // Do this after extension function pointers are initialised as the extension
            // is used to probe further capabilities.
            ConfigOption cfi;
            var rttMode = 0;
            if ( ConfigOptions.TryGetValue( "RTT Preferred Mode", out cfi ) )
            {
                if ( cfi.Value == "PBuffer" )
                {
                    rttMode = 1;
                }
                else if ( cfi.Value == "Copy" )
                {
                    rttMode = 2;
                }
            }


            // Check for framebuffer object extension
		    if(caps.HasCapability(Graphics.Capabilities.FrameBufferObjects) && rttMode < 1)
		    {
			    // Before GL version 2.0, we need to get one of the extensions
			    //if(caps.HasCapability(Graphics.Capabilities.FrameBufferObjectsARB))
				//    GLEW_GET_FUN(__glewDrawBuffers) = Gl.glDrawBuffersARB;
			    //else if(caps.HasCapability(Graphics.Capabilities.FrameBufferObjectsATI))
				//    GLEW_GET_FUN(__glewDrawBuffers) = Gl.glDrawBuffersATI;

			    if(caps.HasCapability(Graphics.Capabilities.HardwareRenderToTexture))
			    {
				    // Create FBO manager
				    LogManager.Instance.Write("GL: Using GL_EXT_framebuffer_object for rendering to textures (best)");
				    rttManager = new GLFBORTTManager(_glSupport, false);
				    caps.SetCapability(Graphics.Capabilities.RTTSerperateDepthBuffer);

				    //TODO: Check if we're using OpenGL 3.0 and add RSC_RTT_DEPTHBUFFER_RESOLUTION_LESSEQUAL flag
			    }
		    } 
            else
		    {
		        // Check GLSupport for PBuffer support
		        if ( caps.HasCapability( Graphics.Capabilities.PBuffer ) && rttMode < 2 )
		        {
		            if ( caps.HasCapability( Graphics.Capabilities.HardwareRenderToTexture ) )
		            {
		                // Use PBuffers
		                rttManager = new GLPBRTTManager( _glSupport, primary );
		                LogManager.Instance.Write( "GL: Using PBuffers for rendering to textures" );

		                //TODO: Depth buffer sharing in pbuffer is left unsupported
		            }
		        }
		        else
		        {
		            // No pbuffer support either -- fallback to simplest copying from framebuffer
		            rttManager = new GLCopyingRTTManager(_glSupport);
		            LogManager.Instance.Write( "GL: Using framebuffer copy for rendering to textures (worst)" );
		            LogManager.Instance.Write(
		                "GL: Warning: RenderTexture size is restricted to size of framebuffer. If you are on Linux, consider using GLX instead of SDL." );

		            //Copy method uses the main depth buffer but no other depth buffer
		            caps.SetCapability( Graphics.Capabilities.RTTMainDepthbufferAttachable );
		            caps.SetCapability( Graphics.Capabilities.RTTDepthbufferResolutionLessEqual );
		        }

		        // Downgrade number of simultaneous targets
		        caps.MultiRenderTargetCount = 1;
		    }

            var defaultLog = LogManager.Instance.DefaultLog;
		    if (defaultLog != null)
		    {
			    caps.Log(defaultLog);
		    }

		    // Create the texture manager        
		    textureManager = new GLTextureManager(_glSupport); 

		    _glInitialised = true;
        }