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));
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        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));
        }
Beispiel #4
0
        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));
        }