Move solution and projects to src
This commit is contained in:
parent
cd124bda58
commit
cee7121058
3466 changed files with 55 additions and 55 deletions
|
@ -1,839 +0,0 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
{
|
||||
/// <summary>
|
||||
/// On-disk shader cache storage for host code.
|
||||
/// </summary>
|
||||
class DiskCacheHostStorage
|
||||
{
|
||||
private const uint TocsMagic = (byte)'T' | ((byte)'O' << 8) | ((byte)'C' << 16) | ((byte)'S' << 24);
|
||||
private const uint TochMagic = (byte)'T' | ((byte)'O' << 8) | ((byte)'C' << 16) | ((byte)'H' << 24);
|
||||
private const uint ShdiMagic = (byte)'S' | ((byte)'H' << 8) | ((byte)'D' << 16) | ((byte)'I' << 24);
|
||||
private const uint BufdMagic = (byte)'B' | ((byte)'U' << 8) | ((byte)'F' << 16) | ((byte)'D' << 24);
|
||||
private const uint TexdMagic = (byte)'T' | ((byte)'E' << 8) | ((byte)'X' << 16) | ((byte)'D' << 24);
|
||||
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 4735;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
||||
private readonly string _basePath;
|
||||
|
||||
public bool CacheEnabled => !string.IsNullOrEmpty(_basePath);
|
||||
|
||||
/// <summary>
|
||||
/// TOC (Table of contents) file header.
|
||||
/// </summary>
|
||||
private struct TocHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic value, for validation and identification.
|
||||
/// </summary>
|
||||
public uint Magic;
|
||||
|
||||
/// <summary>
|
||||
/// File format version.
|
||||
/// </summary>
|
||||
public uint FormatVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Generated shader code version.
|
||||
/// </summary>
|
||||
public uint CodeGenVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Header padding.
|
||||
/// </summary>
|
||||
public uint Padding;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of when the file was first created.
|
||||
/// </summary>
|
||||
public ulong Timestamp;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved space, to be used in the future. Write as zero.
|
||||
/// </summary>
|
||||
public ulong Reserved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offset and size pair.
|
||||
/// </summary>
|
||||
private struct OffsetAndSize
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset.
|
||||
/// </summary>
|
||||
public ulong Offset;
|
||||
|
||||
/// <summary>
|
||||
/// Size of uncompressed data.
|
||||
/// </summary>
|
||||
public uint UncompressedSize;
|
||||
|
||||
/// <summary>
|
||||
/// Size of compressed data.
|
||||
/// </summary>
|
||||
public uint CompressedSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Per-stage data entry.
|
||||
/// </summary>
|
||||
private struct DataEntryPerStage
|
||||
{
|
||||
/// <summary>
|
||||
/// Index of the guest code on the guest code cache TOC file.
|
||||
/// </summary>
|
||||
public int GuestCodeIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Per-program data entry.
|
||||
/// </summary>
|
||||
private struct DataEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Bit mask where each bit set is a used shader stage. Should be zero for compute shaders.
|
||||
/// </summary>
|
||||
public uint StagesBitMask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Per-stage shader information, returned by the translator.
|
||||
/// </summary>
|
||||
private struct DataShaderInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Total constant buffers used.
|
||||
/// </summary>
|
||||
public ushort CBuffersCount;
|
||||
|
||||
/// <summary>
|
||||
/// Total storage buffers used.
|
||||
/// </summary>
|
||||
public ushort SBuffersCount;
|
||||
|
||||
/// <summary>
|
||||
/// Total textures used.
|
||||
/// </summary>
|
||||
public ushort TexturesCount;
|
||||
|
||||
/// <summary>
|
||||
/// Total images used.
|
||||
/// </summary>
|
||||
public ushort ImagesCount;
|
||||
|
||||
/// <summary>
|
||||
/// Shader stage.
|
||||
/// </summary>
|
||||
public ShaderStage Stage;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the shader accesses the Instance ID built-in variable.
|
||||
/// </summary>
|
||||
public bool UsesInstanceId;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the shader modifies the Layer built-in variable.
|
||||
/// </summary>
|
||||
public bool UsesRtLayer;
|
||||
|
||||
/// <summary>
|
||||
/// Bit mask with the clip distances written on the vertex stage.
|
||||
/// </summary>
|
||||
public byte ClipDistancesWritten;
|
||||
|
||||
/// <summary>
|
||||
/// Bit mask of the render target components written by the fragment stage.
|
||||
/// </summary>
|
||||
public int FragmentOutputMap;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the vertex shader accesses draw parameters.
|
||||
/// </summary>
|
||||
public bool UsesDrawParameters;
|
||||
}
|
||||
|
||||
private readonly DiskCacheGuestStorage _guestStorage;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a disk cache host storage.
|
||||
/// </summary>
|
||||
/// <param name="basePath">Base path of the shader cache</param>
|
||||
public DiskCacheHostStorage(string basePath)
|
||||
{
|
||||
_basePath = basePath;
|
||||
_guestStorage = new DiskCacheGuestStorage(basePath);
|
||||
|
||||
if (CacheEnabled)
|
||||
{
|
||||
Directory.CreateDirectory(basePath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total of host programs on the cache.
|
||||
/// </summary>
|
||||
/// <returns>Host programs count</returns>
|
||||
public int GetProgramCount()
|
||||
{
|
||||
string tocFilePath = Path.Combine(_basePath, SharedTocFileName);
|
||||
|
||||
if (!File.Exists(tocFilePath))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.Max((int)((new FileInfo(tocFilePath).Length - Unsafe.SizeOf<TocHeader>()) / sizeof(ulong)), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Guest the name of the host program cache file, with extension.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <returns>Name of the file, without extension</returns>
|
||||
private static string GetHostFileName(GpuContext context)
|
||||
{
|
||||
string apiName = context.Capabilities.Api.ToString().ToLowerInvariant();
|
||||
string vendorName = RemoveInvalidCharacters(context.Capabilities.VendorName.ToLowerInvariant());
|
||||
return $"{apiName}_{vendorName}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes invalid path characters and spaces from a file name.
|
||||
/// </summary>
|
||||
/// <param name="fileName">File name</param>
|
||||
/// <returns>Filtered file name</returns>
|
||||
private static string RemoveInvalidCharacters(string fileName)
|
||||
{
|
||||
int indexOfSpace = fileName.IndexOf(' ');
|
||||
if (indexOfSpace >= 0)
|
||||
{
|
||||
fileName = fileName.Substring(0, indexOfSpace);
|
||||
}
|
||||
|
||||
return string.Concat(fileName.Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the TOC host file.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <returns>File name</returns>
|
||||
private static string GetHostTocFileName(GpuContext context)
|
||||
{
|
||||
return GetHostFileName(context) + ".toc";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the data host file.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <returns>File name</returns>
|
||||
private static string GetHostDataFileName(GpuContext context)
|
||||
{
|
||||
return GetHostFileName(context) + ".data";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a disk cache exists for the current application.
|
||||
/// </summary>
|
||||
/// <returns>True if a disk cache exists, false otherwise</returns>
|
||||
public bool CacheExists()
|
||||
{
|
||||
string tocFilePath = Path.Combine(_basePath, SharedTocFileName);
|
||||
string dataFilePath = Path.Combine(_basePath, SharedDataFileName);
|
||||
|
||||
if (!File.Exists(tocFilePath) || !File.Exists(dataFilePath) || !_guestStorage.TocFileExists() || !_guestStorage.DataFileExists())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
GuestCodeAndCbData?[] guestShaders = new GuestCodeAndCbData?[isCompute ? 1 : Constants.ShaderStages + 1];
|
||||
|
||||
DataEntryPerStage stageEntry = new DataEntryPerStage();
|
||||
|
||||
while (stagesBitMask != 0)
|
||||
{
|
||||
int stageIndex = BitOperations.TrailingZeroCount(stagesBitMask);
|
||||
|
||||
dataReader.Read(ref stageEntry);
|
||||
|
||||
guestShaders[stageIndex] = _guestStorage.LoadShader(
|
||||
guestTocFileStream,
|
||||
guestDataFileStream,
|
||||
stageEntry.GuestCodeIndex);
|
||||
|
||||
stagesBitMask &= ~(1u << stageIndex);
|
||||
}
|
||||
|
||||
ShaderSpecializationState specState = ShaderSpecializationState.Read(ref dataReader);
|
||||
dataReader.EndCompression();
|
||||
|
||||
if (loadHostCache)
|
||||
{
|
||||
(byte[] hostCode, CachedShaderStage[] shaders) = ReadHostCode(
|
||||
context,
|
||||
ref hostTocFileStream,
|
||||
ref hostDataFileStream,
|
||||
guestShaders,
|
||||
programIndex,
|
||||
header.Timestamp);
|
||||
|
||||
if (hostCode != null)
|
||||
{
|
||||
bool hasFragmentShader = shaders.Length > 5 && shaders[5] != null;
|
||||
int fragmentOutputMap = hasFragmentShader ? shaders[5].Info.FragmentOutputMap : -1;
|
||||
|
||||
ShaderInfo shaderInfo = specState.PipelineState.HasValue
|
||||
? new ShaderInfo(fragmentOutputMap, specState.PipelineState.Value, fromCache: true)
|
||||
: new ShaderInfo(fragmentOutputMap, fromCache: true);
|
||||
|
||||
IProgram hostProgram;
|
||||
|
||||
if (context.Capabilities.Api == TargetApi.Vulkan)
|
||||
{
|
||||
ShaderSource[] shaderSources = ShaderBinarySerializer.Unpack(shaders, hostCode);
|
||||
|
||||
hostProgram = context.Renderer.CreateProgram(shaderSources, shaderInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
hostProgram = context.Renderer.LoadProgramBinary(hostCode, hasFragmentShader, shaderInfo);
|
||||
}
|
||||
|
||||
CachedShaderProgram program = new CachedShaderProgram(hostProgram, specState, shaders);
|
||||
|
||||
loader.QueueHostProgram(program, hostCode, programIndex, isCompute);
|
||||
}
|
||||
else
|
||||
{
|
||||
loadHostCache = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadHostCache)
|
||||
{
|
||||
loader.QueueGuestProgram(guestShaders, specState, programIndex, isCompute);
|
||||
}
|
||||
|
||||
loader.CheckCompilation();
|
||||
programIndex++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_guestStorage.ClearMemoryCache();
|
||||
|
||||
hostTocFileStream?.Dispose();
|
||||
hostDataFileStream?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets output streams for the disk cache, for faster batch writing.
|
||||
/// </summary>
|
||||
/// <param name="context">The GPU context, used to determine the host disk cache</param>
|
||||
/// <returns>A collection of disk cache output streams</returns>
|
||||
public DiskCacheOutputStreams GetOutputStreams(GpuContext context)
|
||||
{
|
||||
var tocFileStream = DiskCacheCommon.OpenFile(_basePath, SharedTocFileName, writable: true);
|
||||
var dataFileStream = DiskCacheCommon.OpenFile(_basePath, SharedDataFileName, writable: true);
|
||||
|
||||
var hostTocFileStream = DiskCacheCommon.OpenFile(_basePath, GetHostTocFileName(context), writable: true);
|
||||
var hostDataFileStream = DiskCacheCommon.OpenFile(_basePath, GetHostDataFileName(context), writable: true);
|
||||
|
||||
return new DiskCacheOutputStreams(tocFileStream, dataFileStream, hostTocFileStream, hostDataFileStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a shader to the cache.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="program">Cached program</param>
|
||||
/// <param name="hostCode">Optional host binary code</param>
|
||||
/// <param name="streams">Output streams to use</param>
|
||||
public void AddShader(GpuContext context, CachedShaderProgram program, ReadOnlySpan<byte> hostCode, DiskCacheOutputStreams streams = null)
|
||||
{
|
||||
uint stagesBitMask = 0;
|
||||
|
||||
for (int index = 0; index < program.Shaders.Length; index++)
|
||||
{
|
||||
var shader = program.Shaders[index];
|
||||
if (shader == null || (shader.Info != null && shader.Info.Stage == ShaderStage.Compute))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stagesBitMask |= 1u << index;
|
||||
}
|
||||
|
||||
var tocFileStream = streams != null ? streams.TocFileStream : DiskCacheCommon.OpenFile(_basePath, SharedTocFileName, writable: true);
|
||||
var dataFileStream = streams != null ? streams.DataFileStream : DiskCacheCommon.OpenFile(_basePath, SharedDataFileName, writable: true);
|
||||
|
||||
ulong timestamp = (ulong)DateTime.UtcNow.Subtract(DateTime.UnixEpoch).TotalSeconds;
|
||||
|
||||
if (tocFileStream.Length == 0)
|
||||
{
|
||||
TocHeader header = new TocHeader();
|
||||
CreateToc(tocFileStream, ref header, TocsMagic, CodeGenVersion, timestamp);
|
||||
}
|
||||
|
||||
tocFileStream.Seek(0, SeekOrigin.End);
|
||||
dataFileStream.Seek(0, SeekOrigin.End);
|
||||
|
||||
BinarySerializer tocWriter = new BinarySerializer(tocFileStream);
|
||||
BinarySerializer dataWriter = new BinarySerializer(dataFileStream);
|
||||
|
||||
ulong dataOffset = (ulong)dataFileStream.Position;
|
||||
tocWriter.Write(ref dataOffset);
|
||||
|
||||
DataEntry entry = new DataEntry();
|
||||
|
||||
entry.StagesBitMask = stagesBitMask;
|
||||
|
||||
dataWriter.BeginCompression(DiskCacheCommon.GetCompressionAlgorithm());
|
||||
dataWriter.Write(ref entry);
|
||||
|
||||
DataEntryPerStage stageEntry = new DataEntryPerStage();
|
||||
|
||||
for (int index = 0; index < program.Shaders.Length; index++)
|
||||
{
|
||||
var shader = program.Shaders[index];
|
||||
if (shader == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stageEntry.GuestCodeIndex = _guestStorage.AddShader(shader.Code, shader.Cb1Data);
|
||||
|
||||
dataWriter.Write(ref stageEntry);
|
||||
}
|
||||
|
||||
program.SpecializationState.Write(ref dataWriter);
|
||||
dataWriter.EndCompression();
|
||||
|
||||
if (streams == null)
|
||||
{
|
||||
tocFileStream.Dispose();
|
||||
dataFileStream.Dispose();
|
||||
}
|
||||
|
||||
if (hostCode.IsEmpty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WriteHostCode(context, hostCode, program.Shaders, streams, timestamp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all content from the guest cache files.
|
||||
/// </summary>
|
||||
public void ClearGuestCache()
|
||||
{
|
||||
_guestStorage.ClearCache();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all content from the shared cache files.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
public void ClearSharedCache()
|
||||
{
|
||||
using var tocFileStream = DiskCacheCommon.OpenFile(_basePath, SharedTocFileName, writable: true);
|
||||
using var dataFileStream = DiskCacheCommon.OpenFile(_basePath, SharedDataFileName, writable: true);
|
||||
|
||||
tocFileStream.SetLength(0);
|
||||
dataFileStream.SetLength(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all content from the host cache files.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
public void ClearHostCache(GpuContext context)
|
||||
{
|
||||
using var tocFileStream = DiskCacheCommon.OpenFile(_basePath, GetHostTocFileName(context), writable: true);
|
||||
using var dataFileStream = DiskCacheCommon.OpenFile(_basePath, GetHostDataFileName(context), writable: true);
|
||||
|
||||
tocFileStream.SetLength(0);
|
||||
dataFileStream.SetLength(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the host binary code on the host cache.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="hostCode">Host binary code</param>
|
||||
/// <param name="shaders">Shader stages to be added to the host cache</param>
|
||||
/// <param name="streams">Output streams to use</param>
|
||||
/// <param name="timestamp">File creation timestamp</param>
|
||||
private void WriteHostCode(
|
||||
GpuContext context,
|
||||
ReadOnlySpan<byte> hostCode,
|
||||
CachedShaderStage[] shaders,
|
||||
DiskCacheOutputStreams streams,
|
||||
ulong timestamp)
|
||||
{
|
||||
var tocFileStream = streams != null ? streams.HostTocFileStream : DiskCacheCommon.OpenFile(_basePath, GetHostTocFileName(context), writable: true);
|
||||
var dataFileStream = streams != null ? streams.HostDataFileStream : DiskCacheCommon.OpenFile(_basePath, GetHostDataFileName(context), writable: true);
|
||||
|
||||
if (tocFileStream.Length == 0)
|
||||
{
|
||||
TocHeader header = new TocHeader();
|
||||
CreateToc(tocFileStream, ref header, TochMagic, 0, timestamp);
|
||||
}
|
||||
|
||||
tocFileStream.Seek(0, SeekOrigin.End);
|
||||
dataFileStream.Seek(0, SeekOrigin.End);
|
||||
|
||||
BinarySerializer tocWriter = new BinarySerializer(tocFileStream);
|
||||
BinarySerializer dataWriter = new BinarySerializer(dataFileStream);
|
||||
|
||||
OffsetAndSize offsetAndSize = new OffsetAndSize();
|
||||
offsetAndSize.Offset = (ulong)dataFileStream.Position;
|
||||
offsetAndSize.UncompressedSize = (uint)hostCode.Length;
|
||||
|
||||
long dataStartPosition = dataFileStream.Position;
|
||||
|
||||
BinarySerializer.WriteCompressed(dataFileStream, hostCode, DiskCacheCommon.GetCompressionAlgorithm());
|
||||
|
||||
offsetAndSize.CompressedSize = (uint)(dataFileStream.Position - dataStartPosition);
|
||||
|
||||
tocWriter.Write(ref offsetAndSize);
|
||||
|
||||
dataWriter.BeginCompression(DiskCacheCommon.GetCompressionAlgorithm());
|
||||
|
||||
for (int index = 0; index < shaders.Length; index++)
|
||||
{
|
||||
if (shaders[index] != null)
|
||||
{
|
||||
WriteShaderProgramInfo(ref dataWriter, shaders[index].Info);
|
||||
}
|
||||
}
|
||||
|
||||
dataWriter.EndCompression();
|
||||
|
||||
if (streams == null)
|
||||
{
|
||||
tocFileStream.Dispose();
|
||||
dataFileStream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a TOC file for the host or shared cache.
|
||||
/// </summary>
|
||||
/// <param name="tocFileStream">TOC file stream</param>
|
||||
/// <param name="header">Set to the TOC file header</param>
|
||||
/// <param name="magic">Magic value to be written</param>
|
||||
/// <param name="codegenVersion">Shader codegen version, only valid for the host file</param>
|
||||
/// <param name="timestamp">File creation timestamp</param>
|
||||
private void CreateToc(Stream tocFileStream, ref TocHeader header, uint magic, uint codegenVersion, ulong timestamp)
|
||||
{
|
||||
BinarySerializer writer = new BinarySerializer(tocFileStream);
|
||||
|
||||
header.Magic = magic;
|
||||
header.FormatVersion = FileFormatVersionPacked;
|
||||
header.CodeGenVersion = codegenVersion;
|
||||
header.Padding = 0;
|
||||
header.Reserved = 0;
|
||||
header.Timestamp = timestamp;
|
||||
|
||||
if (tocFileStream.Length > 0)
|
||||
{
|
||||
tocFileStream.Seek(0, SeekOrigin.Begin);
|
||||
tocFileStream.SetLength(0);
|
||||
}
|
||||
|
||||
writer.Write(ref header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the shader program info from the cache.
|
||||
/// </summary>
|
||||
/// <param name="dataReader">Cache data reader</param>
|
||||
/// <returns>Shader program info</returns>
|
||||
private static ShaderProgramInfo ReadShaderProgramInfo(ref BinarySerializer dataReader)
|
||||
{
|
||||
DataShaderInfo dataInfo = new DataShaderInfo();
|
||||
|
||||
dataReader.ReadWithMagicAndSize(ref dataInfo, ShdiMagic);
|
||||
|
||||
BufferDescriptor[] cBuffers = new BufferDescriptor[dataInfo.CBuffersCount];
|
||||
BufferDescriptor[] sBuffers = new BufferDescriptor[dataInfo.SBuffersCount];
|
||||
TextureDescriptor[] textures = new TextureDescriptor[dataInfo.TexturesCount];
|
||||
TextureDescriptor[] images = new TextureDescriptor[dataInfo.ImagesCount];
|
||||
|
||||
for (int index = 0; index < dataInfo.CBuffersCount; index++)
|
||||
{
|
||||
dataReader.ReadWithMagicAndSize(ref cBuffers[index], BufdMagic);
|
||||
}
|
||||
|
||||
for (int index = 0; index < dataInfo.SBuffersCount; index++)
|
||||
{
|
||||
dataReader.ReadWithMagicAndSize(ref sBuffers[index], BufdMagic);
|
||||
}
|
||||
|
||||
for (int index = 0; index < dataInfo.TexturesCount; index++)
|
||||
{
|
||||
dataReader.ReadWithMagicAndSize(ref textures[index], TexdMagic);
|
||||
}
|
||||
|
||||
for (int index = 0; index < dataInfo.ImagesCount; index++)
|
||||
{
|
||||
dataReader.ReadWithMagicAndSize(ref images[index], TexdMagic);
|
||||
}
|
||||
|
||||
return new ShaderProgramInfo(
|
||||
cBuffers,
|
||||
sBuffers,
|
||||
textures,
|
||||
images,
|
||||
ShaderIdentification.None,
|
||||
0,
|
||||
dataInfo.Stage,
|
||||
dataInfo.UsesInstanceId,
|
||||
dataInfo.UsesDrawParameters,
|
||||
dataInfo.UsesRtLayer,
|
||||
dataInfo.ClipDistancesWritten,
|
||||
dataInfo.FragmentOutputMap);
|
||||
}
|
||||
|
||||
/// <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.UsesDrawParameters = info.UsesDrawParameters;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue