Example #1
0
        /// <summary>
        /// Updates storage buffer bindings.
        /// </summary>
        private void UpdateStorageBuffers()
        {
            for (int stage = 0; stage < CurrentGpMeta.Info.Length; stage++)
            {
                ShaderProgramInfo info = CurrentGpMeta.Info[stage];

                if (info == null)
                {
                    continue;
                }

                for (int index = 0; index < info.SBuffers.Count; index++)
                {
                    BufferDescriptor sb = info.SBuffers[index];

                    ulong sbDescAddress = BufferManager.GetGraphicsUniformBufferAddress(stage, 0);

                    int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;

                    sbDescAddress += (ulong)sbDescOffset;

                    ReadOnlySpan <byte> sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10);

                    SbDescriptor sbDescriptor = MemoryMarshal.Cast <byte, SbDescriptor>(sbDescriptorData)[0];

                    BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
                }
            }
        }
Example #2
0
        /// <summary>
        /// Updates storage buffer bindings.
        /// </summary>
        private void UpdateStorageBuffers()
        {
            for (int stage = 0; stage < _currentProgramInfo.Length; stage++)
            {
                ShaderProgramInfo info = _currentProgramInfo[stage];

                if (info == null)
                {
                    continue;
                }

                for (int index = 0; index < info.SBuffers.Count; index++)
                {
                    BufferDescriptor sb = info.SBuffers[index];

                    ulong sbDescAddress = BufferManager.GetGraphicsUniformBufferAddress(stage, 0);

                    int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;

                    sbDescAddress += (ulong)sbDescOffset;

                    SbDescriptor sbDescriptor = _context.PhysicalMemory.Read <SbDescriptor>(sbDescAddress);

                    BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
                }
            }
        }
        public ShaderProgram Translate(
            out ShaderProgramInfo shaderProgramInfo,
            TranslatorContext nextStage = null,
            TranslatorContext other     = null)
        {
            if (nextStage != null)
            {
                _config.MergeOutputUserAttributes(nextStage._config.UsedInputAttributes);
            }

            FunctionCode[] code = EmitShader(_cfg, _config, initializeOutputs: other == null, out _);

            if (other != null)
            {
                other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes);

                FunctionCode[] otherCode = EmitShader(other._cfg, other._config, initializeOutputs: true, out int aStart);

                code = Combine(otherCode, code, aStart);

                _config.InheritFrom(other._config);
            }

            return(Translator.Translate(code, _config, out shaderProgramInfo));
        }
Example #4
0
 /// <summary>
 /// Creates a new instace of the shader code holder.
 /// </summary>
 /// <param name="program">Shader program</param>
 /// <param name="info">Shader program information</param>
 /// <param name="code">Maxwell binary shader code</param>
 /// <param name="code2">Optional binary shader code of the "Vertex A" shader, when combined with "Vertex B"</param>
 public ShaderCodeHolder(ShaderProgram program, ShaderProgramInfo info, byte[] code, byte[] code2 = null)
 {
     Program = program;
     Info    = info;
     Code    = code;
     Code2   = code2;
 }
Example #5
0
        private static ShaderProgram Translate(Operation[] ops, ShaderConfig config, int size)
        {
            BasicBlock[] blocks = ControlFlowGraph.MakeCfg(ops);

            if (blocks.Length > 0)
            {
                Dominance.FindDominators(blocks[0], blocks.Length);

                Dominance.FindDominanceFrontiers(blocks);

                Ssa.Rename(blocks);

                Optimizer.RunPass(blocks, config);

                Lowering.RunPass(blocks, config);
            }

            StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(blocks, config);

            GlslProgram program = GlslGenerator.Generate(sInfo, config);

            ShaderProgramInfo spInfo = new ShaderProgramInfo(
                program.CBufferDescriptors,
                program.SBufferDescriptors,
                program.TextureDescriptors,
                program.ImageDescriptors,
                sInfo.UsesInstanceId);

            string glslCode = program.Code;

            return(new ShaderProgram(spInfo, config.Stage, glslCode, size));
        }
        public static ShaderInfolElement Create(ShaderKeywordInfo keywordInfo,
                                                ShaderProgramInfo programinfo,
                                                List <PassInformation> passInfoms)
        {
            var obj = new ShaderInfolElement(keywordInfo, programinfo, passInfoms);

            return(obj);
        }
Example #7
0
        private void InitShaderElementInfo(ShaderProgramInfo info)
        {
            var positionPerf = InitShaderProgramElement("Vertex(Position)", info.positionVertPerf);
            var varyingPerf  = InitShaderProgramElement("Vertex(Varying)", info.varyingVertPerf);
            var fragPerf     = InitShaderProgramElement("Fragment", info.fragPerf);

            this.resultArea.Add(positionPerf);
            this.resultArea.Add(varyingPerf);
            this.resultArea.Add(fragPerf);
        }
Example #8
0
 private HostShaderCacheEntry(ShaderProgramInfo programInfo)
 {
     Header = new HostShaderCacheEntryHeader(programInfo.CBuffers.Count,
                                             programInfo.SBuffers.Count,
                                             programInfo.Textures.Count,
                                             programInfo.Images.Count,
                                             programInfo.UsesInstanceId);
     CBuffers = programInfo.CBuffers.ToArray();
     SBuffers = programInfo.SBuffers.ToArray();
     Textures = programInfo.Textures.ToArray();
     Images   = programInfo.Images.ToArray();
 }
Example #9
0
        public ShaderProgram Translate(out ShaderProgramInfo shaderProgramInfo, TranslatorContext other = null)
        {
            FunctionCode[] code = EmitShader(_cfg, _config);

            if (other != null)
            {
                code = Combine(EmitShader(other._cfg, other._config), code);

                _config.InheritFrom(other._config);
            }

            return(Translator.Translate(code, _config, out shaderProgramInfo));
        }
Example #10
0
        public ShaderProgram Translate(out ShaderProgramInfo shaderProgramInfo, TranslatorContext other = null)
        {
            FunctionCode[] code = EmitShader(_cfg, _config);

            if (other != null)
            {
                _config.SetUsedFeature(other._config.UsedFeatures);
                TextureHandlesForCache.UnionWith(other.TextureHandlesForCache);

                code = Combine(EmitShader(other._cfg, other._config), code);
            }

            return(Translator.Translate(code, _config, out shaderProgramInfo));
        }
Example #11
0
 private HostShaderCacheEntry(ShaderProgramInfo programInfo)
 {
     Header = new HostShaderCacheEntryHeader(programInfo.CBuffers.Count,
                                             programInfo.SBuffers.Count,
                                             programInfo.Textures.Count,
                                             programInfo.Images.Count,
                                             programInfo.UsesInstanceId,
                                             programInfo.UsesRtLayer,
                                             programInfo.ClipDistancesWritten,
                                             programInfo.FragmentOutputMap);
     CBuffers = programInfo.CBuffers.ToArray();
     SBuffers = programInfo.SBuffers.ToArray();
     Textures = programInfo.Textures.ToArray();
     Images = programInfo.Images.ToArray();
 }
Example #12
0
        public ShaderProgram Translate(out ShaderProgramInfo shaderProgramInfo)
        {
            FunctionCode[] code = EmitShader(_cfg, _config);

            if (_configA != null)
            {
                FunctionCode[] codeA = EmitShader(_cfgA, _configA);

                _config.SetUsedFeature(_configA.UsedFeatures);

                code = Combine(codeA, code);
            }

            return(Translator.Translate(code, _config, out shaderProgramInfo, SizeA));
        }
Example #13
0
        /// <summary>
        /// Writes the shader program info into the cache.
        /// </summary>
        /// <param name="dataWriter">Cache data writer</param>
        /// <param name="info">Program info</param>
        private static void WriteShaderProgramInfo(ref BinarySerializer dataWriter, ShaderProgramInfo info)
        {
            if (info == null)
            {
                return;
            }

            DataShaderInfo dataInfo = new DataShaderInfo();

            dataInfo.CBuffersCount        = (ushort)info.CBuffers.Count;
            dataInfo.SBuffersCount        = (ushort)info.SBuffers.Count;
            dataInfo.TexturesCount        = (ushort)info.Textures.Count;
            dataInfo.ImagesCount          = (ushort)info.Images.Count;
            dataInfo.Stage                = info.Stage;
            dataInfo.UsesInstanceId       = info.UsesInstanceId;
            dataInfo.UsesRtLayer          = info.UsesRtLayer;
            dataInfo.ClipDistancesWritten = info.ClipDistancesWritten;
            dataInfo.FragmentOutputMap    = info.FragmentOutputMap;

            dataWriter.WriteWithMagicAndSize(ref dataInfo, ShdiMagic);

            for (int index = 0; index < info.CBuffers.Count; index++)
            {
                var entry = info.CBuffers[index];
                dataWriter.WriteWithMagicAndSize(ref entry, BufdMagic);
            }

            for (int index = 0; index < info.SBuffers.Count; index++)
            {
                var entry = info.SBuffers[index];
                dataWriter.WriteWithMagicAndSize(ref entry, BufdMagic);
            }

            for (int index = 0; index < info.Textures.Count; index++)
            {
                var entry = info.Textures[index];
                dataWriter.WriteWithMagicAndSize(ref entry, TexdMagic);
            }

            for (int index = 0; index < info.Images.Count; index++)
            {
                var entry = info.Images[index];
                dataWriter.WriteWithMagicAndSize(ref entry, TexdMagic);
            }
        }
        private ShaderInfolElement(ShaderKeywordInfo keywordInfo,
                                   ShaderProgramInfo programinfo,
                                   List <PassInformation> passInfoms)
        {
            var fold = new Foldout();
            var str  = CreateSummaryString(keywordInfo, passInfoms);

            fold.text = str;

            var keywordVe  = CreateKeywordInfoElement(keywordInfo);
            var positionVe = CreateProgramElement("positionVertPerf", programinfo.positionVertPerf);
            var varyingVe  = CreateProgramElement("varyingVertPerf", programinfo.varyingVertPerf);
            var fragVe     = CreateProgramElement("fragPerf", programinfo.fragPerf);

            fold.Add(keywordVe);
            fold.Add(positionVe);
            fold.Add(varyingVe);
            fold.Add(fragVe);
            this.Add(fold);
        }
