예제 #1
0
파일: Shader.cs 프로젝트: LibVega/Vega
        internal Shader(ShaderLayout info, ShaderProgram program)
        {
            Layout = info;
            Layout.IncRefCount();

            Program = program;
            Program.IncRefCount();
        }
예제 #2
0
파일: VSL.cs 프로젝트: LibVega/Vega
        // Parse a compiled VSL shader and return the info and modules
        public static void LoadStream(string path, Stream stream,
                                      out ShaderLayout info,
                                      out VkShaderModule vertMod, out VkShaderModule fragMod)
        {
            // Open the file and check the header
            using var file = new BinaryReader(stream);
            Span <byte> header = stackalloc byte[4];

            file.Read(header);
            if ((header[0] != 'V') || (header[1] != 'B') || (header[2] != 'C'))
            {
                throw new InvalidShaderException(path, "Invalid magic number");
            }
            if (header[3] != 1)
            {
                throw new InvalidShaderException(path, "Invalid shader file version");
            }

            // Read rest of header
            file.Read(header.Slice(0, 1));
            if (header[0] != 1)
            {
                throw new InvalidShaderException(path, "Invalid shader type, only graphics shaders supported");
            }
            Span <ushort> bcLengths = stackalloc ushort[5];

            file.Read(MemoryMarshal.AsBytes(bcLengths));
            Span <ushort> tableSizes = stackalloc ushort[5];

            file.Read(MemoryMarshal.AsBytes(tableSizes));

            // Validate header values
            if (bcLengths[0] == 0)
            {
                throw new InvalidShaderException(path, "Shader has no vertex stage");
            }
            if ((bcLengths[1] != 0) || (bcLengths[2] != 0) || (bcLengths[3] != 0))
            {
                throw new InvalidShaderException(path, "Shader has unsupported stages");
            }
            if (bcLengths[4] == 0)
            {
                throw new InvalidShaderException(path, "Shader has no fragment stage");
            }
            if ((tableSizes[0] != BindingTable.DEFAULT_SIZE_SAMPLER) || (tableSizes[1] != BindingTable.DEFAULT_SIZE_IMAGE) ||
                (tableSizes[2] != BindingTable.DEFAULT_SIZE_BUFFER) || (tableSizes[3] != BindingTable.DEFAULT_SIZE_ROTEXELS) ||
                (tableSizes[4] != BindingTable.DEFAULT_SIZE_RWTEXELS))
            {
                throw new InvalidShaderException(path, "Invalid binding table sizes");
            }

            // Read the vertex inputs
            var inputCount = file.ReadUInt32();
            Span <InterfaceVariable> inputs = stackalloc InterfaceVariable[(int)inputCount];

            file.Read(MemoryMarshal.AsBytes(inputs));
            ProcessVertexInputs(path, inputs, out var reflInputs);

            // Read the fragment outputs
            var outputCount = file.ReadUInt32();
            Span <InterfaceVariable> outputs = stackalloc InterfaceVariable[(int)outputCount];

            file.Read(MemoryMarshal.AsBytes(outputs));
            ProcessFragmentOutputs(path, outputs, out var reflOutputs);

            // Read the bindings
            var bindingCount = file.ReadUInt32();
            Span <BindingVariable> bindings = stackalloc BindingVariable[(int)bindingCount];

            file.Read(MemoryMarshal.AsBytes(bindings));
            ProcessBindings(path, bindings, out var reflBindings);

            // Read the uniform info
            var uniformSize = file.ReadUInt16();

            ShaderLayout.UniformMember[]? reflUniformMembers = null;
            ShaderStages uniformStages = ShaderStages.None;

            if (uniformSize > 0)
            {
                uniformStages = (ShaderStages)file.ReadUInt16();
                var uniformMemberCount      = file.ReadUInt32();
                Span <StructMember> members = stackalloc StructMember[(int)uniformMemberCount];
                var         memberNames     = new string[uniformMemberCount];
                Span <byte> nameBytes       = stackalloc byte[64];
                for (uint i = 0; i < uniformMemberCount; ++i)
                {
                    uint nameLength = file.ReadByte();
                    var  thisName   = nameBytes.Slice(0, (int)nameLength);
                    file.Read(thisName);
                    file.Read(MemoryMarshal.AsBytes(members.Slice((int)i, 1)));
                    memberNames[i] = Encoding.ASCII.GetString(thisName);
                }
                ProcessUniformMembers(path, members, memberNames, out reflUniformMembers);
            }

            // Read the subpass inputs
            var spiCount            = file.ReadUInt32();
            Span <SubpassInput> spi = stackalloc SubpassInput[(int)spiCount];

            if (spiCount > 0)
            {
                file.Read(MemoryMarshal.AsBytes(spi));
            }
            ProcessSubpassInputs(path, spi, out var reflSpi);

            // Read the bytecodes
            var vertBC = new uint[bcLengths[0]];
            var fragBC = new uint[bcLengths[4]];

            file.Read(MemoryMarshal.AsBytes(new Span <uint>(vertBC)));
            file.Read(MemoryMarshal.AsBytes(new Span <uint>(fragBC)));

            // Last validation
            if (file.BaseStream.Position != file.BaseStream.Length)
            {
                throw new InvalidShaderException(path, "File not fully consumed by parser");
            }

            // Create shader modules
            info = new(
                ShaderStages.Vertex | ShaderStages.Fragment,
                reflInputs,
                reflOutputs,
                reflBindings,
                uniformSize, uniformStages, reflUniformMembers ?? Array.Empty <ShaderLayout.UniformMember>(),
                reflSpi
                );
            CreateShaderModules(path, Core.Instance !.Graphics.VkDevice,
                                vertBC, fragBC,
                                out vertMod, out fragMod
                                );
        }