From 48f6570557fc76496936514d94e3ccddf55ec633 Mon Sep 17 00:00:00 2001 From: Mary Date: Fri, 13 Nov 2020 00:15:34 +0100 Subject: Salieri: shader cache (#1701) Here come Salieri, my implementation of a disk shader cache! "I'm sure you know why I named it that." "It doesn't really mean anything." This implementation collects shaders at runtime and cache them to be later compiled when starting a game. --- .../Shader/Cache/Definition/CacheGraphicsApi.cs | 38 ++++ .../Shader/Cache/Definition/CacheHashType.cs | 13 ++ .../Shader/Cache/Definition/CacheManifestHeader.cs | 97 ++++++++++ .../Cache/Definition/GuestGpuAccessorHeader.cs | 62 ++++++ .../Cache/Definition/GuestShaderCacheEntry.cs | 88 +++++++++ .../Definition/GuestShaderCacheEntryHeader.cs | 67 +++++++ .../Cache/Definition/GuestShaderCacheHeader.cs | 42 +++++ .../GuestShaderCacheTransformFeedbackHeader.cs | 38 ++++ .../Cache/Definition/GuestTextureDescriptor.cs | 15 ++ .../Cache/Definition/HostShaderCacheEntry.cs | 210 +++++++++++++++++++++ .../Cache/Definition/HostShaderCacheEntryHeader.cs | 67 +++++++ .../Cache/Definition/HostShaderCacheHeader.cs | 42 +++++ 12 files changed, 779 insertions(+) create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheGraphicsApi.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheHashType.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheManifestHeader.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestGpuAccessorHeader.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheEntry.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheEntryHeader.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheHeader.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheTransformFeedbackHeader.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestTextureDescriptor.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs create mode 100644 Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheHeader.cs (limited to 'Ryujinx.Graphics.Gpu/Shader/Cache/Definition') diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheGraphicsApi.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheGraphicsApi.cs new file mode 100644 index 00000000..9f8b5c39 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheGraphicsApi.cs @@ -0,0 +1,38 @@ +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// Graphics API type accepted by the shader cache. + /// + enum CacheGraphicsApi : byte + { + /// + /// OpenGL Core + /// + OpenGL, + + /// + /// OpenGL ES + /// + OpenGLES, + + /// + /// Vulkan + /// + Vulkan, + + /// + /// DirectX + /// + DirectX, + + /// + /// Metal + /// + Metal, + + /// + /// Guest, used to cache games raw shader programs. + /// + Guest + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheHashType.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheHashType.cs new file mode 100644 index 00000000..e4ebe416 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheHashType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// Hash algorithm accepted by the shader cache. + /// + enum CacheHashType : byte + { + /// + /// xxHash128 + /// + XxHash128 + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheManifestHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheManifestHeader.cs new file mode 100644 index 00000000..3f198dca --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/CacheManifestHeader.cs @@ -0,0 +1,97 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// Header of the shader cache manifest. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] + struct CacheManifestHeader + { + /// + /// The version of the cache. + /// + public ulong Version; + + /// + /// The graphics api used for this cache. + /// + public CacheGraphicsApi GraphicsApi; + + /// + /// The hash type used for this cache. + /// + public CacheHashType HashType; + + /// + /// CRC-16 checksum over the data in the file. + /// + public ushort TableChecksum; + + /// + /// Construct a new cache manifest header. + /// + /// The version of the cache + /// The graphics api used for this cache + /// The hash type used for this cache + public CacheManifestHeader(ulong version, CacheGraphicsApi graphicsApi, CacheHashType hashType) + { + Version = version; + GraphicsApi = graphicsApi; + HashType = hashType; + TableChecksum = 0; + } + + /// + /// Update the checksum in the header. + /// + /// The data to perform the checksum on + public void UpdateChecksum(ReadOnlySpan data) + { + TableChecksum = CalculateCrc16(data); + } + + /// + /// Calculate a CRC-16 over data. + /// + /// The data to perform the CRC-16 on + /// A CRC-16 over data + private static ushort CalculateCrc16(ReadOnlySpan data) + { + int crc = 0; + + const ushort poly = 0x1021; + + for (int i = 0; i < data.Length; i++) + { + crc ^= data[i] << 8; + + for (int j = 0; j < 8; j++) + { + crc <<= 1; + + if ((crc & 0x10000) != 0) + { + crc = (crc ^ poly) & 0xFFFF; + } + } + } + + return (ushort)crc; + } + + /// + /// Check the validity of the header. + /// + /// The target version in use + /// The target graphics api in use + /// The target hash type in use + /// The data after this header + /// True if the header is valid + public bool IsValid(ulong version, CacheGraphicsApi graphicsApi, CacheHashType hashType, ReadOnlySpan data) + { + return Version == version && GraphicsApi == graphicsApi && HashType == hashType && TableChecksum == CalculateCrc16(data); + } + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestGpuAccessorHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestGpuAccessorHeader.cs new file mode 100644 index 00000000..396b0443 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestGpuAccessorHeader.cs @@ -0,0 +1,62 @@ +using Ryujinx.Graphics.Shader; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// Header of a cached guest gpu accessor. + /// + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 1)] + struct GuestGpuAccessorHeader + { + /// + /// The count of texture descriptors. + /// + public int TextureDescriptorCount; + + /// + /// Local Size X for compute shaders. + /// + public int ComputeLocalSizeX; + + /// + /// Local Size Y for compute shaders. + /// + public int ComputeLocalSizeY; + + /// + /// Local Size Z for compute shaders. + /// + public int ComputeLocalSizeZ; + + /// + /// Local Memory size in bytes for compute shaders. + /// + public int ComputeLocalMemorySize; + + /// + /// Shared Memory size in bytes for compute shaders. + /// + public int ComputeSharedMemorySize; + + /// + /// Unused/reserved. + /// + public int Reserved1; + + /// + /// Current primitive topology for geometry shaders. + /// + public InputTopology PrimitiveTopology; + + /// + /// Unused/reserved. + /// + public ushort Reserved2; + + /// + /// Unused/reserved. + /// + public byte Reserved3; + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheEntry.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheEntry.cs new file mode 100644 index 00000000..45a442e2 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheEntry.cs @@ -0,0 +1,88 @@ +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; + } + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheEntryHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheEntryHeader.cs new file mode 100644 index 00000000..6d5bb28d --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheEntryHeader.cs @@ -0,0 +1,67 @@ +using Ryujinx.Graphics.Shader; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// The header of a guest shader entry in a guest shader program. + /// + [StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = 0x30)] + struct GuestShaderCacheEntryHeader + { + /// + /// The stage of this shader. + /// + public ShaderStage Stage; + + /// + /// Unused/reserved. + /// + public byte Reserved1; + + /// + /// Unused/reserved. + /// + public byte Reserved2; + + /// + /// Unused/reserved. + /// + public byte Reserved3; + + /// + /// The size of the code section. + /// + public int Size; + + /// + /// The size of the code2 section if present. (Vertex A) + /// + public int SizeA; + + /// + /// Unused/reserved. + /// + public int Reserved4; + + /// + /// The header of the cached gpu accessor. + /// + public GuestGpuAccessorHeader GpuAccessorHeader; + + /// + /// Create a new guest shader entry header. + /// + /// The stage of this shader + /// The size of the code section + /// The size of the code2 section if present (Vertex A) + /// The header of the cached gpu accessor + public GuestShaderCacheEntryHeader(ShaderStage stage, int size, int sizeA, GuestGpuAccessorHeader gpuAccessorHeader) : this() + { + Stage = stage; + Size = size; + SizeA = sizeA; + GpuAccessorHeader = gpuAccessorHeader; + } + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheHeader.cs new file mode 100644 index 00000000..700be47d --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheHeader.cs @@ -0,0 +1,42 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// The header of a shader program in the guest cache. + /// + [StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = 0x10)] + struct GuestShaderCacheHeader + { + /// + /// The count of shaders defining this program. + /// + public byte Count; + + /// + /// The count of transform feedback data used in this program. + /// + public byte TransformFeedbackCount; + + /// + /// Unused/reserved. + /// + public ushort Reserved1; + + /// + /// Unused/reserved. + /// + public ulong Reserved2; + + /// + /// Create a new guest shader cache header. + /// + /// The count of shaders defining this program + /// The count of transform feedback data used in this program + public GuestShaderCacheHeader(byte count, byte transformFeedbackCount) : this() + { + Count = count; + TransformFeedbackCount = transformFeedbackCount; + } + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheTransformFeedbackHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheTransformFeedbackHeader.cs new file mode 100644 index 00000000..18cfdf55 --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestShaderCacheTransformFeedbackHeader.cs @@ -0,0 +1,38 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// Header for transform feedback. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] + struct GuestShaderCacheTransformFeedbackHeader + { + /// + /// The buffer index of the transform feedback. + /// + public int BufferIndex; + + /// + /// The stride of the transform feedback. + /// + public int Stride; + + /// + /// The length of the varying location buffer of the transform feedback. + /// + public int VaryingLocationsLength; + + /// + /// Reserved/unused. + /// + public int Reserved1; + + public GuestShaderCacheTransformFeedbackHeader(int bufferIndex, int stride, int varyingLocationsLength) : this() + { + BufferIndex = bufferIndex; + Stride = stride; + VaryingLocationsLength = varyingLocationsLength; + } + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestTextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestTextureDescriptor.cs new file mode 100644 index 00000000..7c73ef7b --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestTextureDescriptor.cs @@ -0,0 +1,15 @@ +using Ryujinx.Graphics.Gpu.Image; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// Mostly identical to TextureDescriptor from but we don't store the address of the texture and store its handle instead. + /// + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 1)] + struct GuestTextureDescriptor + { + public uint Handle; + internal TextureDescriptor Descriptor; + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs new file mode 100644 index 00000000..f592919f --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs @@ -0,0 +1,210 @@ +using Ryujinx.Common; +using Ryujinx.Graphics.Shader; +using System; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// Host shader entry used for binding information. + /// + class HostShaderCacheEntry + { + /// + /// The header of the cached shader entry. + /// + public HostShaderCacheEntryHeader Header { get; } + + /// + /// Cached constant buffers. + /// + public BufferDescriptor[] CBuffers { get; } + + /// + /// Cached storage buffers. + /// + public BufferDescriptor[] SBuffers { get; } + + /// + /// Cached texture descriptors. + /// + public TextureDescriptor[] Textures { get; } + + /// + /// Cached image descriptors. + /// + public TextureDescriptor[] Images { get; } + + /// + /// Create a new instance of . + /// + /// The header of the cached shader entry + /// Cached constant buffers + /// Cached storage buffers + /// Cached texture descriptors + /// Cached image descriptors + private HostShaderCacheEntry( + HostShaderCacheEntryHeader header, + BufferDescriptor[] cBuffers, + BufferDescriptor[] sBuffers, + TextureDescriptor[] textures, + TextureDescriptor[] images) + { + Header = header; + CBuffers = cBuffers; + SBuffers = sBuffers; + Textures = textures; + Images = images; + } + + private HostShaderCacheEntry() + { + Header = new HostShaderCacheEntryHeader(); + CBuffers = new BufferDescriptor[0]; + SBuffers = new BufferDescriptor[0]; + Textures = new TextureDescriptor[0]; + Images = new TextureDescriptor[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(); + } + + /// + /// Convert the host shader entry to a . + /// + /// A new from this instance + internal ShaderProgramInfo ToShaderProgramInfo() + { + return new ShaderProgramInfo(CBuffers, SBuffers, Textures, Images, Header.UsesInstanceId); + } + + /// + /// Parse a raw cached user shader program into an array of shader cache entry. + /// + /// The raw cached host shader + /// The host shader program + /// An array of shader cache entry + internal static HostShaderCacheEntry[] Parse(ReadOnlySpan data, out ReadOnlySpan programCode) + { + HostShaderCacheHeader 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()); + + HostShaderCacheEntry[] result = new HostShaderCacheEntry[fileHeader.Count]; + + for (int i = 0; i < result.Length; i++) + { + HostShaderCacheEntryHeader header = entryHeaders[i]; + + if (!header.InUse) + { + continue; + } + + int cBufferDescriptorsSize = header.CBuffersCount * Unsafe.SizeOf(); + int sBufferDescriptorsSize = header.SBuffersCount * Unsafe.SizeOf(); + int textureDescriptorsSize = header.TexturesCount * Unsafe.SizeOf(); + int imageDescriptorsSize = header.ImagesCount * Unsafe.SizeOf(); + + ReadOnlySpan cBuffers = MemoryMarshal.Cast(data.Slice(0, cBufferDescriptorsSize)); + data = data.Slice(cBufferDescriptorsSize); + + ReadOnlySpan sBuffers = MemoryMarshal.Cast(data.Slice(0, sBufferDescriptorsSize)); + data = data.Slice(sBufferDescriptorsSize); + + ReadOnlySpan textureDescriptors = MemoryMarshal.Cast(data.Slice(0, textureDescriptorsSize)); + data = data.Slice(textureDescriptorsSize); + + ReadOnlySpan imageDescriptors = MemoryMarshal.Cast(data.Slice(0, imageDescriptorsSize)); + data = data.Slice(imageDescriptorsSize); + + result[i] = new HostShaderCacheEntry(header, cBuffers.ToArray(), sBuffers.ToArray(), textureDescriptors.ToArray(), imageDescriptors.ToArray()); + } + + programCode = data.Slice(0, fileHeader.CodeSize); + + return result; + } + + /// + /// Create a new host shader cache file. + /// + /// The host shader program + /// The shaders code holder + /// Raw data of a new host shader cache file + internal static byte[] Create(ReadOnlySpan programCode, ShaderCodeHolder[] codeHolders) + { + HostShaderCacheHeader header = new HostShaderCacheHeader((byte)codeHolders.Length, programCode.Length); + + HostShaderCacheEntry[] entries = new HostShaderCacheEntry[codeHolders.Length]; + + for (int i = 0; i < codeHolders.Length; i++) + { + if (codeHolders[i] == null) + { + entries[i] = new HostShaderCacheEntry(); + } + else + { + entries[i] = new HostShaderCacheEntry(codeHolders[i].Info); + } + } + + using (MemoryStream stream = new MemoryStream()) + { + BinaryWriter writer = new BinaryWriter(stream); + + writer.WriteStruct(header); + + foreach (HostShaderCacheEntry entry in entries) + { + writer.WriteStruct(entry.Header); + } + + foreach (HostShaderCacheEntry entry in entries) + { + foreach (BufferDescriptor cBuffer in entry.CBuffers) + { + writer.WriteStruct(cBuffer); + } + + foreach (BufferDescriptor sBuffer in entry.SBuffers) + { + writer.WriteStruct(sBuffer); + } + + foreach (TextureDescriptor texture in entry.Textures) + { + writer.WriteStruct(texture); + } + + foreach (TextureDescriptor image in entry.Images) + { + writer.WriteStruct(image); + } + } + + writer.Write(programCode); + + return stream.ToArray(); + } + } + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs new file mode 100644 index 00000000..9b1af8fb --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs @@ -0,0 +1,67 @@ +using System.Runtime.InteropServices; +using Ryujinx.Graphics.Shader; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// Host shader entry header used for binding information. + /// + [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x14)] + struct HostShaderCacheEntryHeader + { + /// + /// Count of constant buffer descriptors. + /// + public int CBuffersCount; + + /// + /// Count of storage buffer descriptors. + /// + public int SBuffersCount; + + /// + /// Count of texture descriptors. + /// + public int TexturesCount; + + /// + /// Count of image descriptors. + /// + public int ImagesCount; + + /// + /// Set to true if the shader uses instance id. + /// + [MarshalAs(UnmanagedType.I1)] + public bool UsesInstanceId; + + /// + /// Set to true if this entry is in use. + /// + [MarshalAs(UnmanagedType.I1)] + public bool InUse; + + /// + /// Reserved / unused. + /// + public short Reserved; + + /// + /// Create a new host shader cache entry header. + /// + /// Count of constant buffer descriptors + /// Count of storage buffer descriptors + /// Count of texture descriptors + /// Count of image descriptors + /// Set to true if the shader uses instance id + public HostShaderCacheEntryHeader(int cBuffersCount, int sBuffersCount, int texturesCount, int imagesCount, bool usesInstanceId) : this() + { + CBuffersCount = cBuffersCount; + SBuffersCount = sBuffersCount; + TexturesCount = texturesCount; + ImagesCount = imagesCount; + UsesInstanceId = usesInstanceId; + InUse = true; + } + } +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheHeader.cs new file mode 100644 index 00000000..27f216cc --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheHeader.cs @@ -0,0 +1,42 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition +{ + /// + /// The header of a shader program in the guest cache. + /// + [StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = 0x10)] + struct HostShaderCacheHeader + { + /// + /// The count of shaders defining this program. + /// + public byte Count; + + /// + /// Unused/reserved. + /// + public byte Reserved1; + + /// + /// Unused/reserved. + /// + public ushort Reserved2; + + /// + /// Size of the shader binary. + /// + public int CodeSize; + + /// + /// Create a new host shader cache header. + /// + /// The count of shaders defining this program + /// The size of the shader binary + public HostShaderCacheHeader(byte count, int codeSize) : this() + { + Count = count; + CodeSize = codeSize; + } + } +} -- cgit v1.2.3