/// <summary> /// Makes a program object active by making sure it is linked and then putting it in use. /// </summary> public void Activate() { if (!this.linked && !this.triedToLinkAndFailed) { Gl.glGetError(); //Clean up the error. Otherwise will flood log. this.glHandle = Gl.glCreateProgramObjectARB(); GLSLHelper.CheckForGLSLError("Error Creating GLSL Program Object", 0); // TODO: support microcode caching //if (GpuProgramManager.Instance.CanGetCompiledShaderBuffer() && // GpuProgramManager.Instance.IsMicrocodeAvailableInCache(CombinedName)) if (false) { GetMicrocodeFromCache(); } else { CompileAndLink(); } BuildUniformReferences(); ExtractAttributes(); } if (this.linked) { GLSLHelper.CheckForGLSLError("Error prior to using GLSL Program Object : ", this.glHandle, false, false); Gl.glUseProgramObjectARB(this.glHandle); GLSLHelper.CheckForGLSLError("Error using GLSL Program Object : ", this.glHandle, false, false); } }
/// <summary> /// Default constructor. /// </summary> public GLSLLinkProgram() { GLSLHelper.CheckForGLSLError("Error prior to creating GLSL program object.", 0); // create the shader program object glHandle = Gl.glCreateProgramObjectARB(); GLSLHelper.CheckForGLSLError("Error Creating GLSL Program Object", 0); }
/// <summary> /// /// </summary> protected override void LoadFromSource() { Gl.glShaderSourceARB(glHandle, 1, ref source, null); // check for load errors GLSLHelper.CheckForGLSLError("Cannot load GLGL high-level shader source " + name, 0); Compile(); }
///<summary> ///</summary> ///<param name="programObject"></param> public void DetachFromProgramObject(int programObject) { Gl.glDetachObjectARB(programObject, GLHandle); GLSLHelper.CheckForGLSLError("Error detaching " + Name + " shader object from GLSL Program Object", programObject); // attach child objects foreach (var childShader in this.attachedGLSLPrograms.Cast <GLSLProgram>()) { childShader.DetachFromProgramObject(programObject); } }
/// <summary> /// /// </summary> /// <param name="programObject"></param> public void AttachToProgramObject(int programObject) { // atach child objects foreach (var childShader in this.attachedGLSLPrograms.Cast <GLSLProgram>()) { // bug in ATI GLSL linker : modules without main function must be recompiled each time // they are linked to a different program object // don't check for compile errors since there won't be any // *** minor inconvenience until ATI fixes thier driver childShader.Compile(false); childShader.AttachToProgramObject(programObject); } Gl.glAttachObjectARB(programObject, GLHandle); GLSLHelper.CheckForGLSLError("GLSL : Error attaching " + Name + " shader object to GLSL Program Object.", programObject); }
/// <summary> /// Constructor. /// </summary> public GLSLProgram(string name, GpuProgramType type, string language) : base(name, type, language) { // want scenemanager to pass on surface and light states to the rendersystem // these can be accessed in GLSL passSurfaceAndLightStates = true; // only create a shader object if glsl is supported if (IsSupported) { GLSLHelper.CheckForGLSLError("GL Errors before creating shader object.", 0); // create shader object glHandle = Gl.glCreateShaderObjectARB(type == GpuProgramType.Vertex ? Gl.GL_VERTEX_SHADER_ARB : Gl.GL_FRAGMENT_SHADER_ARB); GLSLHelper.CheckForGLSLError("GL Errors creating shader object.", 0); } }
/// <summary> /// /// </summary> /// <param name="programObject"></param> public void AttachToProgramObject(int programObject) { Gl.glAttachObjectARB(programObject, glHandle); GLSLHelper.CheckForGLSLError("Error attaching " + this.name + " shader object to GLSL Program Object.", programObject); // atach child objects for (int i = 0; i < attachedGLSLPrograms.Count; i++) { GLSLProgram childShader = (GLSLProgram)attachedGLSLPrograms[i]; // bug in ATI GLSL linker : modules without main function must be recompiled each time // they are linked to a different program object // don't check for compile errors since there won't be any // *** minor inconvenience until ATI fixes there driver childShader.Compile(false); childShader.AttachToProgramObject(programObject); } }
/// <summary> /// Makes a program object active by making sure it is linked and then putting it in use. /// </summary> public void Activate() { if(!linked) { int linkStatus; Gl.glLinkProgramARB(glHandle); Gl.glGetObjectParameterivARB(glHandle, Gl.GL_OBJECT_LINK_STATUS_ARB, out linkStatus); linked = (linkStatus != 0); // force logging and raise exception if not linked GLSLHelper.CheckForGLSLError("Error linking GLSL Program Object", glHandle, !linked, !linked); if(linked) { GLSLHelper.LogObjectInfo("GLSL link result : ", glHandle); BuildUniformReferences(); } } if(linked) { Gl.glUseProgramObjectARB(glHandle); } }
/// <summary> /// /// </summary> /// <param name="checkErrors"></param> protected bool Compile(bool checkErrors) { Gl.glCompileShaderARB(glHandle); int compiled; // check for compile errors Gl.glGetObjectParameterivARB(glHandle, Gl.GL_OBJECT_COMPILE_STATUS_ARB, out compiled); isCompiled = (compiled != 0); // force exception if not compiled if (checkErrors) { GLSLHelper.CheckForGLSLError("Cannot compile GLSL high-level shader: " + name + " ", glHandle, !isCompiled, !isCompiled); if (isCompiled) { GLSLHelper.LogObjectInfo(name + " : GLGL compiled ", glHandle); } } return(isCompiled); }
protected internal bool Compile(bool checkErrors) { if (this.isCompiled) { return(true); } if (checkErrors) { GLSLHelper.LogObjectInfo("GLSL compiling: " + Name, GLHandle); } if (IsSupported) { GLSLHelper.CheckForGLSLError("GL Errors before creating shader object", 0); var shaderType = 0; switch (Type) { case GpuProgramType.Vertex: shaderType = Gl.GL_VERTEX_SHADER_ARB; break; case GpuProgramType.Fragment: shaderType = Gl.GL_FRAGMENT_SHADER_ARB; break; case GpuProgramType.Geometry: shaderType = Gl.GL_GEOMETRY_SHADER_EXT; break; } GLHandle = Gl.glCreateShaderObjectARB(shaderType); GLSLHelper.CheckForGLSLError("Error creating GLSL shader object", 0); } // Preprocess the GLSL shader in order to get a clean source // CPreprocessor cpp; // TODO: preprocessor not supported yet in axiom // Add preprocessor extras and main source if (!string.IsNullOrEmpty(source)) { Gl.glShaderSourceARB(GLHandle, 1, new[] { source }, new[] { source.Length }); // check for load errors GLSLHelper.CheckForGLSLError("Cannot load GLSL high-level shader source : " + Name, 0); } Gl.glCompileShaderARB(GLHandle); int compiled; // check for compile errors Gl.glGetObjectParameterivARB(GLHandle, Gl.GL_OBJECT_COMPILE_STATUS_ARB, out compiled); this.isCompiled = (compiled != 0); // force exception if not compiled if (checkErrors) { GLSLHelper.CheckForGLSLError("GLSL : Cannot compile GLSL high-level shader: " + Name + ".", GLHandle, !this.isCompiled, !this.isCompiled); if (this.isCompiled) { GLSLHelper.LogObjectInfo("GLSL : " + Name + " : compiled.", GLHandle); } } return(this.isCompiled); }
private void CompileAndLink() { if (this.vertexProgram != null) { // compile and attach Vertex Program if (!this.vertexProgram.GLSLProgram.Compile(true)) { // todo error return; } this.vertexProgram.GLSLProgram.AttachToProgramObject(this.glHandle); IsSkeletalAnimationIncluded = this.vertexProgram.IsSkeletalAnimationIncluded; // Some drivers (e.g. OS X on nvidia) incorrectly determine the attribute binding automatically // and end up aliasing existing built-ins. So avoid! // Bind all used attribs - not all possible ones otherwise we'll get // lots of warnings in the log, and also may end up aliasing names used // as varyings by accident // Because we can't ask GL whether an attribute is used in the shader // until it is linked (chicken and egg!) we have to parse the source var vpSource = this.vertexProgram.GLSLProgram.Source; foreach (var a in this.sCustomAttributes) { // we're looking for either: // attribute vec<n> <semantic_name> // in vec<n> <semantic_name> // The latter is recommended in GLSL 1.3 onwards // be slightly flexible about formatting var pos = vpSource.IndexOf(a.name); if (pos != -1) { var startpos = vpSource.IndexOf("attribute", pos < 20 ? 0 : pos - 20); if (startpos == -1) { startpos = vpSource.IndexOf("in", pos < 20 ? 0 : pos - 20); } if (startpos != -1 && startpos < pos) { // final check var expr = vpSource.Substring(startpos, pos + a.name.Length - startpos); var vec = expr.Split(); if ((vec[0] == "in" || vec[0] == "attribute") && vec[2] == a.name) { Gl.glBindAttribLocationARB(this.glHandle, (int)a.attrib, a.name); } } } } } if (this.geometryProgram != null) { // compile and attach Geometry Program if (!this.geometryProgram.GLSLProgram.Compile(true)) { // todo error return; } this.geometryProgram.GLSLProgram.AttachToProgramObject(this.glHandle); //Don't set adjacency flag. We handle it internally and expose "false" OperationType inputOperationType = this.geometryProgram.GLSLProgram.InputOperationType; Gl.glProgramParameteriEXT(this.glHandle, Gl.GL_GEOMETRY_INPUT_TYPE_EXT, GetGLGeometryInputPrimitiveType(inputOperationType, this.geometryProgram.IsAdjacencyInfoRequired)); OperationType outputOperationType = this.geometryProgram.GLSLProgram.OutputOperationType; switch (outputOperationType) { case OperationType.PointList: case OperationType.LineStrip: case OperationType.TriangleStrip: case OperationType.LineList: case OperationType.TriangleList: case OperationType.TriangleFan: break; } Gl.glProgramParameteriEXT(this.glHandle, Gl.GL_GEOMETRY_OUTPUT_TYPE_EXT, GetGLGeometryOutputPrimitiveType(outputOperationType)); Gl.glProgramParameteriEXT(this.glHandle, Gl.GL_GEOMETRY_VERTICES_OUT_EXT, this.geometryProgram.GLSLProgram.MaxOutputVertices); } if (this.fragmentProgram != null) { if (!this.fragmentProgram.GLSLProgram.Compile(true)) { // todo error return; } this.fragmentProgram.GLSLProgram.AttachToProgramObject(this.glHandle); } // now the link Gl.glLinkProgramARB(this.glHandle); int linkStatus; Gl.glGetObjectParameterivARB(this.glHandle, Gl.GL_OBJECT_LINK_STATUS_ARB, out linkStatus); this.linked = linkStatus != 0; this.triedToLinkAndFailed = !this.linked; GLSLHelper.CheckForGLSLError("Error linking GLSL Program Object", this.glHandle, !this.linked, !this.linked); if (this.linked) { GLSLHelper.LogObjectInfo(CombinedName + " GLSL link result : ", this.glHandle); // TODO: cache the microcode. // OpenTK is not up to date yet for this. // We need deeper engine updates for this as well /* * if (GpuProgramManager.Instance.SaveMicrocodesToCache) * { * // add to the microcode to the cache * var name = CombinedName; * * // get buffer size * int binaryLength; * Gl.glGetProgramiv( glHandle, Gl.GL_PROGRAM_BINARY_LENGTH, out binaryLength ); * * // turns out we need this param when loading * // it will be the first bytes of the array in the microcode * int binaryFormat; * * // create microcode * GpuProgramManager.Microcode newMicrocode = * GpuProgramManager.Instance.CreateMicrocode( binaryLength + sizeof ( GLenum ) ); * * // get binary * uint8* programBuffer = newMicrocode->getPtr() + sizeof ( GLenum ); * glGetProgramBinary( mGLHandle, binaryLength, NULL, &binaryFormat, programBuffer ); * * // save binary format * memcpy( newMicrocode->getPtr(), &binaryFormat, sizeof ( GLenum ) ); * * // add to the microcode to the cache * GpuProgramManager::getSingleton().addMicrocodeToCache( name, newMicrocode ); * }*/ } }
/// <summary> /// Updates program object uniforms using data from GpuProgramParameters. /// normally called by GLSLGpuProgram.BindParameters() just before rendering occurs. /// </summary> /// <param name="parameters">GPU Parameters to use to update the uniforms params.</param> public void UpdateUniforms(GpuProgramParameters parameters, GpuProgramParameters.GpuParamVariability mask, GpuProgramType fromProgType) { foreach (var currentUniform in this.uniformReferences) { // Only pull values from buffer it's supposed to be in (vertex or fragment) // This method will be called twice, once for vertex program params, // and once for fragment program params. if (fromProgType == currentUniform.SourceProgType) { var def = currentUniform.ConstantDef; if ((def.Variability & mask) != 0) { var glArraySize = def.ArraySize; // get the index in the parameter real list switch (def.ConstantType) { case GpuProgramParameters.GpuConstantType.Float1: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniform1fvARB(currentUniform.Location, glArraySize, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Float2: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniform2fvARB(currentUniform.Location, glArraySize, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Float3: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniform3fvARB(currentUniform.Location, glArraySize, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Float4: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniform4fvARB(currentUniform.Location, glArraySize, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_2X2: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix2fvARB(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_2X3: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix2x3fv(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_2X4: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix2x4fv(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_3X2: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix3x2fv(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_3X3: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix3fv(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_3X4: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix3x4fv(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_4X2: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix4x2fv(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_4X3: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix4x3fv(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Matrix_4X4: using (var ptr = parameters.GetFloatPointer(def.PhysicalIndex)) { Gl.glUniformMatrix4fv(currentUniform.Location, glArraySize, 1, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Int1: using (var ptr = parameters.GetIntPointer(def.PhysicalIndex)) { Gl.glUniform1ivARB(currentUniform.Location, glArraySize, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Int2: using (var ptr = parameters.GetIntPointer(def.PhysicalIndex)) { Gl.glUniform2ivARB(currentUniform.Location, glArraySize, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Int3: using (var ptr = parameters.GetIntPointer(def.PhysicalIndex)) { Gl.glUniform3ivARB(currentUniform.Location, glArraySize, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Int4: using (var ptr = parameters.GetIntPointer(def.PhysicalIndex)) { Gl.glUniform4ivARB(currentUniform.Location, glArraySize, ptr.Pointer.Pin()); } break; case GpuProgramParameters.GpuConstantType.Sampler1D: case GpuProgramParameters.GpuConstantType.Sampler1DShadow: case GpuProgramParameters.GpuConstantType.Sampler2D: case GpuProgramParameters.GpuConstantType.Sampler2DShadow: case GpuProgramParameters.GpuConstantType.Sampler3D: case GpuProgramParameters.GpuConstantType.SamplerCube: var value = parameters.GetIntConstant(def.PhysicalIndex); Gl.glUniform1iARB(currentUniform.Location, value); break; case GpuProgramParameters.GpuConstantType.Unknown: break; } // end switch GLSLHelper.CheckForGLSLError("GLSLLinkProgram::updateUniforms", 0); } // variability & mask } // fromProgType == currentUniform->mSourceProgType } // end for }