Beispiel #1
0
        /// <summary>
        /// Processes raw shader source into a new <see cref="ShaderSource"/> object.
        /// </summary>
        /// <param name="manager">The <see cref="ContentManager"/> that is loading the shader source.</param>
        /// <param name="metadata">The content processor metadata for the shader source that is being loaded.</param>
        /// <param name="source">The raw shader source to process.</param>
        /// <returns>A <see cref="ShaderSource"/> object that represents the processed shader source.</returns>
        public static ShaderSource ProcessRawSource(ContentManager manager, IContentProcessorMetadata metadata, String source)
        {
            var ssmd = new ShaderSourceMetadata();

            return(ProcessInternal(ssmd, source, (line, output) =>
            {
                if (ProcessIncludeDirective(manager, metadata, line, output, ssmd))
                {
                    return true;
                }

                if (ProcessIncludeResourceDirective(manager, metadata, line, output, ssmd))
                {
                    return true;
                }

                if (ProcessIfVerDirective(manager, metadata, line, output, ssmd))
                {
                    return true;
                }

                if (ProcessSamplerDirective(manager, metadata, line, output, ssmd))
                {
                    return true;
                }

                if (ProcessParamDirective(manager, metadata, line, output, ssmd))
                {
                    return true;
                }

                if (ProcessCameraDirective(manager, metadata, line, output, ssmd))
                {
                    return true;
                }

                return false;
            }));
        }
Beispiel #2
0
        /// <summary>
        /// Processes #camera directives.
        /// </summary>
        private static Boolean ProcessCameraDirective(ContentManager manager, IContentProcessorMetadata metadata, String line, StringBuilder output, ShaderSourceMetadata ssmd)
        {
            var cameraMatch = regexCameraDirective.Match(line);

            if (cameraMatch.Success)
            {
                var parameter = cameraMatch.Groups["parameter"].Value;
                var uniform   = cameraMatch.Groups["uniform"].Value;

                ssmd.AddCameraHint(parameter, uniform);

                return(true);
            }
            return(false);
        }
Beispiel #3
0
        /// <summary>
        /// Processes #param directives.
        /// </summary>
        private static Boolean ProcessParamDirective(ContentManager manager, IContentProcessorMetadata metadata, String line, StringBuilder output, ShaderSourceMetadata ssmd)
        {
            var paramMatch = regexParamDirective.Match(line);

            if (paramMatch.Success)
            {
                var parameter = paramMatch.Groups["parameter"].Value;

                ssmd.AddParameterHint(parameter);

                return(true);
            }
            return(false);
        }
Beispiel #4
0
        /// <summary>
        /// Processes #sampler directives.
        /// </summary>
        private static Boolean ProcessSamplerDirective(ContentManager manager, IContentProcessorMetadata metadata, String line, StringBuilder output, ShaderSourceMetadata ssmd)
        {
            var samplerMatch = regexSamplerDirective.Match(line);

            if (samplerMatch.Success)
            {
                var sampler = Int32.Parse(samplerMatch.Groups["sampler"].Value);
                var uniform = samplerMatch.Groups["uniform"].Value;

                ssmd.AddPreferredSamplerIndex(uniform, sampler);

                return(true);
            }
            return(false);
        }
