protected override MethodProcessResult GenerateFullTextCore(string setName, ShaderFunction function) { BackendContext context = GetContext(setName); StringBuilder sb = new StringBuilder(); HashSet <ResourceDefinition> resourcesUsed = new HashSet <ResourceDefinition>(); ShaderFunctionAndBlockSyntax entryPoint = context.Functions.SingleOrDefault( sfabs => sfabs.Function.Name == function.Name); if (entryPoint == null) { throw new ShaderGenerationException("Couldn't find given function: " + function.Name); } ValidateRequiredSemantics(setName, entryPoint.Function, function.Type); StructureDefinition[] orderedStructures = StructureDependencyGraph.GetOrderedStructureList(Compilation, context.Structures); foreach (StructureDefinition sd in orderedStructures) { WriteStructure(sb, sd); } foreach (ResourceDefinition rd in context.Resources) { switch (rd.ResourceKind) { case ShaderResourceKind.Uniform: WriteUniform(sb, rd); break; case ShaderResourceKind.Texture2D: WriteTexture2D(sb, rd); break; case ShaderResourceKind.TextureCube: WriteTextureCube(sb, rd); break; case ShaderResourceKind.Texture2DMS: WriteTexture2DMS(sb, rd); break; case ShaderResourceKind.Sampler: WriteSampler(sb, rd); break; case ShaderResourceKind.StructuredBuffer: case ShaderResourceKind.RWStructuredBuffer: WriteStructuredBuffer(sb, rd, rd.ResourceKind == ShaderResourceKind.StructuredBuffer); break; default: throw new ShaderGenerationException("Illegal resource kind: " + rd.ResourceKind); } } foreach (ShaderFunctionAndBlockSyntax f in entryPoint.OrderedFunctionList) { if (!f.Function.IsEntryPoint) { MethodProcessResult processResult = new ShaderMethodVisitor(Compilation, setName, f.Function, this).VisitFunction(f.Block); foreach (ResourceDefinition rd in processResult.ResourcesUsed) { resourcesUsed.Add(rd); } sb.AppendLine(processResult.FullText); } } MethodProcessResult result = new ShaderMethodVisitor(Compilation, setName, entryPoint.Function, this) .VisitFunction(entryPoint.Block); foreach (ResourceDefinition rd in result.ResourcesUsed) { resourcesUsed.Add(rd); } sb.AppendLine(result.FullText); WriteMainFunction(setName, sb, entryPoint.Function); // Append version last because it relies on information from parsing the shader. StringBuilder versionSB = new StringBuilder(); WriteVersionHeader(function, versionSB); sb.Insert(0, versionSB.ToString()); return(new MethodProcessResult(sb.ToString(), resourcesUsed)); }
protected override MethodProcessResult GenerateFullTextCore(string setName, ShaderFunction function) { Debug.Assert(function.IsEntryPoint); StringBuilder sb = new StringBuilder(); HashSet <ResourceDefinition> resourcesUsed = new HashSet <ResourceDefinition>(); BackendContext setContext = GetContext(setName); ShaderFunctionAndBlockSyntax entryPoint = setContext.Functions.SingleOrDefault( sfabs => sfabs.Function.Name == function.Name); if (entryPoint == null) { throw new ShaderGenerationException("Couldn't find given function: " + function.Name); } ValidateRequiredSemantics(setName, entryPoint.Function, function.Type); StructureDefinition[] orderedStructures = StructureDependencyGraph.GetOrderedStructureList(Compilation, setContext.Structures); foreach (StructureDefinition sd in orderedStructures) { WriteStructure(sb, sd); } List <ResourceDefinition[]> resourcesBySet = setContext.Resources.GroupBy(rd => rd.Set) .Select(g => g.ToArray()).ToList(); StringBuilder functionsSB = new StringBuilder(); foreach (ShaderFunctionAndBlockSyntax f in entryPoint.OrderedFunctionList) { if (!f.Function.IsEntryPoint) { MethodProcessResult processResult = new HlslMethodVisitor(Compilation, setName, f.Function, this).VisitFunction(f.Block); foreach (ResourceDefinition rd in processResult.ResourcesUsed) { resourcesUsed.Add(rd); } functionsSB.AppendLine(processResult.FullText); } } MethodProcessResult result = new HlslMethodVisitor(Compilation, setName, entryPoint.Function, this) .VisitFunction(entryPoint.Block); foreach (ResourceDefinition rd in result.ResourcesUsed) { resourcesUsed.Add(rd); } // Emit all of the resources now, because we've learned which ones are actually used by this function. int uniformBinding = 0, textureBinding = 0, samplerBinding = 0, uavBinding = function.ColorOutputCount; int setIndex = 0; foreach (ResourceDefinition[] set in resourcesBySet) { Debug.Assert(set[0].Set == setIndex); setIndex += 1; foreach (ResourceDefinition rd in set) { switch (rd.ResourceKind) { case ShaderResourceKind.Uniform: if (resourcesUsed.Contains(rd)) { WriteUniform(sb, rd, uniformBinding); } uniformBinding++; break; case ShaderResourceKind.Texture2D: if (resourcesUsed.Contains(rd)) { WriteTexture2D(sb, rd, textureBinding); } textureBinding++; break; case ShaderResourceKind.TextureCube: if (resourcesUsed.Contains(rd)) { WriteTextureCube(sb, rd, textureBinding); } textureBinding++; break; case ShaderResourceKind.Texture2DMS: if (resourcesUsed.Contains(rd)) { WriteTexture2DMS(sb, rd, textureBinding); } textureBinding++; break; case ShaderResourceKind.Sampler: if (resourcesUsed.Contains(rd)) { WriteSampler(sb, rd, samplerBinding); } samplerBinding++; break; case ShaderResourceKind.StructuredBuffer: if (resourcesUsed.Contains(rd)) { WriteStructuredBuffer(sb, rd, textureBinding); } textureBinding++; break; case ShaderResourceKind.RWStructuredBuffer: if (resourcesUsed.Contains(rd)) { WriteRWStructuredBuffer(sb, rd, uavBinding); } uavBinding++; break; default: throw new ShaderGenerationException("Illegal resource kind: " + rd.ResourceKind); } } } // Resources need to be defined before the function that uses them -- so append this after the resources. sb.Append(functionsSB.ToString()); sb.AppendLine(result.FullText); return(new MethodProcessResult(sb.ToString(), resourcesUsed)); }
protected override MethodProcessResult GenerateFullTextCore(string setName, ShaderFunction function) { Debug.Assert(function.IsEntryPoint); StringBuilder sb = new StringBuilder(); HashSet <ResourceDefinition> resourcesUsed = new HashSet <ResourceDefinition>(); BackendContext setContext = GetContext(setName); ShaderFunctionAndBlockSyntax entryPoint = setContext.Functions.SingleOrDefault( sfabs => sfabs.Function.Name == function.Name); if (entryPoint == null) { throw new ShaderGenerationException("Couldn't find given function: " + function.Name); } ValidateRequiredSemantics(setName, entryPoint.Function, function.Type); // Write header sb.AppendLine("#include <metal_stdlib>"); sb.AppendLine("using namespace metal;"); // TODO: Necessary for Metal? StructureDefinition[] orderedStructures = StructureDependencyGraph.GetOrderedStructureList(Compilation, setContext.Structures); foreach (StructureDefinition sd in orderedStructures) { WriteStructure(sb, sd); } StringBuilder functionsSB = new StringBuilder(); foreach (ShaderFunctionAndBlockSyntax f in entryPoint.OrderedFunctionList) { if (!f.Function.IsEntryPoint) { MethodProcessResult processResult = new MetalMethodVisitor(Compilation, setName, f.Function, this).VisitFunction(f.Block); foreach (ResourceDefinition rd in processResult.ResourcesUsed) { resourcesUsed.Add(rd); } functionsSB.AppendLine(processResult.FullText); } } MethodProcessResult entryResult = new MetalMethodVisitor(Compilation, setName, entryPoint.Function, this) .VisitFunction(entryPoint.Block); foreach (ResourceDefinition rd in entryResult.ResourcesUsed) { resourcesUsed.Add(rd); } StringBuilder containerSB = new StringBuilder(); containerSB.AppendLine("struct ShaderContainer {"); List <string> structFields = new List <string>(); List <string> ctorParams = new List <string>(); List <string> ctorAssignments = new List <string>(); foreach (ResourceDefinition resource in resourcesUsed) { structFields.Add(GetResourceField(resource)); ctorParams.Add(GetResourceCtorParam(resource)); ctorAssignments.Add($"{resource.Name}({resource.Name}_param)"); } foreach (string sf in structFields) { containerSB.AppendLine(sf); } containerSB.AppendLine(functionsSB.ToString()); // Emit the ctor definition containerSB.AppendLine($"ShaderContainer("); string ctorParamsStr = string.Join(", ", ctorParams); containerSB.AppendLine(ctorParamsStr); containerSB.AppendLine($")"); string allCtorAssignments = string.Join(", ", ctorAssignments); if (!string.IsNullOrEmpty(allCtorAssignments)) { containerSB.AppendLine(":"); containerSB.AppendLine(allCtorAssignments); } containerSB.AppendLine("{}"); containerSB.AppendLine(entryResult.FullText); containerSB.AppendLine("};"); // Close the global containing struct. sb.AppendLine(containerSB.ToString()); // Emit the out function call which creates the container struct and calls the real shader function. string type = entryPoint.Function.Type == ShaderFunctionType.VertexEntryPoint ? "vertex" : entryPoint.Function.Type == ShaderFunctionType.FragmentEntryPoint ? "fragment" : "kernel"; ShaderFunction entryFunction = entryPoint.Function; string returnType = CSharpToShaderType(entryFunction.ReturnType.Name); string fullDeclType = CSharpToShaderType(entryFunction.DeclaringType); string funcName = entryFunction.Name; string baseParameterList = string.Join(", ", entryFunction.Parameters.Select(FormatParameter)); string resourceParameterList = GetResourceParameterList(entryFunction, setName, resourcesUsed); string builtinParameterList = string.Join( ", ", GetBuiltinParameterList(entryFunction).Select(b => $"{b.Type} {b.Name} {b.Attribute}")); string fullParameterList = string.Join( ", ", new string[] { baseParameterList, resourceParameterList, builtinParameterList }.Where(s => !string.IsNullOrEmpty(s))); string functionDeclStr = $"{type} {returnType} {funcName}({fullParameterList})"; string containerArgs = string.Join(", ", resourcesUsed.Select( rd => rd.Name)); string entryFuncArgs = string.Join( ", ", MetalBackend.GetBuiltinParameterList(entryFunction).Select(b => $"{b.Name}")); if (entryFunction.Parameters.Length > 0) { Debug.Assert(entryFunction.Parameters.Length == 1); entryFuncArgs = Utilities.JoinIgnoreNull( ", ", new string[] { $"{entryFunction.Parameters[0].Name}", entryFuncArgs }); } sb.AppendLine(functionDeclStr); sb.AppendLine("{"); sb.AppendLine($"return ShaderContainer({containerArgs}).{entryFunction.Name}({entryFuncArgs});"); sb.AppendLine("}"); return(new MethodProcessResult(sb.ToString(), resourcesUsed)); }