/ src / Ryujinx.Graphics.Gpu / Shader / DiskCache / BackgroundDiskCacheWriter.cs
BackgroundDiskCacheWriter.cs
  1  using Ryujinx.Common;
  2  using Ryujinx.Common.Logging;
  3  using System;
  4  using System.IO;
  5  
  6  namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
  7  {
  8      /// <summary>
  9      /// Represents a background disk cache writer.
 10      /// </summary>
 11      class BackgroundDiskCacheWriter : IDisposable
 12      {
 13          /// <summary>
 14          /// Possible operation to do on the <see cref="_fileWriterWorkerQueue"/>.
 15          /// </summary>
 16          private enum CacheFileOperation
 17          {
 18              /// <summary>
 19              /// Operation to add a shader to the cache.
 20              /// </summary>
 21              AddShader,
 22          }
 23  
 24          /// <summary>
 25          /// Represents an operation to perform on the <see cref="_fileWriterWorkerQueue"/>.
 26          /// </summary>
 27          private readonly struct CacheFileOperationTask
 28          {
 29              /// <summary>
 30              /// The type of operation to perform.
 31              /// </summary>
 32              public readonly CacheFileOperation Type;
 33  
 34              /// <summary>
 35              /// The data associated to this operation or null.
 36              /// </summary>
 37              public readonly object Data;
 38  
 39              public CacheFileOperationTask(CacheFileOperation type, object data)
 40              {
 41                  Type = type;
 42                  Data = data;
 43              }
 44          }
 45  
 46          /// <summary>
 47          /// Background shader cache write information.
 48          /// </summary>
 49          private readonly struct AddShaderData
 50          {
 51              /// <summary>
 52              /// Cached shader program.
 53              /// </summary>
 54              public readonly CachedShaderProgram Program;
 55  
 56              /// <summary>
 57              /// Binary host code.
 58              /// </summary>
 59              public readonly byte[] HostCode;
 60  
 61              /// <summary>
 62              /// Creates a new background shader cache write information.
 63              /// </summary>
 64              /// <param name="program">Cached shader program</param>
 65              /// <param name="hostCode">Binary host code</param>
 66              public AddShaderData(CachedShaderProgram program, byte[] hostCode)
 67              {
 68                  Program = program;
 69                  HostCode = hostCode;
 70              }
 71          }
 72  
 73          private readonly GpuContext _context;
 74          private readonly DiskCacheHostStorage _hostStorage;
 75          private readonly AsyncWorkQueue<CacheFileOperationTask> _fileWriterWorkerQueue;
 76  
 77          /// <summary>
 78          /// Creates a new background disk cache writer.
 79          /// </summary>
 80          /// <param name="context">GPU context</param>
 81          /// <param name="hostStorage">Disk cache host storage</param>
 82          public BackgroundDiskCacheWriter(GpuContext context, DiskCacheHostStorage hostStorage)
 83          {
 84              _context = context;
 85              _hostStorage = hostStorage;
 86              _fileWriterWorkerQueue = new AsyncWorkQueue<CacheFileOperationTask>(ProcessTask, "GPU.BackgroundDiskCacheWriter");
 87          }
 88  
 89          /// <summary>
 90          /// Processes a shader cache background operation.
 91          /// </summary>
 92          /// <param name="task">Task to process</param>
 93          private void ProcessTask(CacheFileOperationTask task)
 94          {
 95              switch (task.Type)
 96              {
 97                  case CacheFileOperation.AddShader:
 98                      AddShaderData data = (AddShaderData)task.Data;
 99                      try
100                      {
101                          _hostStorage.AddShader(_context, data.Program, data.HostCode);
102                      }
103                      catch (DiskCacheLoadException diskCacheLoadException)
104                      {
105                          Logger.Error?.Print(LogClass.Gpu, $"Error writing shader to disk cache. {diskCacheLoadException.Message}");
106                      }
107                      catch (IOException ioException)
108                      {
109                          Logger.Error?.Print(LogClass.Gpu, $"Error writing shader to disk cache. {ioException.Message}");
110                      }
111                      break;
112              }
113          }
114  
115          /// <summary>
116          /// Adds a shader program to be cached in the background.
117          /// </summary>
118          /// <param name="program">Shader program to cache</param>
119          /// <param name="hostCode">Host binary code of the program</param>
120          public void AddShader(CachedShaderProgram program, byte[] hostCode)
121          {
122              _fileWriterWorkerQueue.Add(new CacheFileOperationTask(CacheFileOperation.AddShader, new AddShaderData(program, hostCode)));
123          }
124  
125          public void Dispose()
126          {
127              Dispose(true);
128          }
129  
130          protected virtual void Dispose(bool disposing)
131          {
132              if (disposing)
133              {
134                  _fileWriterWorkerQueue.Dispose();
135              }
136          }
137      }
138  }