Beispiel #5
0
        /// <summary>
        /// Processes #ifver directives.
        /// </summary>
        private static Boolean ProcessIfVerDirective(ContentManager manager, IContentProcessorMetadata metadata, String line, StringBuilder output, ShaderSourceMetadata ssmd)
        {
            var ifVerMatch = regexIfVerDirective.Match(line);

            if (ifVerMatch.Success)
            {
                var source = ifVerMatch.Groups["source"].Value;

                var dirVersionIsGLES = !String.IsNullOrEmpty(ifVerMatch.Groups["gles"].Value);
                var dirVersionMajor  = Int32.Parse(ifVerMatch.Groups["version_maj"].Value);
                var dirVersionMinor  = Int32.Parse(ifVerMatch.Groups["version_min"].Value);
                var dirVersion       = new Version(dirVersionMajor, dirVersionMinor);
                var dirSatisfied     = false;

                var uvVersionIsGLES = gl.IsGLES;
                var uvVersionMajor  = gl.MajorVersion;
                var uvVersionMinor  = gl.MinorVersion;
                var uvVersion       = new Version(uvVersionMajor, uvVersionMinor);

                if (dirVersionIsGLES != uvVersionIsGLES)
                {
                    return(true);
                }

                switch (ifVerMatch.Groups["op"].Value)
                {
                case "ifver":
                    dirSatisfied = (uvVersion == dirVersion);
                    break;

                case "ifver_lt":
                    dirSatisfied = (uvVersion < dirVersion);
                    break;

                case "ifver_lte":
                    dirSatisfied = (uvVersion <= dirVersion);
                    break;

                case "ifver_gt":
                    dirSatisfied = (uvVersion > dirVersion);
                    break;

                case "ifver_gte":
                    dirSatisfied = (uvVersion >= dirVersion);
                    break;
                }

                if (dirSatisfied)
                {
                    var includedSource = ProcessRawSource(manager, metadata, source);
                    ssmd.Concat(includedSource.Metadata);
                    output.Append(includedSource.Source);

                    if (!includedSource.Source.EndsWith("\n"))
                    {
                        output.AppendLine();
                    }
                }

                return(true);
            }
            return(false);
        }
Beispiel #6
0
        /// <summary>
        /// Processes #include directives.
        /// </summary>
        private static Boolean ProcessIncludeDirective(ContentManager manager, IContentProcessorMetadata metadata, String line, StringBuilder output, ShaderSourceMetadata ssmd)
        {
            var includeMatch = regexIncludeDirective.Match(line);

            if (includeMatch.Success)
            {
                if (manager == null || metadata == null)
                {
                    throw new InvalidOperationException(OpenGLStrings.CannotIncludeShaderHeadersInStream);
                }

                var includePath = includeMatch.Groups["file"].Value;
                includePath = ContentManager.NormalizeAssetPath(Path.Combine(Path.GetDirectoryName(metadata.AssetPath), includePath));
                metadata.AddAssetDependency(includePath);

                var includeSrc = manager.Load <ShaderSource>(includePath, metadata.AssetDensity, false, metadata.IsLoadedFromSolution);
                ssmd.Concat(includeSrc.Metadata);
                output.AppendLine(includeSrc.Source);

                return(true);
            }
            return(false);
        }
Beispiel #7
0
        /// <summary>
        /// Processes #includeres directives.
        /// </summary>
        private static Boolean ProcessIncludeResourceDirective(ContentManager manager, IContentProcessorMetadata metadata, String line, StringBuilder output, ShaderSourceMetadata ssmd)
        {
            var includeResourceMatch = regexincludeResourceDirective.Match(line);

            if (includeResourceMatch.Success)
            {
                var includeResource = includeResourceMatch.Groups["resource"].Value;
                var includeAsm      = includeResourceMatch.Groups["asm"]?.Value ?? "entry";
                var asm             =
                    String.Equals("entry", includeAsm, StringComparison.OrdinalIgnoreCase) ? Assembly.GetEntryAssembly() :
                    String.Equals("executing", includeAsm, StringComparison.OrdinalIgnoreCase) ? Assembly.GetExecutingAssembly() : null;

                var info = asm.GetManifestResourceInfo(includeResource);
                if (info == null)
                {
                    throw new InvalidOperationException(OpenGLStrings.InvalidIncludedResource.Format(includeResource));
                }

                using (var resStream = asm.GetManifestResourceStream(includeResource))
                    using (var resReader = new StreamReader(resStream))
                    {
                        var includeSrc = ProcessRawSource(manager, metadata, resReader.ReadToEnd());
                        ssmd.Concat(includeSrc.Metadata);
                        output.Append(includeSrc.Source);

                        if (!includeSrc.Source.EndsWith("\n"))
                        {
                            output.AppendLine();
                        }
                    }

                return(true);
            }
            return(false);
        }
Beispiel #8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ShaderSource"/> class.
 /// </summary>
 /// <param name="source">The source code for this shader.</param>
 /// <param name="metadata">The metadata for this shader.</param>
 private ShaderSource(String source, ShaderSourceMetadata metadata)
 {
     this.Source   = source;
     this.Metadata = metadata;
 }
