protected override MethodProcessResult GenerateFullTextCore(string setName, ShaderFunction function) { Debug.Assert(function.IsEntryPoint); StringBuilder sb = new StringBuilder(); BackendContext setContext = GetContext(setName); ShaderFunctionAndMethodDeclarationSyntax 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); } HashSet <ResourceDefinition> resourcesUsed = ProcessFunctions(setName, entryPoint, out string funcsStr, out string entryStr); ValidateResourcesUsed(setName, resourcesUsed); 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(funcsStr); // 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(entryStr); 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)); }
protected override MethodProcessResult GenerateFullTextCore(string setName, ShaderFunction function) { Debug.Assert(function.IsEntryPoint); StringBuilder sb = new StringBuilder(); BackendContext setContext = GetContext(setName); ShaderFunctionAndMethodDeclarationSyntax 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(); HashSet <ResourceDefinition> resourcesUsed = ProcessFunctions(setName, entryPoint, out string funcStr, out string entryStr); // 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) { if (!resourcesUsed.Contains(rd)) { continue; } switch (rd.ResourceKind) { case ShaderResourceKind.Uniform: WriteUniform(sb, rd, uniformBinding); uniformBinding++; break; case ShaderResourceKind.Texture2D: WriteTexture2D(sb, rd, textureBinding); textureBinding++; break; case ShaderResourceKind.Texture2DArray: WriteTexture2DArray(sb, rd, textureBinding); textureBinding++; break; case ShaderResourceKind.TextureCube: WriteTextureCube(sb, rd, textureBinding); textureBinding++; break; case ShaderResourceKind.Texture2DMS: WriteTexture2DMS(sb, rd, textureBinding); textureBinding++; break; case ShaderResourceKind.Sampler: WriteSampler(sb, rd, samplerBinding); samplerBinding++; break; case ShaderResourceKind.StructuredBuffer: WriteStructuredBuffer(sb, rd, textureBinding); textureBinding++; break; case ShaderResourceKind.RWStructuredBuffer: 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.AppendLine(funcStr); sb.AppendLine(entryStr); return(new MethodProcessResult(sb.ToString(), resourcesUsed)); }
protected override MethodProcessResult GenerateFullTextCore(string setName, ShaderFunction function) { BackendContext context = GetContext(setName); StringBuilder sb = new StringBuilder(); ShaderFunctionAndMethodDeclarationSyntax 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); } HashSet <ResourceDefinition> resourcesUsed = ProcessFunctions(setName, entryPoint, out string funcStr, out string entryStr); foreach (ResourceDefinition rd in context.Resources) { if (!resourcesUsed.Contains(rd)) { continue; } switch (rd.ResourceKind) { case ShaderResourceKind.Uniform: WriteUniform(sb, rd); break; case ShaderResourceKind.Texture2D: WriteTexture2D(sb, rd); break; case ShaderResourceKind.Texture2DArray: WriteTexture2DArray(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); } } sb.AppendLine(funcStr); sb.AppendLine(entryStr); 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) { BackendContext context = GetContext(setName); StringBuilder sb = new StringBuilder(); var writtenResources = new HashSet <ResourceDefinition>(); int outVarIndex = 0; ShaderFunctionAndMethodDeclarationSyntax 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); if (entryPoint.Function.InputPrimitive != PrimitiveType.None) { sb.AppendLine($"layout({InputPrimitiveIdentifier(entryPoint.Function.InputPrimitive)}) in;"); } if (entryPoint.Function.OutputPrimitive != PrimitiveType.None) { sb.AppendLine($"layout({OutputPrimitiveIdentifier(entryPoint.Function.OutputPrimitive)}, max_vertices = {entryPoint.Function.MaxVertices}) out;"); } HashSet <ResourceDefinition> resourcesUsed = ProcessFunctions(setName, entryPoint, out string funcStr, out string entryStr); ValidateResourcesUsed(setName, resourcesUsed); StructureDefinition[] orderedStructures = StructureDependencyGraph.GetOrderedStructureList(Compilation, context.Structures, resourcesUsed); foreach (StructureDefinition osd in orderedStructures) { if (osd.Fields.All(f => !f.IsBuiltIn)) { var resources = resourcesUsed.Concat(context.Statics) .Where(r => r.Matches(osd)) .ToArray(); if (resources.Length == 1) { if (resources[0].ResourceKind == ShaderResourceKind.BuiltIn) { WriteStructure(function, sb, osd, resources[0]); //foreach (var rs in resources.Where(r => r.ResourceKind == ShaderResourceKind.BuiltIn)) //{ // WriteStructure(function, sb, osd, rs); //} writtenResources.Add(resources[0]); continue; } else if (resources[0].ResourceKind == ShaderResourceKind.Emit) { outVarIndex = 0; foreach (var field in osd.Fields) { WriteInOutVariable( sb, false, function.Type, CSharpToShaderType(field.Type.Name), "out_" + CorrectIdentifier(field.Name), outVarIndex); outVarIndex += 1; } writtenResources.Add(resources[0]); continue; } } else if (resources.Length == 0) { //continue; } } WriteStructure(function, sb, osd, null); } int structuredBufferIndex = 0; int rwTextureIndex = 0; StructureDefinition sd; List <FieldDefinition> outputFields = new List <FieldDefinition>(); foreach (ResourceDefinition rd in context.Resources) { if (!resourcesUsed.Contains(rd) || writtenResources.Contains(rd)) { continue; } switch (rd.ResourceKind) { case ShaderResourceKind.Uniform: if (rd.ValueType.TypeInfo is IArrayTypeSymbol) { //sb.AppendLine($"#define {rd.Name}_MAX_SIZE {rd.ValueType.FixedSize}"); } WriteUniform(sb, rd); break; case ShaderResourceKind.Texture1D: WriteTexture1D(sb, rd); break; case ShaderResourceKind.Texture2D: WriteTexture2D(sb, rd); break; case ShaderResourceKind.Texture3D: WriteTexture3D(sb, rd); break; case ShaderResourceKind.Texture2DArray: WriteTexture2DArray(sb, rd); break; case ShaderResourceKind.Texture2DRect: WriteTexture2DRect(sb, rd); break; case ShaderResourceKind.TextureCube: WriteTextureCube(sb, rd); break; case ShaderResourceKind.Texture2DMS: WriteTexture2DMS(sb, rd); function.UsesTexture2DMS = true; break; case ShaderResourceKind.TextureBuffer: WriteTextureBuffer(sb, rd); break; case ShaderResourceKind.Sampler: WriteSampler(sb, rd); break; case ShaderResourceKind.SamplerComparison: WriteSamplerComparison(sb, rd); break; case ShaderResourceKind.StructuredBuffer: case ShaderResourceKind.RWStructuredBuffer: case ShaderResourceKind.AtomicBuffer: WriteStructuredBuffer(sb, rd, rd.ResourceKind == ShaderResourceKind.StructuredBuffer, structuredBufferIndex); structuredBufferIndex++; break; case ShaderResourceKind.RWTexture2D: WriteRWTexture2D(sb, rd, rwTextureIndex); rwTextureIndex++; break; case ShaderResourceKind.DepthTexture2D: WriteDepthTexture2D(sb, rd); break; case ShaderResourceKind.DepthTexture2DArray: WriteDepthTexture2DArray(sb, rd); break; case ShaderResourceKind.Emit: sd = context.Structures.FirstOrDefault(s => rd.Matches(s)); if (sd == null) { WriteInOutVariable( sb, false, entryPoint.Function.Type, CSharpToShaderType(rd.ValueType.Name), "out_" + CorrectIdentifier(rd.Name), outVarIndex); outVarIndex += 1; } else { //WriteStructure(function, sb, sd, rd); outputFields.AddRange(sd.Fields); } break; case ShaderResourceKind.BuiltIn: sd = context.Structures.FirstOrDefault(s => rd.Matches(s)); if (sd != null) { WriteStructure(function, sb, sd, rd); } break; default: throw new ShaderGenerationException("Illegal resource kind: " + rd.ResourceKind); } writtenResources.Add(rd); } entryPoint.Function.OutputFields = outputFields.ToArray(); foreach (var variable in context.Statics) { WriteLocal(sb, variable); } sb.AppendLine(funcStr); sb.AppendLine(entryStr); WriteMainFunction(setName, sb, entryPoint.Function); // Append version last because it relies on information from parsing the shader. StringBuilder versionSB = new StringBuilder(); WriteVersionHeader(function, entryPoint.OrderedFunctionList, versionSB); sb.Insert(0, versionSB.ToString()); resourcesUsed.RemoveWhere(r => r.ResourceKind == ShaderResourceKind.Local); return(new MethodProcessResult(sb.ToString(), resourcesUsed)); }