Example #1
0
        public void DoubleConstant_ParsedCorrectly()
        {
            var res    = SpirvCompilation.CompileGlslToSpirv(@"
#version 450

void main()
{
    double x = 12.3;
    gl_Position = vec4(x);
}
", "shader.vert", ShaderStages.Vertex, GlslCompileOptions.Default);
            var shader = SpirVGraph.Shader.Parse(res.SpirvBytes);

#if DEBUG
            Console.WriteLine(shader);
#endif

            var constants = shader.Instructions.Where(_ => _.OpCode == Op.OpConstant).Select(_ => (OpConstant)_).ToList();
            foreach (var instruction in constants)
            {
                if (instruction.Value.Value.Type.OpCode == Op.OpTypeFloat &&
                    instruction.Value.Value.Type.SizeInWords == 2)
                {
                    if (instruction.Value.Value.ToDouble() == 12.3)
                    {
                        return;
                    }
                }
            }
            Assert.Fail("Didn't find Double constant in the shader code:\n" + shader);
        }
Example #2
0
        public static (Shader vs, Shader fs, SpecializationConstant[] specializations) LoadSPIRV(
            GraphicsDevice gd,
            ResourceFactory factory,
            string vertexShaderName,
            string fragmentShaderName,
            ReadOnlySpan <SpecializationConstant> specializations)
        {
            byte[] vsBytes = LoadBytecode(GraphicsBackend.Vulkan, vertexShaderName, ShaderStages.Vertex);
            byte[] fsBytes = LoadBytecode(GraphicsBackend.Vulkan, fragmentShaderName, ShaderStages.Fragment);

            bool debug = false;

#if DEBUG
            debug = true;
#endif
            CrossCompileOptions options = GetOptions(gd, specializations);

            var dst = SpirvCompilation.CompileVertexFragment(vsBytes, fsBytes, CrossCompileTarget.HLSL);

            Shader[] shaders = factory.CreateFromSpirv(
                new ShaderDescription(ShaderStages.Vertex, vsBytes, "main", debug),
                new ShaderDescription(ShaderStages.Fragment, fsBytes, "main", debug),
                options);

            Shader vs = shaders[0];
            Shader fs = shaders[1];

            vs.Name = vertexShaderName + "-Vertex";
            fs.Name = fragmentShaderName + "-Fragment";

            return(vs, fs, options.Specializations);
        }
Example #3
0
        public void ReflectionFromSpirv_Succeeds(
            string vertex, string fragment,
            VertexElementDescription[] verts,
            ResourceLayoutDescription[] layouts)
        {
            byte[] vsBytes = TestUtil.LoadBytes(vertex);
            byte[] fsBytes = TestUtil.LoadBytes(fragment);
            VertexFragmentCompilationResult result = SpirvCompilation.CompileVertexFragment(
                vsBytes,
                fsBytes,
                CrossCompileTarget.HLSL);

            VertexElementDescription[] reflectedVerts = result.Reflection.VertexElements;
            Assert.Equal(verts.Length, reflectedVerts.Length);
            for (int i = 0; i < verts.Length; i++)
            {
                Assert.Equal(verts[i], reflectedVerts[i]);
            }

            ResourceLayoutDescription[] reflectedLayouts = result.Reflection.ResourceLayouts;
            Assert.Equal(layouts.Length, reflectedLayouts.Length);
            for (int i = 0; i < layouts.Length; i++)
            {
                ResourceLayoutDescription layout          = layouts[i];
                ResourceLayoutDescription reflectedLayout = reflectedLayouts[i];
                Assert.Equal(layout.Elements.Length, reflectedLayout.Elements.Length);
                for (int j = 0; j < layout.Elements.Length; j++)
                {
                    Assert.Equal(layout.Elements[j], reflectedLayout.Elements[j]);
                }
            }
        }
        public void ComputeSucceeds(string cs, CrossCompileTarget target)
        {
            byte[] csBytes = TestUtil.LoadBytes(cs);
            ComputeCompilationResult result = SpirvCompilation.CompileCompute(csBytes, target);

            Assert.NotNull(result.ComputeShader);
        }
Example #5
0
        public void FindAllDecorations()
        {
            var map = new Dictionary <Op, HashSet <Decoration.Enumerant> >();

            foreach (var shader in SampleShaders.EnumerateShaders())
            {
                SpirvCompilationResult shaderBytes;
                try
                {
                    (var shaderSource, var stage) = SampleShaders.LoadShader(shader, typeof(SampleShaders).Assembly);
                    shaderBytes = SpirvCompilation.CompileGlslToSpirv(shaderSource, "shader.vk", stage,
                                                                      new GlslCompileOptions {
                        Debug = true
                    });
                }
                catch (SpirvCompilationException exception)
                {
                    continue;
                }
                var instructions = Shader.Parse(shaderBytes.SpirvBytes);


                //var decorates = instructions.Instructions
                //    .Where(_ => _.OpCode == Op.OpDecorate)
                //    .Select(_ => (OpDecorate) _);
                //foreach (var opDecorate in decorates)
                //{
                //    if (!map.TryGetValue(opDecorate.Target.Instruction.OpCode, out var set))
                //    {
                //        set = new HashSet<Decoration.Enumerant>();
                //        map.Add(opDecorate.Target.Instruction.OpCode, set);
                //    }

                //    set.Add(opDecorate.Decoration.Value);
                //}
                var decorates = instructions.Instructions
                                .Where(_ => _.OpCode == Op.OpMemberDecorate)
                                .Select(_ => (OpMemberDecorate)_);

                foreach (var opDecorate in decorates)
                {
                    if (!map.TryGetValue(opDecorate.StructureType.Instruction.OpCode, out var set))
                    {
                        set = new HashSet <Decoration.Enumerant>();
                        map.Add(opDecorate.StructureType.Instruction.OpCode, set);
                    }

                    set.Add(opDecorate.Decoration.Value);
                }
            }
            foreach (var decorate in map)
            {
                Console.WriteLine($"{decorate.Key}:");
                foreach (var enumerant in decorate.Value)
                {
                    Console.WriteLine($"  {enumerant}");
                }
            }
        }
Example #6
0
        private static (byte[], Shader) CompileToBytecode(string vertexShaderText)
        {
            var vertex = SpirvCompilation.CompileGlslToSpirv(vertexShaderText, "vertex.glsl", ShaderStages.Vertex,
                                                             new GlslCompileOptions {
                Debug = true
            });

            return(vertex.SpirvBytes, Shader.Parse(vertex.SpirvBytes));
        }
 public void CompilationFails(string vs, string fs, CrossCompileTarget target)
 {
     byte[] vsBytes = TestUtil.LoadBytes(vs);
     byte[] fsBytes = TestUtil.LoadBytes(fs);
     Assert.Throws <SpirvCompilationException>(() =>
                                               SpirvCompilation.CompileVertexFragment(
                                                   vsBytes,
                                                   fsBytes,
                                                   target,
                                                   new CrossCompileOptions(false, false)));
 }
Example #8
0
        private byte[] CompileToSpirv(
            VesselShaderDescription shader,
            string fileName,
            ShaderStages stage)
        {
            GlslCompileOptions     glslOptions = VesselShaderUtil.GetOptions(shader);
            string                 glsl        = VesselShaderUtil.LoadGlsl(fileName);
            SpirvCompilationResult result      = SpirvCompilation.CompileGlslToSpirv(
                glsl,
                fileName,
                stage,
                glslOptions);

            return(result.SpirvBytes);
        }
        public void GlslToSpirv_Succeeds(string name, ShaderStages stage)
        {
            SpirvCompilationResult result = SpirvCompilation.CompileGlslToSpirv(
                TestUtil.LoadShaderText(name),
                name,
                stage,
                new GlslCompileOptions(
                    false,
                    new MacroDefinition("Name0", "Value0"),
                    new MacroDefinition("Name1", "Value1"),
                    new MacroDefinition("Name2")));

            Assert.NotNull(result.SpirvBytes);
            Assert.True(result.SpirvBytes.Length > 4);
            Assert.True(result.SpirvBytes.Length % 4 == 0);
        }
Example #10
0
        private string[] CompileCompute(VesselShaderDescription shader)
        {
            List <string> generatedFiles = new List <string>();
            var           csBytes        = CompileToSpirv(shader, shader.Shaders[0].FileName, ShaderStages.Compute);

            // Generate metadata for HLSL, cuz we want to know the semantics since theyre important on HLSL
            var crossData = SpirvCompilation.CompileCompute(csBytes, CrossCompileTarget.HLSL);

            WriteShaderBinary(
                shader.Name + ".shdr",
                new byte[][] { csBytes },
                crossData.Reflection);

            Console.WriteLine($"Successfully compiled \"{Path.GetFileNameWithoutExtension(shader.Shaders[0].FileName)}\" as a Compute shader!");

            return(generatedFiles.ToArray());
        }
Example #11
0
        public void VertexFragmentSucceeds(string vs, string fs, CrossCompileTarget target)
        {
            byte[] vsBytes = TestUtil.LoadBytes(vs);
            byte[] fsBytes = TestUtil.LoadBytes(fs);
            SpecializationConstant[] specializations =
            {
                new SpecializationConstant(100,  125u),
                new SpecializationConstant(101, true),
                new SpecializationConstant(102, 0.75f),
            };
            VertexFragmentCompilationResult result = SpirvCompilation.CompileVertexFragment(
                vsBytes,
                fsBytes,
                target,
                new CrossCompileOptions(false, false, specializations));

            Assert.NotNull(result.VertexShader);
            Assert.NotNull(result.FragmentShader);
        }
Example #12
0
        private (Shader, Veldrid.Shader[]) CompileShaderForFieldSet(TypeStruct fieldSet)
        {
            var vertexShaderText = new VertexShaderTemplate(fieldSet).TransformText();

            var(vertexBytes, shaderInstructions) = CompileToBytecode(vertexShaderText);
            var fragmentShaderText = new FragmentShaderTemplate().TransformText();
            var fragment           = SpirvCompilation.CompileGlslToSpirv(fragmentShaderText, "fragment.glsl",
                                                                         ShaderStages.Fragment, new GlslCompileOptions {
                Debug = true
            });
            var shaders = ResourceFactory.CreateFromSpirv(
                new ShaderDescription(ShaderStages.Vertex, vertexBytes, "main"),
                new ShaderDescription(ShaderStages.Fragment, fragment.SpirvBytes, "main"));

            foreach (var shader in shaders)
            {
                Disposables.Add(shader);
            }
            return(shaderInstructions, shaders);
        }
Example #13
0
        public void LoadSampleShader(string resource)
        {
            string text = null;

            using (var stream = this.GetType().Assembly.GetManifestResourceStream(resource))
            {
                text = new StreamReader(stream).ReadToEnd();
            }

            var stage = ShaderStages.Vertex;

            if (resource.EndsWith(".comp"))
            {
                stage = ShaderStages.Compute;
            }
            if (resource.EndsWith(".vert"))
            {
                stage = ShaderStages.Vertex;
            }
            if (resource.EndsWith(".frag"))
            {
                stage = ShaderStages.Fragment;
            }
            SpirvCompilationResult res;

            try
            {
                res = SpirvCompilation.CompileGlslToSpirv(text, resource, stage, GlslCompileOptions.Default);
            }
            catch (Exception ex)
            {
                Assert.Ignore(ex.Message);
                return;
            }

            var shader = SpirVGraph.Shader.Parse(res.SpirvBytes);

#if DEBUG
            Console.WriteLine(shader);
#endif
        }
Example #14
0
 public static byte[] CompileToBytecode(string vertexShaderText, ShaderStages stage = ShaderStages.Vertex, bool debug = true, bool throwOnError = false)
 {
     if (throwOnError)
     {
         var vertex = SpirvCompilation.CompileGlslToSpirv(vertexShaderText, "shader.vk", stage,
                                                          new GlslCompileOptions {
             Debug = debug
         });
         return(vertex.SpirvBytes);
     }
     try
     {
         var vertex = SpirvCompilation.CompileGlslToSpirv(vertexShaderText, "shader.vk", stage,
                                                          new GlslCompileOptions {
             Debug = debug
         });
         return(vertex.SpirvBytes);
     }
     catch (SpirvCompilationException exception)
     {
         Assert.Ignore(exception.Message);
         return(null);
     }
 }
Example #15
0
        public ShaderSet(AssetFactoryState assets, RawShaderSet raw)
        {
            var graphics = assets.Graphics;

            Shader?Compile(ShaderStages stage, string?glsl)
            {
                return(glsl == null
                    ? null
                    : graphics.Device.ResourceFactory.CreateShader(new ShaderDescription(stage,
                                                                                         SpirvCompilation.CompileGlslToSpirv(glsl, stage.ToString(), stage,
                                                                                                                             GlslCompileOptions.Default).SpirvBytes, "main")));
            }

            Vertex                 = Compile(ShaderStages.Vertex, raw.Vertex);
            Geometry               = Compile(ShaderStages.Geometry, raw.Geometry);
            TessellationControl    = Compile(ShaderStages.TessellationControl, raw.TessellationControl);
            TessellationEvaluation = Compile(ShaderStages.TessellationEvaluation, raw.TessellationEvaluation);
            Fragment               = Compile(ShaderStages.Fragment, raw.Fragment);
            Compute                = Compile(ShaderStages.Compute, raw.Compute);
            var vertexElements = Vertex == null
                ? new VertexElementDescription[0]
                : VertexInputPattern.Matches(raw.Vertex !).Select(x =>
                                                                  new VertexElementDescription(x.Groups["name"].Value, VertexElementSemantic.Position,
                                                                                               x.Groups["type"].Value switch
            {
                "ivec4" => VertexElementFormat.Int4,
                _ => throw new NotImplementedException()
            }, uint.Parse(x.Groups["offset"].Value)
Example #16
0
        private string[] CompileVertexFragment(VesselShaderDescription shader)
        {
            List <string>    generatedFiles        = new List <string>();
            List <Exception> compilationExceptions = new List <Exception>();

            byte[] vsBytes = null;
            byte[] fsBytes = null;

            // Compile vertex shader
            string vertexFileName = shader.Shaders.FirstOrDefault(vsd => vsd.Stage == ShaderStages.Vertex).FileName;

            if (vertexFileName != null)
            {
                try
                {
                    vsBytes = CompileToSpirv(shader, vertexFileName, ShaderStages.Vertex);
                }
                catch (Exception e)
                {
                    compilationExceptions.Add(e);
                }
            }

            // Compile fragment shader
            string fragmentFileName = shader.Shaders.FirstOrDefault(vsd => vsd.Stage == ShaderStages.Fragment).FileName;

            if (fragmentFileName != null)
            {
                try
                {
                    fsBytes = CompileToSpirv(shader, fragmentFileName, ShaderStages.Fragment);
                }
                catch (Exception e)
                {
                    compilationExceptions.Add(e);
                }
            }

            if (compilationExceptions.Count > 0)
            {
                throw new AggregateException(
                          $"Errors were encountered when compiling from GLSL to SPIR-V.",
                          compilationExceptions);
            }

            try
            {
                // Generate reflection data
                VertexFragmentCompilationResult result = SpirvCompilation.CompileVertexFragment(vsBytes, fsBytes, CrossCompileTarget.HLSL);

                WriteShaderBinary(
                    shader.Name + ".shdr",
                    new byte[][] { vsBytes, fsBytes },
                    result.Reflection);
            }
            catch (Exception e)
            {
                compilationExceptions.Add(e);
            }

            if (compilationExceptions.Count > 0)
            {
                throw new AggregateException($"Errors were encountered when compiling shader variant(s).", compilationExceptions);
            }

            Console.WriteLine($"Successfully compiled \"{Path.GetFileNameWithoutExtension(shader.Shaders[0].FileName)}\" as a Vertex, Fragment pair shader!");

            return(generatedFiles.ToArray());
        }
Example #17
0
        private static void CompileAll(string inputDirectory, string outputDirectory)
        {
            Directory.CreateDirectory(outputDirectory);
            IEnumerable <string> files = Directory.EnumerateFiles(inputDirectory);

            var shaderSets =
                from path in files
                let vert                       = path.EndsWith("vert")
                                      let frag = path.EndsWith("frag")
                                                 where vert || frag
                                                 let name = Path.GetFileNameWithoutExtension(path)
                                                            group(path, vert, frag) by name into g
                                                            where g.Count() == 2
                                                            select new
            {
                Name     = g.Key,
                Vertex   = g.FirstOrDefault(x => x.vert).path,
                Fragment = g.FirstOrDefault(x => x.frag).path,
            };

            foreach (var shaderSet in shaderSets)
            {
                string outputBase = Path.Combine(outputDirectory, shaderSet.Name);
                byte[] vs         = File.ReadAllBytes(shaderSet.Vertex);
                byte[] fs         = File.ReadAllBytes(shaderSet.Fragment);

                string vsSource = Encoding.UTF8.GetString(vs);
                string fsSource = Encoding.UTF8.GetString(fs);

                var debugCompileOptions = new GlslCompileOptions(debug: true);
                var vsSpvDebugOutput    = SpirvCompilation.CompileGlslToSpirv(
                    vsSource, string.Empty, ShaderStages.Vertex,
                    debugCompileOptions);
                var fsSpvDebugOutput = SpirvCompilation.CompileGlslToSpirv(
                    fsSource, string.Empty, ShaderStages.Fragment,
                    debugCompileOptions);

                var releaseCompileOptions = new GlslCompileOptions(debug: false);
                var vsSpvReleaseOutput    = SpirvCompilation.CompileGlslToSpirv(
                    vsSource, string.Empty, ShaderStages.Vertex,
                    releaseCompileOptions);
                var fsSpvReleaseOutput = SpirvCompilation.CompileGlslToSpirv(
                    fsSource, string.Empty, ShaderStages.Fragment,
                    releaseCompileOptions);
                File.WriteAllBytes(outputBase + "-vertex.450.glsl.spv", vsSpvReleaseOutput.SpirvBytes);
                File.WriteAllBytes(outputBase + "-fragment.450.glsl.spv", fsSpvDebugOutput.SpirvBytes);

                var glCompileOptions = new CrossCompileOptions(fixClipSpaceZ: true, invertVertexOutputY: false);
                var glslResult       = SpirvCompilation.CompileVertexFragment(
                    vsSpvDebugOutput.SpirvBytes,
                    fsSpvDebugOutput.SpirvBytes,
                    CrossCompileTarget.GLSL,
                    glCompileOptions);
                File.WriteAllText(outputBase + "-vertex.330.glsl", glslResult.VertexShader);
                File.WriteAllText(outputBase + "-fragment.330.glsl", glslResult.FragmentShader);

                var esslResult = SpirvCompilation.CompileVertexFragment(
                    vsSpvDebugOutput.SpirvBytes,
                    fsSpvDebugOutput.SpirvBytes,
                    CrossCompileTarget.ESSL,
                    glCompileOptions);
                File.WriteAllText(outputBase + "-vertex.300.glsles", glslResult.VertexShader);
                File.WriteAllText(outputBase + "-fragment.300.glsles", glslResult.FragmentShader);

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    var hlslDebugOutput = SpirvCompilation.CompileVertexFragment(
                        vsSpvDebugOutput.SpirvBytes,
                        fsSpvDebugOutput.SpirvBytes,
                        CrossCompileTarget.HLSL);
                    File.WriteAllText(outputBase + "-vertex.hlsl", hlslDebugOutput.VertexShader);
                    File.WriteAllText(outputBase + "-fragment.hlsl", hlslDebugOutput.FragmentShader);

                    var hlslReleaseOutput = SpirvCompilation.CompileVertexFragment(
                        vsSpvReleaseOutput.SpirvBytes,
                        fsSpvReleaseOutput.SpirvBytes,
                        CrossCompileTarget.HLSL);

                    byte[] vertBytes = Encoding.UTF8.GetBytes(hlslReleaseOutput.VertexShader);
                    byte[] fragBytes = Encoding.UTF8.GetBytes(hlslReleaseOutput.FragmentShader);
                    File.WriteAllBytes(outputBase + "-vertex.hlsl.bytes", CompileHlsl(ShaderStages.Vertex, vertBytes));
                    File.WriteAllBytes(outputBase + "-fragment.hlsl.bytes", CompileHlsl(ShaderStages.Fragment, fragBytes));
                }
            }
        }
Example #18
0
        private static void GetOrCreateCachedShaders(
            ResourceFactory factory,
            string shaderName,
            bool debug,
            out byte[] vsBytes,
            out byte[] fsBytes)
        {
            const string shaderCacheFolder = "ShaderCache";
            var          backendType       = factory.BackendType;
            var          targetExtension   = backendType.ToString().ToLowerInvariant();

            if (!Directory.Exists(shaderCacheFolder))
            {
                Directory.CreateDirectory(shaderCacheFolder);
            }

            var vsSpvName = $"OpenSage.Assets.Shaders.{shaderName}.vert.spv";
            var fsSpvName = $"OpenSage.Assets.Shaders.{shaderName}.frag.spv";

            var vsSpvBytes = ReadSpvShader(vsSpvName);
            var fsSpvBytes = ReadSpvShader(fsSpvName);

            var vsSpvHash = GetShaderHash(vsSpvBytes);
            var fsSpvHash = GetShaderHash(fsSpvBytes);

            // Check that SPIR-V files on disk match what's in the assembly.
            var vsCacheFilePath = Path.Combine(shaderCacheFolder, $"OpenSage.Assets.Shaders.{shaderName}.vert.{vsSpvHash}.{targetExtension}");
            var fsCacheFilePath = Path.Combine(shaderCacheFolder, $"OpenSage.Assets.Shaders.{shaderName}.frag.{fsSpvHash}.{targetExtension}");

            if (File.Exists(vsCacheFilePath) &&
                File.Exists(fsCacheFilePath))
            {
                // Cache is valid - use it.
                vsBytes = File.ReadAllBytes(vsCacheFilePath);
                fsBytes = File.ReadAllBytes(fsCacheFilePath);
                return;
            }

            // Cache is invalid or doesn't exist - do cross-compilation.

            if (backendType == GraphicsBackend.Vulkan)
            {
                File.WriteAllBytes(vsCacheFilePath, vsSpvBytes);
                File.WriteAllBytes(fsCacheFilePath, fsSpvBytes);
                vsBytes = vsSpvBytes;
                fsBytes = fsSpvBytes;
                return;
            }

            var compilationTarget = GetCompilationTarget(backendType);
            var compilationResult = SpirvCompilation.CompileVertexFragment(
                vsSpvBytes,
                fsSpvBytes,
                compilationTarget,
                new CrossCompileOptions());

            switch (backendType)
            {
            case GraphicsBackend.Direct3D11:
                vsBytes = CompileHlsl(compilationResult.VertexShader, "vs_5_0", debug);
                fsBytes = CompileHlsl(compilationResult.FragmentShader, "ps_5_0", debug);
                break;

            case GraphicsBackend.OpenGL:
            case GraphicsBackend.OpenGLES:
                vsBytes = Encoding.ASCII.GetBytes(compilationResult.VertexShader);
                fsBytes = Encoding.ASCII.GetBytes(compilationResult.FragmentShader);
                break;

            case GraphicsBackend.Metal:
                // TODO: Compile to IR.
                vsBytes = Encoding.UTF8.GetBytes(compilationResult.VertexShader);
                fsBytes = Encoding.UTF8.GetBytes(compilationResult.FragmentShader);
                break;

            default:
                throw new InvalidOperationException();
            }

            File.WriteAllBytes(vsCacheFilePath, vsBytes);
            File.WriteAllBytes(fsCacheFilePath, fsBytes);
        }
Example #19
0
    public static ShaderCacheFile GetOrCreateCachedShaders(
        ResourceFactory factory,
        Assembly shaderAssembly,
        string shaderName)
    {
        const string shaderCacheFolder = "ShaderCache";
        var          backendType       = factory.BackendType;
        var          targetExtension   = backendType.ToString().ToLowerInvariant();

        if (!Directory.Exists(shaderCacheFolder))
        {
            Directory.CreateDirectory(shaderCacheFolder);
        }

        var vsSpvBytes = ReadShaderSpv(shaderAssembly, shaderName, "vert");
        var fsSpvBytes = ReadShaderSpv(shaderAssembly, shaderName, "frag");

        var spvHash = GetShaderHash(vsSpvBytes, fsSpvBytes);

        // Look for cached shader file on disk match the input SPIR-V shaders.
        var cacheFilePath = Path.Combine(shaderCacheFolder, $"OpenSage.Assets.Shaders.{shaderName}.{spvHash}.{targetExtension}");

        if (ShaderCacheFile.TryLoad(cacheFilePath, out var shaderCacheFile))
        {
            // Cache is valid - use it.
            return(shaderCacheFile);
        }

        // Cache is invalid or doesn't exist - do cross-compilation.

        // For Vulkan, we don't actually need to do cross-compilation. But we do need to get reflection data.
        // So we cross-compile to HLSL, throw away the resulting HLSL, and use the reflection data.
        var compilationTarget = backendType == GraphicsBackend.Vulkan
            ? CrossCompileTarget.HLSL
            : GetCompilationTarget(backendType);

        var compilationResult = SpirvCompilation.CompileVertexFragment(
            vsSpvBytes,
            fsSpvBytes,
            compilationTarget,
            new CrossCompileOptions());

        byte[] vsBytes, fsBytes;

        switch (backendType)
        {
        case GraphicsBackend.Vulkan:
            vsBytes = vsSpvBytes;
            fsBytes = fsSpvBytes;
            break;

        case GraphicsBackend.Direct3D11:
            vsBytes = CompileHlsl(compilationResult.VertexShader, "vs_5_0");
            fsBytes = CompileHlsl(compilationResult.FragmentShader, "ps_5_0");
            break;

        case GraphicsBackend.OpenGL:
        case GraphicsBackend.OpenGLES:
            vsBytes = Encoding.ASCII.GetBytes(compilationResult.VertexShader);
            fsBytes = Encoding.ASCII.GetBytes(compilationResult.FragmentShader);
            break;

        case GraphicsBackend.Metal:
            // TODO: Compile to IR.
            vsBytes = Encoding.UTF8.GetBytes(compilationResult.VertexShader);
            fsBytes = Encoding.UTF8.GetBytes(compilationResult.FragmentShader);
            break;

        default:
            throw new InvalidOperationException();
        }

        var entryPoint = factory.BackendType == GraphicsBackend.Metal
            ? $"{EntryPoint}0"
            : EntryPoint;

        shaderCacheFile = new ShaderCacheFile(
            new ShaderDescription(ShaderStages.Vertex, vsBytes, entryPoint),
            new ShaderDescription(ShaderStages.Fragment, fsBytes, entryPoint),
            compilationResult.Reflection.ResourceLayouts);

        shaderCacheFile.Save(cacheFilePath);

        return(shaderCacheFile);
    }
Example #20
0
        protected override void CreateResources(ResourceFactory factory)
        {
            _particleBuffer = factory.CreateBuffer(
                new BufferDescription(
                    (uint)Unsafe.SizeOf <ParticleInfo>() * ParticleCount,
                    BufferUsage.StructuredBufferReadWrite,
                    (uint)Unsafe.SizeOf <ParticleInfo>()));

            _screenSizeBuffer = factory.CreateBuffer(new BufferDescription(16, BufferUsage.UniformBuffer));

            _computeShader = factory.CreateFromSpirv(new ShaderDescription(
                                                         ShaderStages.Compute,
                                                         ReadEmbeddedAssetBytes($"Compute.glsl"),
                                                         "main"));

            ResourceLayout particleStorageLayout = factory.CreateResourceLayout(new ResourceLayoutDescription(
                                                                                    new ResourceLayoutElementDescription("ParticlesBuffer", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute)));

            ResourceLayout screenSizeLayout = factory.CreateResourceLayout(new ResourceLayoutDescription(
                                                                               new ResourceLayoutElementDescription("ScreenSizeBuffer", ResourceKind.UniformBuffer, ShaderStages.Compute)));

            ComputePipelineDescription computePipelineDesc = new ComputePipelineDescription(
                _computeShader,
                new[] { particleStorageLayout, screenSizeLayout },
                1, 1, 1);

            _computePipeline = factory.CreateComputePipeline(ref computePipelineDesc);

            _computeResourceSet = factory.CreateResourceSet(new ResourceSetDescription(particleStorageLayout, _particleBuffer));

            _computeScreenSizeResourceSet = factory.CreateResourceSet(new ResourceSetDescription(screenSizeLayout, _screenSizeBuffer));

            var result = SpirvCompilation.CompileVertexFragment(ReadEmbeddedAssetBytes($"Vertex.glsl"), ReadEmbeddedAssetBytes($"Fragment.glsl"), CrossCompileTarget.MSL);

            var shaders = factory.CreateFromSpirv(
                new ShaderDescription(
                    ShaderStages.Vertex,
                    ReadEmbeddedAssetBytes($"Vertex.glsl"),
                    "main"),
                new ShaderDescription(
                    ShaderStages.Fragment,
                    ReadEmbeddedAssetBytes($"Fragment.glsl"),
                    "main"));

            ShaderSetDescription shaderSet = new ShaderSetDescription(
                Array.Empty <VertexLayoutDescription>(),
                shaders);

            particleStorageLayout = factory.CreateResourceLayout(new ResourceLayoutDescription(
                                                                     new ResourceLayoutElementDescription("ParticlesBuffer", ResourceKind.StructuredBufferReadOnly, ShaderStages.Vertex)));

            screenSizeLayout = factory.CreateResourceLayout(new ResourceLayoutDescription(
                                                                new ResourceLayoutElementDescription("ScreenSizeBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex)));

            GraphicsPipelineDescription particleDrawPipelineDesc = new GraphicsPipelineDescription(
                BlendStateDescription.SingleOverrideBlend,
                DepthStencilStateDescription.Disabled,
                RasterizerStateDescription.Default,
                PrimitiveTopology.PointList,
                shaderSet,
                new[] { particleStorageLayout, screenSizeLayout },
                MainSwapchain.Framebuffer.OutputDescription);

            _graphicsPipeline = factory.CreateGraphicsPipeline(ref particleDrawPipelineDesc);

            _graphicsParticleResourceSet = factory.CreateResourceSet(new ResourceSetDescription(
                                                                         particleStorageLayout,
                                                                         _particleBuffer));

            _screenSizeResourceSet = factory.CreateResourceSet(new ResourceSetDescription(
                                                                   screenSizeLayout,
                                                                   _screenSizeBuffer));

            _cl = factory.CreateCommandList();

            InitResources(factory);
            _initialized = true;
        }
Example #21
0
 public static VertexFragmentCompilationResult DecompileBytecode(byte[] vertexShader, byte[] fragmentShader, CrossCompileTarget target = CrossCompileTarget.GLSL)
 {
     return(SpirvCompilation.CompileVertexFragment(vertexShader, fragmentShader, target));
 }