Пример #1
0
 public void Add(IncludeCollection includes)
 {
     foreach (IncludeCollection.Item item in includes)
     {
         m_Items.Add(item);
     }
 }
Пример #2
0
 public IncludeCollection Add(IncludeCollection includes)
 {
     foreach (IncludeCollection.Item item in includes)
     {
         m_Items.Add(item);
     }
     return(this);
 }
Пример #3
0
 public IncludeCollection Add(IncludeCollection includes)
 {
     if (includes != null)
     {
         foreach (var include in includes)
         {
             AddInternal(include.guid, include.path, include.location, include.fieldConditions);
         }
     }
     return(this);
 }
Пример #4
0
        static void ProcessSubGraph(SubGraphAsset asset, GraphData graph)
        {
            var graphIncludes = new IncludeCollection();
            var registry      = new FunctionRegistry(new ShaderStringBuilder(), graphIncludes, true);

            asset.functions.Clear();
            asset.isValid = true;

            graph.OnEnable();
            graph.messageManager.ClearAll();
            graph.ValidateGraph();

            var assetPath = AssetDatabase.GUIDToAssetPath(asset.assetGuid);

            asset.hlslName        = NodeUtils.GetHLSLSafeName(Path.GetFileNameWithoutExtension(assetPath));
            asset.inputStructName = $"Bindings_{asset.hlslName}_{asset.assetGuid}_$precision";
            asset.functionName    = $"SG_{asset.hlslName}_{asset.assetGuid}_$precision";
            asset.path            = graph.path;

            var outputNode = graph.outputNode;

            var outputSlots = PooledList <MaterialSlot> .Get();

            outputNode.GetInputSlots(outputSlots);

            List <AbstractMaterialNode> nodes = new List <AbstractMaterialNode>();

            NodeUtils.DepthFirstCollectNodesFromNode(nodes, outputNode);

            asset.effectiveShaderStage = ShaderStageCapability.All;
            foreach (var slot in outputSlots)
            {
                var stage = NodeUtils.GetEffectiveShaderStageCapability(slot, true);
                if (stage != ShaderStageCapability.All)
                {
                    asset.effectiveShaderStage = stage;
                    break;
                }
            }

            asset.vtFeedbackVariables = VirtualTexturingFeedbackUtils.GetFeedbackVariables(outputNode as SubGraphOutputNode);
            asset.requirements        = ShaderGraphRequirements.FromNodes(nodes, asset.effectiveShaderStage, false);

            // output precision is whatever the output node has as a graph precision, falling back to the graph default
            asset.outputGraphPrecision = outputNode.graphPrecision.GraphFallback(graph.graphDefaultPrecision);

            // this saves the graph precision, which indicates whether this subgraph is switchable or not
            asset.subGraphGraphPrecision = graph.graphDefaultPrecision;

            asset.previewMode = graph.previewMode;

            asset.includes = graphIncludes;

            GatherDescendentsFromGraph(new GUID(asset.assetGuid), out var containsCircularDependency, out var descendents);
            asset.descendents.AddRange(descendents.Select(g => g.ToString()));
            asset.descendents.Sort();   // ensure deterministic order

            var childrenSet = new HashSet <string>();
            var anyErrors   = false;

            foreach (var node in nodes)
            {
                if (node is SubGraphNode subGraphNode)
                {
                    var subGraphGuid = subGraphNode.subGraphGuid;
                    childrenSet.Add(subGraphGuid);
                }

                if (node.hasError)
                {
                    anyErrors = true;
                }
                asset.children = childrenSet.ToList();
                asset.children.Sort(); // ensure deterministic order
            }

            if (!anyErrors && containsCircularDependency)
            {
                Debug.LogError($"Error in Graph at {assetPath}: Sub Graph contains a circular dependency.", asset);
                anyErrors = true;
            }

            if (anyErrors)
            {
                asset.isValid = false;
                registry.ProvideFunction(asset.functionName, sb => {});
                return;
            }

            foreach (var node in nodes)
            {
                if (node is IGeneratesFunction generatesFunction)
                {
                    registry.builder.currentNode = node;
                    generatesFunction.GenerateNodeFunction(registry, GenerationMode.ForReals);
                }
            }

            // provide top level subgraph function
            // NOTE: actual concrete precision here shouldn't matter, it's irrelevant when building the subgraph asset
            registry.ProvideFunction(asset.functionName, asset.subGraphGraphPrecision, ConcretePrecision.Single, sb =>
            {
                GenerationUtils.GenerateSurfaceInputStruct(sb, asset.requirements, asset.inputStructName);
                sb.AppendNewLine();

                // Generate the arguments... first INPUTS
                var arguments = new List <string>();
                foreach (var prop in graph.properties)
                {
                    // apply fallback to the graph default precision (but don't convert to concrete)
                    // this means "graph switchable" properties will use the precision token
                    GraphPrecision propGraphPrecision = prop.precision.ToGraphPrecision(graph.graphDefaultPrecision);
                    string precisionString            = propGraphPrecision.ToGenericString();
                    arguments.Add(prop.GetPropertyAsArgumentString(precisionString));
                }

                // now pass surface inputs
                arguments.Add(string.Format("{0} IN", asset.inputStructName));

                // Now generate output arguments
                foreach (MaterialSlot output in outputSlots)
                {
                    arguments.Add($"out {output.concreteValueType.ToShaderString(asset.outputGraphPrecision.ToGenericString())} {output.shaderOutputName}_{output.id}");
                }

                // Vt Feedback output arguments (always full float4)
                foreach (var output in asset.vtFeedbackVariables)
                {
                    arguments.Add($"out {ConcreteSlotValueType.Vector4.ToShaderString(ConcretePrecision.Single)} {output}_out");
                }

                // Create the function prototype from the arguments
                sb.AppendLine("void {0}({1})"
                              , asset.functionName
                              , arguments.Aggregate((current, next) => $"{current}, {next}"));

                // now generate the function
                using (sb.BlockScope())
                {
                    // Just grab the body from the active nodes
                    foreach (var node in nodes)
                    {
                        if (node is IGeneratesBodyCode generatesBodyCode)
                        {
                            sb.currentNode = node;
                            generatesBodyCode.GenerateNodeCode(sb, GenerationMode.ForReals);

                            if (node.graphPrecision == GraphPrecision.Graph)
                            {
                                // code generated by nodes that use graph precision stays in generic form with embedded tokens
                                // those tokens are replaced when this subgraph function is pulled into a graph that defines the precision
                            }
                            else
                            {
                                sb.ReplaceInCurrentMapping(PrecisionUtil.Token, node.concretePrecision.ToShaderString());
                            }
                        }
                    }

                    foreach (var slot in outputSlots)
                    {
                        sb.AppendLine($"{slot.shaderOutputName}_{slot.id} = {outputNode.GetSlotValue(slot.id, GenerationMode.ForReals)};");
                    }

                    foreach (var slot in asset.vtFeedbackVariables)
                    {
                        sb.AppendLine($"{slot}_out = {slot};");
                    }
                }
            });

            // save all of the node-declared functions to the subgraph asset
            foreach (var name in registry.names)
            {
                var source = registry.sources[name];
                var func   = new FunctionPair(name, source.code, source.graphPrecisionFlags);
                asset.functions.Add(func);
            }

            var collector = new PropertyCollector();

            foreach (var node in nodes)
            {
                int previousPropertyCount = Math.Max(0, collector.propertyCount - 1);

                node.CollectShaderProperties(collector, GenerationMode.ForReals);

                // This is a stop-gap to prevent the autogenerated values from JsonObject and ShaderInput from
                // resulting in non-deterministic import data. While we should move to local ids in the future,
                // this will prevent cascading shader recompilations.
                for (int i = previousPropertyCount; i < collector.propertyCount; ++i)
                {
                    var prop        = collector.GetProperty(i);
                    var namespaceId = node.objectId;
                    var nameId      = prop.referenceName;

                    prop.OverrideObjectId(namespaceId, nameId + "_ObjectId_" + i);
                    prop.OverrideGuid(namespaceId, nameId + "_Guid_" + i);
                }
            }
            asset.WriteData(graph.properties, graph.keywords, collector.properties, outputSlots, graph.unsupportedTargets);
            outputSlots.Dispose();
        }
