/// <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> private void CreateToc(Stream tocFileStream, ref TocHeader header, uint magic, uint codegenVersion) { BinarySerializer writer = new BinarySerializer(tocFileStream); header.Magic = magic; header.FormatVersion = FileFormatVersionPacked; header.CodeGenVersion = codegenVersion; header.Padding = 0; header.Reserved = 0; header.Reserved2 = 0; if (tocFileStream.Length > 0) { tocFileStream.Seek(0, SeekOrigin.Begin); tocFileStream.SetLength(0); } writer.Write(ref header); }
/// <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> /// 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); if (tocFileStream.Length == 0) { TocHeader header = new TocHeader(); CreateToc(tocFileStream, ref header, TocsMagic, CodeGenVersion); } 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); WriteShaderProgramInfo(ref dataWriter, shader.Info); } program.SpecializationState.Write(ref dataWriter); dataWriter.EndCompression(); if (streams == null) { tocFileStream.Dispose(); dataFileStream.Dispose(); } if (hostCode.IsEmpty) { return; } WriteHostCode(context, hostCode, -1, streams); }