Shader cache support

This commit is contained in:
Isaac Marovitz 2024-07-22 13:40:10 +01:00 committed by Isaac Marovitz
parent eb2dae561f
commit b44167d12a
3 changed files with 73 additions and 32 deletions

View file

@ -38,7 +38,7 @@
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" /> <PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" /> <PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" /> <PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpMetal" Version="1.0.0-preview14" /> <PackageVersion Include="SharpMetal" Version="1.0.0-preview18" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" /> <PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" /> <PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" /> <PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />

View file

@ -324,6 +324,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
bool loadHostCache = header.CodeGenVersion == CodeGenVersion; bool loadHostCache = header.CodeGenVersion == CodeGenVersion;
if (context.Capabilities.Api == TargetApi.Metal)
{
loadHostCache = false;
}
int programIndex = 0; int programIndex = 0;
DataEntry entry = new(); DataEntry entry = new();
@ -630,8 +635,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
return; return;
} }
if (context.Capabilities.Api != TargetApi.Metal)
{
WriteHostCode(context, hostCode, program.Shaders, streams, timestamp); WriteHostCode(context, hostCode, program.Shaders, streams, timestamp);
} }
}
/// <summary> /// <summary>
/// Clears all content from the guest cache files. /// Clears all content from the guest cache files.

View file

@ -6,6 +6,7 @@ using SharpMetal.Metal;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal namespace Ryujinx.Graphics.Metal
@ -13,7 +14,11 @@ namespace Ryujinx.Graphics.Metal
[SupportedOSPlatform("macos")] [SupportedOSPlatform("macos")]
class Program : IProgram class Program : IProgram
{ {
private readonly ProgramLinkStatus _status; private ProgramLinkStatus _status;
private ShaderSource[] _shaders;
private GCHandle[] _handles;
private int _successCount;
public MTLFunction VertexFunction; public MTLFunction VertexFunction;
public MTLFunction FragmentFunction; public MTLFunction FragmentFunction;
public MTLFunction ComputeFunction; public MTLFunction ComputeFunction;
@ -33,45 +38,65 @@ namespace Ryujinx.Graphics.Metal
public Program(ShaderSource[] shaders, ResourceLayout resourceLayout, MTLDevice device, ComputeSize computeLocalSize = default) public Program(ShaderSource[] shaders, ResourceLayout resourceLayout, MTLDevice device, ComputeSize computeLocalSize = default)
{ {
ComputeLocalSize = computeLocalSize; ComputeLocalSize = computeLocalSize;
_shaders = shaders;
_handles = new GCHandle[_shaders.Length];
for (int index = 0; index < shaders.Length; index++) _status = ProgramLinkStatus.Incomplete;
for (int i = 0; i < _shaders.Length; i++)
{ {
ShaderSource shader = shaders[index]; ShaderSource shader = _shaders[i];
var compileOptions = new MTLCompileOptions { PreserveInvariance = true }; var compileOptions = new MTLCompileOptions { PreserveInvariance = true };
var index = i;
var libraryError = new NSError(IntPtr.Zero); _handles[i] = device.NewLibrary(StringHelper.NSString(shader.Code), compileOptions, (library, error) => CompilationResultHandler(library, error, index));
var shaderLibrary = device.NewLibrary(StringHelper.NSString(shader.Code), compileOptions, ref libraryError);
if (libraryError != IntPtr.Zero)
{
Logger.Warning?.PrintMsg(LogClass.Gpu, shader.Code);
Logger.Warning?.Print(LogClass.Gpu, $"{shader.Stage} shader linking failed: \n{StringHelper.String(libraryError.LocalizedDescription)}");
_status = ProgramLinkStatus.Failure;
return;
}
switch (shaders[index].Stage)
{
case ShaderStage.Compute:
ComputeFunction = shaderLibrary.NewFunction(StringHelper.NSString("kernelMain"));
break;
case ShaderStage.Vertex:
VertexFunction = shaderLibrary.NewFunction(StringHelper.NSString("vertexMain"));
break;
case ShaderStage.Fragment:
FragmentFunction = shaderLibrary.NewFunction(StringHelper.NSString("fragmentMain"));
break;
default:
Logger.Warning?.Print(LogClass.Gpu, $"Cannot handle stage {shaders[index].Stage}!");
break;
}
} }
ClearSegments = BuildClearSegments(resourceLayout.Sets); ClearSegments = BuildClearSegments(resourceLayout.Sets);
(BindingSegments, ArgumentBufferSizes, FragArgumentBufferSizes) = BuildBindingSegments(resourceLayout.SetUsages); (BindingSegments, ArgumentBufferSizes, FragArgumentBufferSizes) = BuildBindingSegments(resourceLayout.SetUsages);
}
public void CompilationResultHandler(MTLLibrary library, NSError error, int index)
{
var shader = _shaders[index];
if (_handles[index].IsAllocated)
{
_handles[index].Free();
}
if (error != IntPtr.Zero)
{
Logger.Warning?.PrintMsg(LogClass.Gpu, shader.Code);
Logger.Warning?.Print(LogClass.Gpu, $"{shader.Stage} shader linking failed: \n{StringHelper.String(error.LocalizedDescription)}");
_status = ProgramLinkStatus.Failure;
return;
}
switch (_shaders[index].Stage)
{
case ShaderStage.Compute:
ComputeFunction = library.NewFunction(StringHelper.NSString("kernelMain"));
break;
case ShaderStage.Vertex:
VertexFunction = library.NewFunction(StringHelper.NSString("vertexMain"));
break;
case ShaderStage.Fragment:
FragmentFunction = library.NewFunction(StringHelper.NSString("fragmentMain"));
break;
default:
Logger.Warning?.Print(LogClass.Gpu, $"Cannot handle stage {_shaders[index].Stage}!");
break;
}
_successCount++;
if (_successCount >= _shaders.Length && _status != ProgramLinkStatus.Failure)
{
_status = ProgramLinkStatus.Success; _status = ProgramLinkStatus.Success;
} }
}
private static ResourceBindingSegment[][] BuildClearSegments(ReadOnlyCollection<ResourceDescriptorCollection> sets) private static ResourceBindingSegment[][] BuildClearSegments(ReadOnlyCollection<ResourceDescriptorCollection> sets)
{ {
@ -218,12 +243,20 @@ namespace Ryujinx.Graphics.Metal
public ProgramLinkStatus CheckProgramLink(bool blocking) public ProgramLinkStatus CheckProgramLink(bool blocking)
{ {
if (blocking)
{
while (_status == ProgramLinkStatus.Incomplete)
{ }
return _status;
}
return _status; return _status;
} }
public byte[] GetBinary() public byte[] GetBinary()
{ {
return ""u8.ToArray(); return [];
} }
public void AddGraphicsPipeline(ref PipelineUid key, MTLRenderPipelineState pipeline) public void AddGraphicsPipeline(ref PipelineUid key, MTLRenderPipelineState pipeline)