Пример #5
0
        // TODO: Fix this
        static ShaderGraphVfxAsset GenerateVfxShaderGraphAsset(GraphData graph)
        {
            var target = graph.activeTargets.FirstOrDefault(x => x is VFXTarget) as VFXTarget;

            if (target == null)
            {
                return(null);
            }

            // we need to override graph.isSubgraph, so save old state to restore it
            // (this is not great, but whole VFX pipeline is rather hacky at the moment)
            // use try/finally to ensure it always gets restored
            bool oldIsSubGraph = graph.isSubGraph;

            try
            {
                // override to generate as a subgraph, as that is what VFX is using it as
                graph.isSubGraph = true;

                var nl     = Environment.NewLine;
                var indent = new string(' ', 4);
                var asset  = ScriptableObject.CreateInstance <ShaderGraphVfxAsset>();
                var result = asset.compilationResult = new GraphCompilationResult();
                var mode   = GenerationMode.ForReals;

                asset.lit           = target.lit;
                asset.alphaClipping = target.alphaTest;

                var assetGuid = graph.assetGuid;
                var assetPath = AssetDatabase.GUIDToAssetPath(assetGuid);
                var hlslName  = NodeUtils.GetHLSLSafeName(Path.GetFileNameWithoutExtension(assetPath));

                var ports = new List <MaterialSlot>();
                var nodes = new List <AbstractMaterialNode>();

                foreach (var vertexBlock in graph.vertexContext.blocks)
                {
                    vertexBlock.value.GetInputSlots(ports);
                    NodeUtils.DepthFirstCollectNodesFromNode(nodes, vertexBlock);
                }

                foreach (var fragmentBlock in graph.fragmentContext.blocks)
                {
                    fragmentBlock.value.GetInputSlots(ports);
                    NodeUtils.DepthFirstCollectNodesFromNode(nodes, fragmentBlock);
                }

                //Remove inactive blocks from generation
                {
                    var tmpCtx = new TargetActiveBlockContext(new List <BlockFieldDescriptor>(), null);
                    target.GetActiveBlocks(ref tmpCtx);
                    ports.RemoveAll(materialSlot =>
                    {
                        return(!tmpCtx.activeBlocks.Any(o => materialSlot.RawDisplayName() == o.displayName));
                    });
                }

                var bodySb        = new ShaderStringBuilder(1);
                var graphIncludes = new IncludeCollection();
                var registry      = new FunctionRegistry(new ShaderStringBuilder(), graphIncludes, true);

                foreach (var properties in graph.properties)
                {
                    properties.SetupConcretePrecision(graph.graphDefaultConcretePrecision);
                }

                foreach (var node in nodes)
                {
                    if (node is IGeneratesBodyCode bodyGenerator)
                    {
                        bodySb.currentNode = node;
                        bodyGenerator.GenerateNodeCode(bodySb, mode);
                        bodySb.ReplaceInCurrentMapping(PrecisionUtil.Token, node.concretePrecision.ToShaderString());
                    }

                    if (node is IGeneratesFunction generatesFunction)
                    {
                        registry.builder.currentNode = node;
                        generatesFunction.GenerateNodeFunction(registry, mode);
                    }
                }
                bodySb.currentNode = null;

                var portNodeSets = new HashSet <AbstractMaterialNode> [ports.Count];
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var port    = ports[portIndex];
                    var nodeSet = new HashSet <AbstractMaterialNode>();
                    NodeUtils.CollectNodeSet(nodeSet, port);
                    portNodeSets[portIndex] = nodeSet;
                }

                var portPropertySets = new HashSet <string> [ports.Count];
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    portPropertySets[portIndex] = new HashSet <string>();
                }

                foreach (var node in nodes)
                {
                    if (!(node is PropertyNode propertyNode))
                    {
                        continue;
                    }

                    for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                    {
                        var portNodeSet = portNodeSets[portIndex];
                        if (portNodeSet.Contains(node))
                        {
                            portPropertySets[portIndex].Add(propertyNode.property.objectId);
                        }
                    }
                }

                var shaderProperties = new PropertyCollector();
                foreach (var node in nodes)
                {
                    node.CollectShaderProperties(shaderProperties, GenerationMode.ForReals);
                }

                asset.SetTextureInfos(shaderProperties.GetConfiguredTexutres());

                var codeSnippets      = new List <string>();
                var portCodeIndices   = new List <int> [ports.Count];
                var sharedCodeIndices = new List <int>();
                for (var i = 0; i < portCodeIndices.Length; i++)
                {
                    portCodeIndices[i] = new List <int>();
                }

                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"#include \"Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl\"{nl}");

                foreach (var include in graphIncludes)
                {
                    sharedCodeIndices.Add(codeSnippets.Count);
                    codeSnippets.Add(include.value + nl);
                }

                for (var registryIndex = 0; registryIndex < registry.names.Count; registryIndex++)
                {
                    var name      = registry.names[registryIndex];
                    var source    = registry.sources[name];
                    var precision = source.nodes.First().concretePrecision;

                    var hasPrecisionMismatch = false;
                    var nodeNames            = new HashSet <string>();
                    foreach (var node in source.nodes)
                    {
                        nodeNames.Add(node.name);
                        if (node.concretePrecision != precision)
                        {
                            hasPrecisionMismatch = true;
                            break;
                        }
                    }

                    if (hasPrecisionMismatch)
                    {
                        var message = new StringBuilder($"Precision mismatch for function {name}:");
                        foreach (var node in source.nodes)
                        {
                            message.AppendLine($"{node.name} ({node.objectId}): {node.concretePrecision}");
                        }
                        throw new InvalidOperationException(message.ToString());
                    }

                    var code = source.code.Replace(PrecisionUtil.Token, precision.ToShaderString());
                    code = $"// Node: {string.Join(", ", nodeNames)}{nl}{code}";
                    var codeIndex = codeSnippets.Count;
                    codeSnippets.Add(code + nl);
                    for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                    {
                        var portNodeSet = portNodeSets[portIndex];
                        foreach (var node in source.nodes)
                        {
                            if (portNodeSet.Contains(node))
                            {
                                portCodeIndices[portIndex].Add(codeIndex);
                                break;
                            }
                        }
                    }
                }

                foreach (var property in graph.properties)
                {
                    if (property.isExposed)
                    {
                        continue;
                    }

                    for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                    {
                        var portPropertySet = portPropertySets[portIndex];
                        if (portPropertySet.Contains(property.objectId))
                        {
                            portCodeIndices[portIndex].Add(codeSnippets.Count);
                        }
                    }

                    ShaderStringBuilder builder = new ShaderStringBuilder();
                    property.ForeachHLSLProperty(h => h.AppendTo(builder));

                    codeSnippets.Add($"// Property: {property.displayName}{nl}{builder.ToCodeBlock()}{nl}{nl}");
                }


                var inputStructName        = $"SG_Input_{assetGuid}";
                var outputStructName       = $"SG_Output_{assetGuid}";
                var evaluationFunctionName = $"SG_Evaluate_{assetGuid}";

                #region Input Struct

                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"struct {inputStructName}{nl}{{{nl}");

                #region Requirements

                var portRequirements = new ShaderGraphRequirements[ports.Count];
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var requirementsNodes = portNodeSets[portIndex].ToList();
                    requirementsNodes.Add(ports[portIndex].owner);
                    portRequirements[portIndex] = ShaderGraphRequirements.FromNodes(requirementsNodes, ports[portIndex].stageCapability);
                }

                var portIndices = new List <int>();
                portIndices.Capacity = ports.Count;

                void AddRequirementsSnippet(Func <ShaderGraphRequirements, bool> predicate, string snippet)
                {
                    portIndices.Clear();
                    for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                    {
                        if (predicate(portRequirements[portIndex]))
                        {
                            portIndices.Add(portIndex);
                        }
                    }

                    if (portIndices.Count > 0)
                    {
                        foreach (var portIndex in portIndices)
                        {
                            portCodeIndices[portIndex].Add(codeSnippets.Count);
                        }

                        codeSnippets.Add($"{indent}{snippet};{nl}");
                    }
                }

                void AddCoordinateSpaceSnippets(InterpolatorType interpolatorType, Func <ShaderGraphRequirements, NeededCoordinateSpace> selector)
                {
                    foreach (var space in EnumInfo <CoordinateSpace> .values)
                    {
                        var neededSpace = space.ToNeededCoordinateSpace();
                        AddRequirementsSnippet(r => (selector(r) & neededSpace) > 0, $"float3 {space.ToVariableName(interpolatorType)}");
                    }
                }

                // TODO: Rework requirements system to make this better
                AddCoordinateSpaceSnippets(InterpolatorType.Normal, r => r.requiresNormal);
                AddCoordinateSpaceSnippets(InterpolatorType.Tangent, r => r.requiresTangent);
                AddCoordinateSpaceSnippets(InterpolatorType.BiTangent, r => r.requiresBitangent);
                AddCoordinateSpaceSnippets(InterpolatorType.ViewDirection, r => r.requiresViewDir);
                AddCoordinateSpaceSnippets(InterpolatorType.Position, r => r.requiresPosition);

                AddRequirementsSnippet(r => r.requiresVertexColor, $"float4 {ShaderGeneratorNames.VertexColor}");
                AddRequirementsSnippet(r => r.requiresScreenPosition, $"float4 {ShaderGeneratorNames.ScreenPosition}");
                AddRequirementsSnippet(r => r.requiresFaceSign, $"float4 {ShaderGeneratorNames.FaceSign}");

                foreach (var uvChannel in EnumInfo <UVChannel> .values)
                {
                    AddRequirementsSnippet(r => r.requiresMeshUVs.Contains(uvChannel), $"half4 {uvChannel.GetUVName()}");
                }

                AddRequirementsSnippet(r => r.requiresTime, $"float3 {ShaderGeneratorNames.TimeParameters}");

                #endregion

                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"}};{nl}{nl}");

                #endregion

                // VFX Code heavily relies on the slotId from the original MasterNodes
                // Since we keep these around for upgrades anyway, for now it is simpler to use them
                // Therefore we remap the output blocks back to the original Ids here
                var originialPortIds = new int[ports.Count];
                for (int i = 0; i < originialPortIds.Length; i++)
                {
                    if (!VFXTarget.s_BlockMap.TryGetValue((ports[i].owner as BlockNode).descriptor, out var originalId))
                    {
                        continue;
                    }

                    // In Master Nodes we had a different BaseColor/Color slot id between Unlit/Lit
                    // In the stack we use BaseColor for both cases. Catch this here.
                    if (asset.lit && originalId == ShaderGraphVfxAsset.ColorSlotId)
                    {
                        originalId = ShaderGraphVfxAsset.BaseColorSlotId;
                    }

                    originialPortIds[i] = originalId;
                }

                #region Output Struct

                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"struct {outputStructName}{nl}{{");

                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var port = ports[portIndex];
                    portCodeIndices[portIndex].Add(codeSnippets.Count);
                    codeSnippets.Add($"{nl}{indent}{port.concreteValueType.ToShaderString(graph.graphDefaultConcretePrecision)} {port.shaderOutputName}_{originialPortIds[portIndex]};");
                }

                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"{nl}}};{nl}{nl}");

                #endregion

                #region Graph Function

                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"{outputStructName} {evaluationFunctionName}({nl}{indent}{inputStructName} IN");

                var inputProperties     = new List <AbstractShaderProperty>();
                var portPropertyIndices = new List <int> [ports.Count];
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    portPropertyIndices[portIndex] = new List <int>();
                }

                foreach (var property in graph.properties)
                {
                    if (!property.isExposed)
                    {
                        continue;
                    }

                    var propertyIndex = inputProperties.Count;
                    var codeIndex     = codeSnippets.Count;

                    for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                    {
                        var portPropertySet = portPropertySets[portIndex];
                        if (portPropertySet.Contains(property.objectId))
                        {
                            portCodeIndices[portIndex].Add(codeIndex);
                            portPropertyIndices[portIndex].Add(propertyIndex);
                        }
                    }

                    inputProperties.Add(property);
                    codeSnippets.Add($",{nl}{indent}/* Property: {property.displayName} */ {property.GetPropertyAsArgumentString(property.concretePrecision.ToShaderString())}");
                }

                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"){nl}{{");

                #region Node Code

                for (var mappingIndex = 0; mappingIndex < bodySb.mappings.Count; mappingIndex++)
                {
                    var mapping = bodySb.mappings[mappingIndex];
                    var code    = bodySb.ToString(mapping.startIndex, mapping.count);
                    if (string.IsNullOrWhiteSpace(code))
                    {
                        continue;
                    }

                    code = $"{nl}{indent}// Node: {mapping.node.name}{nl}{code}";
                    var codeIndex = codeSnippets.Count;
                    codeSnippets.Add(code);
                    for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                    {
                        var portNodeSet = portNodeSets[portIndex];
                        if (portNodeSet.Contains(mapping.node))
                        {
                            portCodeIndices[portIndex].Add(codeIndex);
                        }
                    }
                }

                #endregion

                #region Output Mapping

                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"{nl}{indent}// VFXMasterNode{nl}{indent}{outputStructName} OUT;{nl}");

                // Output mapping
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    var port = ports[portIndex];
                    portCodeIndices[portIndex].Add(codeSnippets.Count);
                    codeSnippets.Add($"{indent}OUT.{port.shaderOutputName}_{originialPortIds[portIndex]} = {port.owner.GetSlotValue(port.id, GenerationMode.ForReals, graph.graphDefaultConcretePrecision)};{nl}");
                }

                #endregion

                // Function end
                sharedCodeIndices.Add(codeSnippets.Count);
                codeSnippets.Add($"{indent}return OUT;{nl}}}{nl}");

                #endregion

                result.codeSnippets      = codeSnippets.ToArray();
                result.sharedCodeIndices = sharedCodeIndices.ToArray();
                result.outputCodeIndices = new IntArray[ports.Count];
                for (var i = 0; i < ports.Count; i++)
                {
                    result.outputCodeIndices[i] = portCodeIndices[i].ToArray();
                }

                var outputMetadatas = new OutputMetadata[ports.Count];
                for (int portIndex = 0; portIndex < outputMetadatas.Length; portIndex++)
                {
                    outputMetadatas[portIndex] = new OutputMetadata(portIndex, ports[portIndex].shaderOutputName, originialPortIds[portIndex]);
                }

                asset.SetOutputs(outputMetadatas);

                asset.evaluationFunctionName = evaluationFunctionName;
                asset.inputStructName        = inputStructName;
                asset.outputStructName       = outputStructName;
                asset.portRequirements       = portRequirements;
                asset.concretePrecision      = graph.graphDefaultConcretePrecision;
                asset.SetProperties(inputProperties);
                asset.outputPropertyIndices = new IntArray[ports.Count];
                for (var portIndex = 0; portIndex < ports.Count; portIndex++)
                {
                    asset.outputPropertyIndices[portIndex] = portPropertyIndices[portIndex].ToArray();
                }

                return(asset);
            }
            finally
            {
                graph.isSubGraph = oldIsSubGraph;
            }
        }
Пример #6
0
 public void RequiresIncludes(IncludeCollection includes)
 {
     m_Includes.Add(includes);
 }
Пример #7
0
 public FunctionRegistry(ShaderStringBuilder builder, IncludeCollection includes, bool validate = false)
 {
     m_Builder  = builder;
     m_Includes = includes;
     m_Validate = validate;
 }