using Ryujinx.Common;
using Ryujinx.Common.Logging;
using System;
using System.IO;
namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
/// <summary>
/// Represents a background disk cache writer.
/// </summary>
class BackgroundDiskCacheWriter : IDisposable
/// Possible operation to do on the <see cref="_fileWriterWorkerQueue"/>.
private enum CacheFileOperation
/// Operation to add a shader to the cache.
AddShader
}
/// Represents an operation to perform on the <see cref="_fileWriterWorkerQueue"/>.
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.
/// <param name="program">Cached shader program</param>
/// <param name="hostCode">Binary host code</param>
public AddShaderData(CachedShaderProgram program, byte[] hostCode)
Program = program;
HostCode = hostCode;
private readonly GpuContext _context;
private readonly DiskCacheHostStorage _hostStorage;
private readonly AsyncWorkQueue<CacheFileOperationTask> _fileWriterWorkerQueue;
/// Creates a new background disk cache writer.
/// <param name="context">GPU context</param>
/// <param name="hostStorage">Disk cache host storage</param>
public BackgroundDiskCacheWriter(GpuContext context, DiskCacheHostStorage hostStorage)
_context = context;
_hostStorage = hostStorage;
_fileWriterWorkerQueue = new AsyncWorkQueue<CacheFileOperationTask>(ProcessTask, "GPU.BackgroundDiskCacheWriter");
/// Processes a shader cache background operation.
/// <param name="task">Task to process</param>
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.
/// <param name="program">Shader program to cache</param>
/// <param name="hostCode">Host binary code of the program</param>
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();