Example #15
0
        public static ShaderProgram Translate(
            IGalMemory memory,
            ulong address,
            ulong addressB,
            ShaderConfig config)
        {
            Operation[] shaderOps = DecodeShader(memory, address, config.Type);

            if (addressB != 0)
            {
                // Dual vertex shader.
                Operation[] shaderOpsB = DecodeShader(memory, addressB, config.Type);

                shaderOps = Combine(shaderOps, shaderOpsB);
            }

            BasicBlock[] irBlocks = ControlFlowGraph.MakeCfg(shaderOps);

            Dominance.FindDominators(irBlocks[0], irBlocks.Length);

            Dominance.FindDominanceFrontiers(irBlocks);

            Ssa.Rename(irBlocks);

            Optimizer.Optimize(irBlocks);

            StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(irBlocks);

            GlslProgram program = GlslGenerator.Generate(sInfo, config);

            ShaderProgramInfo spInfo = new ShaderProgramInfo(
                program.CBufferDescriptors,
                program.TextureDescriptors);

            return(new ShaderProgram(spInfo, program.Code));
        }
Example #16
0
        /// <summary>
        /// Initialize the cache.
        /// </summary>
        internal void Initialize()
        {
            if (GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null)
            {
                _cacheManager = new CacheManager(CacheGraphicsApi.OpenGL, CacheHashType.XxHash128, "glsl", GraphicsConfig.TitleId, ShaderCodeGenVersion);

                bool isReadOnly = _cacheManager.IsReadOnly;

                HashSet <Hash128> invalidEntries = null;

                if (isReadOnly)
                {
                    Logger.Warning?.Print(LogClass.Gpu, "Loading shader cache in read-only mode (cache in use by another program!)");
                }
                else
                {
                    invalidEntries = new HashSet <Hash128>();
                }

                ReadOnlySpan <Hash128> guestProgramList = _cacheManager.GetGuestProgramList();

                using AutoResetEvent progressReportEvent = new AutoResetEvent(false);

                _shaderCount      = 0;
                _totalShaderCount = guestProgramList.Length;

                ShaderCacheStateChanged?.Invoke(ShaderCacheState.Start, _shaderCount, _totalShaderCount);
                Thread progressReportThread = null;

                if (guestProgramList.Length > 0)
                {
                    progressReportThread = new Thread(ReportProgress)
                    {
                        Name         = "ShaderCache.ProgressReporter",
                        Priority     = ThreadPriority.Lowest,
                        IsBackground = true
                    };

                    progressReportThread.Start(progressReportEvent);
                }

                // Make sure these are initialized before doing compilation.
                Capabilities caps = _context.Capabilities;

                int maxTaskCount = Math.Min(Environment.ProcessorCount, 8);
                int programIndex = 0;
                List <ShaderCompileTask> activeTasks = new List <ShaderCompileTask>();

                AutoResetEvent taskDoneEvent = new AutoResetEvent(false);

                // This thread dispatches tasks to do shader translation, and creates programs that OpenGL will link in the background.
                // The program link status is checked in a non-blocking manner so that multiple shaders can be compiled at once.

                while (programIndex < guestProgramList.Length || activeTasks.Count > 0)
                {
                    if (activeTasks.Count < maxTaskCount && programIndex < guestProgramList.Length)
                    {
                        // Begin a new shader compilation.
                        Hash128 key = guestProgramList[programIndex];

                        byte[] hostProgramBinary = _cacheManager.GetHostProgramByHash(ref key);
                        bool   hasHostCache      = hostProgramBinary != null;

                        IProgram hostProgram = null;

                        // If the program sources aren't in the cache, compile from saved guest program.
                        byte[] guestProgram = _cacheManager.GetGuestProgramByHash(ref key);

                        if (guestProgram == null)
                        {
                            Logger.Error?.Print(LogClass.Gpu, $"Ignoring orphan shader hash {key} in cache (is the cache incomplete?)");

                            // Should not happen, but if someone messed with the cache it's better to catch it.
                            invalidEntries?.Add(key);

                            _shaderCount = ++programIndex;

                            continue;
                        }

                        ReadOnlySpan <byte> guestProgramReadOnlySpan = guestProgram;

                        ReadOnlySpan <GuestShaderCacheEntry> cachedShaderEntries = GuestShaderCacheEntry.Parse(ref guestProgramReadOnlySpan, out GuestShaderCacheHeader fileHeader);

                        if (cachedShaderEntries[0].Header.Stage == ShaderStage.Compute)
                        {
                            Debug.Assert(cachedShaderEntries.Length == 1);

                            GuestShaderCacheEntry entry = cachedShaderEntries[0];

                            HostShaderCacheEntry[] hostShaderEntries = null;

                            // Try loading host shader binary.
                            if (hasHostCache)
                            {
                                hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan <byte> hostProgramBinarySpan);
                                hostProgramBinary = hostProgramBinarySpan.ToArray();
                                hostProgram       = _context.Renderer.LoadProgramBinary(hostProgramBinary);
                            }

                            ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
                            activeTasks.Add(task);

                            task.OnCompiled(hostProgram, (bool isHostProgramValid, ShaderCompileTask task) =>
                            {
                                ShaderProgram program = null;
                                ShaderProgramInfo shaderProgramInfo = null;

                                if (isHostProgramValid)
                                {
                                    // Reconstruct code holder.

                                    program           = new ShaderProgram(entry.Header.Stage, "");
                                    shaderProgramInfo = hostShaderEntries[0].ToShaderProgramInfo();

                                    ShaderCodeHolder shader = new ShaderCodeHolder(program, shaderProgramInfo, entry.Code);

                                    _cpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shader));

                                    return(true);
                                }
                                else
                                {
                                    // If the host program was rejected by the gpu driver or isn't in cache, try to build from program sources again.

                                    Task compileTask = Task.Run(() =>
                                    {
                                        IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors);

                                        var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, DefaultFlags | TranslationFlags.Compute);
                                        program     = Translator.CreateContext(0, gpuAccessor, options).Translate(out shaderProgramInfo);
                                    });

                                    task.OnTask(compileTask, (bool _, ShaderCompileTask task) =>
                                    {
                                        ShaderCodeHolder shader = new ShaderCodeHolder(program, shaderProgramInfo, entry.Code);

                                        Logger.Info?.Print(LogClass.Gpu, $"Host shader {key} got invalidated, rebuilding from guest...");

                                        // Compile shader and create program as the shader program binary got invalidated.
                                        shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
                                        hostProgram       = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null);

                                        task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
                                        {
                                            // As the host program was invalidated, save the new entry in the cache.
                                            hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), new ShaderCodeHolder[] { shader });

                                            if (!isReadOnly)
                                            {
                                                if (hasHostCache)
                                                {
                                                    _cacheManager.ReplaceHostProgram(ref key, hostProgramBinary);
                                                }
                                                else
                                                {
                                                    Logger.Warning?.Print(LogClass.Gpu, $"Add missing host shader {key} in cache (is the cache incomplete?)");

                                                    _cacheManager.AddHostProgram(ref key, hostProgramBinary);
                                                }
                                            }

                                            _cpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shader));

                                            return(true);
                                        });

                                        return(false); // Not finished: still need to compile the host program.
                                    });

                                    return(false); // Not finished: translating the program.
                                }
                            });
                        }
                        else
                        {
                            Debug.Assert(cachedShaderEntries.Length == Constants.ShaderStages);

                            ShaderCodeHolder[]   shaders        = new ShaderCodeHolder[cachedShaderEntries.Length];
                            List <ShaderProgram> shaderPrograms = new List <ShaderProgram>();

                            TransformFeedbackDescriptor[] tfd = CacheHelper.ReadTransformFeedbackInformation(ref guestProgramReadOnlySpan, fileHeader);

                            TranslationFlags flags = DefaultFlags;

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

                            TranslationCounts counts = new TranslationCounts();

                            HostShaderCacheEntry[] hostShaderEntries = null;

                            // Try loading host shader binary.
                            if (hasHostCache)
                            {
                                hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan <byte> hostProgramBinarySpan);
                                hostProgramBinary = hostProgramBinarySpan.ToArray();
                                hostProgram       = _context.Renderer.LoadProgramBinary(hostProgramBinary);
                            }

                            ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
                            activeTasks.Add(task);

                            GuestShaderCacheEntry[] entries = cachedShaderEntries.ToArray();

                            task.OnCompiled(hostProgram, (bool isHostProgramValid, ShaderCompileTask task) =>
                            {
                                Task compileTask = Task.Run(() =>
                                {
                                    TranslatorContext[] shaderContexts = null;

                                    if (!isHostProgramValid)
                                    {
                                        shaderContexts = new TranslatorContext[1 + entries.Length];

                                        for (int i = 0; i < entries.Length; i++)
                                        {
                                            GuestShaderCacheEntry entry = entries[i];

                                            if (entry == null)
                                            {
                                                continue;
                                            }

                                            IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors);

                                            var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags);

                                            shaderContexts[i + 1] = Translator.CreateContext(0, gpuAccessor, options, counts);

                                            if (entry.Header.SizeA != 0)
                                            {
                                                var options2 = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags | TranslationFlags.VertexA);

                                                shaderContexts[0] = Translator.CreateContext((ulong)entry.Header.Size, gpuAccessor, options2, counts);
                                            }
                                        }
                                    }

                                    // Reconstruct code holder.
                                    for (int i = 0; i < entries.Length; i++)
                                    {
                                        GuestShaderCacheEntry entry = entries[i];

                                        if (entry == null)
                                        {
                                            continue;
                                        }

                                        ShaderProgram program;
                                        ShaderProgramInfo shaderProgramInfo;

                                        if (isHostProgramValid)
                                        {
                                            program           = new ShaderProgram(entry.Header.Stage, "");
                                            shaderProgramInfo = hostShaderEntries[i].ToShaderProgramInfo();
                                        }
                                        else
                                        {
                                            IGpuAccessor gpuAccessor = new CachedGpuAccessor(_context, entry.Code, entry.Header.GpuAccessorHeader, entry.TextureDescriptors);

                                            int stageIndex = i + 1;

                                            TranslatorContext currentStage = shaderContexts[stageIndex];
                                            TranslatorContext nextStage    = GetNextStageContext(shaderContexts, stageIndex);
                                            TranslatorContext vertexA      = stageIndex == 1 ? shaderContexts[0] : null;

                                            program = currentStage.Translate(out shaderProgramInfo, nextStage, vertexA);
                                        }

                                        // NOTE: Vertex B comes first in the shader cache.
                                        byte[] code  = entry.Code.AsSpan().Slice(0, entry.Header.Size).ToArray();
                                        byte[] code2 = entry.Header.SizeA != 0 ? entry.Code.AsSpan().Slice(entry.Header.Size, entry.Header.SizeA).ToArray() : null;

                                        shaders[i] = new ShaderCodeHolder(program, shaderProgramInfo, code, code2);

                                        shaderPrograms.Add(program);
                                    }
                                });

                                task.OnTask(compileTask, (bool _, ShaderCompileTask task) =>
                                {
                                    // If the host program was rejected by the gpu driver or isn't in cache, try to build from program sources again.
                                    if (!isHostProgramValid)
                                    {
                                        Logger.Info?.Print(LogClass.Gpu, $"Host shader {key} got invalidated, rebuilding from guest...");

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

                                        // Compile shaders and create program as the shader program binary got invalidated.
                                        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);
                                        }

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

                                        task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
                                        {
                                            // As the host program was invalidated, save the new entry in the cache.
                                            hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), shaders);

                                            if (!isReadOnly)
                                            {
                                                if (hasHostCache)
                                                {
                                                    _cacheManager.ReplaceHostProgram(ref key, hostProgramBinary);
                                                }
                                                else
                                                {
                                                    Logger.Warning?.Print(LogClass.Gpu, $"Add missing host shader {key} in cache (is the cache incomplete?)");

                                                    _cacheManager.AddHostProgram(ref key, hostProgramBinary);
                                                }
                                            }

                                            _gpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shaders));

                                            return(true);
                                        });

                                        return(false); // Not finished: still need to compile the host program.
                                    }
                                    else
                                    {
                                        _gpProgramsDiskCache.Add(key, new ShaderBundle(hostProgram, shaders));

                                        return(true);
                                    }
                                });

                                return(false); // Not finished: translating the program.
                            });
                        }

                        _shaderCount = ++programIndex;
                    }

                    // Process the queue.
                    for (int i = 0; i < activeTasks.Count; i++)
                    {
                        ShaderCompileTask task = activeTasks[i];

                        if (task.IsDone())
                        {
                            activeTasks.RemoveAt(i--);
                        }
                    }

                    if (activeTasks.Count == maxTaskCount)
                    {
                        // Wait for a task to be done, or for 1ms.
                        // Host shader compilation cannot signal when it is done,
                        // so the 1ms timeout is required to poll status.

                        taskDoneEvent.WaitOne(1);
                    }
                }

                if (!isReadOnly)
                {
                    // Remove entries that are broken in the cache
                    _cacheManager.RemoveManifestEntries(invalidEntries);
                    _cacheManager.FlushToArchive();
                    _cacheManager.Synchronize();
                }

                progressReportEvent.Set();
                progressReportThread?.Join();

                ShaderCacheStateChanged?.Invoke(ShaderCacheState.Loaded, _shaderCount, _totalShaderCount);

                Logger.Info?.Print(LogClass.Gpu, $"Shader cache loaded {_shaderCount} entries.");
            }
        }
