Exemplo n.º 1
0
        /// <summary>
        /// Check the completion status of the shader compile task, and run callbacks on step completion.
        /// Calling this periodically is required to progress through steps of the compilation.
        /// </summary>
        /// <returns>True if the task is complete, false if it is in progress</returns>
        public bool IsDone()
        {
            if (_compiling)
            {
                ProgramLinkStatus status = _program.CheckProgramLink(false);

                if (status != ProgramLinkStatus.Incomplete)
                {
                    return(_action(status == ProgramLinkStatus.Success, this));
                }
            }
            else
            {
                // Waiting on the task.

                if (_programsTask.IsCompleted)
                {
                    return(_action(true, this));
                }
            }

            return(false);
        }
Exemplo n.º 2
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">GPU state</param>
        /// <param name="channel">GPU channel</param>
        /// <param name="gas">GPU accessor state</param>
        /// <param name="addresses">Addresses of the shaders for each stage</param>
        /// <returns>Compiled graphics shader code</returns>
        public ShaderBundle GetGraphicsShader(ref ThreedClassState state, GpuChannel channel, GpuAccessorState gas, ShaderAddresses addresses)
        {
            bool isCached = _gpPrograms.TryGetValue(addresses, out List <ShaderBundle> list);

            if (isCached)
            {
                foreach (ShaderBundle cachedGpShaders in list)
                {
                    if (IsShaderEqual(channel.MemoryManager, cachedGpShaders, addresses))
                    {
                        return(cachedGpShaders);
                    }
                }
            }

            TranslatorContext[] shaderContexts = new TranslatorContext[Constants.ShaderStages + 1];

            TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(ref state);

            TranslationFlags flags = DefaultFlags;

            if (tfd != null)
            {
                flags |= TranslationFlags.Feedback;
            }

            TranslationCounts counts = new TranslationCounts();

            if (addresses.VertexA != 0)
            {
                shaderContexts[0] = DecodeGraphicsShader(channel, gas, counts, flags | TranslationFlags.VertexA, ShaderStage.Vertex, addresses.VertexA);
            }

            shaderContexts[1] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Vertex, addresses.Vertex);
            shaderContexts[2] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationControl, addresses.TessControl);
            shaderContexts[3] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
            shaderContexts[4] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Geometry, addresses.Geometry);
            shaderContexts[5] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Fragment, addresses.Fragment);

            bool isShaderCacheEnabled  = _cacheManager != null;
            bool isShaderCacheReadOnly = false;

            Hash128 programCodeHash = default;

            GuestShaderCacheEntry[] shaderCacheEntries = null;

            // Current shader cache doesn't support bindless textures
            for (int i = 0; i < shaderContexts.Length; i++)
            {
                if (shaderContexts[i] != null && shaderContexts[i].UsedFeatures.HasFlag(FeatureFlags.Bindless))
                {
                    isShaderCacheEnabled = false;
                    break;
                }
            }

            if (isShaderCacheEnabled)
            {
                isShaderCacheReadOnly = _cacheManager.IsReadOnly;

                // Compute hash and prepare data for shader disk cache comparison.
                shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(channel.MemoryManager, shaderContexts);
                programCodeHash    = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries, tfd);
            }

            ShaderBundle gpShaders;

            // Search for the program hash in loaded shaders.
            if (!isShaderCacheEnabled || !_gpProgramsDiskCache.TryGetValue(programCodeHash, out gpShaders))
            {
                if (isShaderCacheEnabled)
                {
                    Logger.Debug?.Print(LogClass.Gpu, $"Shader {programCodeHash} not in cache, compiling!");
                }

                // The shader isn't currently cached, translate it and compile it.
                ShaderCodeHolder[] shaders = new ShaderCodeHolder[Constants.ShaderStages];

                for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
                {
                    shaders[stageIndex] = TranslateShader(_dumper, channel.MemoryManager, shaderContexts, stageIndex + 1);
                }

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

                for (int stage = 0; stage < Constants.ShaderStages; stage++)
                {
                    ShaderProgram program = shaders[stage]?.Program;

                    if (program == null)
                    {
                        continue;
                    }

                    IShader hostShader = _context.Renderer.CompileShader(program.Stage, program.Code);

                    shaders[stage].HostShader = hostShader;

                    hostShaders.Add(hostShader);
                }

                IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd);

                hostProgram.CheckProgramLink(true);

                byte[] hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), shaders);

                gpShaders = new ShaderBundle(hostProgram, shaders);

                if (isShaderCacheEnabled)
                {
                    _gpProgramsDiskCache.Add(programCodeHash, gpShaders);

                    if (!isShaderCacheReadOnly)
                    {
                        _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries, tfd), hostProgramBinary);
                    }
                }
            }

            if (!isCached)
            {
                list = new List <ShaderBundle>();

                _gpPrograms.Add(addresses, list);
            }

            list.Add(gpShaders);

            return(gpShaders);
        }
