EXPERIMENTAL: Metal backend (#441)

This is not a continuation of the Metal backend; this is simply bringing
the branch up to date and merging it as-is behind an experiment.

---------

Co-authored-by: Isaac Marovitz <isaacryu@icloud.com>
Co-authored-by: Samuliak <samuliak77@gmail.com>
Co-authored-by: SamoZ256 <96914946+SamoZ256@users.noreply.github.com>
Co-authored-by: Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com>
Co-authored-by: riperiperi <rhy3756547@hotmail.com>
Co-authored-by: Gabriel A <gab.dark.100@gmail.com>
This commit is contained in:
Evan Husted 2024-12-24 00:55:16 -06:00 committed by GitHub
parent 3094df54dd
commit 852823104f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
131 changed files with 14992 additions and 140 deletions

View file

@ -26,5 +26,6 @@ namespace Ryujinx.Graphics.Shader.Translation
SharedMemory = 1 << 11,
Store = 1 << 12,
VtgAsCompute = 1 << 13,
Precise = 1 << 14,
}
}

View file

@ -43,6 +43,11 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly Dictionary<TextureInfo, TextureMeta> _usedTextures;
private readonly Dictionary<TextureInfo, TextureMeta> _usedImages;
private readonly List<BufferDefinition> _vacConstantBuffers;
private readonly List<BufferDefinition> _vacStorageBuffers;
private readonly List<TextureDefinition> _vacTextures;
private readonly List<TextureDefinition> _vacImages;
public int LocalMemoryId { get; private set; }
public int SharedMemoryId { get; private set; }
@ -78,6 +83,11 @@ namespace Ryujinx.Graphics.Shader.Translation
_usedTextures = new();
_usedImages = new();
_vacConstantBuffers = new();
_vacStorageBuffers = new();
_vacTextures = new();
_vacImages = new();
Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, 0, SupportBuffer.Binding, "support_buffer", SupportBuffer.GetStructureType()));
LocalMemoryId = -1;
@ -563,6 +573,75 @@ namespace Ryujinx.Graphics.Shader.Translation
return descriptors.ToArray();
}
public ShaderProgramInfo GetVertexAsComputeInfo(bool isVertex = false)
{
var cbDescriptors = new BufferDescriptor[_vacConstantBuffers.Count];
int cbDescriptorIndex = 0;
foreach (BufferDefinition definition in _vacConstantBuffers)
{
cbDescriptors[cbDescriptorIndex++] = new BufferDescriptor(definition.Set, definition.Binding, 0, 0, 0, BufferUsageFlags.None);
}
var sbDescriptors = new BufferDescriptor[_vacStorageBuffers.Count];
int sbDescriptorIndex = 0;
foreach (BufferDefinition definition in _vacStorageBuffers)
{
sbDescriptors[sbDescriptorIndex++] = new BufferDescriptor(definition.Set, definition.Binding, 0, 0, 0, BufferUsageFlags.Write);
}
var tDescriptors = new TextureDescriptor[_vacTextures.Count];
int tDescriptorIndex = 0;
foreach (TextureDefinition definition in _vacTextures)
{
tDescriptors[tDescriptorIndex++] = new TextureDescriptor(
definition.Set,
definition.Binding,
definition.Type,
definition.Format,
0,
0,
definition.ArrayLength,
definition.Separate,
definition.Flags);
}
var iDescriptors = new TextureDescriptor[_vacImages.Count];
int iDescriptorIndex = 0;
foreach (TextureDefinition definition in _vacImages)
{
iDescriptors[iDescriptorIndex++] = new TextureDescriptor(
definition.Set,
definition.Binding,
definition.Type,
definition.Format,
0,
0,
definition.ArrayLength,
definition.Separate,
definition.Flags);
}
return new ShaderProgramInfo(
cbDescriptors,
sbDescriptors,
tDescriptors,
iDescriptors,
isVertex ? ShaderStage.Vertex : ShaderStage.Compute,
0,
0,
0,
false,
false,
false,
false,
0,
0);
}
public bool TryGetCbufSlotAndHandleForTexture(int binding, out int cbufSlot, out int handle)
{
foreach ((TextureInfo info, TextureMeta meta) in _usedTextures)
@ -629,6 +708,30 @@ namespace Ryujinx.Graphics.Shader.Translation
Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, setIndex, binding, name, type));
}
public void AddVertexAsComputeConstantBuffer(BufferDefinition definition)
{
_vacConstantBuffers.Add(definition);
Properties.AddOrUpdateConstantBuffer(definition);
}
public void AddVertexAsComputeStorageBuffer(BufferDefinition definition)
{
_vacStorageBuffers.Add(definition);
Properties.AddOrUpdateStorageBuffer(definition);
}
public void AddVertexAsComputeTexture(TextureDefinition definition)
{
_vacTextures.Add(definition);
Properties.AddOrUpdateTexture(definition);
}
public void AddVertexAsComputeImage(TextureDefinition definition)
{
_vacImages.Add(definition);
Properties.AddOrUpdateImage(definition);
}
public static string GetShaderStagePrefix(ShaderStage stage)
{
uint index = (uint)stage;

View file

@ -4,5 +4,6 @@ namespace Ryujinx.Graphics.Shader.Translation
{
OpenGL,
Vulkan,
Metal
}
}