Example #17
0
        /// <summary>
        /// Updates host shaders based on the guest GPU state.
        /// </summary>
        private void UpdateShaderState()
        {
            ShaderAddresses addresses = new ShaderAddresses();

            Span <ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);

            Span <ulong> addressesArray = MemoryMarshal.Cast <ShaderAddresses, ulong>(addressesSpan);

            ulong baseAddress = _state.State.ShaderBaseAddress.Pack();

            for (int index = 0; index < 6; index++)
            {
                var shader = _state.State.ShaderState[index];

                if (!shader.UnpackEnable() && index != 1)
                {
                    continue;
                }

                addressesArray[index] = baseAddress + shader.Offset;
            }

            GpuAccessorState gas = new GpuAccessorState(
                _state.State.TexturePoolState.Address.Pack(),
                _state.State.TexturePoolState.MaximumId,
                (int)_state.State.TextureBufferIndex,
                _state.State.EarlyZForce,
                _drawState.Topology);

            ShaderBundle gs = _channel.MemoryManager.Physical.ShaderCache.GetGraphicsShader(ref _state.State, _channel, gas, addresses);

            byte oldVsClipDistancesWritten = _vsClipDistancesWritten;

            _drawState.VsUsesInstanceId = gs.Shaders[0]?.Info.UsesInstanceId ?? false;
            _vsClipDistancesWritten     = gs.Shaders[0]?.Info.ClipDistancesWritten ?? 0;

            if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
            {
                UpdateUserClipState();
            }

            int storageBufferBindingsCount = 0;
            int uniformBufferBindingsCount = 0;

            for (int stage = 0; stage < Constants.ShaderStages; stage++)
            {
                ShaderProgramInfo info = gs.Shaders[stage]?.Info;

                _currentProgramInfo[stage] = info;

                if (info == null)
                {
                    _channel.TextureManager.SetGraphicsTextures(stage, Array.Empty <TextureBindingInfo>());
                    _channel.TextureManager.SetGraphicsImages(stage, Array.Empty <TextureBindingInfo>());
                    _channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
                    _channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
                    continue;
                }

                var textureBindings = new TextureBindingInfo[info.Textures.Count];

                for (int index = 0; index < info.Textures.Count; index++)
                {
                    var descriptor = info.Textures[index];

                    Target target = ShaderTexture.GetTarget(descriptor.Type);

                    textureBindings[index] = new TextureBindingInfo(
                        target,
                        descriptor.Binding,
                        descriptor.CbufSlot,
                        descriptor.HandleIndex,
                        descriptor.Flags);
                }

                _channel.TextureManager.SetGraphicsTextures(stage, textureBindings);

                var imageBindings = new TextureBindingInfo[info.Images.Count];

                for (int index = 0; index < info.Images.Count; index++)
                {
                    var descriptor = info.Images[index];

                    Target target = ShaderTexture.GetTarget(descriptor.Type);
                    Format format = ShaderTexture.GetFormat(descriptor.Format);

                    imageBindings[index] = new TextureBindingInfo(
                        target,
                        format,
                        descriptor.Binding,
                        descriptor.CbufSlot,
                        descriptor.HandleIndex,
                        descriptor.Flags);
                }

                _channel.TextureManager.SetGraphicsImages(stage, imageBindings);

                _channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
                _channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);

                if (info.SBuffers.Count != 0)
                {
                    storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1);
                }

                if (info.CBuffers.Count != 0)
                {
                    uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1);
                }
            }

            _channel.BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount);
            _channel.BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount);

            _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
        }
