using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition { /// /// Represent a cached shader entry in a guest shader program. /// class GuestShaderCacheEntry { /// /// The header of the cached shader entry. /// public GuestShaderCacheEntryHeader Header { get; } /// /// The code of this shader. /// /// If a Vertex A is present, this also contains the code 2 section. public byte[] Code { get; } /// /// The textures descriptors used for this shader. /// public Dictionary TextureDescriptors { get; } /// /// Create a new instance of . /// /// The header of the cached shader entry /// The code of this shader private GuestShaderCacheEntry(GuestShaderCacheEntryHeader header, byte[] code) { Header = header; Code = code; TextureDescriptors = new Dictionary(); } /// /// Parse a raw cached user shader program into an array of shader cache entry. /// /// The raw cached user shader program /// The user shader program header /// An array of shader cache entry public static GuestShaderCacheEntry[] Parse(ref ReadOnlySpan data, out GuestShaderCacheHeader fileHeader) { fileHeader = MemoryMarshal.Read(data); data = data.Slice(Unsafe.SizeOf()); ReadOnlySpan entryHeaders = MemoryMarshal.Cast(data.Slice(0, fileHeader.Count * Unsafe.SizeOf())); data = data.Slice(fileHeader.Count * Unsafe.SizeOf()); GuestShaderCacheEntry[] result = new GuestShaderCacheEntry[fileHeader.Count]; for (int i = 0; i < result.Length; i++) { GuestShaderCacheEntryHeader header = entryHeaders[i]; // Ignore empty entries if (header.Size == 0 && header.SizeA == 0) { continue; } byte[] code = data.Slice(0, header.Size + header.SizeA).ToArray(); data = data.Slice(header.Size + header.SizeA); result[i] = new GuestShaderCacheEntry(header, code); ReadOnlySpan textureDescriptors = MemoryMarshal.Cast(data.Slice(0, header.GpuAccessorHeader.TextureDescriptorCount * Unsafe.SizeOf())); foreach (GuestTextureDescriptor textureDescriptor in textureDescriptors) { result[i].TextureDescriptors.Add((int)textureDescriptor.Handle, textureDescriptor); } data = data.Slice(header.GpuAccessorHeader.TextureDescriptorCount * Unsafe.SizeOf()); } return result; } } }