Image shader gen support

This commit is contained in:
Isaac Marovitz 2024-07-24 12:13:40 +01:00 committed by Isaac Marovitz
parent b44167d12a
commit 4e5cf38009
6 changed files with 162 additions and 7 deletions

View file

@ -77,6 +77,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
DeclareBufferStructures(context, context.Properties.ConstantBuffers.Values, true); DeclareBufferStructures(context, context.Properties.ConstantBuffers.Values, true);
DeclareBufferStructures(context, context.Properties.StorageBuffers.Values, false); DeclareBufferStructures(context, context.Properties.StorageBuffers.Values, false);
DeclareTextures(context, context.Properties.Textures.Values); DeclareTextures(context, context.Properties.Textures.Values);
DeclareImages(context, context.Properties.Images.Values);
if ((info.HelperFunctionsMask & HelperFunctionsMask.FindLSB) != 0) if ((info.HelperFunctionsMask & HelperFunctionsMask.FindLSB) != 0)
{ {
@ -270,6 +271,31 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
context.AppendLine(); context.AppendLine();
} }
private static void DeclareImages(CodeGenContext context, IEnumerable<TextureDefinition> images)
{
context.AppendLine("struct Images");
context.EnterScope();
List<string> argBufferPointers = [];
// TODO: Avoid Linq if we can
var sortedImages = images.OrderBy(x => x.Binding).ToArray();
foreach (TextureDefinition image in sortedImages)
{
var imageTypeName = image.Type.ToMslTextureType(true);
argBufferPointers.Add($"{imageTypeName} {image.Name};");
}
foreach (var pointer in argBufferPointers)
{
context.AppendLine(pointer);
}
context.LeaveScope(";");
context.AppendLine();
}
private static void DeclareInputAttributes(CodeGenContext context, IEnumerable<IoDefinition> inputs) private static void DeclareInputAttributes(CodeGenContext context, IEnumerable<IoDefinition> inputs)
{ {
if (context.Definitions.IaIndexing) if (context.Definitions.IaIndexing)

View file

@ -21,5 +21,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
public const uint ConstantBuffersIndex = 20; public const uint ConstantBuffersIndex = 20;
public const uint StorageBuffersIndex = 21; public const uint StorageBuffersIndex = 21;
public const uint TexturesIndex = 22; public const uint TexturesIndex = 22;
public const uint ImagesIndex = 23;
} }
} }

View file

@ -133,11 +133,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
case Instruction.GroupMemoryBarrier: case Instruction.GroupMemoryBarrier:
return "|| FIND GROUP MEMORY BARRIER ||"; return "|| FIND GROUP MEMORY BARRIER ||";
case Instruction.ImageLoad: case Instruction.ImageLoad:
return "|| IMAGE LOAD ||";
case Instruction.ImageStore: case Instruction.ImageStore:
return "|| IMAGE STORE ||";
case Instruction.ImageAtomic: case Instruction.ImageAtomic:
return "|| IMAGE ATOMIC ||"; return ImageLoadOrStore(context, operation);
case Instruction.Load: case Instruction.Load:
return Load(context, operation); return Load(context, operation);
case Instruction.Lod: case Instruction.Lod:

View file