Example #18
0
        /// <summary>
        /// Performs the compute dispatch operation.
        /// </summary>
        /// <param name="argument">Method call argument</param>
        private void SendSignalingPcasB(int argument)
        {
            var memoryManager = _channel.MemoryManager;

            _3dEngine.FlushUboDirty();

            uint qmdAddress = _state.State.SendPcasA;

            var qmd = _channel.MemoryManager.Read <ComputeQmd>((ulong)qmdAddress << 8);

            ulong shaderGpuVa = ((ulong)_state.State.SetProgramRegionAAddressUpper << 32) | _state.State.SetProgramRegionB;

            shaderGpuVa += (uint)qmd.ProgramOffset;

            int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize;

            int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);

            for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
            {
                if (!qmd.ConstantBufferValid(index))
                {
                    continue;
                }

                ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
                ulong size  = (ulong)qmd.ConstantBufferSize(index);

                _channel.BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
            }

            ulong samplerPoolGpuVa = ((ulong)_state.State.SetTexSamplerPoolAOffsetUpper << 32) | _state.State.SetTexSamplerPoolB;
            ulong texturePoolGpuVa = ((ulong)_state.State.SetTexHeaderPoolAOffsetUpper << 32) | _state.State.SetTexHeaderPoolB;

            GpuChannelPoolState poolState = new GpuChannelPoolState(
                texturePoolGpuVa,
                _state.State.SetTexHeaderPoolCMaximumIndex,
                _state.State.SetBindlessTextureConstantBufferSlotSelect);

            GpuChannelComputeState computeState = new GpuChannelComputeState(
                qmd.CtaThreadDimension0,
                qmd.CtaThreadDimension1,
                qmd.CtaThreadDimension2,
                localMemorySize,
                sharedMemorySize);

            CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa);

            _context.Renderer.Pipeline.SetProgram(cs.HostProgram);

            _channel.TextureManager.SetComputeSamplerPool(samplerPoolGpuVa, _state.State.SetTexSamplerPoolCMaximumIndex, qmd.SamplerIndex);
            _channel.TextureManager.SetComputeTexturePool(texturePoolGpuVa, _state.State.SetTexHeaderPoolCMaximumIndex);
            _channel.TextureManager.SetComputeTextureBufferIndex(_state.State.SetBindlessTextureConstantBufferSlotSelect);

            ShaderProgramInfo info = cs.Shaders[0].Info;

            for (int index = 0; index < info.CBuffers.Count; index++)
            {
                BufferDescriptor cb = info.CBuffers[index];

                // NVN uses the "hardware" constant buffer for anything that is less than 8,
                // and those are already bound above.
                // Anything greater than or equal to 8 uses the emulated constant buffers.
                // They are emulated using global memory loads.
                if (cb.Slot < 8)
                {
                    continue;
                }

                ulong cbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(0);

                int cbDescOffset = 0x260 + (cb.Slot - 8) * 0x10;

                cbDescAddress += (ulong)cbDescOffset;

                SbDescriptor cbDescriptor = _channel.MemoryManager.Physical.Read <SbDescriptor>(cbDescAddress);

                _channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
            }

            for (int index = 0; index < info.SBuffers.Count; index++)
            {
                BufferDescriptor sb = info.SBuffers[index];

                ulong sbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(0);

                int sbDescOffset = 0x310 + sb.Slot * 0x10;

                sbDescAddress += (ulong)sbDescOffset;

                SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read <SbDescriptor>(sbDescAddress);

                _channel.BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
            }

            _channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
            _channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);

            int maxTextureBinding = -1;
            int maxImageBinding   = -1;

            TextureBindingInfo[] textureBindings = _channel.TextureManager.RentComputeTextureBindings(info.Textures.Count);

            for (int index = 0; index < info.Textures.Count; index++)
            {
                var descriptor = info.Textures[index];

                Target target = ShaderTexture.GetTarget(descriptor.Type);

                textureBindings[index] = new TextureBindingInfo(
                    target,
                    descriptor.Binding,
                    descriptor.CbufSlot,
                    descriptor.HandleIndex,
                    descriptor.Flags);

                if (descriptor.Binding > maxTextureBinding)
                {
                    maxTextureBinding = descriptor.Binding;
                }
            }

            TextureBindingInfo[] imageBindings = _channel.TextureManager.RentComputeImageBindings(info.Images.Count);

            for (int index = 0; index < info.Images.Count; index++)
            {
                var descriptor = info.Images[index];

                Target target = ShaderTexture.GetTarget(descriptor.Type);
                Format format = ShaderTexture.GetFormat(descriptor.Format);

                imageBindings[index] = new TextureBindingInfo(
                    target,
                    format,
                    descriptor.Binding,
                    descriptor.CbufSlot,
                    descriptor.HandleIndex,
                    descriptor.Flags);

                if (descriptor.Binding > maxImageBinding)
                {
                    maxImageBinding = descriptor.Binding;
                }
            }

            _channel.TextureManager.SetComputeMaxBindings(maxTextureBinding, maxImageBinding);

            // Should never return false for mismatching spec state, since the shader was fetched above.
            _channel.TextureManager.CommitComputeBindings(cs.SpecializationState);

            _channel.BufferManager.CommitComputeBindings();

            _context.Renderer.Pipeline.DispatchCompute(qmd.CtaRasterWidth, qmd.CtaRasterHeight, qmd.CtaRasterDepth);

            _3dEngine.ForceShaderUpdate();
        }
Example #19
0
        /// <summary>
        /// Updates host shaders based on the guest GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdateShaderState(GpuState state)
        {
            ShaderAddresses addresses = new ShaderAddresses();

            Span <ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);

            Span <ulong> addressesArray = MemoryMarshal.Cast <ShaderAddresses, ulong>(addressesSpan);

            ulong baseAddress = state.Get <GpuVa>(MethodOffset.ShaderBaseAddress).Pack();

            for (int index = 0; index < 6; index++)
            {
                var shader = state.Get <ShaderState>(MethodOffset.ShaderState, index);

                if (!shader.UnpackEnable() && index != 1)
                {
                    continue;
                }

                addressesArray[index] = baseAddress + shader.Offset;
            }

            ShaderBundle gs = ShaderCache.GetGraphicsShader(state, addresses);

            _vsUsesInstanceId = gs.Shaders[0]?.Info.UsesInstanceId ?? false;

            int storageBufferBindingsCount = 0;
            int uniformBufferBindingsCount = 0;

            for (int stage = 0; stage < Constants.ShaderStages; stage++)
            {
                ShaderProgramInfo info = gs.Shaders[stage]?.Info;

                _currentProgramInfo[stage] = info;

                if (info == null)
                {
                    TextureManager.SetGraphicsTextures(stage, Array.Empty <TextureBindingInfo>());
                    TextureManager.SetGraphicsImages(stage, Array.Empty <TextureBindingInfo>());
                    BufferManager.SetGraphicsStorageBufferBindings(stage, null);
                    BufferManager.SetGraphicsUniformBufferBindings(stage, null);
                    continue;
                }

                var textureBindings = new TextureBindingInfo[info.Textures.Count];

                for (int index = 0; index < info.Textures.Count; index++)
                {
                    var descriptor = info.Textures[index];

                    Target target = ShaderTexture.GetTarget(descriptor.Type);

                    textureBindings[index] = new TextureBindingInfo(
                        target,
                        descriptor.Binding,
                        descriptor.CbufSlot,
                        descriptor.HandleIndex,
                        descriptor.Flags);
                }

                TextureManager.SetGraphicsTextures(stage, textureBindings);

                var imageBindings = new TextureBindingInfo[info.Images.Count];

                for (int index = 0; index < info.Images.Count; index++)
                {
                    var descriptor = info.Images[index];

                    Target target = ShaderTexture.GetTarget(descriptor.Type);
                    Format format = ShaderTexture.GetFormat(descriptor.Format);

                    imageBindings[index] = new TextureBindingInfo(
                        target,
                        format,
                        descriptor.Binding,
                        descriptor.CbufSlot,
                        descriptor.HandleIndex,
                        descriptor.Flags);
                }

                TextureManager.SetGraphicsImages(stage, imageBindings);

                BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
                BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);

                if (info.SBuffers.Count != 0)
                {
                    storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1);
                }

                if (info.CBuffers.Count != 0)
                {
                    uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1);
                }
            }

            BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount);
            BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount);

            _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
        }
Example #20
0
        /// <summary>
        /// Dispatches compute work.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="argument">Method call argument</param>
        public void Dispatch(GpuState state, int argument)
        {
            uint qmdAddress = (uint)state.Get <int>(MethodOffset.DispatchParamsAddress);

            var qmd = _context.MemoryAccessor.Read <ComputeQmd>((ulong)qmdAddress << 8);

            GpuVa shaderBaseAddress = state.Get <GpuVa>(MethodOffset.ShaderBaseAddress);

            ulong shaderGpuVa = shaderBaseAddress.Pack() + (uint)qmd.ProgramOffset;

            int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize;

            int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);

            Shader.Shader cs = ShaderCache.GetComputeShader(
                shaderGpuVa,
                qmd.CtaThreadDimension0,
                qmd.CtaThreadDimension1,
                qmd.CtaThreadDimension2,
                localMemorySize,
                sharedMemorySize);

            CurrentCpMeta = cs.Meta;

            _context.Renderer.Pipeline.SetProgram(cs.HostProgram);

            var samplerPool = state.Get <PoolState>(MethodOffset.SamplerPoolState);

            TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex);

            var texturePool = state.Get <PoolState>(MethodOffset.TexturePoolState);

            TextureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);

            TextureManager.SetComputeTextureBufferIndex(state.Get <int>(MethodOffset.TextureBufferIndex));

            ShaderProgramInfo info = cs.Meta.Info[0];

            uint sbEnableMask = 0;
            uint ubEnableMask = 0;

            for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
            {
                if (!qmd.ConstantBufferValid(index))
                {
                    continue;
                }

                ubEnableMask |= 1u << index;

                ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
                ulong size  = (ulong)qmd.ConstantBufferSize(index);

                BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
            }

            for (int index = 0; index < info.CBuffers.Count; index++)
            {
                BufferDescriptor cb = info.CBuffers[index];

                // NVN uses the "hardware" constant buffer for anything that is less than 8,
                // and those are already bound above.
                // Anything greater than or equal to 8 uses the emulated constant buffers.
                // They are emulated using global memory loads.
                if (cb.Slot < 8)
                {
                    continue;
                }

                ubEnableMask |= 1u << cb.Slot;

                ulong cbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);

                int cbDescOffset = 0x260 + cb.Slot * 0x10;

                cbDescAddress += (ulong)cbDescOffset;

                ReadOnlySpan <byte> cbDescriptorData = _context.PhysicalMemory.GetSpan(cbDescAddress, 0x10);

                SbDescriptor cbDescriptor = MemoryMarshal.Cast <byte, SbDescriptor>(cbDescriptorData)[0];

                BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
            }

            for (int index = 0; index < info.SBuffers.Count; index++)
            {
                BufferDescriptor sb = info.SBuffers[index];

                sbEnableMask |= 1u << sb.Slot;

                ulong sbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);

                int sbDescOffset = 0x310 + sb.Slot * 0x10;

                sbDescAddress += (ulong)sbDescOffset;

                ReadOnlySpan <byte> sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10);

                SbDescriptor sbDescriptor = MemoryMarshal.Cast <byte, SbDescriptor>(sbDescriptorData)[0];

                BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
            }

            ubEnableMask = 0;

            for (int index = 0; index < info.CBuffers.Count; index++)
            {
                ubEnableMask |= 1u << info.CBuffers[index].Slot;
            }

            BufferManager.SetComputeStorageBufferEnableMask(sbEnableMask);
            BufferManager.SetComputeUniformBufferEnableMask(ubEnableMask);

            var textureBindings = new TextureBindingInfo[info.Textures.Count];

            for (int index = 0; index < info.Textures.Count; index++)
            {
                var descriptor = info.Textures[index];

                Target target = GetTarget(descriptor.Type);

                if (descriptor.IsBindless)
                {
                    textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufOffset, descriptor.CbufSlot);
                }
                else
                {
                    textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
                }
            }

            TextureManager.SetComputeTextures(textureBindings);

            var imageBindings = new TextureBindingInfo[info.Images.Count];

            for (int index = 0; index < info.Images.Count; index++)
            {
                var descriptor = info.Images[index];

                Target target = GetTarget(descriptor.Type);

                imageBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
            }

            TextureManager.SetComputeImages(imageBindings);

            BufferManager.CommitComputeBindings();
            TextureManager.CommitComputeBindings();

            _context.Renderer.Pipeline.DispatchCompute(
                qmd.CtaRasterWidth,
                qmd.CtaRasterHeight,
                qmd.CtaRasterDepth);

            UpdateShaderState(state);
        }
Example #21
0
        /// <summary>
        /// Dispatches compute work.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="argument">Method call argument</param>
        public void Dispatch(GpuState state, int argument)
        {
            FlushUboDirty();

            uint qmdAddress = (uint)state.Get <int>(MethodOffset.DispatchParamsAddress);

            var qmd = _context.MemoryManager.Read <ComputeQmd>((ulong)qmdAddress << 8);

            GpuVa shaderBaseAddress = state.Get <GpuVa>(MethodOffset.ShaderBaseAddress);

            ulong shaderGpuVa = shaderBaseAddress.Pack() + (uint)qmd.ProgramOffset;

            int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize;

            int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);

            for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
            {
                if (!qmd.ConstantBufferValid(index))
                {
                    continue;
                }

                ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
                ulong size  = (ulong)qmd.ConstantBufferSize(index);

                BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
            }

            ShaderBundle cs = ShaderCache.GetComputeShader(
                state,
                shaderGpuVa,
                qmd.CtaThreadDimension0,
                qmd.CtaThreadDimension1,
                qmd.CtaThreadDimension2,
                localMemorySize,
                sharedMemorySize);

            _context.Renderer.Pipeline.SetProgram(cs.HostProgram);

            var samplerPool = state.Get <PoolState>(MethodOffset.SamplerPoolState);
            var texturePool = state.Get <PoolState>(MethodOffset.TexturePoolState);

            TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex);
            TextureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
            TextureManager.SetComputeTextureBufferIndex(state.Get <int>(MethodOffset.TextureBufferIndex));

            ShaderProgramInfo info = cs.Shaders[0].Info;

            for (int index = 0; index < info.CBuffers.Count; index++)
            {
                BufferDescriptor cb = info.CBuffers[index];

                // NVN uses the "hardware" constant buffer for anything that is less than 8,
                // and those are already bound above.
                // Anything greater than or equal to 8 uses the emulated constant buffers.
                // They are emulated using global memory loads.
                if (cb.Slot < 8)
                {
                    continue;
                }

                ulong cbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);

                int cbDescOffset = 0x260 + (cb.Slot - 8) * 0x10;

                cbDescAddress += (ulong)cbDescOffset;

                SbDescriptor cbDescriptor = _context.PhysicalMemory.Read <SbDescriptor>(cbDescAddress);

                BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
            }

            for (int index = 0; index < info.SBuffers.Count; index++)
            {
                BufferDescriptor sb = info.SBuffers[index];

                ulong sbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);

                int sbDescOffset = 0x310 + sb.Slot * 0x10;

                sbDescAddress += (ulong)sbDescOffset;

                SbDescriptor sbDescriptor = _context.PhysicalMemory.Read <SbDescriptor>(sbDescAddress);

                BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
            }

            BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
            BufferManager.SetComputeUniformBufferBindings(info.CBuffers);

            var textureBindings = new TextureBindingInfo[info.Textures.Count];

            for (int index = 0; index < info.Textures.Count; index++)
            {
                var descriptor = info.Textures[index];

                Target target = ShaderTexture.GetTarget(descriptor.Type);

                textureBindings[index] = new TextureBindingInfo(
                    target,
                    descriptor.Binding,
                    descriptor.CbufSlot,
                    descriptor.HandleIndex,
                    descriptor.Flags);
            }

            TextureManager.SetComputeTextures(textureBindings);

            var imageBindings = new TextureBindingInfo[info.Images.Count];

            for (int index = 0; index < info.Images.Count; index++)
            {
                var descriptor = info.Images[index];

                Target target = ShaderTexture.GetTarget(descriptor.Type);
                Format format = ShaderTexture.GetFormat(descriptor.Format);

                imageBindings[index] = new TextureBindingInfo(
                    target,
                    format,
                    descriptor.Binding,
                    descriptor.CbufSlot,
                    descriptor.HandleIndex,
                    descriptor.Flags);
            }

            TextureManager.SetComputeImages(imageBindings);

            TextureManager.CommitComputeBindings();
            BufferManager.CommitComputeBindings();

            _context.Renderer.Pipeline.DispatchCompute(
                qmd.CtaRasterWidth,
                qmd.CtaRasterHeight,
                qmd.CtaRasterDepth);

            _forceShaderUpdate = true;
        }
Example #22
0
 internal ShaderProgram(ShaderProgramInfo info, string code)
 {
     Info = info;
     Code = code;
 }
