Use a new approach for shader BRX targets (#2532)
* Use a new approach for shader BRX targets * Make shader cache actually work * Improve the shader pattern matching a bit * Extend LDC search to predecessor blocks, catches more cases * Nit * Only save the amount of constant buffer data actually used. Avoids crashes on partially mapped buffers * Ignore Rd on predicate instructions, as they do not have a Rd register (catches more cases)
This commit is contained in:
parent
70f79e689b
commit
d9d18439f6
12 changed files with 472 additions and 149 deletions
|
@ -38,6 +38,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
/// </summary>
|
||||
RemoveManifestEntries,
|
||||
|
||||
/// <summary>
|
||||
/// Remove entries from the hash manifest and save it, and also deletes the temporary file.
|
||||
/// </summary>
|
||||
RemoveManifestEntryAndTempFile,
|
||||
|
||||
/// <summary>
|
||||
/// Flush temporary cache to archive.
|
||||
/// </summary>
|
||||
|
@ -116,6 +121,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
/// </summary>
|
||||
private ZipArchive _cacheArchive;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the cache collection supports modification.
|
||||
/// </summary>
|
||||
public bool IsReadOnly { get; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -264,6 +272,21 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove given entry from the manifest and delete the temporary file.
|
||||
/// </summary>
|
||||
/// <param name="entry">Entry to remove from the manifest</param>
|
||||
private void RemoveManifestEntryAndTempFile(Hash128 entry)
|
||||
{
|
||||
lock (_hashTable)
|
||||
{
|
||||
_hashTable.Remove(entry);
|
||||
SaveManifest();
|
||||
}
|
||||
|
||||
File.Delete(GenCacheTempFilePath(entry));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a task to flush temporary files to the archive on the worker.
|
||||
/// </summary>
|
||||
|
@ -440,6 +463,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
case CacheFileOperation.RemoveManifestEntries:
|
||||
RemoveManifestEntries((HashSet<Hash128>)task.Data);
|
||||
break;
|
||||
case CacheFileOperation.RemoveManifestEntryAndTempFile:
|
||||
RemoveManifestEntryAndTempFile((Hash128)task.Data);
|
||||
break;
|
||||
case CacheFileOperation.FlushToArchive:
|
||||
FlushToArchive();
|
||||
break;
|
||||
|
@ -472,7 +498,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
{
|
||||
if (IsReadOnly)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Trying to add {keyHash} on a read-only cache, ignoring.");
|
||||
Logger.Warning?.Print(LogClass.Gpu, $"Trying to add {keyHash} on a read-only cache, ignoring.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -521,7 +547,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
{
|
||||
if (IsReadOnly)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, "Trying to replace {keyHash} on a read-only cache, ignoring.");
|
||||
Logger.Warning?.Print(LogClass.Gpu, $"Trying to replace {keyHash} on a read-only cache, ignoring.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -540,6 +566,27 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a value at the given hash from the cache.
|
||||
/// </summary>
|
||||
/// <param name="keyHash">The hash of the value in the cache</param>
|
||||
public void RemoveValue(ref Hash128 keyHash)
|
||||
{
|
||||
if (IsReadOnly)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Gpu, $"Trying to remove {keyHash} on a read-only cache, ignoring.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Only queue file change operations
|
||||
_fileWriterWorkerQueue.Add(new CacheFileOperationTask
|
||||
{
|
||||
Type = CacheFileOperation.RemoveManifestEntryAndTempFile,
|
||||
Data = keyHash
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
|
|
@ -371,11 +371,13 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
/// <summary>
|
||||
/// Create guest shader cache entries from the runtime contexts.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">The GPU memory manager in use</param>
|
||||
/// <param name="channel">The GPU channel in use</param>
|
||||
/// <param name="shaderContexts">The runtime contexts</param>
|
||||
/// <returns>Guest shader cahe entries from the runtime contexts</returns>
|
||||
public static GuestShaderCacheEntry[] CreateShaderCacheEntries(MemoryManager memoryManager, ReadOnlySpan<TranslatorContext> shaderContexts)
|
||||
public static GuestShaderCacheEntry[] CreateShaderCacheEntries(GpuChannel channel, ReadOnlySpan<TranslatorContext> shaderContexts)
|
||||
{
|
||||
MemoryManager memoryManager = channel.MemoryManager;
|
||||
|
||||
int startIndex = shaderContexts.Length > 1 ? 1 : 0;
|
||||
|
||||
GuestShaderCacheEntry[] entries = new GuestShaderCacheEntry[shaderContexts.Length - startIndex];
|
||||
|
@ -389,31 +391,66 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
continue;
|
||||
}
|
||||
|
||||
GpuAccessor gpuAccessor = context.GpuAccessor as GpuAccessor;
|
||||
|
||||
ulong cb1DataAddress;
|
||||
int cb1DataSize = gpuAccessor?.Cb1DataSize ?? 0;
|
||||
|
||||
if (context.Stage == ShaderStage.Compute)
|
||||
{
|
||||
cb1DataAddress = channel.BufferManager.GetComputeUniformBufferAddress(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int stageIndex = context.Stage switch
|
||||
{
|
||||
ShaderStage.TessellationControl => 1,
|
||||
ShaderStage.TessellationEvaluation => 2,
|
||||
ShaderStage.Geometry => 3,
|
||||
ShaderStage.Fragment => 4,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
cb1DataAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, 1);
|
||||
}
|
||||
|
||||
int size = context.Size;
|
||||
|
||||
TranslatorContext translatorContext2 = i == 1 ? shaderContexts[0] : null;
|
||||
|
||||
int sizeA = translatorContext2 != null ? translatorContext2.Size : 0;
|
||||
|
||||
byte[] code = new byte[context.Size + sizeA];
|
||||
byte[] code = new byte[size + cb1DataSize + sizeA];
|
||||
|
||||
memoryManager.GetSpan(context.Address, context.Size).CopyTo(code);
|
||||
memoryManager.GetSpan(context.Address, size).CopyTo(code);
|
||||
|
||||
if (cb1DataAddress != 0 && cb1DataSize != 0)
|
||||
{
|
||||
memoryManager.Physical.GetSpan(cb1DataAddress, cb1DataSize).CopyTo(code.AsSpan().Slice(size, cb1DataSize));
|
||||
}
|
||||
|
||||
if (translatorContext2 != null)
|
||||
{
|
||||
memoryManager.GetSpan(translatorContext2.Address, sizeA).CopyTo(code.AsSpan().Slice(context.Size, sizeA));
|
||||
memoryManager.GetSpan(translatorContext2.Address, sizeA).CopyTo(code.AsSpan().Slice(size + cb1DataSize, sizeA));
|
||||
}
|
||||
|
||||
GuestGpuAccessorHeader gpuAccessorHeader = CreateGuestGpuAccessorCache(context.GpuAccessor);
|
||||
|
||||
if (context.GpuAccessor is GpuAccessor)
|
||||
if (gpuAccessor != null)
|
||||
{
|
||||
gpuAccessorHeader.TextureDescriptorCount = context.TextureHandlesForCache.Count;
|
||||
}
|
||||
|
||||
GuestShaderCacheEntryHeader header = new GuestShaderCacheEntryHeader(context.Stage, context.Size, sizeA, gpuAccessorHeader);
|
||||
GuestShaderCacheEntryHeader header = new GuestShaderCacheEntryHeader(
|
||||
context.Stage,
|
||||
size + cb1DataSize,
|
||||
sizeA,
|
||||
cb1DataSize,
|
||||
gpuAccessorHeader);
|
||||
|
||||
GuestShaderCacheEntry entry = new GuestShaderCacheEntry(header, code);
|
||||
|
||||
if (context.GpuAccessor is GpuAccessor gpuAccessor)
|
||||
if (gpuAccessor != null)
|
||||
{
|
||||
foreach (int textureHandle in context.TextureHandlesForCache)
|
||||
{
|
||||
|
|
|
@ -114,6 +114,16 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
|
|||
_hostProgramCache.ReplaceValue(ref programCodeHash, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a shader program present in the program cache.
|
||||
/// </summary>
|
||||
/// <param name="programCodeHash">Target program code hash</param>
|
||||
public void RemoveProgram(ref Hash128 programCodeHash)
|
||||
{
|
||||
_guestProgramCache.RemoveValue(ref programCodeHash);
|
||||
_hostProgramCache.RemoveValue(ref programCodeHash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all guest program hashes.
|
||||
/// </summary>
|
||||
|
|
|
@ -40,9 +40,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
|||
public int SizeA;
|
||||
|
||||
/// <summary>
|
||||
/// Unused/reserved.
|
||||
/// Constant buffer 1 data size.
|
||||
/// </summary>
|
||||
public int Reserved4;
|
||||
public int Cb1DataSize;
|
||||
|
||||
/// <summary>
|
||||
/// The header of the cached gpu accessor.
|
||||
|
@ -55,12 +55,14 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
|||
/// <param name="stage">The stage of this shader</param>
|
||||
/// <param name="size">The size of the code section</param>
|
||||
/// <param name="sizeA">The size of the code2 section if present (Vertex A)</param>
|
||||
/// <param name="cb1DataSize">Constant buffer 1 data size</param>
|
||||
/// <param name="gpuAccessorHeader">The header of the cached gpu accessor</param>
|
||||
public GuestShaderCacheEntryHeader(ShaderStage stage, int size, int sizeA, GuestGpuAccessorHeader gpuAccessorHeader) : this()
|
||||
public GuestShaderCacheEntryHeader(ShaderStage stage, int size, int sizeA, int cb1DataSize, GuestGpuAccessorHeader gpuAccessorHeader) : this()
|
||||
{
|
||||
Stage = stage;
|
||||
Size = size;
|
||||
Size = size;
|
||||
SizeA = sizeA;
|
||||
Cb1DataSize = cb1DataSize;
|
||||
GpuAccessorHeader = gpuAccessorHeader;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue