/// <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> /// 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="programIndex">Index of the program on the cache</param> /// <returns>Host binary code, or null if not found</returns> private byte[] ReadHostCode(GpuContext context, ref Stream tocFileStream, ref Stream dataFileStream, int programIndex) { 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); } tocFileStream = DiskCacheCommon.OpenFile(_basePath, GetHostTocFileName(context), writable: false); dataFileStream = DiskCacheCommon.OpenFile(_basePath, GetHostDataFileName(context), writable: false); } int offset = Unsafe.SizeOf <TocHeader>() + programIndex * Unsafe.SizeOf <OffsetAndSize>(); if (offset + Unsafe.SizeOf <OffsetAndSize>() > tocFileStream.Length) { return(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.Size]; BinarySerializer.ReadCompressed(dataFileStream, hostCode); return(hostCode); }
/// <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="programIndex">Index of the program in the cache</param> /// <param name="streams">Output streams to use</param> private void WriteHostCode(GpuContext context, ReadOnlySpan <byte> hostCode, int programIndex, DiskCacheOutputStreams streams = null) { 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); } if (programIndex == -1) { tocFileStream.Seek(0, SeekOrigin.End); } else { tocFileStream.Seek(Unsafe.SizeOf <TocHeader>() + (programIndex * Unsafe.SizeOf <OffsetAndSize>()), SeekOrigin.Begin); } dataFileStream.Seek(0, SeekOrigin.End); BinarySerializer tocWriter = new BinarySerializer(tocFileStream); OffsetAndSize offsetAndSize = new OffsetAndSize(); offsetAndSize.Offset = (ulong)dataFileStream.Position; offsetAndSize.Size = (uint)hostCode.Length; tocWriter.Write(ref offsetAndSize); BinarySerializer.WriteCompressed(dataFileStream, hostCode, DiskCacheCommon.GetCompressionAlgorithm()); if (streams == null) { tocFileStream.Dispose(); dataFileStream.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); }