Example #23
0
        /// <summary>
        /// Loads all shaders from the cache.
        /// </summary>
        /// <param name="context">GPU context</param>
        /// <param name="loader">Parallel disk cache loader</param>
        public void LoadShaders(GpuContext context, ParallelDiskCacheLoader loader)
        {
            if (!CacheExists())
            {
                return;
            }

            Stream hostTocFileStream  = null;
            Stream hostDataFileStream = null;

            try
            {
                using var tocFileStream  = DiskCacheCommon.OpenFile(_basePath, SharedTocFileName, writable: false);
                using var dataFileStream = DiskCacheCommon.OpenFile(_basePath, SharedDataFileName, writable: false);

                using var guestTocFileStream  = _guestStorage.OpenTocFileStream();
                using var guestDataFileStream = _guestStorage.OpenDataFileStream();

                BinarySerializer tocReader  = new BinarySerializer(tocFileStream);
                BinarySerializer dataReader = new BinarySerializer(dataFileStream);

                TocHeader header = new TocHeader();

                if (!tocReader.TryRead(ref header) || header.Magic != TocsMagic)
                {
                    throw new DiskCacheLoadException(DiskCacheLoadResult.FileCorruptedGeneric);
                }

                if (header.FormatVersion != FileFormatVersionPacked)
                {
                    throw new DiskCacheLoadException(DiskCacheLoadResult.IncompatibleVersion);
                }

                bool loadHostCache = header.CodeGenVersion == CodeGenVersion;

                int programIndex = 0;

                DataEntry entry = new DataEntry();

                while (tocFileStream.Position < tocFileStream.Length && loader.Active)
                {
                    ulong dataOffset = 0;
                    tocReader.Read(ref dataOffset);

                    if ((ulong)dataOffset >= (ulong)dataFileStream.Length)
                    {
                        throw new DiskCacheLoadException(DiskCacheLoadResult.FileCorruptedGeneric);
                    }

                    dataFileStream.Seek((long)dataOffset, SeekOrigin.Begin);

                    dataReader.BeginCompression();
                    dataReader.Read(ref entry);
                    uint stagesBitMask = entry.StagesBitMask;

                    if ((stagesBitMask & ~0x3fu) != 0)
                    {
                        throw new DiskCacheLoadException(DiskCacheLoadResult.FileCorruptedGeneric);
                    }

                    bool isCompute = stagesBitMask == 0;
                    if (isCompute)
                    {
                        stagesBitMask = 1;
                    }

                    CachedShaderStage[] shaders = new CachedShaderStage[isCompute ? 1 : Constants.ShaderStages + 1];

                    DataEntryPerStage stageEntry = new DataEntryPerStage();

                    while (stagesBitMask != 0)
                    {
                        int stageIndex = BitOperations.TrailingZeroCount(stagesBitMask);

                        dataReader.Read(ref stageEntry);

                        ShaderProgramInfo info = stageIndex != 0 || isCompute?ReadShaderProgramInfo(ref dataReader) : null;

                        (byte[] guestCode, byte[] cb1Data) = _guestStorage.LoadShader(
                            guestTocFileStream,
                            guestDataFileStream,
                            stageEntry.GuestCodeIndex);

                        shaders[stageIndex] = new CachedShaderStage(info, guestCode, cb1Data);

                        stagesBitMask &= ~(1u << stageIndex);
                    }

                    ShaderSpecializationState specState = ShaderSpecializationState.Read(ref dataReader);
                    dataReader.EndCompression();

                    if (loadHostCache)
                    {
                        byte[] hostCode = ReadHostCode(context, ref hostTocFileStream, ref hostDataFileStream, programIndex);

                        if (hostCode != null)
                        {
                            bool     hasFragmentShader = shaders.Length > 5 && shaders[5] != null;
                            int      fragmentOutputMap = hasFragmentShader ? shaders[5].Info.FragmentOutputMap : -1;
                            IProgram hostProgram       = context.Renderer.LoadProgramBinary(hostCode, hasFragmentShader, new ShaderInfo(fragmentOutputMap));

                            CachedShaderProgram program = new CachedShaderProgram(hostProgram, specState, shaders);

                            loader.QueueHostProgram(program, hostProgram, programIndex, isCompute);
                        }
                        else
                        {
                            loadHostCache = false;
                        }
                    }

                    if (!loadHostCache)
                    {
                        loader.QueueGuestProgram(shaders, specState, programIndex, isCompute);
                    }

                    loader.CheckCompilation();
                    programIndex++;
                }
            }
            finally
            {
                _guestStorage.ClearMemoryCache();

                hostTocFileStream?.Dispose();
                hostDataFileStream?.Dispose();
            }
        }
Example #24
0
        /// <summary>
        /// Reads the host code for a given shader, if existent.
        /// </summary>
        /// <param name="context">GPU context</param>
        /// <param name="tocFileStream">Host TOC file stream, intialized if needed</param>
        /// <param name="dataFileStream">Host data file stream, initialized if needed</param>
        /// <param name="guestShaders">Guest shader code for each active stage</param>
        /// <param name="programIndex">Index of the program on the cache</param>
        /// <param name="expectedTimestamp">Timestamp of the shared cache file. The host file must be newer than it</param>
        /// <returns>Host binary code, or null if not found</returns>
        private (byte[], CachedShaderStage[]) ReadHostCode(
            GpuContext context,
            ref Stream tocFileStream,
            ref Stream dataFileStream,
            GuestCodeAndCbData?[] guestShaders,
            int programIndex,
            ulong expectedTimestamp)
        {
            if (tocFileStream == null && dataFileStream == null)
            {
                string tocFilePath  = Path.Combine(_basePath, GetHostTocFileName(context));
                string dataFilePath = Path.Combine(_basePath, GetHostDataFileName(context));

                if (!File.Exists(tocFilePath) || !File.Exists(dataFilePath))
                {
                    return(null, null);
                }

                tocFileStream  = DiskCacheCommon.OpenFile(_basePath, GetHostTocFileName(context), writable: false);
                dataFileStream = DiskCacheCommon.OpenFile(_basePath, GetHostDataFileName(context), writable: false);

                BinarySerializer tempTocReader = new BinarySerializer(tocFileStream);

                TocHeader header = new TocHeader();

                tempTocReader.Read(ref header);

                if (header.Timestamp < expectedTimestamp)
                {
                    return(null, null);
                }
            }

            int offset = Unsafe.SizeOf <TocHeader>() + programIndex * Unsafe.SizeOf <OffsetAndSize>();

            if (offset + Unsafe.SizeOf <OffsetAndSize>() > tocFileStream.Length)
            {
                return(null, null);
            }

            if ((ulong)offset >= (ulong)dataFileStream.Length)
            {
                throw new DiskCacheLoadException(DiskCacheLoadResult.FileCorruptedGeneric);
            }

            tocFileStream.Seek(offset, SeekOrigin.Begin);

            BinarySerializer tocReader = new BinarySerializer(tocFileStream);

            OffsetAndSize offsetAndSize = new OffsetAndSize();

            tocReader.Read(ref offsetAndSize);

            if (offsetAndSize.Offset >= (ulong)dataFileStream.Length)
            {
                throw new DiskCacheLoadException(DiskCacheLoadResult.FileCorruptedGeneric);
            }

            dataFileStream.Seek((long)offsetAndSize.Offset, SeekOrigin.Begin);

            byte[] hostCode = new byte[offsetAndSize.UncompressedSize];

            BinarySerializer.ReadCompressed(dataFileStream, hostCode);

            CachedShaderStage[] shaders    = new CachedShaderStage[guestShaders.Length];
            BinarySerializer    dataReader = new BinarySerializer(dataFileStream);

            dataFileStream.Seek((long)(offsetAndSize.Offset + offsetAndSize.CompressedSize), SeekOrigin.Begin);

            dataReader.BeginCompression();

            for (int index = 0; index < guestShaders.Length; index++)
            {
                if (!guestShaders[index].HasValue)
                {
                    continue;
                }

                GuestCodeAndCbData guestShader = guestShaders[index].Value;
                ShaderProgramInfo  info        = index != 0 || guestShaders.Length == 1 ? ReadShaderProgramInfo(ref dataReader) : null;

                shaders[index] = new CachedShaderStage(info, guestShader.Code, guestShader.Cb1Data);
            }

            dataReader.EndCompression();

            return(hostCode, shaders);
        }
Example #25
0
 /// <summary>
 /// Creates a new instance of the shader code holder.
 /// </summary>
 /// <param name="info">Shader program information</param>
 /// <param name="code">Maxwell binary shader code</param>
 /// <param name="cb1Data">Constant buffer 1 data accessed by the shader</param>
 public CachedShaderStage(ShaderProgramInfo info, byte[] code, byte[] cb1Data)
 {
     Info    = info;
     Code    = code;
     Cb1Data = cb1Data;
 }
Example #26
0
        internal static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config, out ShaderProgramInfo shaderProgramInfo)
        {
            var cfgs = new ControlFlowGraph[functions.Length];
            var frus = new RegisterUsage.FunctionRegisterUsage[functions.Length];

            for (int i = 0; i < functions.Length; i++)
            {
                cfgs[i] = ControlFlowGraph.Create(functions[i].Code);

                if (i != 0)
                {
                    frus[i] = RegisterUsage.RunPass(cfgs[i]);
                }
            }

            Function[] funcs = new Function[functions.Length];

            for (int i = 0; i < functions.Length; i++)
            {
                var cfg = cfgs[i];

                int inArgumentsCount  = 0;
                int outArgumentsCount = 0;

                if (i != 0)
                {
                    var fru = frus[i];

                    inArgumentsCount  = fru.InArguments.Length;
                    outArgumentsCount = fru.OutArguments.Length;
                }

                if (cfg.Blocks.Length != 0)
                {
                    RegisterUsage.FixupCalls(cfg.Blocks, frus);

                    Dominance.FindDominators(cfg);
                    Dominance.FindDominanceFrontiers(cfg.Blocks);

                    Ssa.Rename(cfg.Blocks);

                    Optimizer.RunPass(cfg.Blocks, config);

                    Rewriter.RunPass(cfg.Blocks, config);
                }

                funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);
            }

            StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(funcs, config);

            ShaderProgram program;

            switch (config.Options.TargetLanguage)
            {
            case TargetLanguage.Glsl:
                program = new ShaderProgram(config.Stage, GlslGenerator.Generate(sInfo, config));
                break;

            default:
                throw new NotImplementedException(config.Options.TargetLanguage.ToString());
            }

            shaderProgramInfo = new ShaderProgramInfo(
                config.GetConstantBufferDescriptors(),
                config.GetStorageBufferDescriptors(),
                config.GetTextureDescriptors(),
                config.GetImageDescriptors(),
                config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
                config.UsedFeatures.HasFlag(FeatureFlags.RtLayer),
                config.ClipDistancesWritten,
                config.OmapTargets);

            return(program);
        }
Example #27
0
        /// <summary>
        /// Updates host shaders based on the guest GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdateShaderState(GpuState state)
        {
            ShaderAddresses addresses = new ShaderAddresses();

            Span <ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);

            Span <ulong> addressesArray = MemoryMarshal.Cast <ShaderAddresses, ulong>(addressesSpan);

            ulong baseAddress = state.Get <GpuVa>(MethodOffset.ShaderBaseAddress).Pack();

            for (int index = 0; index < 6; index++)
            {
                var shader = state.Get <ShaderState>(MethodOffset.ShaderState, index);

                if (!shader.UnpackEnable() && index != 1)
                {
                    continue;
                }

                addressesArray[index] = baseAddress + shader.Offset;
            }

            ShaderBundle gs = ShaderCache.GetGraphicsShader(state, addresses);

            _vsUsesInstanceId = gs.Shaders[0]?.Program.Info.UsesInstanceId ?? false;

            for (int stage = 0; stage < Constants.ShaderStages; stage++)
            {
                ShaderProgramInfo info = gs.Shaders[stage]?.Program.Info;

                _currentProgramInfo[stage] = info;

                if (info == null)
                {
                    continue;
                }

                var textureBindings = new TextureBindingInfo[info.Textures.Count];

                for (int index = 0; index < info.Textures.Count; index++)
                {
                    var descriptor = info.Textures[index];

                    Target target = GetTarget(descriptor.Type);

                    if (descriptor.IsBindless)
                    {
                        textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufSlot, descriptor.CbufOffset, descriptor.Flags);
                    }
                    else
                    {
                        textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex, descriptor.Flags);
                    }
                }

                TextureManager.SetGraphicsTextures(stage, textureBindings);

                var imageBindings = new TextureBindingInfo[info.Images.Count];

                for (int index = 0; index < info.Images.Count; index++)
                {
                    var descriptor = info.Images[index];

                    Target target = GetTarget(descriptor.Type);

                    imageBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex, descriptor.Flags);
                }

                TextureManager.SetGraphicsImages(stage, imageBindings);

                uint sbEnableMask = 0;
                uint ubEnableMask = 0;

                for (int index = 0; index < info.SBuffers.Count; index++)
                {
                    sbEnableMask |= 1u << info.SBuffers[index].Slot;
                }

                for (int index = 0; index < info.CBuffers.Count; index++)
                {
                    ubEnableMask |= 1u << info.CBuffers[index].Slot;
                }

                BufferManager.SetGraphicsStorageBufferEnableMask(stage, sbEnableMask);
                BufferManager.SetGraphicsUniformBufferEnableMask(stage, ubEnableMask);
            }

            _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
        }
Example #28
0
        /// <summary>
        /// Migrates from the old cache format to the new one.
        /// </summary>
        /// <param name="context">GPU context</param>
        /// <param name="hostStorage">Disk cache host storage (used to create the new shader files)</param>
        /// <returns>Number of migrated shaders</returns>
        public static int MigrateFromLegacyCache(GpuContext context, DiskCacheHostStorage hostStorage)
        {
            string baseCacheDirectory = CacheHelper.GetBaseCacheDirectory(GraphicsConfig.TitleId);
            string cacheDirectory     = CacheHelper.GenerateCachePath(baseCacheDirectory, CacheGraphicsApi.Guest, "", "program");

            // If the directory does not exist, we have no old cache.
            // Exist early as the CacheManager constructor will create the directories.
            if (!Directory.Exists(cacheDirectory))
            {
                return(0);
            }

            if (GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null)
            {
                CacheManager cacheManager = new CacheManager(CacheGraphicsApi.OpenGL, CacheHashType.XxHash128, "glsl", GraphicsConfig.TitleId, ShaderCodeGenVersion);

                bool isReadOnly = cacheManager.IsReadOnly;

                HashSet <Hash128> invalidEntries = null;

                if (isReadOnly)
                {
                    Logger.Warning?.Print(LogClass.Gpu, "Loading shader cache in read-only mode (cache in use by another program!)");
                }
                else
                {
                    invalidEntries = new HashSet <Hash128>();
                }

                ReadOnlySpan <Hash128> guestProgramList = cacheManager.GetGuestProgramList();

                for (int programIndex = 0; programIndex < guestProgramList.Length; programIndex++)
                {
                    Hash128 key = guestProgramList[programIndex];

                    byte[] guestProgram = cacheManager.GetGuestProgramByHash(ref key);

                    if (guestProgram == null)
                    {
                        Logger.Error?.Print(LogClass.Gpu, $"Ignoring orphan shader hash {key} in cache (is the cache incomplete?)");

                        continue;
                    }

                    ReadOnlySpan <byte> guestProgramReadOnlySpan = guestProgram;

                    ReadOnlySpan <GuestShaderCacheEntry> cachedShaderEntries = GuestShaderCacheEntry.Parse(ref guestProgramReadOnlySpan, out GuestShaderCacheHeader fileHeader);

                    if (cachedShaderEntries[0].Header.Stage == ShaderStage.Compute)
                    {
                        Debug.Assert(cachedShaderEntries.Length == 1);

                        GuestShaderCacheEntry entry = cachedShaderEntries[0];

                        byte[] code = entry.Code.AsSpan(0, entry.Header.Size - entry.Header.Cb1DataSize).ToArray();

                        Span <byte> codeSpan = entry.Code;
                        byte[]      cb1Data  = codeSpan.Slice(codeSpan.Length - entry.Header.Cb1DataSize).ToArray();

                        ShaderProgramInfo info = new ShaderProgramInfo(
                            Array.Empty <BufferDescriptor>(),
                            Array.Empty <BufferDescriptor>(),
                            Array.Empty <TextureDescriptor>(),
                            Array.Empty <TextureDescriptor>(),
                            ShaderStage.Compute,
                            false,
                            false,
                            0,
                            0);

                        GpuChannelComputeState computeState = new GpuChannelComputeState(
                            entry.Header.GpuAccessorHeader.ComputeLocalSizeX,
                            entry.Header.GpuAccessorHeader.ComputeLocalSizeY,
                            entry.Header.GpuAccessorHeader.ComputeLocalSizeZ,
                            entry.Header.GpuAccessorHeader.ComputeLocalMemorySize,
                            entry.Header.GpuAccessorHeader.ComputeSharedMemorySize);

                        ShaderSpecializationState specState = new ShaderSpecializationState(computeState);

                        foreach (var td in entry.TextureDescriptors)
                        {
                            var handle = td.Key;
                            var data   = td.Value;

                            specState.RegisterTexture(
                                0,
                                handle,
                                -1,
                                data.UnpackFormat(),
                                data.UnpackSrgb(),
                                data.UnpackTextureTarget(),
                                data.UnpackTextureCoordNormalized());
                        }

                        CachedShaderStage   shader  = new CachedShaderStage(info, code, cb1Data);
                        CachedShaderProgram program = new CachedShaderProgram(null, specState, shader);

                        hostStorage.AddShader(context, program, ReadOnlySpan <byte> .Empty);
                    }
                    else
                    {
                        Debug.Assert(cachedShaderEntries.Length == Constants.ShaderStages);

                        CachedShaderStage[]  shaders        = new CachedShaderStage[Constants.ShaderStages + 1];
                        List <ShaderProgram> shaderPrograms = new List <ShaderProgram>();

                        TransformFeedbackDescriptorOld[] tfd = CacheHelper.ReadTransformFeedbackInformation(ref guestProgramReadOnlySpan, fileHeader);

                        GuestShaderCacheEntry[] entries = cachedShaderEntries.ToArray();

                        GuestGpuAccessorHeader accessorHeader = entries[0].Header.GpuAccessorHeader;

                        TessMode tessMode = new TessMode();

                        int  tessPatchType = accessorHeader.TessellationModePacked & 3;
                        int  tessSpacing   = (accessorHeader.TessellationModePacked >> 2) & 3;
                        bool tessCw        = (accessorHeader.TessellationModePacked & 0x10) != 0;

                        tessMode.Packed  = (uint)tessPatchType;
                        tessMode.Packed |= (uint)(tessSpacing << 4);

                        if (tessCw)
                        {
                            tessMode.Packed |= 0x100;
                        }

                        PrimitiveTopology topology = accessorHeader.PrimitiveTopology switch
                        {
                            InputTopology.Lines => PrimitiveTopology.Lines,
                            InputTopology.LinesAdjacency => PrimitiveTopology.LinesAdjacency,
                            InputTopology.Triangles => PrimitiveTopology.Triangles,
                            InputTopology.TrianglesAdjacency => PrimitiveTopology.TrianglesAdjacency,
                            _ => PrimitiveTopology.Points
                        };

                        GpuChannelGraphicsState graphicsState = new GpuChannelGraphicsState(
                            accessorHeader.StateFlags.HasFlag(GuestGpuStateFlags.EarlyZForce),
                            topology,
                            tessMode);

                        TransformFeedbackDescriptor[] tfdNew = null;

                        if (tfd != null)
                        {
                            tfdNew = new TransformFeedbackDescriptor[tfd.Length];

                            for (int tfIndex = 0; tfIndex < tfd.Length; tfIndex++)
                            {
                                Array32 <uint> varyingLocations     = new Array32 <uint>();
                                Span <byte>    varyingLocationsSpan = MemoryMarshal.Cast <uint, byte>(varyingLocations.ToSpan());
                                tfd[tfIndex].VaryingLocations.CopyTo(varyingLocationsSpan.Slice(0, tfd[tfIndex].VaryingLocations.Length));

                                tfdNew[tfIndex] = new TransformFeedbackDescriptor(
                                    tfd[tfIndex].BufferIndex,
                                    tfd[tfIndex].Stride,
                                    tfd[tfIndex].VaryingLocations.Length,
                                    ref varyingLocations);
                            }
                        }

                        ShaderSpecializationState specState = new ShaderSpecializationState(graphicsState, tfdNew);

                        for (int i = 0; i < entries.Length; i++)
                        {
                            GuestShaderCacheEntry entry = entries[i];

                            if (entry == null)
                            {
                                continue;
                            }

                            ShaderProgramInfo info = new ShaderProgramInfo(
                                Array.Empty <BufferDescriptor>(),
                                Array.Empty <BufferDescriptor>(),
                                Array.Empty <TextureDescriptor>(),
                                Array.Empty <TextureDescriptor>(),
                                (ShaderStage)(i + 1),
                                false,
                                false,
                                0,
                                0);

                            // NOTE: Vertex B comes first in the shader cache.
                            byte[] code  = entry.Code.AsSpan(0, entry.Header.Size - entry.Header.Cb1DataSize).ToArray();
                            byte[] code2 = entry.Header.SizeA != 0 ? entry.Code.AsSpan(entry.Header.Size, entry.Header.SizeA).ToArray() : null;

                            Span <byte> codeSpan = entry.Code;
                            byte[]      cb1Data  = codeSpan.Slice(codeSpan.Length - entry.Header.Cb1DataSize).ToArray();

                            shaders[i + 1] = new CachedShaderStage(info, code, cb1Data);

                            if (code2 != null)
                            {
                                shaders[0] = new CachedShaderStage(null, code2, cb1Data);
                            }

                            foreach (var td in entry.TextureDescriptors)
                            {
                                var handle = td.Key;
                                var data   = td.Value;

                                specState.RegisterTexture(
                                    i,
                                    handle,
                                    -1,
                                    data.UnpackFormat(),
                                    data.UnpackSrgb(),
                                    data.UnpackTextureTarget(),
                                    data.UnpackTextureCoordNormalized());
                            }
                        }

                        CachedShaderProgram program = new CachedShaderProgram(null, specState, shaders);

                        hostStorage.AddShader(context, program, ReadOnlySpan <byte> .Empty);
                    }
                }

                return(guestProgramList.Length);
            }

            return(0);
        }
    }
Example #29
0
        internal static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config, out ShaderProgramInfo shaderProgramInfo, int sizeA = 0)
        {
            var cfgs = new ControlFlowGraph[functions.Length];
            var frus = new RegisterUsage.FunctionRegisterUsage[functions.Length];

            for (int i = 0; i < functions.Length; i++)
            {
                cfgs[i] = ControlFlowGraph.Create(functions[i].Code);

                if (i != 0)
                {
                    frus[i] = RegisterUsage.RunPass(cfgs[i]);
                }
            }

            Function[] funcs = new Function[functions.Length];

            for (int i = 0; i < functions.Length; i++)
            {
                var cfg = cfgs[i];

                int inArgumentsCount  = 0;
                int outArgumentsCount = 0;

                if (i != 0)
                {
                    var fru = frus[i];

                    inArgumentsCount  = fru.InArguments.Length;
                    outArgumentsCount = fru.OutArguments.Length;
                }

                if (cfg.Blocks.Length != 0)
                {
                    RegisterUsage.FixupCalls(cfg.Blocks, frus);

                    Dominance.FindDominators(cfg);
                    Dominance.FindDominanceFrontiers(cfg.Blocks);

                    Ssa.Rename(cfg.Blocks);

                    Optimizer.RunPass(cfg.Blocks, config);

                    Rewriter.RunPass(cfg.Blocks, config);
                }

                funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);
            }

            StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(funcs, config);

            GlslProgram program = GlslGenerator.Generate(sInfo, config);

            shaderProgramInfo = new ShaderProgramInfo(
                program.CBufferDescriptors,
                program.SBufferDescriptors,
                program.TextureDescriptors,
                program.ImageDescriptors,
                sInfo.UsesInstanceId);

            string glslCode = program.Code;

            return(new ShaderProgram(config.Stage, glslCode, config.Size, sizeA));
        }
Example #30
0
        /// <summary>
        /// Creates a new instace of the shader meta data.
        /// </summary>
        /// <param name="hostProgram">Host shader program</param>
        /// <param name="infos">Shader program information, per stage</param>
        public ShaderMeta(IProgram hostProgram, params ShaderProgramInfo[] infos)
        {
            _ubBindingPoints = new int[UbsPerStage * ShaderStages];
            _sbBindingPoints = new int[SbsPerStage * ShaderStages];
            _textureUnits    = new int[TexsPerStage * ShaderStages];
            _imageUnits      = new int[ImgsPerStage * ShaderStages];

            for (int index = 0; index < _ubBindingPoints.Length; index++)
            {
                _ubBindingPoints[index] = -1;
            }

            for (int index = 0; index < _sbBindingPoints.Length; index++)
            {
                _sbBindingPoints[index] = -1;
            }

            for (int index = 0; index < _textureUnits.Length; index++)
            {
                _textureUnits[index] = -1;
            }

            for (int index = 0; index < _imageUnits.Length; index++)
            {
                _imageUnits[index] = -1;
            }

            int ubBindingPoint = 0;
            int sbBindingPoint = 0;
            int textureUnit    = 0;
            int imageUnit      = 0;

            Info = new ShaderProgramInfo[infos.Length];

            for (int index = 0; index < infos.Length; index++)
            {
                ShaderProgramInfo info = infos[index];

                if (info == null)
                {
                    continue;
                }

                foreach (BufferDescriptor descriptor in info.CBuffers)
                {
                    hostProgram.SetUniformBufferBindingPoint(descriptor.Name, ubBindingPoint);

                    int bpIndex = (int)info.Stage << UbStageShift | descriptor.Slot;

                    _ubBindingPoints[bpIndex] = ubBindingPoint;

                    ubBindingPoint++;
                }

                foreach (BufferDescriptor descriptor in info.SBuffers)
                {
                    hostProgram.SetStorageBufferBindingPoint(descriptor.Name, sbBindingPoint);

                    int bpIndex = (int)info.Stage << SbStageShift | descriptor.Slot;

                    _sbBindingPoints[bpIndex] = sbBindingPoint;

                    sbBindingPoint++;
                }

                int samplerIndex = 0;

                foreach (TextureDescriptor descriptor in info.Textures)
                {
                    hostProgram.SetImageUnit(descriptor.Name, textureUnit);

                    int uIndex = (int)info.Stage << TexStageShift | samplerIndex++;

                    _textureUnits[uIndex] = textureUnit;

                    textureUnit++;
                }

                int imageIndex = 0;

                foreach (TextureDescriptor descriptor in info.Images)
                {
                    hostProgram.SetImageUnit(descriptor.Name, imageUnit);

                    int uIndex = (int)info.Stage << ImgStageShift | imageIndex++;

                    _imageUnits[uIndex] = imageUnit;

                    imageUnit++;
                }

                Info[index] = info;
            }
        }