| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837 |
- 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 = 4106;
- 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,
- 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);
- }
- }
- }
- }
|