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();
}
}
}
}