Beispiel #9
0
        /// <summary>
        /// Processes #extern directives.
        /// </summary>
        private static Boolean ProcessExternDirective(String line, StringBuilder output, ShaderSourceMetadata ssmd, Dictionary <String, String> externs)
        {
            var externMatch = regexExternDirective.Match(line);

            if (externMatch.Success)
            {
                var externName = externMatch.Groups["name"].Value;
                if (String.IsNullOrWhiteSpace(externName))
                {
                    throw new InvalidOperationException(OpenGLStrings.ShaderExternHasInvalidName);
                }

                var externValue = String.Empty;
                if (externs?.TryGetValue(externName, out externValue) ?? false)
                {
                    output.AppendLine($"#define {externName} {externValue}");
                }
                return(true);
            }
            return(false);
        }
        /// <summary>
        /// Compiles the specified shader.
        /// </summary>
        /// <param name="shader">The shader handle.</param>
        /// <param name="source">The shader source.</param>
        /// <param name="log">The compiler log.</param>
        /// <param name="ssmd">The source metadata for this shader.</param>
        /// <returns>true if the shader compiled; otherwise, false.</returns>
        public static Boolean Compile(UInt32 shader, ShaderSource[] source, out String log, out ShaderSourceMetadata ssmd)
        {
            Contract.Require(source, nameof(source));

            ssmd = new ShaderSourceMetadata();
            foreach (var s in source)
            {
                ssmd.Concat(s.Metadata);
            }

            unsafe
            {
                var pSource = stackalloc IntPtr[source.Length];
                var pLength = stackalloc Int32[source.Length];
                for (var i = 0; i < source.Length; i++)
                {
                    pSource[i] = Marshal.StringToHGlobalAnsi(source[i].Source);
                    pLength[i] = source[i].Source.Length;
                }

                try
                {
                    gl.ShaderSource(shader, source.Length, (sbyte **)pSource, pLength);
                    gl.ThrowIfError();

                    gl.CompileShader(shader);
                    gl.ThrowIfError();

                    gl.GetShaderInfoLog(shader, out log);
                    gl.ThrowIfError();
                }
                finally
                {
                    for (var i = 0; i < source.Length; i++)
                    {
                        Marshal.FreeHGlobal(pSource[i]);
                    }
                }

                var status = gl.GetShaderi(shader, gl.GL_COMPILE_STATUS);
                gl.ThrowIfError();

                return(status != 0);
            }
        }
Beispiel #11
0
        /// <summary>
        /// Initializes a new instance of the OpenGLShaderProgram class.
        /// </summary>
        /// <param name="uv">The Ultraviolet context.</param>
        /// <param name="vertexShader">The program's vertex shader.</param>
        /// <param name="fragmentShader">The program's fragment shader.</param>
        /// <param name="programOwnsShaders">A value indicating whether the program owns the shader objects.</param>
        public OpenGLShaderProgram(UltravioletContext uv, OpenGLVertexShader vertexShader, OpenGLFragmentShader fragmentShader, Boolean programOwnsShaders)
            : base(uv)
        {
            Contract.Require(vertexShader, nameof(vertexShader));
            Contract.Require(fragmentShader, nameof(fragmentShader));

            Ultraviolet.ValidateResource(vertexShader);
            Ultraviolet.ValidateResource(fragmentShader);

            this.vertexShader       = vertexShader;
            this.fragmentShader     = fragmentShader;
            this.programOwnsShaders = programOwnsShaders;

            var concatenatedSourceMetadata = new ShaderSourceMetadata();

            concatenatedSourceMetadata.Concat(vertexShader.ShaderSourceMetadata);
            concatenatedSourceMetadata.Concat(fragmentShader.ShaderSourceMetadata);

            var program = 0u;

            uv.QueueWorkItem(state =>
            {
                program = gl.CreateProgram();
                gl.ThrowIfError();

                gl.AttachShader(program, vertexShader.OpenGLName);
                gl.ThrowIfError();

                gl.AttachShader(program, fragmentShader.OpenGLName);
                gl.ThrowIfError();

                gl.LinkProgram(program);
                gl.ThrowIfError();

                var log = gl.GetProgramInfoLog(program);
                gl.ThrowIfError();

                var status = gl.GetProgrami(program, gl.GL_LINK_STATUS);
                gl.ThrowIfError();

                var attributeCount = gl.GetProgrami(program, gl.GL_ACTIVE_ATTRIBUTES);
                gl.ThrowIfError();

                unsafe
                {
                    var namebuf = Marshal.AllocHGlobal(256);
                    try
                    {
                        for (int i = 0; i < attributeCount; i++)
                        {
                            var attrNameLen = 0;
                            var attrName    = default(String);
                            var attrSize    = 0;
                            var attrType    = 0u;
                            gl.GetActiveAttrib(program, (uint)i, 256, &attrNameLen, &attrSize, &attrType, (sbyte *)namebuf);
                            gl.ThrowIfError();

                            attrName = Marshal.PtrToStringAnsi(namebuf);

                            var location = gl.GetAttribLocation(program, attrName);
                            gl.ThrowIfError();

                            attributeLocations[attrName] = location;
                            attributeTypes[attrName]     = attrType;
                        }
                    }
                    finally { Marshal.FreeHGlobal(namebuf); }
                }

                if (status == 0)
                {
                    throw new InvalidOperationException(log);
                }
            }).Wait();

            this.program  = program;
            this.uniforms = CreateUniformCollection(concatenatedSourceMetadata);
        }
