internal override void WriteSourceCode(System.IO.StreamWriter stream, Program program) { var gpuType = program.Type; if (gpuType == GpuProgramType.Geometry) { throw new Core.AxiomException("Geometry Programs not supported in GLSL ES writer"); } this.fragInputParams.Clear(); var functionList = program.Functions; var parameterList = program.Parameters; // Write the current version (this forces the driver to fulfill the glsl es standard) stream.WriteLine("#version" + this.glslVersion.ToString()); //Default precision declaration is required in fragment and vertex shaders. stream.WriteLine("precision highp float"); stream.WriteLine("precision highp int"); //Generate source code header WriteProgramTitle(stream, program); stream.WriteLine(); //Embed depndencies. WriteProgramDependencies(stream, program); stream.WriteLine(); //Generate global variable code. WriteUniformParametersTitle(stream, program); stream.WriteLine(); //Write the uniforms foreach (var uniformParams in parameterList) { stream.Write("uniform\t"); stream.Write(this.gpuConstTypeMap[uniformParams.Type]); stream.Write("\t"); stream.Write(uniformParams.Name); if (uniformParams.IsArray) { stream.Write("[" + uniformParams.Size.ToString() + "]"); } stream.WriteLine(";"); } stream.WriteLine(); //Write program function(s) foreach (var curFunction in functionList) { WriteFunctionTitle(stream, curFunction); this.inputToGLStatesMap.Clear(); WriteInputParameters(stream, curFunction, gpuType); WriteOutParameters(stream, curFunction, gpuType); stream.WriteLine("void main() {"); if (gpuType == GpuProgramType.Fragment) { stream.WriteLine("\tvec4 outputColor;"); } else if (gpuType == GpuProgramType.Vertex) { stream.WriteLine("\tvec4 outputPosition;"); } //Write local paraemters var localParam = curFunction.LocalParameters; foreach (var itParam in localParam) { stream.Write("\t"); WriteLocalParameter(stream, itParam); stream.WriteLine(";"); } stream.WriteLine(); //sort function atoms curFunction.SortAtomInstances(); var atomInstances = curFunction.AtomInstances; foreach (var itAtom in atomInstances) { var funcInvoc = (FunctionInvocation)itAtom; int itOperand = 0; int itOperandEnd = funcInvoc.OperandList.Count; var localOs = new StringBuilder(); localOs.Append("\t" + funcInvoc.FunctionName + "("); int curIndLevel = 0; while (itOperand != itOperandEnd) { Operand op = funcInvoc.OperandList[itOperand]; Operand.OpSemantic opSemantic = op.Semantic; string paramName = op.Parameter.Name; Parameter.ContentType content = op.Parameter.Content; // Check if we write to a varying because the are only readable in fragment programs if (opSemantic == Operand.OpSemantic.Out || opSemantic == Operand.OpSemantic.InOut) { bool isVarying = false; if (gpuType == GpuProgramType.Fragment) { if (this.fragInputParams.Contains(paramName)) { //Declare the copy variable string newVar = "local_" + paramName; string tempVar = paramName; isVarying = true; // We stored the original values in the mFragInputParams thats why we have to replace the first var with o // because all vertex output vars are prefixed with o in glsl the name has to match in the fragment program. tempVar.Remove(0); tempVar.Insert(0, "o"); //Declare the copy variable and assign the original stream.WriteLine("\t" + this.gpuConstTypeMap[op.Parameter.Type] + " " + newVar + " = " + tempVar + ";\n"); //Fromnow on we replace it automatic this.inputToGLStatesMap.Add(paramName, newVar); this.fragInputParams.Remove(paramName); } } if (!isVarying) { foreach (var param in parameterList) { if (CompareUniformByName(param, paramName)) { string newVar = "local_" + paramName; if (this.inputToGLStatesMap.ContainsKey(newVar) == false) { //Declare the copy variable and assign the original stream.WriteLine("\t" + this.gpuConstTypeMap[param.Type] + " " + newVar + " = " + paramName + ";\n"); //From now on we replace it automatic this.inputToGLStatesMap.Add(paramName, newVar); } } } } string newParam; if (this.inputToGLStatesMap.ContainsKey(paramName)) { int mask = op.Mask; //our swizzle mask //Here we insert the renamed param name newParam = this.inputToGLStatesMap[paramName]; if (mask != (int)Operand.OpMask.All) { newParam += "." + Operand.GetMaskAsString(mask); } // Now that every texcoord is a vec4 (passed as vertex attributes) we // have to swizzle them according the desired type. else if (gpuType == GpuProgramType.Vertex && content == Parameter.ContentType.TextureCoordinate0 || content == Parameter.ContentType.TextureCoordinate1 || content == Parameter.ContentType.TextureCoordinate2 || content == Parameter.ContentType.TextureCoordinate3 || content == Parameter.ContentType.TextureCoordinate4 || content == Parameter.ContentType.TextureCoordinate5 || content == Parameter.ContentType.TextureCoordinate6 || content == Parameter.ContentType.TextureCoordinate7) { //Now generate the swizzle mask according // the type. switch (op.Parameter.Type) { case GpuProgramParameters.GpuConstantType.Float1: newParam += ".x"; break; case GpuProgramParameters.GpuConstantType.Float2: newParam += ".xy"; break; case GpuProgramParameters.GpuConstantType.Float3: newParam += ".xyz"; break; case GpuProgramParameters.GpuConstantType.Float4: newParam += ".xyzw"; break; default: break; } } } else { newParam = op.ToString(); } itOperand++; //Prepare for the next operand localOs.Append(newParam); int opIndLevel = 0; if (itOperand != itOperandEnd) { opIndLevel = funcInvoc.OperandList[itOperand].IndirectionLevel; } if (curIndLevel != 0) { localOs.Append(")"); } if (curIndLevel < opIndLevel) { while (curIndLevel < opIndLevel) { curIndLevel++; localOs.Append("["); } } else { while (curIndLevel > opIndLevel) { curIndLevel--; localOs.Append("]"); } if (opIndLevel != 0) { localOs.Append("]["); } else if (itOperand != itOperandEnd) { localOs.Append(", "); } } if (curIndLevel != 0) { localOs.Append("int("); } } //Write function call closer localOs.AppendLine(");"); localOs.AppendLine(); stream.Write(localOs.ToString()); } } if (gpuType == GpuProgramType.Fragment) { stream.WriteLine("\tgl_FragColor = outputColor;"); } else if (gpuType == GpuProgramType.Vertex) { stream.WriteLine("\tgl_Position = outputPosition;"); } stream.WriteLine("}"); } stream.WriteLine(); }
private FunctionInvocation CreateInvocationFromString(string input) { string functionName, returnType; FunctionInvocation invoc = null; //Get the function name and return type var leftTokens = input.Split('('); var leftTokens2 = leftTokens[0].Split(' '); leftTokens2[0] = leftTokens2[0].Trim(); leftTokens2[1] = leftTokens2[1].Trim(); returnType = leftTokens2[0]; functionName = leftTokens2[1]; invoc = new FunctionInvocation(functionName, 0, 0, returnType); string[] parameters; int lparen_pos = -1; for (int i = 0; i < input.Length; i++) { if (input[i] == '(') { lparen_pos = i; break; } } if (lparen_pos != -1) { string[] tokens = input.Split('('); parameters = tokens[1].Split(','); } else { parameters = input.Split(','); } for (int i = 0; i < parameters.Length; i++) { string itParam = parameters[i]; itParam = itParam.Replace(")", string.Empty); itParam = itParam.Replace(",", string.Empty); string[] paramTokens = itParam.Split(' '); // There should be three parts for each token // 1. The operand type(in, out, inout) // 2. The type // 3. The name if (paramTokens.Length == 3) { Operand.OpSemantic semantic = Operand.OpSemantic.In; GpuProgramParameters.GpuConstantType gpuType = GpuProgramParameters.GpuConstantType.Unknown; if (paramTokens[0] == "in") { semantic = Operand.OpSemantic.In; } else if (paramTokens[0] == "out") { semantic = Operand.OpSemantic.Out; } else if (paramTokens[0] == "inout") { semantic = Operand.OpSemantic.InOut; } //Find the internal type based on the string that we're given foreach (var key in this.gpuConstTypeMap.Keys) { if (this.gpuConstTypeMap[key] == paramTokens[1]) { gpuType = key; break; } } //We need a valid type otherwise glsl compilation will not work if (gpuType == GpuProgramParameters.GpuConstantType.Unknown) { throw new Core.AxiomException("Cannot convert Operand.OpMask to GpuConstantType"); } if (gpuType == GpuProgramParameters.GpuConstantType.Sampler1D) { gpuType = GpuProgramParameters.GpuConstantType.Sampler2D; } var p = new Parameter(gpuType, paramTokens[2], Parameter.SemanticType.Unknown, i, Parameter.ContentType.Unknown, 0); invoc.PushOperand(p, semantic, (int)Operand.OpMask.All, 0); } } return(invoc); }
private void WriteProgramDependencies(StreamWriter stream, Program program) { for (int i = 0; i < program.DependencyCount; i++) { string curDependency = program.GetDependency(i); CacheDependencyFunctions(curDependency); } stream.WriteLine("//-----------------------------------------------------------------------------"); stream.WriteLine("// PROGRAM DEPENDENCIES"); stream.WriteLine(); var forwardDecl = new List <FunctionInvocation>(); var functionList = program.Functions; int itFunction = 0; Function curFunction = functionList[0]; var atomInstances = curFunction.AtomInstances; int itAtom = 0; int itAtomEnd = atomInstances.Count; //Now iterate over all function atoms for ( ; itAtom != itAtomEnd; itAtom++) { //Skip non function invocation atom if (atomInstances[itAtom] is FunctionInvocation == false) { continue; } var funcInvoc = atomInstances[itAtom] as FunctionInvocation; forwardDecl.Add(funcInvoc); // Now look into that function for other non-builtin functions and add them to the declaration list // Look for non-builtin functions // Do so by assuming that these functions do not have several variations. // Also, because GLSL is C based, functions must be defined before they are used // so we can make the assumption that we already have this function cached. // // If we find a function, look it up in the map and write it out DiscoverFunctionDependencies(funcInvoc, forwardDecl); } //Now remove duplicate declarations forwardDecl.Sort(); forwardDecl = forwardDecl.Distinct(new FunctionInvocation.FunctionInvocationComparer()).ToList(); for (int i = 0; i < program.DependencyCount; i++) { string curDependency = program.GetDependency(i); foreach (var key in this.definesMap.Keys) { if (this.definesMap[key] == curDependency) { stream.Write(this.definesMap[key]); stream.Write("\n"); } } } // Parse the source shader and write out only the needed functions foreach (var it in forwardDecl) { var invoc = new FunctionInvocation(string.Empty, 0, 0, string.Empty); string body = string.Empty; //find the function in the cache foreach (var key in this.functionCacheMap.Keys) { if (!(it == key)) { continue; } invoc = key; body = this.functionCacheMap[key]; break; } if (invoc.FunctionName.Length > 0) { //Write out the funciton name from the cached FunctionInvocation stream.Write(invoc.ReturnType); stream.Write(" "); stream.Write(invoc.FunctionName); stream.Write("("); int itOperand = 0; int itOperandEnd = invoc.OperandList.Count; while (itOperand != itOperandEnd) { Operand op = invoc.OperandList[itOperand]; Operand.OpSemantic opSemantic = op.Semantic; string paramName = op.Parameter.Name; int opMask = op.Mask; GpuProgramParameters.GpuConstantType gpuType = GpuProgramParameters.GpuConstantType.Unknown; switch (opSemantic) { case Operand.OpSemantic.In: stream.Write("in "); break; case Operand.OpSemantic.Out: stream.Write("out "); break; case Operand.OpSemantic.InOut: stream.Write("inout "); break; default: break; } //Swizzle masks are onluy defined for types like vec2, vec3, vec4 if (opMask == (int)Operand.OpMask.All) { gpuType = op.Parameter.Type; } else { gpuType = Operand.GetGpuConstantType(opMask); } //We need a valid type otherwise glsl compilation will not work if (gpuType == GpuProgramParameters.GpuConstantType.Unknown) { throw new Core.AxiomException("Cannot convert Operand.OpMask to GpuConstantType"); } stream.Write(this.gpuConstTypeMap[gpuType] + " " + paramName); itOperand++; //Prepare for the next operand if (itOperand != itOperandEnd) { stream.Write(", "); } } stream.WriteLine(); stream.WriteLine("{"); stream.WriteLine(body); stream.WriteLine("}"); stream.WriteLine(); } } }
private void WriteForwardDeclarations(StreamWriter stream, Program program) { stream.WriteLine("//-----------------------------------------------------------------------------"); stream.WriteLine("// FORWARD DECLARATIONS"); stream.WriteLine("//-----------------------------------------------------------------------------"); var forwardDecl = new List <string>(); // hold all generated function declarations var functionList = program.Functions; foreach (var curFunction in functionList) { var atomInstances = curFunction.AtomInstances; for (int i = 0; i < atomInstances.Count; i++) { var itAtom = atomInstances[i]; //Skip non function invocation atoms if (!(itAtom is FunctionInvocation)) { continue; } var funcInvoc = itAtom as FunctionInvocation; int itOperator = 0; int itOperatorEnd = funcInvoc.OperandList.Count; //Start with function declaration string funcDecl = funcInvoc.ReturnType + " " + funcInvoc.FunctionName + "("; //Now iterate overall operands while (itOperator != itOperatorEnd) { Parameter param = funcInvoc.OperandList[itOperator].Parameter; Operand.OpSemantic opSemantic = funcInvoc.OperandList[itOperator].Semantic; int opMask = funcInvoc.OperandList[itOperator].Mask; Axiom.Graphics.GpuProgramParameters.GpuConstantType gpuType = GpuProgramParameters.GpuConstantType.Unknown; //Write the semantic in, out, inout switch (opSemantic) { case Operand.OpSemantic.In: funcDecl += "in "; break; case Operand.OpSemantic.Out: funcDecl += "out "; break; case Operand.OpSemantic.InOut: funcDecl += "inout "; break; default: break; } //Swizzle masks are only defined fro types like vec2, vec3, vec4 if (opMask == (int)Operand.OpMask.All) { gpuType = param.Type; } else { //Now we have to conver the mask to operator gpuType = Operand.GetGpuConstantType(opMask); } //We need a valid type otherwise glsl compilation will not work if (gpuType == GpuProgramParameters.GpuConstantType.Unknown) { throw new Core.AxiomException("Cannot convert Operand.OpMask to GpuConstantType"); } //Write the operand type. funcDecl += this.gpuConstTypeMap[gpuType]; itOperator++; //move over all operators with indirection while ((itOperator != itOperatorEnd) && (funcInvoc.OperandList[itOperator].IndirectionLevel != 0)) { itOperator++; } //Prepare for the next operand if (itOperator != itOperatorEnd) { funcDecl += ", "; } } //Write function call closer. funcDecl += ");\n"; //Push the generated declaration into the vector //duplicate declarations will be removed later. forwardDecl.Add(funcDecl); } } //Now remove duplicate declaration, first we have to sort the vector. forwardDecl.Sort(); forwardDecl = forwardDecl.Distinct().ToList(); foreach (var it in forwardDecl) { stream.Write(it); } }
internal override void WriteSourceCode(System.IO.StreamWriter stream, Program program) { var gpuType = program.Type; if (gpuType == GpuProgramType.Geometry) { throw new Core.AxiomException("Geometry Program not supported iin GLSL writer"); } this.fragInputParams.Clear(); var functionList = program.Functions; var parameterList = program.Parameters; // Write the current version (this force the driver to more fulfill the glsl standard) stream.WriteLine("#version " + this.glslVersion.ToString()); //Generate source code header WriteProgramTitle(stream, program); stream.WriteLine(); //Write forward declarations WriteForwardDeclarations(stream, program); stream.WriteLine(); //Generate global variable code WriteUniformParametersTitle(stream, program); stream.WriteLine(); //Write the uniforms foreach (var uniformParam in parameterList) { stream.Write("uniform\t"); stream.Write(this.gpuConstTypeMap[uniformParam.Type]); stream.Write("\t"); stream.Write(uniformParam.Name); if (uniformParam.IsArray) { stream.Write("[" + uniformParam.Size.ToString() + "]"); } stream.Write(";"); stream.WriteLine(); } stream.WriteLine(); //Write program function(s) foreach (var curFunction in functionList) { WriteFunctionTitle(stream, curFunction); //Clear output mapping this map is used when we use //glsl built in types like gl_Color for example this.inputToGLStatesMap.Clear(); //Write inout params and fill inputToGLStatesMap WriteInputParameters(stream, curFunction, gpuType); WriteOutParameters(stream, curFunction, gpuType); stream.Write("void main() {"); stream.WriteLine(); //Write local parameters var localParams = curFunction.LocalParameters; foreach (var itParam in localParams) { stream.Write("\t"); WriteLocalParameter(stream, itParam); stream.Write(";"); stream.WriteLine(); } stream.WriteLine(); //Sort function atoms curFunction.SortAtomInstances(); var atomInstances = curFunction.AtomInstances; foreach (var itAtom in atomInstances) { var funcInvoc = itAtom as FunctionInvocation; var localOs = new StringBuilder(); //Write function name localOs.Append("\t" + funcInvoc.FunctionAtomType + "("); int curIndLevel = 0; int itOperand = 0; int itOperandEnd = funcInvoc.OperandList.Count; while (itOperand != itOperandEnd) { Operand op = funcInvoc.OperandList[itOperand]; Operand.OpSemantic opSemantic = op.Semantic; string paramName = op.Parameter.Name; Parameter.ContentType content = op.Parameter.Content; if (opSemantic == Operand.OpSemantic.Out || opSemantic == Operand.OpSemantic.InOut) { bool isVarying = false; // Check if we write to an varying because the are only readable in fragment programs if (gpuType == GpuProgramType.Fragment) { if (this.fragInputParams.Contains(paramName)) { //Declare the copy variable string newVar = "local_" + paramName; string tempVar = paramName; isVarying = true; // We stored the original values in the mFragInputParams thats why we have to replace the first var with o // because all vertex output vars are prefixed with o in glsl the name has to match in the fragment program. tempVar = tempVar.Remove(0); tempVar = tempVar.Insert(0, "o"); //Declare the copy variable and assign the original stream.WriteLine("\t" + this.gpuConstTypeMap[op.Parameter.Type] + " " + newVar + " = " + tempVar); //From now on we replace it automatic this.inputToGLStatesMap[paramName] = newVar; //Remove the param because now it is replaced automatic with the local variable //(which could be written). this.fragInputParams.Remove(paramName); } } //If its not varying param check if a uniform is written if (!isVarying) { foreach (var param in parameterList) { if (GLSLProgramWriter.CompareUniformByName(param, paramName)) { //Declare the copy variable string newVar = "local_" + paramName; //now we check if we already declared a uniform redirector var if (this.inputToGLStatesMap.ContainsKey(newVar) == false) { //Declare the copy variable and assign the original stream.WriteLine("\t" + this.gpuConstTypeMap[param.Type] + " " + newVar + paramName + ";\n"); //From now on we replace it automatic this.inputToGLStatesMap.Add(paramName, newVar); } } } } } if (this.inputToGLStatesMap.ContainsKey(paramName)) { int mask = op.Mask; // our swizzle mask //Here we insert the renamed param name localOs.Append("." + Operand.GetMaskAsString(mask)); if (mask != (int)Operand.OpMask.All) { localOs.Append("." + Operand.GetMaskAsString(mask)); } //Now that every texcoord is a vec4 (passed as vertex attributes) //we have to swizzle them aoccording the desired type. else if (gpuType == GpuProgramType.Vertex && content == Parameter.ContentType.TextureCoordinate0 || content == Parameter.ContentType.TextureCoordinate1 || content == Parameter.ContentType.TextureCoordinate2 || content == Parameter.ContentType.TextureCoordinate3 || content == Parameter.ContentType.TextureCoordinate4 || content == Parameter.ContentType.TextureCoordinate5 || content == Parameter.ContentType.TextureCoordinate6 || content == Parameter.ContentType.TextureCoordinate7) { //Now generate the swizzel mask according //the type. switch (op.Parameter.Type) { case GpuProgramParameters.GpuConstantType.Float1: localOs.Append(".x"); break; case GpuProgramParameters.GpuConstantType.Float2: localOs.Append(".xy"); break; case GpuProgramParameters.GpuConstantType.Float3: localOs.Append(".xyz"); break; case GpuProgramParameters.GpuConstantType.Float4: localOs.Append(".xyzw"); break; default: break; } } } else { localOs.Append(op.ToString()); } itOperand++; //Prepare for the next operand int opIndLevel = 0; if (itOperand != itOperandEnd) { opIndLevel = funcInvoc.OperandList[itOperand].IndirectionLevel; } if (curIndLevel < opIndLevel) { while (curIndLevel < opIndLevel) { curIndLevel++; localOs.Append("["); } } else { while (curIndLevel > opIndLevel) { curIndLevel--; localOs.Append("]"); } if (opIndLevel != 0) { localOs.Append("]["); } else if (itOperand != itOperandEnd) { localOs.Append(", "); } } if (curIndLevel != 0) { localOs.Append("int("); } } //Write function call closer localOs.AppendLine(");"); localOs.AppendLine(); stream.Write(localOs.ToString()); } stream.WriteLine("}"); } stream.WriteLine(); }
public void PushOperand(Parameter parameter, Operand.OpSemantic opSemantic) { PushOperand(parameter, opSemantic, (int)Operand.OpMask.All, 0); }
public void PushOperand(Parameter parameter, Operand.OpSemantic opSemantic, int opMask, int indirectionalLevel) { this.operands.Add(new Operand(parameter, opSemantic, opMask, indirectionalLevel)); }
public void PushOperand(Parameter parameter, Operand.OpSemantic opSemantic, Operand.OpMask opMask) { PushOperand(parameter, opSemantic, (int)opMask, 0); }