GuestShaderCacheEntry.cs 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.CompilerServices;
  4. using System.Runtime.InteropServices;
  5. namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
  6. {
  7. /// <summary>
  8. /// Represent a cached shader entry in a guest shader program.
  9. /// </summary>
  10. class GuestShaderCacheEntry
  11. {
  12. /// <summary>
  13. /// The header of the cached shader entry.
  14. /// </summary>
  15. public GuestShaderCacheEntryHeader Header { get; }
  16. /// <summary>
  17. /// The code of this shader.
  18. /// </summary>
  19. /// <remarks>If a Vertex A is present, this also contains the code 2 section.</remarks>
  20. public byte[] Code { get; }
  21. /// <summary>
  22. /// The textures descriptors used for this shader.
  23. /// </summary>
  24. public Dictionary<int, GuestTextureDescriptor> TextureDescriptors { get; }
  25. /// <summary>
  26. /// Create a new instance of <see cref="GuestShaderCacheEntry"/>.
  27. /// </summary>
  28. /// <param name="header">The header of the cached shader entry</param>
  29. /// <param name="code">The code of this shader</param>
  30. public GuestShaderCacheEntry(GuestShaderCacheEntryHeader header, byte[] code)
  31. {
  32. Header = header;
  33. Code = code;
  34. TextureDescriptors = new Dictionary<int, GuestTextureDescriptor>();
  35. }
  36. /// <summary>
  37. /// Parse a raw cached user shader program into an array of shader cache entry.
  38. /// </summary>
  39. /// <param name="data">The raw cached user shader program</param>
  40. /// <param name="fileHeader">The user shader program header</param>
  41. /// <returns>An array of shader cache entry</returns>
  42. public static GuestShaderCacheEntry[] Parse(ref ReadOnlySpan<byte> data, out GuestShaderCacheHeader fileHeader)
  43. {
  44. fileHeader = MemoryMarshal.Read<GuestShaderCacheHeader>(data);
  45. data = data.Slice(Unsafe.SizeOf<GuestShaderCacheHeader>());
  46. ReadOnlySpan<GuestShaderCacheEntryHeader> entryHeaders = MemoryMarshal.Cast<byte, GuestShaderCacheEntryHeader>(data.Slice(0, fileHeader.Count * Unsafe.SizeOf<GuestShaderCacheEntryHeader>()));
  47. data = data.Slice(fileHeader.Count * Unsafe.SizeOf<GuestShaderCacheEntryHeader>());
  48. GuestShaderCacheEntry[] result = new GuestShaderCacheEntry[fileHeader.Count];
  49. for (int i = 0; i < result.Length; i++)
  50. {
  51. GuestShaderCacheEntryHeader header = entryHeaders[i];
  52. // Ignore empty entries
  53. if (header.Size == 0 && header.SizeA == 0)
  54. {
  55. continue;
  56. }
  57. byte[] code = data.Slice(0, header.Size + header.SizeA).ToArray();
  58. data = data.Slice(header.Size + header.SizeA);
  59. result[i] = new GuestShaderCacheEntry(header, code);
  60. ReadOnlySpan<GuestTextureDescriptor> textureDescriptors = MemoryMarshal.Cast<byte, GuestTextureDescriptor>(data.Slice(0, header.GpuAccessorHeader.TextureDescriptorCount * Unsafe.SizeOf<GuestTextureDescriptor>()));
  61. foreach (GuestTextureDescriptor textureDescriptor in textureDescriptors)
  62. {
  63. result[i].TextureDescriptors.Add((int)textureDescriptor.Handle, textureDescriptor);
  64. }
  65. data = data.Slice(header.GpuAccessorHeader.TextureDescriptorCount * Unsafe.SizeOf<GuestTextureDescriptor>());
  66. }
  67. return result;
  68. }
  69. }
  70. }