aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
diff options
context:
space:
mode:
authorMary <me@thog.eu>2020-12-01 22:48:31 +0100
committerGitHub <noreply@github.com>2020-12-01 22:48:31 +0100
commitf6d88558b1780df25088042771a75ab174f0a06c (patch)
treee3e1d1ece3b20be6a7b460226eb1e920f78e2087 /Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
parent5e6dc37aed22bd596db6a0e9c9a0527fc2a8e5b5 (diff)
salieri: Fix missing guest GPU accessor missing on hashes (#1759)
This adds the guest GPU accessor to hashes computation. As this change all the hashes from the cache, I added some migration logic. This is required for #1755.
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs209
1 files changed, 10 insertions, 199 deletions
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index b469aab5..a04affc2 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -9,9 +9,6 @@ using Ryujinx.Graphics.Shader.Translation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.Shader
{
@@ -37,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Version of the codegen (to be changed when codegen or guest format change).
/// </summary>
- private const ulong ShaderCodeGenVersion = 1717;
+ private const ulong ShaderCodeGenVersion = 1759;
/// <summary>
/// Creates a new instance of the shader cache.
@@ -165,7 +162,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
ShaderCodeHolder[] shaders = new ShaderCodeHolder[cachedShaderEntries.Length];
List<ShaderProgram> shaderPrograms = new List<ShaderProgram>();
- TransformFeedbackDescriptor[] tfd = ReadTransformationFeedbackInformations(ref guestProgramReadOnlySpan, fileHeader);
+ TransformFeedbackDescriptor[] tfd = CacheHelper.ReadTransformationFeedbackInformations(ref guestProgramReadOnlySpan, fileHeader);
TranslationFlags flags = DefaultFlags;
@@ -347,14 +344,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
bool isShaderCacheEnabled = _cacheManager != null;
- byte[] programCode = null;
Hash128 programCodeHash = default;
- GuestShaderCacheEntryHeader[] shaderCacheEntries = null;
+ GuestShaderCacheEntry[] shaderCacheEntries = null;
if (isShaderCacheEnabled)
{
// Compute hash and prepare data for shader disk cache comparison.
- GetProgramInformations(null, shaderContexts, out programCode, out programCodeHash, out shaderCacheEntries);
+ shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(_context.MemoryManager, shaderContexts);
+ programCodeHash = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries);
}
ShaderBundle cpShader;
@@ -381,7 +378,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
if (isShaderCacheEnabled)
{
_cpProgramsDiskCache.Add(programCodeHash, cpShader);
- _cacheManager.SaveProgram(ref programCodeHash, CreateGuestProgramDump(programCode, shaderCacheEntries, null), hostProgramBinary);
+ _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries), hostProgramBinary);
}
}
@@ -451,14 +448,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
bool isShaderCacheEnabled = _cacheManager != null;
- byte[] programCode = null;
Hash128 programCodeHash = default;
- GuestShaderCacheEntryHeader[] shaderCacheEntries = null;
+ GuestShaderCacheEntry[] shaderCacheEntries = null;
if (isShaderCacheEnabled)
{
// Compute hash and prepare data for shader disk cache comparison.
- GetProgramInformations(tfd, shaderContexts, out programCode, out programCodeHash, out shaderCacheEntries);
+ shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(_context.MemoryManager, shaderContexts);
+ programCodeHash = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries, tfd);
}
ShaderBundle gpShaders;
@@ -507,7 +504,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
if (isShaderCacheEnabled)
{
_gpProgramsDiskCache.Add(programCodeHash, gpShaders);
- _cacheManager.SaveProgram(ref programCodeHash, CreateGuestProgramDump(programCode, shaderCacheEntries, tfd), hostProgramBinary);
+ _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries, tfd), hostProgramBinary);
}
}
@@ -766,191 +763,5 @@ namespace Ryujinx.Graphics.Gpu.Shader
_cacheManager?.Dispose();
}
-
- /// <summary>
- /// Create a guest shader program.
- /// </summary>
- /// <param name="programCode">The program code of the shader code</param>
- /// <param name="shaderCacheEntries">The resulting guest shader entries header</param>
- /// <param name="tfd">The transform feedback descriptors in use</param>
- /// <returns>The resulting guest shader program</returns>
- private static byte[] CreateGuestProgramDump(ReadOnlySpan<byte> programCode, GuestShaderCacheEntryHeader[] shaderCacheEntries, TransformFeedbackDescriptor[] tfd)
- {
- using (MemoryStream resultStream = new MemoryStream())
- {
- BinaryWriter resultStreamWriter = new BinaryWriter(resultStream);
-
- byte transformFeedbackCount = 0;
-
- if (tfd != null)
- {
- transformFeedbackCount = (byte)tfd.Length;
- }
-
- // Header
- resultStreamWriter.WriteStruct(new GuestShaderCacheHeader((byte)shaderCacheEntries.Length, transformFeedbackCount));
-
- // Write all entries header
- foreach (GuestShaderCacheEntryHeader entry in shaderCacheEntries)
- {
- resultStreamWriter.WriteStruct(entry);
- }
-
- // Finally, write all program code and all transform feedback information.
- resultStreamWriter.Write(programCode);
-
- return resultStream.ToArray();
- }
- }
-
- /// <summary>
- /// Write transform feedback guest information to the given stream.
- /// </summary>
- /// <param name="stream">The stream to write data to</param>
- /// <param name="tfd">The current transform feedback descriptors used</param>
- private static void WriteTransformationFeedbackInformation(Stream stream, TransformFeedbackDescriptor[] tfd)
- {
- if (tfd != null)
- {
- BinaryWriter writer = new BinaryWriter(stream);
-
- foreach (TransformFeedbackDescriptor transform in tfd)
- {
- writer.WriteStruct(new GuestShaderCacheTransformFeedbackHeader(transform.BufferIndex, transform.Stride, transform.VaryingLocations.Length));
- writer.Write(transform.VaryingLocations);
- }
- }
- }
-
- /// <summary>
- /// Read transform feedback descriptors from guest.
- /// </summary>
- /// <param name="data">The raw guest transform feedback descriptors</param>
- /// <param name="header">The guest shader program header</param>
- /// <returns>The transform feedback descriptors read from guest</returns>
- private static TransformFeedbackDescriptor[] ReadTransformationFeedbackInformations(ref ReadOnlySpan<byte> data, GuestShaderCacheHeader header)
- {
- if (header.TransformFeedbackCount != 0)
- {
- TransformFeedbackDescriptor[] result = new TransformFeedbackDescriptor[header.TransformFeedbackCount];
-
- for (int i = 0; i < result.Length; i++)
- {
- GuestShaderCacheTransformFeedbackHeader feedbackHeader = MemoryMarshal.Read<GuestShaderCacheTransformFeedbackHeader>(data);
-
- result[i] = new TransformFeedbackDescriptor(feedbackHeader.BufferIndex, feedbackHeader.Stride, data.Slice(Unsafe.SizeOf<GuestShaderCacheTransformFeedbackHeader>(), feedbackHeader.VaryingLocationsLength).ToArray());
-
- data = data.Slice(Unsafe.SizeOf<GuestShaderCacheTransformFeedbackHeader>() + feedbackHeader.VaryingLocationsLength);
- }
-
- return result;
- }
-
- return null;
- }
-
- /// <summary>
- /// Create a new instance of <see cref="GuestGpuAccessorHeader"/> from an gpu accessor.
- /// </summary>
- /// <param name="gpuAccessor">The gpu accessor</param>
- /// <returns>a new instance of <see cref="GuestGpuAccessorHeader"/></returns>
- private static GuestGpuAccessorHeader CreateGuestGpuAccessorCache(IGpuAccessor gpuAccessor)
- {
- return new GuestGpuAccessorHeader
- {
- ComputeLocalSizeX = gpuAccessor.QueryComputeLocalSizeX(),
- ComputeLocalSizeY = gpuAccessor.QueryComputeLocalSizeY(),
- ComputeLocalSizeZ = gpuAccessor.QueryComputeLocalSizeZ(),
- ComputeLocalMemorySize = gpuAccessor.QueryComputeLocalMemorySize(),
- ComputeSharedMemorySize = gpuAccessor.QueryComputeSharedMemorySize(),
- PrimitiveTopology = gpuAccessor.QueryPrimitiveTopology(),
- };
- }
-
- /// <summary>
- /// Write the guest GpuAccessor informations to the given stream.
- /// </summary>
- /// <param name="stream">The stream to write the guest GpuAcessor</param>
- /// <param name="shaderContext">The shader tranlator context in use</param>
- /// <returns>The guest gpu accessor header</returns>
- private static GuestGpuAccessorHeader WriteGuestGpuAccessorCache(Stream stream, TranslatorContext shaderContext)
- {
- BinaryWriter writer = new BinaryWriter(stream);
-
- GuestGpuAccessorHeader header = CreateGuestGpuAccessorCache(shaderContext.GpuAccessor);
-
- // If we have a full gpu accessor, cache textures descriptors
- if (shaderContext.GpuAccessor is GpuAccessor gpuAccessor)
- {
- HashSet<int> textureHandlesInUse = shaderContext.TextureHandlesForCache;
-
- header.TextureDescriptorCount = textureHandlesInUse.Count;
-
- foreach (int textureHandle in textureHandlesInUse)
- {
- GuestTextureDescriptor textureDescriptor = ((Image.TextureDescriptor)gpuAccessor.GetTextureDescriptor(textureHandle)).ToCache();
-
- textureDescriptor.Handle = (uint)textureHandle;
-
- writer.WriteStruct(textureDescriptor);
- }
- }
-
- return header;
- }
-
- /// <summary>
- /// Get the shader program information for use on the shader cache.
- /// </summary>
- /// <param name="tfd">The current transform feedback descriptors used</param>
- /// <param name="shaderContexts">The shader translators context in use</param>
- /// <param name="programCode">The resulting raw shader program code</param>
- /// <param name="programCodeHash">The resulting raw shader program code hash</param>
- /// <param name="entries">The resulting guest shader entries header</param>
- private void GetProgramInformations(TransformFeedbackDescriptor[] tfd, ReadOnlySpan<TranslatorContext> shaderContexts, out byte[] programCode, out Hash128 programCodeHash, out GuestShaderCacheEntryHeader[] entries)
- {
- GuestShaderCacheEntryHeader ComputeStage(Stream stream, TranslatorContext context)
- {
- if (context == null)
- {
- return new GuestShaderCacheEntryHeader();
- }
-
- ReadOnlySpan<byte> data = _context.MemoryManager.GetSpan(context.Address, context.Size);
-
- stream.Write(data);
-
- int size = data.Length;
- int sizeA = 0;
-
- if (context.AddressA != 0)
- {
- data = _context.MemoryManager.GetSpan(context.AddressA, context.SizeA);
-
- sizeA = data.Length;
-
- stream.Write(data);
- }
-
- GuestGpuAccessorHeader gpuAccessorHeader = WriteGuestGpuAccessorCache(stream, context);
-
- return new GuestShaderCacheEntryHeader(context.Stage, size, sizeA, gpuAccessorHeader);
- }
-
- entries = new GuestShaderCacheEntryHeader[shaderContexts.Length];
-
- using (MemoryStream stream = new MemoryStream())
- {
- for (int i = 0; i < shaderContexts.Length; i++)
- {
- entries[i] = ComputeStage(stream, shaderContexts[i]);
- }
-
- WriteTransformationFeedbackInformation(stream, tfd);
-
- programCode = stream.ToArray();
- programCodeHash = _cacheManager.ComputeHash(programCode);
- }
- }
}
} \ No newline at end of file