Back to where we were
First special instruction Start Load/Store implementation Start TextureSample Sample progress I/O Load/Store Progress Rest of load/store TODO: Currently, the generator still assumes the GLSL style of I/O attributres. On MSL, the vertex function should output a struct which contains a float4 with the required position attribute. TextureSize and VectorExtract Fix UserDefined IO Vars Fix stage input struct names
This commit is contained in:
parent
5198fcb881
commit
a1b314acd2
10 changed files with 507 additions and 43 deletions
|
@ -3,6 +3,7 @@ using Ryujinx.Graphics.Shader.StructuredIr;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeclareInputAttributes(context, info.IoDefinitions.Where(x => IsUserDefined(x, StorageKind.Input)));
|
DeclareInputAttributes(context, info.IoDefinitions.Where(x => IsUserDefined(x, StorageKind.Input)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsUserDefined(IoDefinition ioDefinition, StorageKind storageKind)
|
static bool IsUserDefined(IoDefinition ioDefinition, StorageKind storageKind)
|
||||||
|
@ -66,28 +67,45 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Redo for new Shader IR rep
|
private static void DeclareInputAttributes(CodeGenContext context, IEnumerable<IoDefinition> inputs)
|
||||||
// private static void DeclareInputAttributes(CodeGenContext context, IEnumerable<IoDefinition> inputs)
|
{
|
||||||
// {
|
if (context.Definitions.IaIndexing)
|
||||||
// if (context.AttributeUsage.UsedInputAttributes != 0)
|
{
|
||||||
// {
|
// Not handled
|
||||||
// context.AppendLine("struct VertexIn");
|
}
|
||||||
// context.EnterScope();
|
else
|
||||||
//
|
{
|
||||||
// int usedAttributes = context.AttributeUsage.UsedInputAttributes | context.AttributeUsage.PassthroughAttributes;
|
if (inputs.Any())
|
||||||
// while (usedAttributes != 0)
|
{
|
||||||
// {
|
string prefix = "";
|
||||||
// int index = BitOperations.TrailingZeroCount(usedAttributes);
|
|
||||||
//
|
switch (context.Definitions.Stage)
|
||||||
// string name = $"{DefaultNames.IAttributePrefix}{index}";
|
{
|
||||||
// var type = context.AttributeUsage.get .QueryAttributeType(index).ToVec4Type(TargetLanguage.Msl);
|
case ShaderStage.Vertex:
|
||||||
// context.AppendLine($"{type} {name} [[attribute({index})]];");
|
prefix = "Vertex";
|
||||||
//
|
break;
|
||||||
// usedAttributes &= ~(1 << index);
|
case ShaderStage.Fragment:
|
||||||
// }
|
prefix = "Fragment";
|
||||||
//
|
break;
|
||||||
// context.LeaveScope(";");
|
case ShaderStage.Compute:
|
||||||
// }
|
prefix = "Compute";
|
||||||
// }
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.AppendLine($"struct {prefix}In");
|
||||||
|
context.EnterScope();
|
||||||
|
|
||||||
|
foreach (var ioDefinition in inputs.OrderBy(x => x.Location))
|
||||||
|
{
|
||||||
|
string type = GetVarTypeName(context, context.Definitions.GetUserDefinedType(ioDefinition.Location, isOutput: false));
|
||||||
|
string name = $"{DefaultNames.IAttributePrefix}{ioDefinition.Location}";
|
||||||
|
|
||||||
|
context.AppendLine($"{type} {name} [[attribute({ioDefinition.Location})]];");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.LeaveScope(";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,7 +3,10 @@ using Ryujinx.Graphics.Shader.StructuredIr;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenCall;
|
||||||
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenHelper;
|
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenHelper;
|
||||||
|
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenMemory;
|
||||||
|
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenVector;
|
||||||
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
|
@ -105,7 +108,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
case Instruction.Barrier:
|
case Instruction.Barrier:
|
||||||
return "|| BARRIER ||";
|
return "|| BARRIER ||";
|
||||||
case Instruction.Call:
|
case Instruction.Call:
|
||||||
return "|| CALL ||";
|
return Call(context, operation);
|
||||||
case Instruction.FSIBegin:
|
case Instruction.FSIBegin:
|
||||||
return "|| FSI BEGIN ||";
|
return "|| FSI BEGIN ||";
|
||||||
case Instruction.FSIEnd:
|
case Instruction.FSIEnd:
|
||||||
|
@ -125,25 +128,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
case Instruction.ImageAtomic:
|
case Instruction.ImageAtomic:
|
||||||
return "|| IMAGE ATOMIC ||";
|
return "|| IMAGE ATOMIC ||";
|
||||||
case Instruction.Load:
|
case Instruction.Load:
|
||||||
return "|| LOAD ||";
|
return Load(context, operation);
|
||||||
case Instruction.Lod:
|
case Instruction.Lod:
|
||||||
return "|| LOD ||";
|
return "|| LOD ||";
|
||||||
case Instruction.MemoryBarrier:
|
case Instruction.MemoryBarrier:
|
||||||
return "|| MEMORY BARRIER ||";
|
return "|| MEMORY BARRIER ||";
|
||||||
case Instruction.Store:
|
case Instruction.Store:
|
||||||
return "|| STORE ||";
|
return Store(context, operation);
|
||||||
case Instruction.TextureSample:
|
case Instruction.TextureSample:
|
||||||
return "|| TEXTURE SAMPLE ||";
|
return TextureSample(context, operation);
|
||||||
case Instruction.TextureSize:
|
case Instruction.TextureSize:
|
||||||
return "|| TEXTURE SIZE ||";
|
return TextureSize(context, operation);
|
||||||
case Instruction.VectorExtract:
|
case Instruction.VectorExtract:
|
||||||
return "|| VECTOR EXTRACT ||";
|
return VectorExtract(context, operation);
|
||||||
case Instruction.VoteAllEqual:
|
case Instruction.VoteAllEqual:
|
||||||
return "|| VOTE ALL EQUAL ||";
|
return "|| VOTE ALL EQUAL ||";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidOperationException($"Unexpected instruction type \"{info.Type}\".");
|
// TODO: Return this to being an error
|
||||||
|
return $"Unexpected instruction type \"{info.Type}\".";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||||
|
|
||||||
|
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenHelper;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
|
{
|
||||||
|
static class InstGenCall
|
||||||
|
{
|
||||||
|
public static string Call(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
AstOperand funcId = (AstOperand)operation.GetSource(0);
|
||||||
|
|
||||||
|
var functon = context.GetFunction(funcId.Value);
|
||||||
|
|
||||||
|
string[] args = new string[operation.SourcesCount - 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
args[i] = GetSourceExpr(context, operation.GetSource(i + 1), functon.GetArgumentType(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{functon.Name}({string.Join(", ", args)})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ 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 static Ryujinx.Graphics.Shader.CodeGen.Msl.TypeConversion;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
{
|
{
|
||||||
static class InstGenHelper
|
static class InstGenHelper
|
||||||
|
@ -140,9 +142,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
|
|
||||||
public static string GetSourceExpr(CodeGenContext context, IAstNode node, AggregateType dstType)
|
public static string GetSourceExpr(CodeGenContext context, IAstNode node, AggregateType dstType)
|
||||||
{
|
{
|
||||||
// TODO: Implement this
|
return ReinterpretCast(context, node, OperandManager.GetNodeDestType(context, node), dstType);
|
||||||
// return ReinterpretCast(context, node, OperandManager.GetNodeDestType(context, node), dstType);
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Enclose(string expr, IAstNode node, Instruction pInst, bool isLhs)
|
public static string Enclose(string expr, IAstNode node, Instruction pInst, bool isLhs)
|
||||||
|
|
|
@ -0,0 +1,318 @@
|
||||||
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
|
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||||
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
|
using System;
|
||||||
|
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenHelper;
|
||||||
|
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
|
{
|
||||||
|
static class InstGenMemory
|
||||||
|
{
|
||||||
|
public static string GenerateLoadOrStore(CodeGenContext context, AstOperation operation, bool isStore)
|
||||||
|
{
|
||||||
|
StorageKind storageKind = operation.StorageKind;
|
||||||
|
|
||||||
|
string varName;
|
||||||
|
AggregateType varType;
|
||||||
|
int srcIndex = 0;
|
||||||
|
bool isStoreOrAtomic = operation.Inst == Instruction.Store || operation.Inst.IsAtomic();
|
||||||
|
int inputsCount = isStoreOrAtomic ? operation.SourcesCount - 1 : operation.SourcesCount;
|
||||||
|
|
||||||
|
if (operation.Inst == Instruction.AtomicCompareAndSwap)
|
||||||
|
{
|
||||||
|
inputsCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (storageKind)
|
||||||
|
{
|
||||||
|
case StorageKind.ConstantBuffer:
|
||||||
|
case StorageKind.StorageBuffer:
|
||||||
|
if (operation.GetSource(srcIndex++) is not AstOperand bindingIndex || bindingIndex.Type != OperandType.Constant)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int binding = bindingIndex.Value;
|
||||||
|
BufferDefinition buffer = storageKind == StorageKind.ConstantBuffer
|
||||||
|
? context.Properties.ConstantBuffers[binding]
|
||||||
|
: context.Properties.StorageBuffers[binding];
|
||||||
|
|
||||||
|
if (operation.GetSource(srcIndex++) is not AstOperand fieldIndex || fieldIndex.Type != OperandType.Constant)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Second input of {operation.Inst} with {storageKind} storage must be a constant operand.");
|
||||||
|
}
|
||||||
|
|
||||||
|
StructureField field = buffer.Type.Fields[fieldIndex.Value];
|
||||||
|
varName = $"{buffer.Name}.{field.Name}";
|
||||||
|
varType = field.Type;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StorageKind.LocalMemory:
|
||||||
|
case StorageKind.SharedMemory:
|
||||||
|
if (operation.GetSource(srcIndex++) is not AstOperand { Type: OperandType.Constant } bindingId)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand.");
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryDefinition memory = storageKind == StorageKind.LocalMemory
|
||||||
|
? context.Properties.LocalMemories[bindingId.Value]
|
||||||
|
: context.Properties.SharedMemories[bindingId.Value];
|
||||||
|
|
||||||
|
varName = memory.Name;
|
||||||
|
varType = memory.Type;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StorageKind.Input:
|
||||||
|
case StorageKind.InputPerPatch:
|
||||||
|
case StorageKind.Output:
|
||||||
|
case StorageKind.OutputPerPatch:
|
||||||
|
if (operation.GetSource(srcIndex++) is not AstOperand varId || varId.Type != OperandType.Constant)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand.");
|
||||||
|
}
|
||||||
|
|
||||||
|
IoVariable ioVariable = (IoVariable)varId.Value;
|
||||||
|
bool isOutput = storageKind.IsOutput();
|
||||||
|
bool isPerPatch = storageKind.IsPerPatch();
|
||||||
|
int location = -1;
|
||||||
|
int component = 0;
|
||||||
|
|
||||||
|
if (context.Definitions.HasPerLocationInputOrOutput(ioVariable, isOutput))
|
||||||
|
{
|
||||||
|
if (operation.GetSource(srcIndex++) is not AstOperand vecIndex || vecIndex.Type != OperandType.Constant)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Second input of {operation.Inst} with {storageKind} storage must be a constant operand.");
|
||||||
|
}
|
||||||
|
|
||||||
|
location = vecIndex.Value;
|
||||||
|
|
||||||
|
if (operation.SourcesCount > srcIndex &&
|
||||||
|
operation.GetSource(srcIndex) is AstOperand elemIndex &&
|
||||||
|
elemIndex.Type == OperandType.Constant &&
|
||||||
|
context.Definitions.HasPerLocationInputOrOutputComponent(ioVariable, vecIndex.Value, elemIndex.Value, isOutput))
|
||||||
|
{
|
||||||
|
component = elemIndex.Value;
|
||||||
|
srcIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(varName, varType) = IoMap.GetMslBuiltIn(
|
||||||
|
context.Definitions,
|
||||||
|
ioVariable,
|
||||||
|
location,
|
||||||
|
component,
|
||||||
|
isOutput,
|
||||||
|
isPerPatch);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException($"Invalid storage kind {storageKind}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; srcIndex < inputsCount; srcIndex++)
|
||||||
|
{
|
||||||
|
IAstNode src = operation.GetSource(srcIndex);
|
||||||
|
|
||||||
|
if ((varType & AggregateType.ElementCountMask) != 0 &&
|
||||||
|
srcIndex == inputsCount - 1 &&
|
||||||
|
src is AstOperand elementIndex &&
|
||||||
|
elementIndex.Type == OperandType.Constant)
|
||||||
|
{
|
||||||
|
varName += "." + "xyzw"[elementIndex.Value & 3];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
varName += $"[{GetSourceExpr(context, src, AggregateType.S32)}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStore)
|
||||||
|
{
|
||||||
|
varType &= AggregateType.ElementTypeMask;
|
||||||
|
varName = $"{varName} = {GetSourceExpr(context, operation.GetSource(srcIndex), varType)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return varName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Load(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
return GenerateLoadOrStore(context, operation, isStore: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Store(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
return GenerateLoadOrStore(context, operation, isStore: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string TextureSample(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||||
|
|
||||||
|
bool isGather = (texOp.Flags & TextureFlags.Gather) != 0;
|
||||||
|
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
|
||||||
|
bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0;
|
||||||
|
|
||||||
|
bool isArray = (texOp.Type & SamplerType.Array) != 0;
|
||||||
|
|
||||||
|
bool colorIsVector = isGather || !isShadow;
|
||||||
|
|
||||||
|
string texCall = "texture.";
|
||||||
|
|
||||||
|
int srcIndex = 0;
|
||||||
|
|
||||||
|
string Src(AggregateType type)
|
||||||
|
{
|
||||||
|
return GetSourceExpr(context, texOp.GetSource(srcIndex++), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intCoords)
|
||||||
|
{
|
||||||
|
texCall += "read(";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texCall += "sample(";
|
||||||
|
|
||||||
|
string samplerName = GetSamplerName(context.Properties, texOp);
|
||||||
|
|
||||||
|
texCall += samplerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
int coordsCount = texOp.Type.GetDimensions();
|
||||||
|
|
||||||
|
int pCount = coordsCount;
|
||||||
|
|
||||||
|
int arrayIndexElem = -1;
|
||||||
|
|
||||||
|
if (isArray)
|
||||||
|
{
|
||||||
|
arrayIndexElem = pCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isShadow && !isGather)
|
||||||
|
{
|
||||||
|
pCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Append(string str)
|
||||||
|
{
|
||||||
|
texCall += ", " + str;
|
||||||
|
}
|
||||||
|
|
||||||
|
AggregateType coordType = intCoords ? AggregateType.S32 : AggregateType.FP32;
|
||||||
|
|
||||||
|
string AssemblePVector(int count)
|
||||||
|
{
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
string[] elems = new string[count];
|
||||||
|
|
||||||
|
for (int index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
if (arrayIndexElem == index)
|
||||||
|
{
|
||||||
|
elems[index] = Src(AggregateType.S32);
|
||||||
|
|
||||||
|
if (!intCoords)
|
||||||
|
{
|
||||||
|
elems[index] = "float(" + elems[index] + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
elems[index] = Src(coordType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string prefix = intCoords ? "int" : "float";
|
||||||
|
|
||||||
|
return prefix + count + "(" + string.Join(", ", elems) + ")";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Src(coordType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Append(AssemblePVector(pCount));
|
||||||
|
|
||||||
|
texCall += ")" + (colorIsVector ? GetMaskMultiDest(texOp.Index) : "");
|
||||||
|
|
||||||
|
return texCall;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetSamplerName(ShaderProperties resourceDefinitions, AstTextureOperation textOp)
|
||||||
|
{
|
||||||
|
return resourceDefinitions.Textures[textOp.Binding].Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Verify that this is valid in MSL
|
||||||
|
private static string GetMask(int index)
|
||||||
|
{
|
||||||
|
return $".{"rgba".AsSpan(index, 1)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetMaskMultiDest(int mask)
|
||||||
|
{
|
||||||
|
string swizzle = ".";
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if ((mask & (1 << i)) != 0)
|
||||||
|
{
|
||||||
|
swizzle += "xyzw"[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return swizzle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string TextureSize(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||||
|
|
||||||
|
string textureName = "texture";
|
||||||
|
string texCall = textureName + ".";
|
||||||
|
|
||||||
|
if (texOp.Index == 3)
|
||||||
|
{
|
||||||
|
texCall += $"get_num_mip_levels()";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Properties.Textures.TryGetValue(texOp.Binding, out TextureDefinition definition);
|
||||||
|
bool hasLod = !definition.Type.HasFlag(SamplerType.Multisample) && (definition.Type & SamplerType.Mask) != SamplerType.TextureBuffer;
|
||||||
|
texCall += "get_";
|
||||||
|
|
||||||
|
if (texOp.Index == 0)
|
||||||
|
{
|
||||||
|
texCall += "width";
|
||||||
|
}
|
||||||
|
else if (texOp.Index == 1)
|
||||||
|
{
|
||||||
|
texCall += "height";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texCall += "depth";
|
||||||
|
}
|
||||||
|
|
||||||
|
texCall += "(";
|
||||||
|
|
||||||
|
if (hasLod)
|
||||||
|
{
|
||||||
|
IAstNode lod = operation.GetSource(0);
|
||||||
|
string lodExpr = GetSourceExpr(context, lod, GetSrcVarType(operation.Inst, 0));
|
||||||
|
|
||||||
|
texCall += $"{lodExpr}";
|
||||||
|
}
|
||||||
|
|
||||||
|
texCall += $"){GetMask(texOp.Index)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return texCall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
|
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||||
|
|
||||||
|
using static Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions.InstGenHelper;
|
||||||
|
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
|
{
|
||||||
|
static class InstGenVector
|
||||||
|
{
|
||||||
|
public static string VectorExtract(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
IAstNode vector = operation.GetSource(0);
|
||||||
|
IAstNode index = operation.GetSource(1);
|
||||||
|
|
||||||
|
string vectorExpr = GetSourceExpr(context, vector, OperandManager.GetNodeDestType(context, vector));
|
||||||
|
|
||||||
|
if (index is AstOperand indexOperand && indexOperand.Type == OperandType.Constant)
|
||||||
|
{
|
||||||
|
char elem = "xyzw"[indexOperand.Value];
|
||||||
|
|
||||||
|
return $"{vectorExpr}.{elem}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string indexExpr = GetSourceExpr(context, index, GetSrcVarType(operation.Inst, 1));
|
||||||
|
|
||||||
|
return $"{vectorExpr}[{indexExpr}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,18 @@
|
||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
{
|
{
|
||||||
static class IoMap
|
static class IoMap
|
||||||
{
|
{
|
||||||
public static (string, AggregateType) GetMSLBuiltIn(IoVariable ioVariable)
|
public static (string, AggregateType) GetMslBuiltIn(
|
||||||
|
ShaderDefinitions definitions,
|
||||||
|
IoVariable ioVariable,
|
||||||
|
int location,
|
||||||
|
int component,
|
||||||
|
bool isOutput,
|
||||||
|
bool isPerPatch)
|
||||||
{
|
{
|
||||||
return ioVariable switch
|
return ioVariable switch
|
||||||
{
|
{
|
||||||
|
@ -18,12 +25,50 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
IoVariable.InstanceId => ("instance_id", AggregateType.S32),
|
IoVariable.InstanceId => ("instance_id", AggregateType.S32),
|
||||||
IoVariable.PointCoord => ("point_coord", AggregateType.Vector2),
|
IoVariable.PointCoord => ("point_coord", AggregateType.Vector2),
|
||||||
IoVariable.PointSize => ("point_size", AggregateType.FP32),
|
IoVariable.PointSize => ("point_size", AggregateType.FP32),
|
||||||
IoVariable.Position => ("position", AggregateType.Vector4),
|
IoVariable.Position => ("position", AggregateType.Vector4 | AggregateType.FP32),
|
||||||
IoVariable.PrimitiveId => ("primitive_id", AggregateType.S32),
|
IoVariable.PrimitiveId => ("primitive_id", AggregateType.S32),
|
||||||
|
IoVariable.UserDefined => GetUserDefinedVariableName(definitions, location, component, isOutput, isPerPatch),
|
||||||
IoVariable.VertexId => ("vertex_id", AggregateType.S32),
|
IoVariable.VertexId => ("vertex_id", AggregateType.S32),
|
||||||
IoVariable.ViewportIndex => ("viewport_array_index", AggregateType.S32),
|
IoVariable.ViewportIndex => ("viewport_array_index", AggregateType.S32),
|
||||||
_ => (null, AggregateType.Invalid),
|
_ => (null, AggregateType.Invalid),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static (string, AggregateType) GetUserDefinedVariableName(ShaderDefinitions definitions, int location, int component, bool isOutput, bool isPerPatch)
|
||||||
|
{
|
||||||
|
string name = isPerPatch
|
||||||
|
? DefaultNames.PerPatchAttributePrefix
|
||||||
|
: (isOutput ? DefaultNames.OAttributePrefix : DefaultNames.IAttributePrefix);
|
||||||
|
|
||||||
|
if (location < 0)
|
||||||
|
{
|
||||||
|
return (name, definitions.GetUserDefinedType(0, isOutput));
|
||||||
|
}
|
||||||
|
|
||||||
|
name += location.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
if (definitions.HasPerLocationInputOrOutputComponent(IoVariable.UserDefined, location, component, isOutput))
|
||||||
|
{
|
||||||
|
name += "_" + "xyzw"[component & 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
string prefix = "";
|
||||||
|
switch (definitions.Stage)
|
||||||
|
{
|
||||||
|
case ShaderStage.Vertex:
|
||||||
|
prefix = "Vertex";
|
||||||
|
break;
|
||||||
|
case ShaderStage.Fragment:
|
||||||
|
prefix = "Fragment";
|
||||||
|
break;
|
||||||
|
case ShaderStage.Compute:
|
||||||
|
prefix = "Compute";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix += isOutput ? "Out" : "In";
|
||||||
|
|
||||||
|
return (prefix + "." + name, definitions.GetUserDefinedType(location, isOutput));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,10 +90,25 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
funcKeyword = "fragment";
|
funcKeyword = "fragment";
|
||||||
funcName = "fragmentMain";
|
funcName = "fragmentMain";
|
||||||
}
|
}
|
||||||
|
else if (stage == ShaderStage.Compute)
|
||||||
|
{
|
||||||
|
// TODO: Compute main
|
||||||
|
}
|
||||||
|
|
||||||
if (context.AttributeUsage.UsedInputAttributes != 0)
|
if (context.AttributeUsage.UsedInputAttributes != 0)
|
||||||
{
|
{
|
||||||
args = args.Prepend("VertexIn in [[stage_in]]").ToArray();
|
if (stage == ShaderStage.Vertex)
|
||||||
|
{
|
||||||
|
args = args.Prepend("VertexIn in [[stage_in]]").ToArray();
|
||||||
|
}
|
||||||
|
else if (stage == ShaderStage.Fragment)
|
||||||
|
{
|
||||||
|
args = args.Prepend("FragmentIn in [[stage_in]]").ToArray();
|
||||||
|
}
|
||||||
|
else if (stage == ShaderStage.Compute)
|
||||||
|
{
|
||||||
|
// TODO: Compute input
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,9 +46,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
|
|
||||||
public static AggregateType GetNodeDestType(CodeGenContext context, IAstNode node)
|
public static AggregateType GetNodeDestType(CodeGenContext context, IAstNode node)
|
||||||
{
|
{
|
||||||
// TODO: Get rid of that function entirely and return the type from the operation generation
|
|
||||||
// functions directly, like SPIR-V does.
|
|
||||||
|
|
||||||
if (node is AstOperation operation)
|
if (node is AstOperation operation)
|
||||||
{
|
{
|
||||||
if (operation.Inst == Instruction.Load || operation.Inst.IsAtomic())
|
if (operation.Inst == Instruction.Load || operation.Inst.IsAtomic())
|
||||||
|
@ -99,6 +96,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
IoVariable ioVariable = (IoVariable)varId.Value;
|
IoVariable ioVariable = (IoVariable)varId.Value;
|
||||||
bool isOutput = operation.StorageKind == StorageKind.Output || operation.StorageKind == StorageKind.OutputPerPatch;
|
bool isOutput = operation.StorageKind == StorageKind.Output || operation.StorageKind == StorageKind.OutputPerPatch;
|
||||||
bool isPerPatch = operation.StorageKind == StorageKind.InputPerPatch || operation.StorageKind == StorageKind.OutputPerPatch;
|
bool isPerPatch = operation.StorageKind == StorageKind.InputPerPatch || operation.StorageKind == StorageKind.OutputPerPatch;
|
||||||
|
int location = 0;
|
||||||
|
int component = 0;
|
||||||
|
|
||||||
if (context.Definitions.HasPerLocationInputOrOutput(ioVariable, isOutput))
|
if (context.Definitions.HasPerLocationInputOrOutput(ioVariable, isOutput))
|
||||||
{
|
{
|
||||||
|
@ -107,18 +106,24 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
throw new InvalidOperationException($"Second input of {operation.Inst} with {operation.StorageKind} storage must be a constant operand.");
|
throw new InvalidOperationException($"Second input of {operation.Inst} with {operation.StorageKind} storage must be a constant operand.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int location = vecIndex.Value;
|
location = vecIndex.Value;
|
||||||
|
|
||||||
if (operation.SourcesCount > 2 &&
|
if (operation.SourcesCount > 2 &&
|
||||||
operation.GetSource(2) is AstOperand elemIndex &&
|
operation.GetSource(2) is AstOperand elemIndex &&
|
||||||
elemIndex.Type == OperandType.Constant &&
|
elemIndex.Type == OperandType.Constant &&
|
||||||
context.Definitions.HasPerLocationInputOrOutputComponent(ioVariable, location, elemIndex.Value, isOutput))
|
context.Definitions.HasPerLocationInputOrOutputComponent(ioVariable, location, elemIndex.Value, isOutput))
|
||||||
{
|
{
|
||||||
int component = elemIndex.Value;
|
component = elemIndex.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, AggregateType varType) = IoMap.GetMSLBuiltIn(ioVariable);
|
(_, AggregateType varType) = IoMap.GetMslBuiltIn(
|
||||||
|
context.Definitions,
|
||||||
|
ioVariable,
|
||||||
|
location,
|
||||||
|
component,
|
||||||
|
isOutput,
|
||||||
|
isPerPatch);
|
||||||
|
|
||||||
return varType & AggregateType.ElementTypeMask;
|
return varType & AggregateType.ElementTypeMask;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Graphics.Shader.CodeGen;
|
using Ryujinx.Graphics.Shader.CodeGen;
|
||||||
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
||||||
|
using Ryujinx.Graphics.Shader.CodeGen.Msl;
|
||||||
using Ryujinx.Graphics.Shader.CodeGen.Spirv;
|
using Ryujinx.Graphics.Shader.CodeGen.Spirv;
|
||||||
using Ryujinx.Graphics.Shader.Decoders;
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
|
@ -373,6 +374,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
TargetLanguage.Glsl => new ShaderProgram(info, TargetLanguage.Glsl, GlslGenerator.Generate(sInfo, parameters)),
|
TargetLanguage.Glsl => new ShaderProgram(info, TargetLanguage.Glsl, GlslGenerator.Generate(sInfo, parameters)),
|
||||||
TargetLanguage.Spirv => new ShaderProgram(info, TargetLanguage.Spirv, SpirvGenerator.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()),
|
_ => throw new NotImplementedException(Options.TargetLanguage.ToString()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue