Beispiel #1
0
            private void ProcessIncludeCommand(Token includeCommand, int lineEnd)
            {
                if (Expect(includeCommand.s, includeCommand.end, '('))
                {
                    Token param = ParseString(includeCommand.s, includeCommand.end + 1, lineEnd);

                    if (!param.IsValid())
                    {
                        Error("ERROR: $include expected a string file path parameter", includeCommand.s, includeCommand.end + 1);
                    }
                    else
                    {
                        var includeLocation = Path.Combine(templatePath, param.GetString());
                        if (!File.Exists(includeLocation))
                        {
                            Error("ERROR: $include cannot find file : " + includeLocation, includeCommand.s, param.start);
                        }
                        else
                        {
                            int endIndex = result.length;
                            using (var temp = new ShaderStringBuilder())
                            {
                                // Wrap in debug mode
                                if (isDebug)
                                {
                                    result.AppendLine("//-------------------------------------------------------------------------------------");
                                    result.AppendLine("// TEMPLATE INCLUDE : " + param.GetString());
                                    result.AppendLine("//-------------------------------------------------------------------------------------");
                                    result.AppendNewLine();
                                }

                                // Recursively process templates
                                ProcessTemplateFile(includeLocation);

                                // Wrap in debug mode
                                if (isDebug)
                                {
                                    result.AppendNewLine();
                                    result.AppendLine("//-------------------------------------------------------------------------------------");
                                    result.AppendLine("// END TEMPLATE INCLUDE : " + param.GetString());
                                    result.AppendLine("//-------------------------------------------------------------------------------------");
                                }

                                result.AppendNewLine();

                                // Required to enforce indentation rules
                                // Append lines from this include into temporary StringBuilder
                                // Reduce result length to remove this include
                                temp.AppendLines(result.ToString(endIndex, result.length - endIndex));
                                result.length = endIndex;
                                result.AppendLines(temp.ToCodeBlock());
                            }
                        }
                    }
                }
            }
        public static string ToShaderString(this StencilDescriptor descriptor)
        {
            ShaderStringBuilder builder = new ShaderStringBuilder();

            builder.AppendLine("Stencil");
            using (builder.BlockScope())
            {
                string compBack  = descriptor.CompBack != null && descriptor.CompBack.Length > 0 ? descriptor.CompBack : descriptor.Comp;
                string zFailBack = descriptor.ZFailBack != null && descriptor.ZFailBack.Length > 0 ? descriptor.ZFailBack : descriptor.ZFail;
                string failBack  = descriptor.FailBack != null && descriptor.FailBack.Length > 0 ? descriptor.FailBack : descriptor.Fail;
                string passBack  = descriptor.PassBack != null && descriptor.PassBack.Length > 0 ? descriptor.PassBack : descriptor.Pass;

                if (descriptor.WriteMask != null && descriptor.WriteMask.Length > 0)
                {
                    builder.AppendLine($"WriteMask {descriptor.WriteMask}");
                }
                if (descriptor.Ref != null && descriptor.Ref.Length > 0)
                {
                    builder.AppendLine($"Ref {descriptor.Ref}");
                }
                if (descriptor.Comp != null && descriptor.Comp.Length > 0)
                {
                    builder.AppendLine($"CompFront {descriptor.Comp}");
                }
                if (descriptor.ZFail != null && descriptor.ZFail.Length > 0)
                {
                    builder.AppendLine($"ZFailFront {descriptor.ZFail}");
                }
                if (descriptor.Fail != null && descriptor.Fail.Length > 0)
                {
                    builder.AppendLine($"FailFront {descriptor.Fail}");
                }
                if (descriptor.Pass != null && descriptor.Pass.Length > 0)
                {
                    builder.AppendLine($"PassFront {descriptor.Pass}");
                }
                if (compBack != null && compBack.Length > 0)
                {
                    builder.AppendLine($"CompBack {compBack}");
                }
                if (zFailBack != null && zFailBack.Length > 0)
                {
                    builder.AppendLine($"ZFailBack {zFailBack}");
                }
                if (failBack != null && failBack.Length > 0)
                {
                    builder.AppendLine($"FailBack {failBack}");
                }
                if (passBack != null && passBack.Length > 0)
                {
                    builder.AppendLine($"PassBack {passBack}");
                }
            }
            return(builder.ToCodeBlock());
        }
Beispiel #3
0
        public static string ToShaderString(this StencilDescriptor descriptor)
        {
            ShaderStringBuilder builder = new ShaderStringBuilder();

            builder.AppendLine("Stencil");
            using (builder.BlockScope())
            {
                builder.AppendLine($"WriteMask {descriptor.WriteMask}");
                builder.AppendLine($"Ref {descriptor.Ref}");
                builder.AppendLine($"Comp {descriptor.Comp}");
                builder.AppendLine($"Pass {descriptor.Pass}");
            }
            return(builder.ToCodeBlock());
        }
Beispiel #4
0
        private static bool EquivalentHLSLProperties(AbstractShaderProperty a, AbstractShaderProperty b)
        {
            bool equivalent = true;
            var  bHLSLProps = new List <HLSLProperty>();

            b.ForeachHLSLProperty(bh => bHLSLProps.Add(bh));
            a.ForeachHLSLProperty(ah =>
            {
                var i = bHLSLProps.FindIndex(bh => bh.name == ah.name);
                if (i < 0)
                {
                    equivalent = false;
                }
                else
                {
                    var bh = bHLSLProps[i];
                    if ((ah.name != bh.name) ||
                        (ah.type != bh.type) ||
                        (ah.precision != bh.precision) ||
                        (ah.declaration != bh.declaration) ||
                        ((ah.customDeclaration == null) != (bh.customDeclaration == null)))
                    {
                        equivalent = false;
                    }
                    else if (ah.customDeclaration != null)
                    {
                        var ssba = new ShaderStringBuilder();
                        var ssbb = new ShaderStringBuilder();
                        ah.customDeclaration(ssba);
                        bh.customDeclaration(ssbb);
                        if (ssba.ToCodeBlock() != ssbb.ToCodeBlock())
                        {
                            equivalent = false;
                        }
                    }
                    bHLSLProps.RemoveAt(i);
                }
            });
            return(equivalent && (bHLSLProps.Count == 0));
        }
Beispiel #5
0
        void GenerateShaderPass(int targetIndex, PassDescriptor pass, ActiveFields activeFields)
        {
            // Early exit if pass is not used in preview
            if (m_Mode == GenerationMode.Preview && !pass.useInPreview)
            {
                return;
            }

            // --------------------------------------------------
            // Debug

            // Get scripting symbols
            BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
            string           defines          = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup);

            bool isDebug = defines.Contains(kDebugSymbol);

            // --------------------------------------------------
            // Setup

            // Initiailize Collectors
            var propertyCollector = new PropertyCollector();
            var keywordCollector  = new KeywordCollector();

            m_OutputNode.owner.CollectShaderKeywords(keywordCollector, m_Mode);

            // Get upstream nodes from ShaderPass port mask
            List <AbstractMaterialNode> vertexNodes;
            List <AbstractMaterialNode> pixelNodes;

            GenerationUtils.GetUpstreamNodesForShaderPass(m_OutputNode, pass, out vertexNodes, out pixelNodes);

            // Track permutation indices for all nodes
            List <int>[] vertexNodePermutations = new List <int> [vertexNodes.Count];
            List <int>[] pixelNodePermutations  = new List <int> [pixelNodes.Count];

            // Get active fields from upstream Node requirements
            ShaderGraphRequirementsPerKeyword graphRequirements;

            GenerationUtils.GetActiveFieldsAndPermutationsForNodes(m_OutputNode, pass, keywordCollector, vertexNodes, pixelNodes,
                                                                   vertexNodePermutations, pixelNodePermutations, activeFields, out graphRequirements);

            // GET CUSTOM ACTIVE FIELDS HERE!

            // Get active fields from ShaderPass
            GenerationUtils.AddRequiredFields(pass.requiredFields, activeFields.baseInstance);

            // Get Port references from ShaderPass
            List <MaterialSlot> pixelSlots;
            List <MaterialSlot> vertexSlots;

            if (m_OutputNode is IMasterNode)
            {
                pixelSlots  = GenerationUtils.FindMaterialSlotsOnNode(pass.pixelPorts, m_OutputNode);
                vertexSlots = GenerationUtils.FindMaterialSlotsOnNode(pass.vertexPorts, m_OutputNode);
            }
            else if (m_OutputNode is SubGraphOutputNode)
            {
                pixelSlots = new List <MaterialSlot>()
                {
                    m_OutputNode.GetInputSlots <MaterialSlot>().FirstOrDefault(),
                };
                vertexSlots = new List <MaterialSlot>();
            }
            else
            {
                pixelSlots = new List <MaterialSlot>()
                {
                    new Vector4MaterialSlot(0, "Out", "Out", SlotType.Output, Vector4.zero)
                    {
                        owner = m_OutputNode
                    },
                };
                vertexSlots = new List <MaterialSlot>();
            }

            // Function Registry
            var functionBuilder  = new ShaderStringBuilder();
            var functionRegistry = new FunctionRegistry(functionBuilder);

            // Hash table of named $splice(name) commands
            // Key: splice token
            // Value: string to splice
            Dictionary <string, string> spliceCommands = new Dictionary <string, string>();

            // --------------------------------------------------
            // Dependencies

            // Propagate active field requirements using dependencies
            // Must be executed before types are built
            foreach (var instance in activeFields.all.instances)
            {
                GenerationUtils.ApplyFieldDependencies(instance, pass.fieldDependencies);
            }

            // --------------------------------------------------
            // Pass Setup

            // Name
            if (!string.IsNullOrEmpty(pass.displayName))
            {
                spliceCommands.Add("PassName", $"Name \"{pass.displayName}\"");
            }
            else
            {
                spliceCommands.Add("PassName", "// Name: <None>");
            }

            // Tags
            if (!string.IsNullOrEmpty(pass.lightMode))
            {
                spliceCommands.Add("LightMode", $"\"LightMode\" = \"{pass.lightMode}\"");
            }
            else
            {
                spliceCommands.Add("LightMode", "// LightMode: <None>");
            }

            // --------------------------------------------------
            // Pass Code

            // Render State
            using (var renderStateBuilder = new ShaderStringBuilder())
            {
                // Render states need to be separated by RenderState.Type
                // The first passing ConditionalRenderState of each type is inserted
                foreach (RenderStateType type in Enum.GetValues(typeof(RenderStateType)))
                {
                    var renderStates = pass.renderStates?.Where(x => x.descriptor.type == type);
                    if (renderStates != null)
                    {
                        foreach (RenderStateCollection.Item renderState in renderStates)
                        {
                            if (renderState.TestActive(activeFields))
                            {
                                renderStateBuilder.AppendLine(renderState.value);
                                break;
                            }
                        }
                    }
                }

                string command = GenerationUtils.GetSpliceCommand(renderStateBuilder.ToCodeBlock(), "RenderState");
                spliceCommands.Add("RenderState", command);
            }

            // Pragmas
            using (var passPragmaBuilder = new ShaderStringBuilder())
            {
                if (pass.pragmas != null)
                {
                    foreach (PragmaCollection.Item pragma in pass.pragmas)
                    {
                        if (pragma.TestActive(activeFields))
                        {
                            passPragmaBuilder.AppendLine(pragma.value);
                        }
                    }
                }

                string command = GenerationUtils.GetSpliceCommand(passPragmaBuilder.ToCodeBlock(), "PassPragmas");
                spliceCommands.Add("PassPragmas", command);
            }

            // Includes
            using (var preGraphIncludeBuilder = new ShaderStringBuilder())
            {
                if (pass.includes != null)
                {
                    foreach (IncludeCollection.Item include in pass.includes.Where(x => x.descriptor.location == IncludeLocation.Pregraph))
                    {
                        if (include.TestActive(activeFields))
                        {
                            preGraphIncludeBuilder.AppendLine(include.value);
                        }
                    }
                }

                string command = GenerationUtils.GetSpliceCommand(preGraphIncludeBuilder.ToCodeBlock(), "PreGraphIncludes");
                spliceCommands.Add("PreGraphIncludes", command);
            }
            using (var postGraphIncludeBuilder = new ShaderStringBuilder())
            {
                if (pass.includes != null)
                {
                    foreach (IncludeCollection.Item include in pass.includes.Where(x => x.descriptor.location == IncludeLocation.Postgraph))
                    {
                        if (include.TestActive(activeFields))
                        {
                            postGraphIncludeBuilder.AppendLine(include.value);
                        }
                    }
                }

                string command = GenerationUtils.GetSpliceCommand(postGraphIncludeBuilder.ToCodeBlock(), "PostGraphIncludes");
                spliceCommands.Add("PostGraphIncludes", command);
            }

            // Keywords
            using (var passKeywordBuilder = new ShaderStringBuilder())
            {
                if (pass.keywords != null)
                {
                    foreach (KeywordCollection.Item keyword in pass.keywords)
                    {
                        if (keyword.TestActive(activeFields))
                        {
                            passKeywordBuilder.AppendLine(keyword.value);
                        }
                    }
                }

                string command = GenerationUtils.GetSpliceCommand(passKeywordBuilder.ToCodeBlock(), "PassKeywords");
                spliceCommands.Add("PassKeywords", command);
            }

            // -----------------------------
            // Generated structs and Packing code
            var interpolatorBuilder = new ShaderStringBuilder();
            var passStructs         = new List <StructDescriptor>();

            if (pass.structs != null)
            {
                passStructs.AddRange(pass.structs.Select(x => x.descriptor));

                foreach (StructCollection.Item shaderStruct in pass.structs)
                {
                    if (shaderStruct.descriptor.packFields == false)
                    {
                        continue; //skip structs that do not need interpolator packs
                    }
                    List <int> packedCounts = new List <int>();
                    var        packStruct   = new StructDescriptor();

                    //generate packed functions
                    if (activeFields.permutationCount > 0)
                    {
                        var generatedPackedTypes = new Dictionary <string, (ShaderStringBuilder, List <int>)>();
                        foreach (var instance in activeFields.allPermutations.instances)
                        {
                            var instanceGenerator = new ShaderStringBuilder();
                            GenerationUtils.GenerateInterpolatorFunctions(shaderStruct.descriptor, instance, out instanceGenerator);
                            var key = instanceGenerator.ToCodeBlock();
                            if (generatedPackedTypes.TryGetValue(key, out var value))
                            {
                                value.Item2.Add(instance.permutationIndex);
                            }
                            else
                            {
                                generatedPackedTypes.Add(key, (instanceGenerator, new List <int> {
                                    instance.permutationIndex
                                }));
            private void ProcessIncludeCommand(Token includeCommand, int lineEnd)
            {
                if (Expect(includeCommand.s, includeCommand.end, '('))
                {
                    Token param = ParseString(includeCommand.s, includeCommand.end + 1, lineEnd);

                    if (!param.IsValid())
                    {
                        Error("ERROR: $include expected a string file path parameter", includeCommand.s, includeCommand.end + 1);
                    }
                    else
                    {
                        bool   found           = false;
                        string includeLocation = null;

                        // Use reverse order in the array, higher number element have higher priority in case $include exist in several directories
                        for (int i = templatePaths.Length - 1; i >= 0; i--)
                        {
                            string templatePath = templatePaths[i];
                            includeLocation = Path.Combine(templatePath, param.GetString());
                            if (File.Exists(includeLocation))
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found)
                        {
                            string errorStr = "ERROR: $include cannot find file : " + param.GetString() + ". Looked into:\n";

                            foreach (string templatePath in templatePaths)
                            {
                                errorStr += "// " + templatePath + "\n";
                            }

                            Error(errorStr, includeCommand.s, param.start);
                        }
                        else
                        {
                            int endIndex = result.length;
                            using (var temp = new ShaderStringBuilder())
                            {
                                // Wrap in debug mode
                                if (isDebug)
                                {
                                    result.AppendLine("//-------------------------------------------------------------------------------------");
                                    result.AppendLine("// TEMPLATE INCLUDE : " + param.GetString());
                                    result.AppendLine("//-------------------------------------------------------------------------------------");
                                    result.AppendNewLine();
                                }

                                // Recursively process templates
                                ProcessTemplateFile(includeLocation);

                                // Wrap in debug mode
                                if (isDebug)
                                {
                                    result.AppendNewLine();
                                    result.AppendLine("//-------------------------------------------------------------------------------------");
                                    result.AppendLine("// END TEMPLATE INCLUDE : " + param.GetString());
                                    result.AppendLine("//-------------------------------------------------------------------------------------");
                                }

                                result.AppendNewLine();

                                // Required to enforce indentation rules
                                // Append lines from this include into temporary StringBuilder
                                // Reduce result length to remove this include
                                temp.AppendLines(result.ToString(endIndex, result.length - endIndex));
                                result.length = endIndex;
                                result.AppendLines(temp.ToCodeBlock());
                            }
                        }
                    }
                }
            }