Ejemplo n.º 1
0
        /// <summary>
        /// Gets transform feedback state from the current GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <returns>Four transform feedback descriptors for the enabled TFBs, or null if TFB is disabled</returns>
        private static TransformFeedbackDescriptor[] GetTransformFeedbackDescriptors(ref ThreedClassState state)
        {
            bool tfEnable = state.TfEnable;

            if (!tfEnable)
            {
                return(null);
            }

            TransformFeedbackDescriptor[] descs = new TransformFeedbackDescriptor[Constants.TotalTransformFeedbackBuffers];

            for (int i = 0; i < Constants.TotalTransformFeedbackBuffers; i++)
            {
                var tf = state.TfState[i];

                int length = (int)Math.Min((uint)tf.VaryingsCount, 0x80);

                var varyingLocations = MemoryMarshal.Cast <uint, byte>(state.TfVaryingLocations[i].ToSpan()).Slice(0, length);

                descs[i] = new TransformFeedbackDescriptor(tf.BufferIndex, tf.Stride, varyingLocations.ToArray());
            }

            return(descs);
        }
Ejemplo 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);
        }