Exemplo n.º 3
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="channel">GPU channel</param>
        /// <param name="gas">GPU accessor state</param>
        /// <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 ShaderBundle GetComputeShader(
            GpuChannel channel,
            GpuAccessorState gas,
            ulong gpuVa,
            int localSizeX,
            int localSizeY,
            int localSizeZ,
            int localMemorySize,
            int sharedMemorySize)
        {
            bool isCached = _cpPrograms.TryGetValue(gpuVa, out List <ShaderBundle> list);

            if (isCached)
            {
                foreach (ShaderBundle cachedCpShader in list)
                {
                    if (IsShaderEqual(channel.MemoryManager, cachedCpShader, gpuVa))
                    {
                        return(cachedCpShader);
                    }
                }
            }

            TranslatorContext[] shaderContexts = new TranslatorContext[1];

            shaderContexts[0] = DecodeComputeShader(
                channel,
                gas,
                gpuVa,
                localSizeX,
                localSizeY,
                localSizeZ,
                localMemorySize,
                sharedMemorySize);

            bool isShaderCacheEnabled  = _cacheManager != null;
            bool isShaderCacheReadOnly = false;

            Hash128 programCodeHash = default;

            GuestShaderCacheEntry[] shaderCacheEntries = null;

            // Current shader cache doesn't support bindless textures
            if (shaderContexts[0].UsedFeatures.HasFlag(FeatureFlags.Bindless))
            {
                isShaderCacheEnabled = false;
            }

            if (isShaderCacheEnabled)
            {
                isShaderCacheReadOnly = _cacheManager.IsReadOnly;

                // Compute hash and prepare data for shader disk cache comparison.
                shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(channel.MemoryManager, shaderContexts);
                programCodeHash    = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries);
            }

            ShaderBundle cpShader;

            // Search for the program hash in loaded shaders.
            if (!isShaderCacheEnabled || !_cpProgramsDiskCache.TryGetValue(programCodeHash, out cpShader))
            {
                if (isShaderCacheEnabled)
                {
                    Logger.Debug?.Print(LogClass.Gpu, $"Shader {programCodeHash} not in cache, compiling!");
                }

                // The shader isn't currently cached, translate it and compile it.
                ShaderCodeHolder shader = TranslateShader(_dumper, channel.MemoryManager, shaderContexts[0], null, null);

                shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);

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

                hostProgram.CheckProgramLink(true);

                byte[] hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), new ShaderCodeHolder[] { shader });

                cpShader = new ShaderBundle(hostProgram, shader);

                if (isShaderCacheEnabled)
                {
                    _cpProgramsDiskCache.Add(programCodeHash, cpShader);

                    if (!isShaderCacheReadOnly)
                    {
                        _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries), hostProgramBinary);
                    }
                }
            }

            if (!isCached)
            {
                list = new List <ShaderBundle>();

                _cpPrograms.Add(gpuVa, list);
            }

            list.Add(cpShader);

            return(cpShader);
        }