diff options
Diffstat (limited to 'Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs')
-rw-r--r-- | Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs | 147 |
1 files changed, 113 insertions, 34 deletions
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs index ae280377..a02c4c22 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs @@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader.Translation; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Numerics; using static Spv.Specification; namespace Ryujinx.Graphics.Shader.CodeGen.Spirv @@ -146,6 +147,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv Add(Instruction.Truncate, GenerateTruncate); Add(Instruction.UnpackDouble2x32, GenerateUnpackDouble2x32); Add(Instruction.UnpackHalf2x16, GenerateUnpackHalf2x16); + Add(Instruction.VectorExtract, GenerateVectorExtract); Add(Instruction.VoteAll, GenerateVoteAll); Add(Instruction.VoteAllEqual, GenerateVoteAllEqual); Add(Instruction.VoteAny, GenerateVoteAny); @@ -317,7 +319,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv } else { - var type = function.GetArgumentType(i).Convert(); + var type = function.GetArgumentType(i); var value = context.Get(type, operand); var spvLocal = spvLocals[i]; @@ -327,7 +329,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv } } - var retType = function.ReturnType.Convert(); + var retType = function.ReturnType; var result = context.FunctionCall(context.GetType(retType), spvFunc, args); return new OperationResult(retType, result); } @@ -604,10 +606,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv // TODO: Bindless texture support. For now we just return 0/do nothing. if (isBindless) { - return new OperationResult(componentType.Convert(), componentType switch + return new OperationResult(componentType, componentType switch { - VariableType.S32 => context.Constant(context.TypeS32(), 0), - VariableType.U32 => context.Constant(context.TypeU32(), 0u), + AggregateType.S32 => context.Constant(context.TypeS32(), 0), + AggregateType.U32 => context.Constant(context.TypeU32(), 0u), _ => context.Constant(context.TypeFP32(), 0f), }); } @@ -652,13 +654,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv pCoords = Src(AggregateType.S32); } - SpvInstruction value = Src(componentType.Convert()); + SpvInstruction value = Src(componentType); (var imageType, var imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)]; var image = context.Load(imageType, imageVariable); - SpvInstruction resultType = context.GetType(componentType.Convert()); + SpvInstruction resultType = context.GetType(componentType); SpvInstruction imagePointerType = context.TypePointer(StorageClass.Image, resultType); var pointer = context.ImageTexelPointer(imagePointerType, imageVariable, pCoords, context.Constant(context.TypeU32(), 0)); @@ -668,10 +670,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var result = (texOp.Flags & TextureFlags.AtomicMask) switch { TextureFlags.Add => context.AtomicIAdd(resultType, pointer, one, zero, value), - TextureFlags.Minimum => componentType == VariableType.S32 + TextureFlags.Minimum => componentType == AggregateType.S32 ? context.AtomicSMin(resultType, pointer, one, zero, value) : context.AtomicUMin(resultType, pointer, one, zero, value), - TextureFlags.Maximum => componentType == VariableType.S32 + TextureFlags.Maximum => componentType == AggregateType.S32 ? context.AtomicSMax(resultType, pointer, one, zero, value) : context.AtomicUMax(resultType, pointer, one, zero, value), TextureFlags.Increment => context.AtomicIIncrement(resultType, pointer, one, zero), @@ -680,11 +682,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv TextureFlags.BitwiseOr => context.AtomicOr(resultType, pointer, one, zero, value), TextureFlags.BitwiseXor => context.AtomicXor(resultType, pointer, one, zero, value), TextureFlags.Swap => context.AtomicExchange(resultType, pointer, one, zero, value), - TextureFlags.CAS => context.AtomicCompareExchange(resultType, pointer, one, zero, zero, Src(componentType.Convert()), value), + TextureFlags.CAS => context.AtomicCompareExchange(resultType, pointer, one, zero, zero, Src(componentType), value), _ => context.AtomicIAdd(resultType, pointer, one, zero, value), }; - return new OperationResult(componentType.Convert(), result); + return new OperationResult(componentType, result); } private static OperationResult GenerateImageLoad(CodeGenContext context, AstOperation operation) @@ -698,14 +700,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv // TODO: Bindless texture support. For now we just return 0/do nothing. if (isBindless) { - var zero = componentType switch - { - VariableType.S32 => context.Constant(context.TypeS32(), 0), - VariableType.U32 => context.Constant(context.TypeU32(), 0u), - _ => context.Constant(context.TypeFP32(), 0f), - }; - - return new OperationResult(componentType.Convert(), zero); + return GetZeroOperationResult(context, texOp, componentType, isVector: true); } bool isArray = (texOp.Type & SamplerType.Array) != 0; @@ -753,12 +748,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv (var imageType, var imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)]; var image = context.Load(imageType, imageVariable); - var imageComponentType = context.GetType(componentType.Convert()); + var imageComponentType = context.GetType(componentType); + var swizzledResultType = texOp.GetVectorType(componentType); var texel = context.ImageRead(context.TypeVector(imageComponentType, 4), image, pCoords, ImageOperandsMask.MaskNone); - var result = context.CompositeExtract(imageComponentType, texel, (SpvLiteralInteger)texOp.Index); + var result = GetSwizzledResult(context, texel, swizzledResultType, texOp.Index); - return new OperationResult(componentType.Convert(), result); + return new OperationResult(componentType, result); } private static OperationResult GenerateImageStore(CodeGenContext context, AstOperation operation) @@ -823,20 +819,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { if (srcIndex < texOp.SourcesCount) { - cElems[i] = Src(componentType.Convert()); + cElems[i] = Src(componentType); } else { cElems[i] = componentType switch { - VariableType.S32 => context.Constant(context.TypeS32(), 0), - VariableType.U32 => context.Constant(context.TypeU32(), 0u), + AggregateType.S32 => context.Constant(context.TypeS32(), 0), + AggregateType.U32 => context.Constant(context.TypeU32(), 0u), _ => context.Constant(context.TypeFP32(), 0f), }; } } - var texel = context.CompositeConstruct(context.TypeVector(context.GetType(componentType.Convert()), ComponentsCount), cElems); + var texel = context.CompositeConstruct(context.TypeVector(context.GetType(componentType), ComponentsCount), cElems); (var imageType, var imageVariable) = context.Images[new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format)]; @@ -1238,7 +1234,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var validLocal = (AstOperand)operation.GetSource(3); - context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType.Convert(), AggregateType.Bool, valid)); + context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType, AggregateType.Bool, valid)); return new OperationResult(AggregateType.FP32, result); } @@ -1268,7 +1264,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var validLocal = (AstOperand)operation.GetSource(3); - context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType.Convert(), AggregateType.Bool, valid)); + context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType, AggregateType.Bool, valid)); return new OperationResult(AggregateType.FP32, result); } @@ -1294,7 +1290,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var validLocal = (AstOperand)operation.GetSource(3); - context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType.Convert(), AggregateType.Bool, valid)); + context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType, AggregateType.Bool, valid)); return new OperationResult(AggregateType.FP32, result); } @@ -1324,7 +1320,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var validLocal = (AstOperand)operation.GetSource(3); - context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType.Convert(), AggregateType.Bool, valid)); + context.Store(context.GetLocalPointer(validLocal), context.BitcastIfNeeded(validLocal.VarType, AggregateType.Bool, valid)); return new OperationResult(AggregateType.FP32, result); } @@ -1485,10 +1481,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0; bool isShadow = (texOp.Type & SamplerType.Shadow) != 0; + bool colorIsVector = isGather || !isShadow; + // TODO: Bindless texture support. For now we just return 0. if (isBindless) { - return new OperationResult(AggregateType.FP32, context.Constant(context.TypeFP32(), 0f)); + return GetZeroOperationResult(context, texOp, AggregateType.FP32, colorIsVector); } // This combination is valid, but not available on GLSL. @@ -1705,7 +1703,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv operandsList.Add(sample); } - bool colorIsVector = isGather || !isShadow; var resultType = colorIsVector ? context.TypeVector(context.TypeFP32(), 4) : context.TypeFP32(); var meta = new TextureMeta(texOp.CbufSlot, texOp.Handle, texOp.Format); @@ -1758,12 +1755,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv result = context.ImageSampleImplicitLod(resultType, image, pCoords, operandsMask, operands); } + var swizzledResultType = AggregateType.FP32; + if (colorIsVector) { - result = context.CompositeExtract(context.TypeFP32(), result, (SpvLiteralInteger)texOp.Index); + swizzledResultType = texOp.GetVectorType(swizzledResultType); + + result = GetSwizzledResult(context, result, swizzledResultType, texOp.Index); } - return new OperationResult(AggregateType.FP32, result); + return new OperationResult(swizzledResultType, result); } private static OperationResult GenerateTextureSize(CodeGenContext context, AstOperation operation) @@ -1862,6 +1863,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv return new OperationResult(AggregateType.FP32, result); } + private static OperationResult GenerateVectorExtract(CodeGenContext context, AstOperation operation) + { + var vector = context.GetWithType(operation.GetSource(0), out AggregateType vectorType); + var scalarType = vectorType & ~AggregateType.ElementCountMask; + var resultType = context.GetType(scalarType); + SpvInstruction result; + + if (operation.GetSource(1) is AstOperand indexOperand && indexOperand.Type == OperandType.Constant) + { + result = context.CompositeExtract(resultType, vector, (SpvLiteralInteger)indexOperand.Value); + } + else + { + var index = context.Get(AggregateType.S32, operation.GetSource(1)); + result = context.VectorExtractDynamic(resultType, vector, index); + } + + return new OperationResult(scalarType, result); + } + private static OperationResult GenerateVoteAll(CodeGenContext context, AstOperation operation) { var execution = context.Constant(context.TypeU32(), Scope.Subgroup); @@ -2044,6 +2065,64 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.AddLabel(loopEnd); } + private static OperationResult GetZeroOperationResult( + CodeGenContext context, + AstTextureOperation texOp, + AggregateType scalarType, + bool isVector) + { + var zero = scalarType switch + { + AggregateType.S32 => context.Constant(context.TypeS32(), 0), + AggregateType.U32 => context.Constant(context.TypeU32(), 0u), + _ => context.Constant(context.TypeFP32(), 0f), + }; + + if (isVector) + { + AggregateType outputType = texOp.GetVectorType(scalarType); + + if ((outputType & AggregateType.ElementCountMask) != 0) + { + int componentsCount = BitOperations.PopCount((uint)texOp.Index); + + SpvInstruction[] values = new SpvInstruction[componentsCount]; + + values.AsSpan().Fill(zero); + + return new OperationResult(outputType, context.ConstantComposite(context.GetType(outputType), values)); + } + } + + return new OperationResult(scalarType, zero); + } + + private static SpvInstruction GetSwizzledResult(CodeGenContext context, SpvInstruction vector, AggregateType swizzledResultType, int mask) + { + if ((swizzledResultType & AggregateType.ElementCountMask) != 0) + { + SpvLiteralInteger[] components = new SpvLiteralInteger[BitOperations.PopCount((uint)mask)]; + + int componentIndex = 0; + + for (int i = 0; i < 4; i++) + { + if ((mask & (1 << i)) != 0) + { + components[componentIndex++] = i; + } + } + + return context.VectorShuffle(context.GetType(swizzledResultType), vector, vector, components); + } + else + { + int componentIndex = (int)BitOperations.TrailingZeroCount(mask); + + return context.CompositeExtract(context.GetType(swizzledResultType), vector, (SpvLiteralInteger)componentIndex); + } + } + private static SpvInstruction GetStorageElemPointer(CodeGenContext context, AstOperation operation) { var sbVariable = context.StorageBuffersArray; |