/// <summary>
 /// Creates the shader cache file format structure.
 /// </summary>
 /// <param name="hash">Hash of the guest shader code</param>
 /// <param name="pack">Spans of guest shader code</param>
 /// <param name="code">Host binary shader code</param>
 /// <param name="info">Shader program information</param>
 public ShaderCacheFileFormat(int hash, ShaderPack pack, byte[] code, ShaderProgramInfo[] info)
 {
     Hash      = hash;
     GuestCode = pack.ToArray();
     Code      = code;
     Info      = info;
 }
Beispiel #2
0
        /// <summary>
        /// Loads all pre-compiled shaders cached on disk.
        /// </summary>
        public void LoadShaderCache()
        {
            if (!Configuration.Enabled)
            {
                return;
            }

            ShaderCacheFileFormat[] cached = ShaderCacheFile.Load(Configuration.ShaderPath);

            foreach (ShaderCacheFileFormat scff in cached)
            {
                IProgram hostProgram = _context.Renderer.CreateProgramFromGpuBinary(scff.Code);

                Shader shader = new Shader(hostProgram, new ShaderMeta(hostProgram, scff.Info));

                ShaderPack pack = new ShaderPack();

                for (int index = 0; index < scff.GuestCode.Length; index++)
                {
                    pack.Add(scff.GuestCode[index]);
                }

                _cache.Add(scff.Hash, shader, pack);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Gets the host shader for the guest shader code,
        /// or the default value for the type if not found.
        /// </summary>
        /// <param name="pack">Pack with spans of guest shader code</param>
        /// <param name="hash">Calculated hash of all the shader code on the pack</param>
        /// <returns>Host shader, or the default value if not found</returns>
        public T Get(ShaderPack pack, out int hash)
        {
            Fnv1a hasher = new Fnv1a();

            hasher.Initialize();

            for (int index = 0; index < pack.Count; index++)
            {
                hasher.Add(pack[index]);
            }

            hash = hasher.Hash;

            if (_shaders.TryGetValue(hash, out List <ShaderEntry> list))
            {
                for (int index = 0; index < list.Count; index++)
                {
                    ShaderEntry entry = list[index];

                    if (entry.CodeEquals(pack))
                    {
                        return(entry.Shader);
                    }
                }
            }

            return(default);
Beispiel #4
0
        /// <summary>
        /// Gets a graphics shader program from the shader cache.
        /// This includes all the specified shader stages.
        /// </summary>
        /// <remarks>
        /// This automatically translates, compiles and adds the code to the cache if not present.
        /// </remarks>
        /// <param name="state">Current GPU state</param>
        /// <param name="addresses">Addresses of the shaders for each stage</param>
        /// <returns>Compiled graphics shader code</returns>
        public Shader GetGraphicsShader(GpuState state, ShaderAddresses addresses)
        {
            ShaderPack pack = new ShaderPack();

            if (addresses.Vertex != 0)
            {
                pack.Add(GetShaderCode(addresses.Vertex));
            }

            if (addresses.TessControl != 0)
            {
                pack.Add(GetShaderCode(addresses.TessControl));
            }

            if (addresses.TessEvaluation != 0)
            {
                pack.Add(GetShaderCode(addresses.TessEvaluation));
            }


            gpShaders.Shaders[1] = TranslateGraphicsShader(state, ShaderStage.TessellationControl,    addresses.TessControl);
            gpShaders.Shaders[2] = TranslateGraphicsShader(state, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
            gpShaders.Shaders[3] = TranslateGraphicsShader(state, ShaderStage.Geometry,               addresses.Geometry);
            gpShaders.Shaders[4] = TranslateGraphicsShader(state, ShaderStage.Fragment,               addresses.Fragment);

            List<IShader> hostShaders = new List<IShader>();

            for (int stage = 0; stage < gpShaders.Shaders.Length; stage++)

            if (addresses.Geometry != 0)

            {
                pack.Add(GetShaderCode(addresses.Geometry));
            }

            if (addresses.Fragment != 0)
            {
                pack.Add(GetShaderCode(addresses.Fragment));
            }

            Shader gs = _cache.Get(pack, out int hash);

            if (gs != null)
            {
                return gs;
            }

            ShaderProgram[] programs = new ShaderProgram[5];

            programs[0] = TranslateGraphicsShader(state, ShaderStage.Vertex, addresses.Vertex);
            programs[1] = TranslateGraphicsShader(state, ShaderStage.TessellationControl, addresses.TessControl);
            programs[2] = TranslateGraphicsShader(state, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
            programs[3] = TranslateGraphicsShader(state, ShaderStage.Geometry, addresses.Geometry);
            programs[4] = TranslateGraphicsShader(state, ShaderStage.Fragment, addresses.Fragment);

            BackpropQualifiers(programs);

            IShader[] shaders = new IShader[programs.Count(x => x != null)];
Beispiel #5
0
        /// <summary>
        /// Saves shader code to disk.
        /// </summary>
        /// <param name="basePath">Base path of the shader cache</param>
        /// <param name="info">Array of shader program information for all stages</param>
        /// <param name="pack">Pack with spans of guest shader code</param>
        /// <param name="code">Host binary shader code</param>
        /// <param name="hash">Hash calculated from the guest shader code</param>
        /// <param name="index">Index to disambiguate the shader in case of hash collisions</param>
        public static void Save(string basePath, ShaderProgramInfo[] info, ShaderPack pack, byte[] code, int hash, int index)
        {
            ShaderCacheFileFormat scff = new ShaderCacheFileFormat(hash, pack, code, info);

            BinaryFormatter formatter = new BinaryFormatter();

            string fileName = GetShaderPath(basePath, hash, index);

            using FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);

            formatter.Serialize(fs, scff);
        }
Beispiel #6
0
            /// <summary>
            /// Checks if the shader code on this entry is equal to the guest shader code in memory.
            /// </summary>
            /// <param name="pack">Pack of guest shader code</param>
            /// <returns>True if the code is equal, false otherwise</returns>
            public bool CodeEquals(ShaderPack pack)
            {
                if (pack.Count != _code.Length)
                {
                    return(false);
                }

                for (int index = 0; index < pack.Count; index++)
                {
                    if (!pack[index].SequenceEqual(_code[index]))
                    {
                        return(false);
                    }
                }

                return(true);
            }
Beispiel #7
0
        /// <summary>
        /// Gets a compute shader from the cache.
        /// </summary>
        /// <remarks>
        /// This automatically translates, compiles and adds the code to the cache if not present.
        /// </remarks>
        /// <param name="gpuVa">GPU virtual address of the binary shader code</param>
        /// <param name="localSizeX">Local group size X of the computer shader</param>
        /// <param name="localSizeY">Local group size Y of the computer shader</param>
        /// <param name="localSizeZ">Local group size Z of the computer shader</param>
        /// <param name="localMemorySize">Local memory size of the compute shader</param>
        /// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
        /// <returns>Compiled compute shader code</returns>
        public Shader GetComputeShader(
            ulong gpuVa,
            int localSizeX,
            int localSizeY,
            int localSizeZ,
            int localMemorySize,
            int sharedMemorySize)
        {
            if (gpuVa == 0)
            {
                return(null);
            }

            ShaderPack pack = new ShaderPack();

            ReadOnlySpan <byte> code = GetShaderCodeHeaderless(gpuVa);

            pack.Add(code);

            Shader cs = _cache.Get(pack, out int hash);

            if (cs != null)
            {
                return(cs);
            }

            _dumper.Dump(code, compute: true, out string fullPath, out string codePath);

            int QueryInfo(QueryInfoName info, int index)
            {
                return(info switch
                {
                    QueryInfoName.ComputeLocalSizeX => localSizeX,
                    QueryInfoName.ComputeLocalSizeY => localSizeY,
                    QueryInfoName.ComputeLocalSizeZ => localSizeZ,
                    QueryInfoName.ComputeLocalMemorySize => localMemorySize,
                    QueryInfoName.ComputeSharedMemorySize => sharedMemorySize,
                    _ => QueryInfoCommon(info)
                });
            }
Beispiel #8
0
        public Shader GetComputeShader(

            ulong gpuVa,
            int localSizeX,
            int localSizeY,
            int localSizeZ,
            int localMemorySize,
            int sharedMemorySize)
        {
            if (gpuVa == 0)
            {
                return null;
            }

            ShaderPack pack = new ShaderPack();

            ReadOnlySpan<byte> code = GetShaderCodeHeaderless(gpuVa);

            pack.Add(code);

            Shader cs = _cache.Get(pack, out int hash);

            if (cs != null)
            {
                return cs;
            }

            _dumper.Dump(code, compute: true, out string fullPath, out string codePath);

            int QueryInfo(QueryInfoName info, int index)
            {
                return info switch
                {
                    QueryInfoName.ComputeLocalSizeX => localSizeX,
                    QueryInfoName.ComputeLocalSizeY => localSizeY,
                    QueryInfoName.ComputeLocalSizeZ => localSizeZ,
                    QueryInfoName.ComputeLocalMemorySize => localMemorySize,
                    QueryInfoName.ComputeSharedMemorySize => sharedMemorySize,
                    _ => QueryInfoCommon(info)
                };
            }


            CachedShader shader = TranslateComputeShader(
                state,
                gpuVa,
                localSizeX,
                localSizeY,
                localSizeZ,
                localMemorySize,
                sharedMemorySize);

            TranslatorCallbacks callbacks = new TranslatorCallbacks(QueryInfo, PrintLog);


            ShaderProgram program = Translator.Translate(code, callbacks, DefaultFlags | TranslationFlags.Compute);

            if (fullPath != null && codePath != null)
            {
                program.Prepend("// " + codePath);
                program.Prepend("// " + fullPath);
            }

            IShader shader = _context.Renderer.CompileShader(program);

            IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader });

            cs = new Shader(hostProgram, new ShaderMeta(hostProgram, program.Info));

            int insertIndex = _cache.Add(hash, cs, pack);

            if (Configuration.Enabled)
            {
                ShaderProgramInfo[] info = new ShaderProgramInfo[] { program.Info };

                ShaderCacheFile.Save(Configuration.ShaderPath, info, pack, hostProgram.GetGpuBinary(), hash, insertIndex);
            }

            return cs;
        }