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;
}
}
}