using Ryujinx.Common; using Ryujinx.Common.Logging; using System; using System.IO; namespace Ryujinx.Graphics.Gpu.Shader.DiskCache { /// /// Represents a background disk cache writer. /// class BackgroundDiskCacheWriter : IDisposable { /// /// Possible operation to do on the . /// private enum CacheFileOperation { /// /// Operation to add a shader to the cache. /// AddShader } /// /// Represents an operation to perform on the . /// private readonly struct CacheFileOperationTask { /// /// The type of operation to perform. /// public readonly CacheFileOperation Type; /// /// The data associated to this operation or null. /// public readonly object Data; public CacheFileOperationTask(CacheFileOperation type, object data) { Type = type; Data = data; } } /// /// Background shader cache write information. /// private readonly struct AddShaderData { /// /// Cached shader program. /// public readonly CachedShaderProgram Program; /// /// Binary host code. /// public readonly byte[] HostCode; /// /// Creates a new background shader cache write information. /// /// Cached shader program /// Binary host code public AddShaderData(CachedShaderProgram program, byte[] hostCode) { Program = program; HostCode = hostCode; } } private readonly GpuContext _context; private readonly DiskCacheHostStorage _hostStorage; private readonly AsyncWorkQueue _fileWriterWorkerQueue; /// /// Creates a new background disk cache writer. /// /// GPU context /// Disk cache host storage public BackgroundDiskCacheWriter(GpuContext context, DiskCacheHostStorage hostStorage) { _context = context; _hostStorage = hostStorage; _fileWriterWorkerQueue = new AsyncWorkQueue(ProcessTask, "GPU.BackgroundDiskCacheWriter"); } /// /// Processes a shader cache background operation. /// /// Task to process private void ProcessTask(CacheFileOperationTask task) { switch (task.Type) { case CacheFileOperation.AddShader: AddShaderData data = (AddShaderData)task.Data; try { _hostStorage.AddShader(_context, data.Program, data.HostCode); } catch (DiskCacheLoadException diskCacheLoadException) { Logger.Error?.Print(LogClass.Gpu, $"Error writing shader to disk cache. {diskCacheLoadException.Message}"); } catch (IOException ioException) { Logger.Error?.Print(LogClass.Gpu, $"Error writing shader to disk cache. {ioException.Message}"); } break; } } /// /// Adds a shader program to be cached in the background. /// /// Shader program to cache /// Host binary code of the program public void AddShader(CachedShaderProgram program, byte[] hostCode) { _fileWriterWorkerQueue.Add(new CacheFileOperationTask(CacheFileOperation.AddShader, new AddShaderData(program, hostCode))); } public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (disposing) { _fileWriterWorkerQueue.Dispose(); } } } }