diff options
| author | gdk <gab.dark.100@gmail.com> | 2019-10-17 23:41:18 -0300 |
|---|---|---|
| committer | Thog <thog@protonmail.com> | 2020-01-09 02:13:00 +0100 |
| commit | 1b7d95519569639135a68e7ebda5148f3263217c (patch) | |
| tree | 52a5e471418bf28ce970a268e1b86b64abc9048f /Ryujinx.Graphics.Shader | |
| parent | 717ace6f6ed65118148dc78976c6e818a095fa4d (diff) | |
Initial support for image stores, support texture sample on compute
Diffstat (limited to 'Ryujinx.Graphics.Shader')
25 files changed, 498 insertions, 121 deletions
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs index 322bfbf5..abfe55a5 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs @@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl public List<BufferDescriptor> CBufferDescriptors { get; } public List<BufferDescriptor> SBufferDescriptors { get; } public List<TextureDescriptor> TextureDescriptors { get; } + public List<TextureDescriptor> ImageDescriptors { get; } public OperandManager OperandManager { get; } @@ -28,6 +29,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl CBufferDescriptors = new List<BufferDescriptor>(); SBufferDescriptors = new List<BufferDescriptor>(); TextureDescriptors = new List<TextureDescriptor>(); + ImageDescriptors = new List<TextureDescriptor>(); OperandManager = new OperandManager(); diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index 3644b21a..ab10d91a 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -88,6 +88,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.AppendLine(); } + if (info.Images.Count != 0) + { + DeclareImages(context, info); + + context.AppendLine(); + } + if (context.Config.Stage != ShaderStage.Compute) { if (info.IAttributes.Count != 0) @@ -204,7 +211,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl continue; } - string samplerTypeName = GetSamplerTypeName(texOp.Target); + string samplerTypeName = GetSamplerTypeName(texOp.Type); context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";"); } @@ -221,17 +228,47 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl { AstOperand operand = texOp.GetSource(0) as AstOperand; - desc = new TextureDescriptor(samplerName, texOp.Target, operand.CbufSlot, operand.CbufOffset); + desc = new TextureDescriptor(samplerName, texOp.Type, operand.CbufSlot, operand.CbufOffset); } else { - desc = new TextureDescriptor(samplerName, texOp.Target, texOp.Handle); + desc = new TextureDescriptor(samplerName, texOp.Type, texOp.Handle); } context.TextureDescriptors.Add(desc); } } + private static void DeclareImages(CodeGenContext context, StructuredProgramInfo info) + { + Dictionary<string, AstTextureOperation> images = new Dictionary<string, AstTextureOperation>(); + + foreach (AstTextureOperation texOp in info.Images.OrderBy(x => x.Handle)) + { + string imageName = OperandManager.GetImageName(context.Config.Stage, texOp); + + if (!images.TryAdd(imageName, texOp)) + { + continue; + } + + string imageTypeName = GetImageTypeName(texOp.Type); + + context.AppendLine("writeonly uniform " + imageTypeName + " " + imageName + ";"); + } + + foreach (KeyValuePair<string, AstTextureOperation> kv in images) + { + string imageName = kv.Key; + + AstTextureOperation texOp = kv.Value; + + TextureDescriptor desc = new TextureDescriptor(imageName, texOp.Type, texOp.Handle); + + context.ImageDescriptors.Add(desc); + } + } + private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info) { string suffix = context.Config.Stage == ShaderStage.Geometry ? "[]" : string.Empty; @@ -284,36 +321,65 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl } } - private static string GetSamplerTypeName(TextureTarget type) + private static string GetSamplerTypeName(SamplerType type) { string typeName; - switch (type & TextureTarget.Mask) + switch (type & SamplerType.Mask) { - case TextureTarget.Texture1D: typeName = "sampler1D"; break; - case TextureTarget.Texture2D: typeName = "sampler2D"; break; - case TextureTarget.Texture3D: typeName = "sampler3D"; break; - case TextureTarget.TextureCube: typeName = "samplerCube"; break; + case SamplerType.Texture1D: typeName = "sampler1D"; break; + case SamplerType.TextureBuffer: typeName = "samplerBuffer"; break; + case SamplerType.Texture2D: typeName = "sampler2D"; break; + case SamplerType.Texture3D: typeName = "sampler3D"; break; + case SamplerType.TextureCube: typeName = "samplerCube"; break; default: throw new ArgumentException($"Invalid sampler type \"{type}\"."); } - if ((type & TextureTarget.Multisample) != 0) + if ((type & SamplerType.Multisample) != 0) { typeName += "MS"; } - if ((type & TextureTarget.Array) != 0) + if ((type & SamplerType.Array) != 0) { typeName += "Array"; } - if ((type & TextureTarget.Shadow) != 0) + if ((type & SamplerType.Shadow) != 0) { typeName += "Shadow"; } return typeName; } + + private static string GetImageTypeName(SamplerType type) + { + string typeName; + + switch (type & SamplerType.Mask) + { + case SamplerType.Texture1D: typeName = "image1D"; break; + case SamplerType.TextureBuffer: typeName = "imageBuffer"; break; + case SamplerType.Texture2D: typeName = "image2D"; break; + case SamplerType.Texture3D: typeName = "image3D"; break; + case SamplerType.TextureCube: typeName = "imageCube"; break; + + default: throw new ArgumentException($"Invalid sampler type \"{type}\"."); + } + + if ((type & SamplerType.Multisample) != 0) + { + typeName += "MS"; + } + + if ((type & SamplerType.Array) != 0) + { + typeName += "Array"; + } + + return typeName; + } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs index 67de3b43..a06b0cc8 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs @@ -5,6 +5,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl public const string LocalNamePrefix = "temp"; public const string SamplerNamePrefix = "tex"; + public const string ImageNamePrefix = "img"; public const string IAttributePrefix = "in_attr"; public const string OAttributePrefix = "out_attr"; diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs index 65246d97..b5407eb8 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs @@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.CBufferDescriptors.ToArray(), context.SBufferDescriptors.ToArray(), context.TextureDescriptors.ToArray(), + context.ImageDescriptors.ToArray(), context.GetCode()); } diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslProgram.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslProgram.cs index 7807cb49..31b7f312 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslProgram.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslProgram.cs @@ -5,6 +5,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl public BufferDescriptor[] CBufferDescriptors { get; } public BufferDescriptor[] SBufferDescriptors { get; } public TextureDescriptor[] TextureDescriptors { get; } + public TextureDescriptor[] ImageDescriptors { get; } public string Code { get; } @@ -12,11 +13,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl BufferDescriptor[] cBufferDescriptors, BufferDescriptor[] sBufferDescriptors, TextureDescriptor[] textureDescriptors, + TextureDescriptor[] imageDescriptors, string code) { CBufferDescriptors = cBufferDescriptors; SBufferDescriptors = sBufferDescriptors; TextureDescriptors = textureDescriptors; + ImageDescriptors = imageDescriptors; Code = code; } } diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs index 350de348..3bf31c16 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs @@ -87,6 +87,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { switch (inst) { + case Instruction.ImageStore: + return InstGenMemory.ImageStore(context, operation); + case Instruction.LoadAttribute: return InstGenMemory.LoadAttribute(context, operation); diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs index 6989e997..6dfbe61a 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs @@ -48,6 +48,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions Add(Instruction.ExponentB2, InstType.CallUnary, "exp2"); Add(Instruction.Floor, InstType.CallUnary, "floor"); Add(Instruction.FusedMultiplyAdd, InstType.CallTernary, "fma"); + Add(Instruction.ImageLoad, InstType.Special); + Add(Instruction.ImageStore, InstType.Special); Add(Instruction.IsNan, InstType.CallUnary, "isnan"); Add(Instruction.LoadAttribute, InstType.Special); Add(Instruction.LoadConstant, InstType.Special); diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs index 5c9ec830..f2f6ae0c 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs @@ -9,6 +9,80 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { static class InstGenMemory { + public static string ImageStore(CodeGenContext context, AstOperation operation) + { + AstTextureOperation texOp = (AstTextureOperation)operation; + + bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + + bool isArray = (texOp.Type & SamplerType.Array) != 0; + + string texCall = "imageStore"; + + string imageName = OperandManager.GetImageName(context.Config.Stage, texOp); + + texCall += "(" + imageName; + + int coordsCount = texOp.Type.GetDimensions(); + + int pCount = coordsCount; + + int arrayIndexElem = -1; + + if (isArray) + { + arrayIndexElem = pCount++; + } + + int srcIndex = isBindless ? 1 : 0; + + string Src(VariableType type) + { + return GetSoureExpr(context, texOp.GetSource(srcIndex++), type); + } + + void Append(string str) + { + texCall += ", " + str; + } + + if (pCount > 1) + { + string[] elems = new string[pCount]; + + for (int index = 0; index < pCount; index++) + { + elems[index] = Src(VariableType.S32); + } + + Append("ivec" + pCount + "(" + string.Join(", ", elems) + ")"); + } + else + { + Append(Src(VariableType.S32)); + } + + string[] cElems = new string[4]; + + for (int index = 0; index < 4; index++) + { + if (srcIndex < texOp.SourcesCount) + { + cElems[index] = Src(VariableType.F32); + } + else + { + cElems[index] = NumberFormatter.FormatFloat(0); + } + } + + Append("vec4(" + string.Join(", ", cElems) + ")"); + + texCall += ")"; + + return texCall; + } + public static string LoadAttribute(CodeGenContext context, AstOperation operation) { IAstNode src1 = operation.GetSource(0); @@ -98,9 +172,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0; bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0; - bool isArray = (texOp.Target & TextureTarget.Array) != 0; - bool isMultisample = (texOp.Target & TextureTarget.Multisample) != 0; - bool isShadow = (texOp.Target & TextureTarget.Shadow) != 0; + bool isArray = (texOp.Type & SamplerType.Array) != 0; + bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0; + bool isShadow = (texOp.Type & SamplerType.Shadow) != 0; // This combination is valid, but not available on GLSL. // For now, ignore the LOD level and do a normal sample. @@ -134,7 +208,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions texCall += "(" + samplerName; - int coordsCount = texOp.Target.GetDimensions(); + int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount; @@ -147,7 +221,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions // The sampler 1D shadow overload expects a // dummy value on the middle of the vector, who knows why... - bool hasDummy1DShadowElem = texOp.Target == (TextureTarget.Texture1D | TextureTarget.Shadow); + bool hasDummy1DShadowElem = texOp.Type == (SamplerType.Texture1D | SamplerType.Shadow); if (hasDummy1DShadowElem) { diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs index 88095920..fe307396 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs @@ -241,6 +241,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl return GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix; } + public static string GetImageName(ShaderStage stage, AstTextureOperation texOp) + { + string suffix = texOp.Handle.ToString(); + + return GetShaderStagePrefix(stage) + "_" + DefaultNames.ImageNamePrefix + suffix; + } + public static string GetShaderStagePrefix(ShaderStage stage) { int index = (int)stage; diff --git a/Ryujinx.Graphics.Shader/Decoders/ImageComponents.cs b/Ryujinx.Graphics.Shader/Decoders/ImageComponents.cs new file mode 100644 index 00000000..b8a4f6d5 --- /dev/null +++ b/Ryujinx.Graphics.Shader/Decoders/ImageComponents.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum ImageComponents + { + Red = 1 << 0, + Green = 1 << 1, + Blue = 1 << 2, + Alpha = 1 << 3 + + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Decoders/ImageDimensions.cs b/Ryujinx.Graphics.Shader/Decoders/ImageDimensions.cs new file mode 100644 index 00000000..ecf41a82 --- /dev/null +++ b/Ryujinx.Graphics.Shader/Decoders/ImageDimensions.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum ImageDimensions + { + Image1D, + ImageBuffer, + Image1DArray, + Image2D, + Image2DArray, + Image3D + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeImage.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeImage.cs new file mode 100644 index 00000000..42fe677b --- /dev/null +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeImage.cs @@ -0,0 +1,48 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeImage : OpCode + { + public Register Ra { get; } + public Register Rb { get; } + public Register Rc { get; } + + public ImageComponents Components { get; } + public IntegerSize Size { get; } + + public bool ByteAddress { get; } + + public ImageDimensions Dimensions { get; } + + public int Immediate { get; } + + public bool UseComponents { get; } + public bool IsBindless { get; } + + public OpCodeImage(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr); + Rb = new Register(opCode.Extract(0, 8), RegisterType.Gpr); + Rc = new Register(opCode.Extract(39, 8), RegisterType.Gpr); + + UseComponents = !opCode.Extract(52); + + if (UseComponents) + { + Components = (ImageComponents)opCode.Extract(20, 4); + } + else + { + Size = (IntegerSize)opCode.Extract(20, 4); + } + + ByteAddress = !opCode.Extract(23); + + Dimensions = (ImageDimensions)opCode.Extract(33, 3); + + Immediate = opCode.Extract(36, 13); + IsBindless = !opCode.Extract(51); + } + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs index 3fd1de86..5128dae3 100644 --- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs @@ -143,6 +143,7 @@ namespace Ryujinx.Graphics.Shader.Decoders Set("111000101001xx", InstEmit.Ssy, typeof(OpCodeSsy)); Set("1110111101010x", InstEmit.St, typeof(OpCodeMemory)); Set("1110111011011x", InstEmit.Stg, typeof(OpCodeMemory)); + Set("11101011001xxx", InstEmit.Sust, typeof(OpCodeImage)); Set("1111000011111x", InstEmit.Sync, typeof(OpCodeSync)); Set("110000xxxx111x", InstEmit.Tex, typeof(OpCodeTex)); Set("1101111010111x", InstEmit.TexB, typeof(OpCodeTexB)); diff --git a/Ryujinx.Graphics.Shader/Decoders/TexelLoadTarget.cs b/Ryujinx.Graphics.Shader/Decoders/TexelLoadTarget.cs index 478cac44..e5a0c004 100644 --- a/Ryujinx.Graphics.Shader/Decoders/TexelLoadTarget.cs +++ b/Ryujinx.Graphics.Shader/Decoders/TexelLoadTarget.cs @@ -2,14 +2,14 @@ namespace Ryujinx.Graphics.Shader.Decoders { enum TexelLoadTarget { - Texture1DLodZero = 0x0, - Texture1DLodLevel = 0x1, - Texture2DLodZero = 0x2, - Texture2DLodZeroOffset = 0x4, - Texture2DLodLevel = 0x5, + Texture1DLodZero = 0x0, + Texture1DLodLevel = 0x1, + Texture2DLodZero = 0x2, + Texture2DLodZeroOffset = 0x4, + Texture2DLodLevel = 0x5, Texture2DLodZeroMultisample = 0x6, - Texture3DLodZero = 0x7, - Texture2DArrayLodZero = 0x8, - Texture2DLodLevelOffset = 0xc + Texture3DLodZero = 0x7, + Texture2DArrayLodZero = 0x8, + Texture2DLodLevelOffset = 0xc } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs index 554deb7b..39672789 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs @@ -10,6 +10,96 @@ namespace Ryujinx.Graphics.Shader.Instructions { static partial class InstEmit { + public static void Sust(EmitterContext context) + { + OpCodeImage op = (OpCodeImage)context.CurrOp; + + int raIndex = op.Ra.Index; + int rbIndex = op.Rb.Index; + + Operand Ra() + { + if (raIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(raIndex++, RegisterType.Gpr)); + } + + Operand Rb() + { + if (rbIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(rbIndex++, RegisterType.Gpr)); + } + + bool isArray = op.Dimensions == ImageDimensions.Image1DArray || + op.Dimensions == ImageDimensions.Image2DArray; + + Operand arrayIndex = isArray ? Ra() : null; + + List<Operand> sourcesList = new List<Operand>(); + + if (op.IsBindless) + { + sourcesList.Add(context.Copy(Register(op.Rc))); + } + + SamplerType type = GetSamplerType(op.Dimensions); + + int coordsCount = type.GetDimensions(); + + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(Ra()); + } + + if (isArray) + { + sourcesList.Add(arrayIndex); + + type |= SamplerType.Array; + } + + if (op.UseComponents) + { + int componentMask = (int)op.Components; + + for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + sourcesList.Add(Rb()); + } + } + } + else + { + // TODO. + } + + Operand[] sources = sourcesList.ToArray(); + + int handle = !op.IsBindless ? op.Immediate : 0; + + TextureFlags flags = op.IsBindless ? TextureFlags.Bindless : TextureFlags.None; + + TextureOperation operation = new TextureOperation( + Instruction.ImageStore, + type, + flags, + handle, + 0, + null, + sources); + + context.Add(operation); + } + public static void Tex(EmitterContext context) { Tex(context, TextureFlags.None); @@ -74,15 +164,15 @@ namespace Ryujinx.Graphics.Shader.Instructions } } - TextureTarget type; + SamplerType type; TextureFlags flags; if (op is OpCodeTexs texsOp) { - type = GetTextureType (texsOp.Target); - flags = GetTextureFlags(texsOp.Target); + type = GetSamplerType (texsOp.Target); + flags = GetSamplerFlags(texsOp.Target); - if ((type & TextureTarget.Array) != 0) + if ((type & SamplerType.Array) != 0) { Operand arrayIndex = Ra(); @@ -91,7 +181,7 @@ namespace Ryujinx.Graphics.Shader.Instructions sourcesList.Add(arrayIndex); - if ((type & TextureTarget.Shadow) != 0) + if ((type & SamplerType.Shadow) != 0) { sourcesList.Add(Rb()); } @@ -149,8 +239,8 @@ namespace Ryujinx.Graphics.Shader.Instructions } else if (op is OpCodeTlds tldsOp) { - type = GetTextureType (tldsOp.Target); - flags = GetTextureFlags(tldsOp.Target) | TextureFlags.IntCoords; + type = GetSamplerType (tldsOp.Target); + flags = GetSamplerFlags(tldsOp.Target) | TextureFlags.IntCoords; switch (tldsOp.Target) { @@ -217,14 +307,14 @@ namespace Ryujinx.Graphics.Shader.Instructions sourcesList.Add(Ra()); } - type = TextureTarget.Texture2D; + type = SamplerType.Texture2D; flags = TextureFlags.Gather; if (tld4sOp.HasDepthCompare) { sourcesList.Add(Rb()); - type |= TextureTarget.Shadow; + type |= SamplerType.Shadow; } if (tld4sOp.HasOffset) @@ -338,7 +428,7 @@ namespace Ryujinx.Graphics.Shader.Instructions List<Operand> sourcesList = new List<Operand>(); - TextureTarget type = GetTextureType(op.Dimensions); + SamplerType type = GetSamplerType(op.Dimensions); TextureFlags flags = TextureFlags.Gather; @@ -353,7 +443,7 @@ namespace Ryujinx.Graphics.Shader.Instructions { sourcesList.Add(arrayIndex); - type |= TextureTarget.Array; + type |= SamplerType.Array; } Operand[] packedOffs = new Operand[2]; @@ -365,7 +455,7 @@ namespace Ryujinx.Graphics.Shader.Instructions { sourcesList.Add(Rb()); - type |= TextureTarget.Shadow; + type |= SamplerType.Shadow; } if (op.Offset != TextureGatherOffset.None) @@ -446,7 +536,7 @@ namespace Ryujinx.Graphics.Shader.Instructions // TODO: Validate and use property. Instruction inst = Instruction.TextureSize; - TextureTarget type = TextureTarget.Texture2D; + SamplerType type = SamplerType.Texture2D; TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None; @@ -551,7 +641,7 @@ namespace Ryujinx.Graphics.Shader.Instructions sourcesList.Add(Rb()); } - TextureTarget type = GetTextureType(op.Dimensions); + SamplerType type = GetSamplerType(op.Dimensions); int coordsCount = type.GetDimensions(); @@ -564,7 +654,7 @@ namespace Ryujinx.Graphics.Shader.Instructions { sourcesList.Add(arrayIndex); - type |= TextureTarget.Array; + type |= SamplerType.Array; } bool hasLod = op.LodMode > TextureLodMode.LodZero; @@ -577,7 +667,7 @@ namespace Ryujinx.Graphics.Shader.Instructions { sourcesList.Add(Rb()); - type |= TextureTarget.Shadow; + type |= SamplerType.Shadow; } if ((op.LodMode == TextureLodMode.LodZero || @@ -611,7 +701,7 @@ namespace Ryujinx.Graphics.Shader.Instructions { sourcesList.Add(Rb()); - type |= TextureTarget.Multisample; + type |= SamplerType.Multisample; } Operand[] sources = sourcesList.ToArray(); @@ -650,83 +740,109 @@ namespace Ryujinx.Graphics.Shader.Instructions } } - private static TextureTarget GetTextureType(TextureDimensions dimensions) + private static SamplerType GetSamplerType(ImageDimensions target) + { + switch (target) + { + case ImageDimensions.Image1D: + return SamplerType.Texture1D; + + case ImageDimensions.ImageBuffer: + return SamplerType.TextureBuffer; + + case ImageDimensions.Image1DArray: + return SamplerType.Texture1D | SamplerType.Array; + + case ImageDimensions.Image2D: + return SamplerType.Texture2D; + + case ImageDimensions.Image2DArray: + return SamplerType.Texture2D | SamplerType.Array; + + case ImageDimensions.Image3D: + return SamplerType.Texture3D; + } + + throw new ArgumentException($"Invalid image target \"{target}\"."); + } + + private static SamplerType GetSamplerType(TextureDimensions dimensions) { switch (dimensions) { - case TextureDimensions.Texture1D: return TextureTarget.Texture1D; - case TextureDimensions.Texture2D: return TextureTarget.Texture2D; - case TextureDimensions.Texture3D: return TextureTarget.Texture3D; - case TextureDimensions.TextureCube: return TextureTarget.TextureCube; + case TextureDimensions.Texture1D: return SamplerType.Texture1D; + case TextureDimensions.Texture2D: return SamplerType.Texture2D; + case TextureDimensions.Texture3D: return SamplerType.Texture3D; + case TextureDimensions.TextureCube: return SamplerType.TextureCube; } throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\"."); } - private static TextureTarget GetTextureType(Decoders.TextureTarget type) + private static SamplerType GetSamplerType(Decoders.TextureTarget type) { switch (type) { case Decoders.TextureTarget.Texture1DLodZero: - return TextureTarget.Texture1D; + return SamplerType.Texture1D; case Decoders.TextureTarget.Texture2D: case Decoders.TextureTarget.Texture2DLodZero: case Decoders.TextureTarget.Texture2DLodLevel: - return TextureTarget.Texture2D; + return SamplerType.Texture2D; case Decoders.TextureTarget.Texture2DDepthCompare: case Decoders.TextureTarget.Texture2DLodLevelDepthCompare: case Decoders.TextureTarget.Texture2DLodZeroDepthCompare: - return TextureTarget.Texture2D | TextureTarget.Shadow; + return SamplerType.Texture2D | SamplerType.Shadow; case Decoders.TextureTarget.Texture2DArray: case Decoders.TextureTarget.Texture2DArrayLodZero: - return TextureTarget.Texture2D | TextureTarget.Array; + return SamplerType.Texture2D | SamplerType.Array; case Decoders.TextureTarget.Texture2DArrayLodZeroDepthCompare: - return TextureTarget.Texture2D | TextureTarget.Array | TextureTarget.Shadow; + return SamplerType.Texture2D | SamplerType.Array | SamplerType.Shadow; case Decoders.TextureTarget.Texture3D: case Decoders.TextureTarget.Texture3DLodZero: - return TextureTarget.Texture3D; + return SamplerType.Texture3D; case Decoders.TextureTarget.TextureCube: case Decoders.TextureTarget.TextureCubeLodLevel: - return TextureTarget.TextureCube; + return SamplerType.TextureCube; } throw new ArgumentException($"Invalid texture type \"{type}\"."); } - private static TextureTarget GetTextureType(TexelLoadTarget type) + private static SamplerType GetSamplerType(TexelLoadTarget type) { switch (type) { case TexelLoadTarget.Texture1DLodZero: case TexelLoadTarget.Texture1DLodLevel: - return TextureTarget.Texture1D; + return SamplerType.Texture1D; case TexelLoadTarget.Texture2DLodZero: case TexelLoadTarget.Texture2DLodZeroOffset: case TexelLoadTarget.Texture2DLodLevel: case TexelLoadTarget.Texture2DLodLevelOffset: - return TextureTarget.Texture2D; + return SamplerType.Texture2D; case TexelLoadTarget.Texture2DLodZeroMultisample: - return TextureTarget.Texture2D | TextureTarget.Multisample; + return SamplerType.Texture2D | SamplerType.Multisample; case TexelLoadTarget.Texture3DLodZero: - return TextureTarget.Texture3D; + return SamplerType.Texture3D; case TexelLoadTarget.Texture2DArrayLodZero: - return TextureTarget.Texture2D | TextureTarget.Array; + return SamplerType.Texture2D | SamplerType.Array; } throw new ArgumentException($"Invalid texture type \"{type}\"."); } - private static TextureFlags GetTextureFlags(Decoders.TextureTarget type) + private static TextureFlags GetSamplerFlags(Decoders.TextureTarget type) { switch (type) { @@ -752,7 +868,7 @@ namespace Ryujinx.Graphics.Shader.Instructions throw new ArgumentException($"Invalid texture type \"{type}\"."); } - private static TextureFlags GetTextureFlags(TexelLoadTarget type) + private static TextureFlags GetSamplerFlags(TexelLoadTarget type) { switch (type) { diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs index e580965e..74194f35 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs @@ -45,6 +45,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation ExponentB2, Floor, FusedMultiplyAdd, + ImageLoad, + ImageStore, IsNan, LoadAttribute, LoadConstant, diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs index 0c768345..b96c55e8 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs @@ -2,21 +2,21 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation { class TextureOperation : Operation { - public TextureTarget Target { get; } - public TextureFlags Flags { get; } + public SamplerType Type { get; } + public TextureFlags Flags { get; } public int Handle { get; } public TextureOperation( Instruction inst, - TextureTarget target, + SamplerType type, TextureFlags flags, int handle, int compIndex, Operand dest, params Operand[] sources) : base(inst, compIndex, dest, sources) { - Target = target; + Type = type; Flags = flags; Handle = handle; } diff --git a/Ryujinx.Graphics.Shader/SamplerType.cs b/Ryujinx.Graphics.Shader/SamplerType.cs new file mode 100644 index 00000000..42854c97 --- /dev/null +++ b/Ryujinx.Graphics.Shader/SamplerType.cs @@ -0,0 +1,37 @@ +using System; + +namespace Ryujinx.Graphics.Shader +{ + [Flags] + public enum SamplerType + { + Texture1D, + TextureBuffer, + Texture2D, + Texture3D, + TextureCube, + + Mask = 0xff, + + Array = 1 << 8, + Multisample = 1 << 9, + Shadow = 1 << 10 + } + + static class SamplerTypeExtensions + { + public static int GetDimensions(this SamplerType type) + { + switch (type & SamplerType.Mask) + { + case SamplerType.Texture1D: return 1; + case SamplerType.TextureBuffer: return 1; + case SamplerType.Texture2D: return 2; + case SamplerType.Texture3D: return 3; + case SamplerType.TextureCube: return 3; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs b/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs index 841e636d..1ff602a2 100644 --- a/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs +++ b/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader public ReadOnlyCollection<BufferDescriptor> CBuffers { get; } public ReadOnlyCollection<BufferDescriptor> SBuffers { get; } public ReadOnlyCollection<TextureDescriptor> Textures { get; } + public ReadOnlyCollection<TextureDescriptor> Images { get; } public ReadOnlyCollection<InterpolationQualifier> InterpolationQualifiers { get; } @@ -17,12 +18,14 @@ namespace Ryujinx.Graphics.Shader BufferDescriptor[] cBuffers, BufferDescriptor[] sBuffers, TextureDescriptor[] textures, + TextureDescriptor[] images, InterpolationQualifier[] interpolationQualifiers, bool usesInstanceId) { CBuffers = Array.AsReadOnly(cBuffers); SBuffers = Array.AsReadOnly(sBuffers); Textures = Array.AsReadOnly(textures); + Images = Array.AsReadOnly(images); InterpolationQualifiers = Array.AsReadOnly(interpolationQualifiers); diff --git a/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs b/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs index c9bd5750..7261b9ff 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs @@ -4,20 +4,20 @@ namespace Ryujinx.Graphics.Shader.StructuredIr { class AstTextureOperation : AstOperation { - public TextureTarget Target { get; } - public TextureFlags Flags { get; } + public SamplerType Type { get; } + public TextureFlags Flags { get; } public int Handle { get; } public AstTextureOperation( Instruction inst, - TextureTarget target, + SamplerType type, TextureFlags flags, int handle, int compMask, params IAstNode[] sources) : base(inst, compMask, sources) { - Target = target; + Type = type; Flags = flags; Handle = handle; } diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs index dc822621..53ca6700 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs @@ -51,6 +51,19 @@ namespace Ryujinx.Graphics.Shader.StructuredIr sources[index] = context.GetOperandUse(operation.GetSource(index)); } + int componentMask = 1 << operation.ComponentIndex; + + AstTextureOperation GetAstTextureOperation(TextureOperation texOp) + { + return new AstTextureOperation( + inst, + texOp.Type, + texOp.Flags, + texOp.Handle, + componentMask, + sources); + } + if (operation.Dest != null) { AstOperand dest = context.GetOperandDef(operation.Dest); @@ -108,21 +121,20 @@ namespace Ryujinx.Graphics.Shader.StructuredIr dest.VarType = InstructionInfo.GetDestVarType(inst); } - int componentMask = 1 << operation.ComponentIndex; - IAstNode source; if (operation is TextureOperation texOp) { - AstTextureOperation astTexOp = new AstTextureOperation( - inst, - texOp.Target, - texOp.Flags, - texOp.Handle, - componentMask, - sources); + AstTextureOperation astTexOp = GetAstTextureOperation(texOp); - context.Info.Samplers.Add(astTexOp); + if (texOp.Inst == Instruction.ImageLoad) + { + context.Info.Images.Add(astTexOp); + } + else + { + context.Info.Samplers.Add(astTexOp); + } source = astTexOp; } @@ -143,6 +155,14 @@ namespace Ryujinx.Graphics.Shader.StructuredIr { context.AddNode(new AstComment(((CommentNode)operation).Comment)); } + else if (operation is TextureOperation texOp) + { + AstTextureOperation astTexOp = GetAstTextureOperation(texOp); + + context.Info.Images.Add(astTexOp); + + context.AddNode(astTexOp); + } else { if (inst == Instruction.StoreStorage) diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs index 27fd1487..1094fba2 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs @@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr public bool UsesInstanceId { get; set; } public HashSet<AstTextureOperation> Samplers { get; } + public HashSet<AstTextureOperation> Images { get; } public StructuredProgramInfo(AstBlock mainBlock) { @@ -35,6 +36,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr InterpolationQualifiers = new InterpolationQualifier[32]; Samplers = new HashSet<AstTextureOperation>(); + Images = new HashSet<AstTextureOperation>(); } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/TextureDescriptor.cs b/Ryujinx.Graphics.Shader/TextureDescriptor.cs index 484fa1bc..bfcdde59 100644 --- a/Ryujinx.Graphics.Shader/TextureDescriptor.cs +++ b/Ryujinx.Graphics.Shader/TextureDescriptor.cs @@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Shader { public string Name { get; } - public TextureTarget Target { get; } + public SamplerType Type { get; } public int HandleIndex { get; } @@ -13,10 +13,10 @@ namespace Ryujinx.Graphics.Shader public int CbufSlot { get; } public int CbufOffset { get; } - public TextureDescriptor(string name, TextureTarget target, int hIndex) + public TextureDescriptor(string name, SamplerType type, int hIndex) { Name = name; - Target = target; + Type = type; HandleIndex = hIndex; IsBindless = false; @@ -25,10 +25,10 @@ namespace Ryujinx.Graphics.Shader CbufOffset = 0; } - public TextureDescriptor(string name, TextureTarget target, int cbufSlot, int cbufOffset) + public TextureDescriptor(string name, SamplerType type, int cbufSlot, int cbufOffset) { Name = name; - Target = target; + Type = type; HandleIndex = 0; IsBindless = true; diff --git a/Ryujinx.Graphics.Shader/TextureTarget.cs b/Ryujinx.Graphics.Shader/TextureTarget.cs deleted file mode 100644 index 3642ef23..00000000 --- a/Ryujinx.Graphics.Shader/TextureTarget.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; - -namespace Ryujinx.Graphics.Shader -{ - [Flags] - public enum TextureTarget - { - Texture1D, - Texture2D, - Texture3D, - TextureCube, - - Mask = 0xff, - - Array = 1 << 8, - Multisample = 1 << 9, - Shadow = 1 << 10 - } - - static class TextureTargetExtensions - { - public static int GetDimensions(this TextureTarget type) - { - switch (type & TextureTarget.Mask) - { - case TextureTarget.Texture1D: return 1; - case TextureTarget.Texture2D: return 2; - case TextureTarget.Texture3D: return 3; - case TextureTarget.TextureCube: return 3; - } - - throw new ArgumentException($"Invalid texture type \"{type}\"."); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs index 4838b1e2..aaf618e9 100644 --- a/Ryujinx.Graphics.Shader/Translation/Translator.cs +++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs @@ -81,6 +81,7 @@ namespace Ryujinx.Graphics.Shader.Translation program.CBufferDescriptors, program.SBufferDescriptors, program.TextureDescriptors, + program.ImageDescriptors, sInfo.InterpolationQualifiers, sInfo.UsesInstanceId); |