View file

@ -4,6 +4,6 @@ namespace Ryujinx.Graphics.Shader.Translation
{
Glsl,
Spirv,
Arb,
Msl
}
}

View file

@ -27,6 +27,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
addOp.Inst == (Instruction.FP32 | Instruction.Add) &&
addOp.GetSource(1).Type == OperandType.Constant)
{
context.UsedFeatures |= FeatureFlags.Precise;
addOp.ForcePrecise = true;
}

View file

@ -1,5 +1,6 @@
using Ryujinx.Graphics.Shader.CodeGen;
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
using Ryujinx.Graphics.Shader.CodeGen.Msl;
using Ryujinx.Graphics.Shader.CodeGen.Spirv;
using Ryujinx.Graphics.Shader.Decoders;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
@ -331,6 +332,7 @@ namespace Ryujinx.Graphics.Shader.Translation
definitions,
resourceManager,
Options.TargetLanguage,
usedFeatures.HasFlag(FeatureFlags.Precise),
Options.Flags.HasFlag(TranslationFlags.DebugMode));
int geometryVerticesPerPrimitive = Definitions.OutputTopology switch
@ -373,6 +375,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
TargetLanguage.Glsl => new ShaderProgram(info, TargetLanguage.Glsl, GlslGenerator.Generate(sInfo, parameters)),
TargetLanguage.Spirv => new ShaderProgram(info, TargetLanguage.Spirv, SpirvGenerator.Generate(sInfo, parameters)),
TargetLanguage.Msl => new ShaderProgram(info, TargetLanguage.Msl, MslGenerator.Generate(sInfo, parameters)),
_ => throw new NotImplementedException(Options.TargetLanguage.ToString()),
};
}
@ -392,7 +395,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
int binding = resourceManager.Reservations.GetTfeBufferStorageBufferBinding(i);
BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
resourceManager.Properties.AddOrUpdateStorageBuffer(tfeDataBuffer);
resourceManager.AddVertexAsComputeStorageBuffer(tfeDataBuffer);
}
}
@ -400,7 +403,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
BufferDefinition vertexInfoBuffer = new(BufferLayout.Std140, 0, vertexInfoCbBinding, "vb_info", VertexInfoBuffer.GetStructureType());
resourceManager.Properties.AddOrUpdateConstantBuffer(vertexInfoBuffer);
resourceManager.AddVertexAsComputeConstantBuffer(vertexInfoBuffer);
StructureType vertexOutputStruct = new(new StructureField[]
{
@ -409,13 +412,13 @@ namespace Ryujinx.Graphics.Shader.Translation
int vertexOutputSbBinding = resourceManager.Reservations.VertexOutputStorageBufferBinding;
BufferDefinition vertexOutputBuffer = new(BufferLayout.Std430, 1, vertexOutputSbBinding, "vertex_output", vertexOutputStruct);
resourceManager.Properties.AddOrUpdateStorageBuffer(vertexOutputBuffer);
resourceManager.AddVertexAsComputeStorageBuffer(vertexOutputBuffer);
if (Stage == ShaderStage.Vertex)
{
SetBindingPair ibSetAndBinding = resourceManager.Reservations.GetIndexBufferTextureSetAndBinding();
TextureDefinition indexBuffer = new(ibSetAndBinding.SetIndex, ibSetAndBinding.Binding, "ib_data", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(indexBuffer);
resourceManager.AddVertexAsComputeTexture(indexBuffer);
int inputMap = _program.AttributeUsage.UsedInputAttributes;
@ -424,7 +427,7 @@ namespace Ryujinx.Graphics.Shader.Translation
int location = BitOperations.TrailingZeroCount(inputMap);
SetBindingPair setAndBinding = resourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
TextureDefinition vaBuffer = new(setAndBinding.SetIndex, setAndBinding.Binding, $"vb_data{location}", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(vaBuffer);
resourceManager.AddVertexAsComputeTexture(vaBuffer);
inputMap &= ~(1 << location);
}
@ -433,11 +436,11 @@ namespace Ryujinx.Graphics.Shader.Translation
{
SetBindingPair trbSetAndBinding = resourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding();
TextureDefinition remapBuffer = new(trbSetAndBinding.SetIndex, trbSetAndBinding.Binding, "trb_data", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(remapBuffer);
resourceManager.AddVertexAsComputeTexture(remapBuffer);
int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;
BufferDefinition geometryVbOutputBuffer = new(BufferLayout.Std430, 1, geometryVbOutputSbBinding, "geometry_vb_output", vertexOutputStruct);
resourceManager.Properties.AddOrUpdateStorageBuffer(geometryVbOutputBuffer);
resourceManager.AddVertexAsComputeStorageBuffer(geometryVbOutputBuffer);
StructureType geometryIbOutputStruct = new(new StructureField[]
{
@ -446,7 +449,7 @@ namespace Ryujinx.Graphics.Shader.Translation
int geometryIbOutputSbBinding = resourceManager.Reservations.GeometryIndexOutputStorageBufferBinding;
BufferDefinition geometryIbOutputBuffer = new(BufferLayout.Std430, 1, geometryIbOutputSbBinding, "geometry_ib_output", geometryIbOutputStruct);
resourceManager.Properties.AddOrUpdateStorageBuffer(geometryIbOutputBuffer);
resourceManager.AddVertexAsComputeStorageBuffer(geometryIbOutputBuffer);
}
resourceManager.SetVertexAsComputeLocalMemories(Definitions.Stage, Definitions.InputTopology);
@ -479,12 +482,17 @@ namespace Ryujinx.Graphics.Shader.Translation
return new ResourceReservations(GpuAccessor, IsTransformFeedbackEmulated, vertexAsCompute: true, _vertexOutput, ioUsage);
}
public ShaderProgramInfo GetVertexAsComputeInfo()
{
return CreateResourceManager(true).GetVertexAsComputeInfo();
}
public void SetVertexOutputMapForGeometryAsCompute(TranslatorContext vertexContext)
{
_vertexOutput = vertexContext._program.GetIoUsage();
}
public ShaderProgram GenerateVertexPassthroughForCompute()
public (ShaderProgram, ShaderProgramInfo) GenerateVertexPassthroughForCompute()
{
var attributeUsage = new AttributeUsage(GpuAccessor);
var resourceManager = new ResourceManager(ShaderStage.Vertex, GpuAccessor);
@ -496,7 +504,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (Stage == ShaderStage.Vertex)
{
BufferDefinition vertexInfoBuffer = new(BufferLayout.Std140, 0, vertexInfoCbBinding, "vb_info", VertexInfoBuffer.GetStructureType());
resourceManager.Properties.AddOrUpdateConstantBuffer(vertexInfoBuffer);
resourceManager.AddVertexAsComputeConstantBuffer(vertexInfoBuffer);
}
StructureType vertexInputStruct = new(new StructureField[]
@ -506,7 +514,7 @@ namespace Ryujinx.Graphics.Shader.Translation
int vertexDataSbBinding = reservations.VertexOutputStorageBufferBinding;
BufferDefinition vertexOutputBuffer = new(BufferLayout.Std430, 1, vertexDataSbBinding, "vb_input", vertexInputStruct);
resourceManager.Properties.AddOrUpdateStorageBuffer(vertexOutputBuffer);
resourceManager.AddVertexAsComputeStorageBuffer(vertexOutputBuffer);
var context = new EmitterContext();
@ -564,14 +572,14 @@ namespace Ryujinx.Graphics.Shader.Translation
LastInVertexPipeline = true
};
return Generate(
return (Generate(
new[] { function },
attributeUsage,
definitions,
definitions,
resourceManager,
FeatureFlags.None,
0);
0), resourceManager.GetVertexAsComputeInfo(isVertex: true));
}
public ShaderProgram GenerateGeometryPassthrough()