Beispiel #12
0
        /// <summary>
        /// Creates the effect pass' collection of uniforms.
        /// </summary>
        /// <param name="ssmd">The source metadata for this program.</param>
        /// <returns>The collection of uniforms that was created.</returns>
        private OpenGLShaderUniformCollection CreateUniformCollection(ShaderSourceMetadata ssmd)
        {
            var result = Ultraviolet.QueueWorkItem(state =>
            {
                var programObject = ((OpenGLShaderProgram)state);
                var program       = programObject.program;
                var uniforms      = new List <OpenGLShaderUniform>();
                var samplerCount  = 0;

                var count = gl.GetProgrami(program, gl.GL_ACTIVE_UNIFORMS);
                gl.ThrowIfError();

                for (uint i = 0; i < count; i++)
                {
                    var type = 0u;
                    var name = gl.GetActiveUniform(program, i, out type);
                    gl.ThrowIfError();

                    var location = gl.GetUniformLocation(program, name);
                    gl.ThrowIfError();

                    var isSampler = false;
                    switch (type)
                    {
                    case gl.GL_SAMPLER_1D:
                    case gl.GL_SAMPLER_1D_ARRAY:
                    case gl.GL_SAMPLER_1D_ARRAY_SHADOW:
                    case gl.GL_SAMPLER_1D_SHADOW:
                    case gl.GL_SAMPLER_2D:
                    case gl.GL_SAMPLER_2D_ARRAY:
                    case gl.GL_SAMPLER_2D_ARRAY_SHADOW:
                    case gl.GL_SAMPLER_2D_MULTISAMPLE:
                    case gl.GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
                    case gl.GL_SAMPLER_2D_RECT:
                    case gl.GL_SAMPLER_2D_RECT_SHADOW:
                    case gl.GL_SAMPLER_2D_SHADOW:
                    case gl.GL_SAMPLER_3D:
                    case gl.GL_SAMPLER_CUBE:
                    case gl.GL_SAMPLER_CUBE_MAP_ARRAY:
                    case gl.GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
                    case gl.GL_SAMPLER_CUBE_SHADOW:
                        isSampler = true;
                        break;
                    }

                    var sampler = isSampler ? samplerCount++ : -1;
                    if (isSampler && ssmd.PreferredSamplerIndices.ContainsKey(name))
                    {
                        samplerCount = ssmd.PreferredSamplerIndices[name];
                        sampler      = samplerCount++;
                    }
                    uniforms.Add(new OpenGLShaderUniform(programObject.Ultraviolet, name, type, program, location, sampler));
                }

                return(uniforms);
            }, this).Result;

            // Validation: make sure all preferred samplers correspond to an actual uniform
            var missingUniform = ssmd.PreferredSamplerIndices.Keys.Where(x => !result.Where(y => String.Equals(y.Name, x, StringComparison.Ordinal)).Any()).FirstOrDefault();

            if (missingUniform != null)
            {
                throw new ArgumentException(OpenGLStrings.SamplerDirectiveInvalidUniform.Format(missingUniform));
            }

            return(new OpenGLShaderUniformCollection(result));
        }