Beispiel #1
0
        private LoadedShaderClassType LoadShaderClass(ShaderClassCode classSource, string generics, LoggerResult log, Stride.Core.Shaders.Parser.ShaderMacro[] macros = null)
        {
            var type = classSource.ClassName;

            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            var shaderSourceKey = new ShaderSourceKey(type, generics, macros);

            lock (loadedShaders)
            {
                // Already instantiated
                LoadedShaderClassType shaderClass;

                if (loadedShaders.TryGetValue(shaderSourceKey, out shaderClass))
                {
                    return(shaderClass);
                }

                ShaderSourceManager.ShaderSourceWithHash shaderSource;

                // Load shader source code
                if (classSource is ShaderClassString shaderClassString)
                {
                    shaderSource = SourceManager.LoadShaderSource(type, shaderClassString.ShaderSourceCode);
                }
                else
                {
                    shaderSource = SourceManager.LoadShaderSource(type);
                }

                string preprocessedSource;
                try
                {
                    preprocessedSource = PreProcessor.Run(shaderSource.Source, shaderSource.Path, macros);
                }
                catch (Exception ex)
                {
                    log.Error(MessageCode.ErrorUnexpectedException, new SourceSpan(new SourceLocation(shaderSource.Path, 0, 1, 1), 1), ex);
                    return(null);
                }

                byte[] byteArray            = Encoding.UTF8.GetBytes(preprocessedSource);
                var    hashPreprocessSource = ObjectId.FromBytes(byteArray);

                // Compile
                var parsingResult = StrideShaderParser.TryParse(preprocessedSource, shaderSource.Path);
                parsingResult.CopyTo(log);

                if (parsingResult.HasErrors)
                {
                    return(null);
                }

                var shader = parsingResult.Shader;

                // As shaders can be embedded in namespaces, get only the shader class and make sure there is only one in a sdsl.
                var shaderClassTypes = StrideShaderParser.GetShaderClassTypes(shader.Declarations).ToList();
                if (shaderClassTypes.Count != 1)
                {
                    var sourceSpan = new SourceSpan(new SourceLocation(shaderSource.Path, 0, 0, 0), 1);
                    if (shaderClassTypes.Count > 1)
                    {
                        sourceSpan = shaderClassTypes[1].Span;
                    }
                    log.Error(StrideMessageCode.ShaderMustContainSingleClassDeclaration, sourceSpan, type);
                    return(null);
                }

                shaderClass                        = new LoadedShaderClassType();
                shaderClass.Type                   = shaderClassTypes.First();
                shaderClass.SourcePath             = shaderSource.Path;
                shaderClass.SourceHash             = shaderSource.Hash;
                shaderClass.PreprocessedSourceHash = hashPreprocessSource;
                shaderClass.IsInstanciated         = false;

                // TODO: We should not use Console. Change the way we log things here
                // Console.WriteLine("Loading Shader {0}{1}", type, macros != null && macros.Length > 0 ? String.Format("<{0}>", string.Join(", ", macros)) : string.Empty);

                // If the file name is not matching the class name, provide an error
                if (shaderClass.Type.Name.Text != type)
                {
                    log.Error(StrideMessageCode.FileNameNotMatchingClassName, shaderClass.Type.Name.Span, type, shaderClass.Type.Name.Text);
                    return(null);
                }

                loadedShaders.Add(shaderSourceKey, shaderClass);

                return(shaderClass);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Loads the <see cref="ShaderClassType" />.
        /// </summary>
        /// <param name="shaderClassSource">The shader class source.</param>
        /// <param name="shaderMacros">The shader macros.</param>
        /// <param name="log">The log to output error logs.</param>
        /// <param name="autoGenericInstances"></param>
        /// <returns>A ShaderClassType or null if there was some errors.</returns>
        /// <exception cref="System.ArgumentNullException">shaderClassSource</exception>
        public LoadedShaderClassType LoadClassSource(ShaderClassCode shaderClassSource, Stride.Core.Shaders.Parser.ShaderMacro[] shaderMacros, LoggerResult log, bool autoGenericInstances)
        {
            if (shaderClassSource == null)
            {
                throw new ArgumentNullException("shaderClassSource");
            }

            string generics = null;

            if (shaderClassSource.GenericArguments != null)
            {
                generics = "";
                foreach (var gen in shaderClassSource.GenericArguments)
                {
                    generics += "___" + gen;
                }
            }
            var shaderClassType = LoadShaderClass(shaderClassSource, generics, log, shaderMacros);

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

            // Instantiate generic class
            if (shaderClassSource.GenericArguments != null || (shaderClassType.Type.ShaderGenerics.Count > 0 && autoGenericInstances))
            {
                if (shaderClassType.IsInstanciated)
                {
                    return(shaderClassType);
                }

                // If we want to automatically generate a generic instance (in case we just want to parse and verify the generic)
                if (autoGenericInstances)
                {
                    shaderClassSource.GenericArguments = new string[shaderClassType.Type.ShaderGenerics.Count];
                    for (int i = 0; i < shaderClassSource.GenericArguments.Length; i++)
                    {
                        var variableGeneric = shaderClassType.Type.ShaderGenerics[i];
                        shaderClassSource.GenericArguments[i] = GetDefaultConstValue(variableGeneric);
                    }
                }

                if (shaderClassSource.GenericArguments.Length != shaderClassType.Type.ShaderGenerics.Count)
                {
                    log.Error(StrideMessageCode.WrongGenericNumber, shaderClassType.Type.Span, shaderClassSource.ClassName);
                    return(null);
                }

                // check the name of the generics
                foreach (var generic in shaderClassType.Type.ShaderGenerics)
                {
                    foreach (var genericCompare in shaderClassType.Type.ShaderGenerics.Where(x => x != generic))
                    {
                        if (generic.Name.Text == genericCompare.Name.Text)
                        {
                            log.Error(StrideMessageCode.SameNameGenerics, generic.Span, generic, genericCompare, shaderClassSource.ClassName);
                        }
                    }
                }

                if (log.HasErrors)
                {
                    return(null);
                }

                // When we use an actual generic instance, we replace the name with the name of the class + a hash of the generic parameters
                if (!autoGenericInstances)
                {
                    var className = GenerateGenericClassName(shaderClassSource);
                    shaderClassType.Type.Name = new Identifier(className);
                }

                var genericAssociation = CreateGenericAssociation(shaderClassType.Type.ShaderGenerics, shaderClassSource.GenericArguments);
                var identifierGenerics = GenerateIdentifierFromGenerics(genericAssociation);
                var expressionGenerics = GenerateGenericsExpressionValues(shaderClassType.Type.ShaderGenerics, shaderClassSource.GenericArguments);
                StrideClassInstantiator.Instantiate(shaderClassType.Type, expressionGenerics, identifierGenerics, autoGenericInstances, log);
                shaderClassType.Type.ShaderGenerics.Clear();
                shaderClassType.IsInstanciated = true;
            }
            return(shaderClassType);
        }