@ -3,6 +3,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.StructuredIr;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
using System; using System;
using System.Text;
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenHelper; using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenHelper;
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
@ -150,6 +151,129 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
return varName; return varName;
} }
public static string ImageLoadOrStore(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isArray = (texOp.Type & SamplerType.Array) != 0;
var texCallBuilder = new StringBuilder();
string imageName = GetImageName(context.Properties, texOp);
texCallBuilder.Append($"images.{imageName}");
texCallBuilder.Append('.');
if (texOp.Inst == Instruction.ImageAtomic)
{
texCallBuilder.Append((texOp.Flags & TextureFlags.AtomicMask) switch
{
TextureFlags.Add => "atomic_fetch_add",
TextureFlags.Minimum => "atomic_min",
TextureFlags.Maximum => "atomic_max",
TextureFlags.Increment => "atomic_fetch_add",
TextureFlags.Decrement => "atomic_fetch_sub",
TextureFlags.BitwiseAnd => "atomic_fetch_and",
TextureFlags.BitwiseOr => "atomic_fetch_or",
TextureFlags.BitwiseXor => "atomic_fetch_xor",
TextureFlags.Swap => "atomic_exchange",
TextureFlags.CAS => "atomic_compare_exchange_weak",
_ => "atomic_fetch_add",
});
}
else
{
texCallBuilder.Append(texOp.Inst == Instruction.ImageLoad ? "read" : "write");
}
int srcIndex = 0;
string Src(AggregateType type)
{
return GetSourceExpr(context, texOp.GetSource(srcIndex++), type);
}
texCallBuilder.Append('(');
var coordsBuilder = new StringBuilder();
int coordsCount = texOp.Type.GetDimensions();
if (coordsCount > 1)
{
string[] elems = new string[coordsCount];
for (int index = 0; index < coordsCount; index++)
{
elems[index] = Src(AggregateType.S32);
}
coordsBuilder.Append($"uint{coordsCount}({string.Join(", ", elems)})");
}
else
{
coordsBuilder.Append(Src(AggregateType.S32));
}
if (isArray)
{
coordsBuilder.Append(", ");
coordsBuilder.Append(Src(AggregateType.S32));
}
if (texOp.Inst == Instruction.ImageStore)
{
AggregateType type = texOp.Format.GetComponentType();
string[] cElems = new string[4];
for (int index = 0; index < 4; index++)
{
if (srcIndex < texOp.SourcesCount)
{
cElems[index] = Src(type);
}
else
{
cElems[index] = type switch
{
AggregateType.S32 => NumberFormatter.FormatInt(0),
AggregateType.U32 => NumberFormatter.FormatUint(0),
_ => NumberFormatter.FormatFloat(0),
};
}
}
string prefix = type switch
{
AggregateType.S32 => "int",
AggregateType.U32 => "uint",
AggregateType.FP32 => "float",
_ => string.Empty,
};
texCallBuilder.Append($"{prefix}4({string.Join(", ", cElems)})");
}
texCallBuilder.Append(", ");
texCallBuilder.Append(coordsBuilder);
if (texOp.Inst == Instruction.ImageAtomic)
{
// TODO: Finish atomic stuff
}
else
{
texCallBuilder.Append(')');
if (texOp.Inst == Instruction.ImageLoad)
{
texCallBuilder.Append(GetMaskMultiDest(texOp.Index));
}
}
return texCallBuilder.ToString();
}
public static string Load(CodeGenContext context, AstOperation operation) public static string Load(CodeGenContext context, AstOperation operation)
{ {
return GenerateLoadOrStore(context, operation, isStore: false); return GenerateLoadOrStore(context, operation, isStore: false);
@ -359,9 +483,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
return texCall; return texCall;
} }
private static string GetSamplerName(ShaderProperties resourceDefinitions, AstTextureOperation textOp) private static string GetSamplerName(ShaderProperties resourceDefinitions, AstTextureOperation texOp)
{ {
return resourceDefinitions.Textures[textOp.GetTextureSetAndBinding()].Name; return resourceDefinitions.Textures[texOp.GetTextureSetAndBinding()].Name;
}
private static string GetImageName(ShaderProperties resourceDefinitions, AstTextureOperation texOp)
{
return resourceDefinitions.Images[texOp.GetTextureSetAndBinding()].Name;
} }
private static string GetMaskMultiDest(int mask) private static string GetMaskMultiDest(int mask)

View file

@ -150,6 +150,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
args = args.Append($"constant ConstantBuffers &constant_buffers [[buffer({Defaults.ConstantBuffersIndex})]]").ToArray(); args = args.Append($"constant ConstantBuffers &constant_buffers [[buffer({Defaults.ConstantBuffersIndex})]]").ToArray();
args = args.Append($"device StorageBuffers &storage_buffers [[buffer({Defaults.StorageBuffersIndex})]]").ToArray(); args = args.Append($"device StorageBuffers &storage_buffers [[buffer({Defaults.StorageBuffersIndex})]]").ToArray();
args = args.Append($"constant Textures &textures [[buffer({Defaults.TexturesIndex})]]").ToArray(); args = args.Append($"constant Textures &textures [[buffer({Defaults.TexturesIndex})]]").ToArray();
args = args.Append($"constant Images &images [[buffer({Defaults.ImagesIndex})]]").ToArray();
} }
var funcPrefix = $"{funcKeyword} {returnType} {funcName ?? function.Name}("; var funcPrefix = $"{funcKeyword} {returnType} {funcName ?? function.Name}(";

View file

@ -156,7 +156,7 @@ namespace Ryujinx.Graphics.Shader
return typeName; return typeName;
} }
public static string ToMslTextureType(this SamplerType type) public static string ToMslTextureType(this SamplerType type, bool image = false)
{ {
string typeName; string typeName;
@ -192,7 +192,7 @@ namespace Ryujinx.Graphics.Shader
typeName += "_array"; typeName += "_array";
} }
return typeName + "<float>"; return $"{typeName} <float{(image ? ", access::read_write" : "")}>";
} }
} }
} }