diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitMemory.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitMemory.cs index f899d556fa..d81e97a13f 100644 --- a/Ryujinx.Graphics/Shader/Instructions/InstEmitMemory.cs +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitMemory.cs @@ -1,8 +1,6 @@ using Ryujinx.Graphics.Shader.Decoders; using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.Translation; -using System; -using System.Collections.Generic; using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; @@ -136,759 +134,5 @@ namespace Ryujinx.Graphics.Shader.Instructions context.EndPrimitive(); } } - - public static void Tex(EmitterContext context) - { - Tex(context, TextureFlags.None); - } - - public static void Tex_B(EmitterContext context) - { - Tex(context, TextureFlags.Bindless); - } - - public static void Tld(EmitterContext context) - { - Tex(context, TextureFlags.IntCoords); - } - - public static void Tld_B(EmitterContext context) - { - Tex(context, TextureFlags.IntCoords | TextureFlags.Bindless); - } - - public static void Texs(EmitterContext context) - { - OpCodeTextureScalar op = (OpCodeTextureScalar)context.CurrOp; - - if (op.Rd0.IsRZ && op.Rd1.IsRZ) - { - return; - } - - List sourcesList = new List(); - - 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)); - } - - TextureType type; - TextureFlags flags; - - if (op is OpCodeTexs texsOp) - { - type = GetTextureType (texsOp.Type); - flags = GetTextureFlags(texsOp.Type); - - if ((type & TextureType.Array) != 0) - { - Operand arrayIndex = Ra(); - - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - - sourcesList.Add(arrayIndex); - - if ((type & TextureType.Shadow) != 0) - { - sourcesList.Add(Rb()); - } - - if ((flags & TextureFlags.LodLevel) != 0) - { - sourcesList.Add(ConstF(0)); - } - } - else - { - switch (texsOp.Type) - { - case TextureScalarType.Texture1DLodZero: - sourcesList.Add(Ra()); - break; - - case TextureScalarType.Texture2D: - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - break; - - case TextureScalarType.Texture2DLodZero: - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - sourcesList.Add(ConstF(0)); - break; - - case TextureScalarType.Texture2DLodLevel: - case TextureScalarType.Texture2DDepthCompare: - case TextureScalarType.Texture3D: - case TextureScalarType.TextureCube: - sourcesList.Add(Ra()); - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - break; - - case TextureScalarType.Texture2DLodZeroDepthCompare: - case TextureScalarType.Texture3DLodZero: - sourcesList.Add(Ra()); - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - sourcesList.Add(ConstF(0)); - break; - - case TextureScalarType.Texture2DLodLevelDepthCompare: - case TextureScalarType.TextureCubeLodLevel: - sourcesList.Add(Ra()); - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - sourcesList.Add(Rb()); - break; - } - } - } - else if (op is OpCodeTlds tldsOp) - { - type = GetTextureType (tldsOp.Type); - flags = GetTextureFlags(tldsOp.Type) | TextureFlags.IntCoords; - - switch (tldsOp.Type) - { - case TexelLoadScalarType.Texture1DLodZero: - sourcesList.Add(Ra()); - sourcesList.Add(Const(0)); - break; - - case TexelLoadScalarType.Texture1DLodLevel: - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - break; - - case TexelLoadScalarType.Texture2DLodZero: - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - sourcesList.Add(Const(0)); - break; - - case TexelLoadScalarType.Texture2DLodZeroOffset: - case TexelLoadScalarType.Texture2DLodZeroMultisample: - sourcesList.Add(Ra()); - sourcesList.Add(Ra()); - sourcesList.Add(Const(0)); - sourcesList.Add(Rb()); - break; - - case TexelLoadScalarType.Texture2DLodLevel: - sourcesList.Add(Ra()); - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - break; - - case TexelLoadScalarType.Texture3DLodZero: - sourcesList.Add(Ra()); - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - sourcesList.Add(Const(0)); - break; - - case TexelLoadScalarType.Texture2DArrayLodZero: - sourcesList.Add(Rb()); - sourcesList.Add(Rb()); - sourcesList.Add(Ra()); - sourcesList.Add(Const(0)); - break; - - case TexelLoadScalarType.Texture2DLodLevelOffset: - sourcesList.Add(Ra()); - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - sourcesList.Add(Rb()); - break; - } - } - else if (op is OpCodeTld4s tld4sOp) - { - if (!(tld4sOp.HasDepthCompare || tld4sOp.HasOffset)) - { - sourcesList.Add(Ra()); - sourcesList.Add(Rb()); - } - else - { - sourcesList.Add(Ra()); - sourcesList.Add(Ra()); - } - - type = TextureType.Texture2D; - flags = TextureFlags.Gather; - - if (tld4sOp.HasDepthCompare) - { - sourcesList.Add(Rb()); - - type |= TextureType.Shadow; - } - - if (tld4sOp.HasOffset) - { - Operand packedOffs = Rb(); - - for (int index = 0; index < type.GetCoordsCount(); index++) - { - sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 8), Const(6))); - } - - flags |= TextureFlags.Offset; - } - - sourcesList.Add(Const(tld4sOp.GatherCompIndex)); - } - else - { - throw new InvalidOperationException($"Invalid opcode type \"{op.GetType().Name}\"."); - } - - Operand[] sources = sourcesList.ToArray(); - - Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) }; - Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) }; - - int destIncrement = 0; - - Operand GetDest() - { - int high = destIncrement >> 1; - int low = destIncrement & 1; - - destIncrement++; - - if (op.IsFp16) - { - return high != 0 - ? (rd1[low] = Local()) - : (rd0[low] = Local()); - } - else - { - int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index; - - if (rdIndex < RegisterConsts.RegisterZeroIndex) - { - rdIndex += low; - } - - return Register(rdIndex, RegisterType.Gpr); - } - } - - int handle = op.Immediate; - - for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) - { - if ((compMask & 1) != 0) - { - Operand dest = GetDest(); - - TextureOperation operation = new TextureOperation( - Instruction.TextureSample, - type, - flags, - handle, - compIndex, - dest, - sources); - - context.Add(operation); - } - } - - if (op.IsFp16) - { - context.Copy(Register(op.Rd0), context.PackHalf2x16(rd0[0], rd0[1])); - context.Copy(Register(op.Rd1), context.PackHalf2x16(rd1[0], rd1[1])); - } - } - - public static void Tld4(EmitterContext context) - { - OpCodeTld4 op = (OpCodeTld4)context.CurrOp; - - if (op.Rd.IsRZ) - { - return; - } - - 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)); - } - - Operand arrayIndex = op.IsArray ? Ra() : null; - - List sourcesList = new List(); - - TextureType type = GetTextureType(op.Dimensions); - - TextureFlags flags = TextureFlags.Gather; - - int coordsCount = type.GetCoordsCount(); - - for (int index = 0; index < coordsCount; index++) - { - sourcesList.Add(Ra()); - } - - if (op.IsArray) - { - sourcesList.Add(arrayIndex); - - type |= TextureType.Array; - } - - Operand[] packedOffs = new Operand[2]; - - packedOffs[0] = op.Offset != TextureGatherOffset.None ? Rb() : null; - packedOffs[1] = op.Offset == TextureGatherOffset.Offsets ? Rb() : null; - - if (op.HasDepthCompare) - { - sourcesList.Add(Rb()); - } - - if (op.Offset != TextureGatherOffset.None) - { - int offsetTexelsCount = op.Offset == TextureGatherOffset.Offsets ? 4 : 1; - - for (int index = 0; index < coordsCount * offsetTexelsCount; index++) - { - Operand packed = packedOffs[(index >> 2) & 1]; - - sourcesList.Add(context.BitfieldExtractS32(packed, Const((index & 3) * 8), Const(6))); - } - - flags |= op.Offset == TextureGatherOffset.Offsets - ? TextureFlags.Offsets - : TextureFlags.Offset; - } - - sourcesList.Add(Const(op.GatherCompIndex)); - - Operand[] sources = sourcesList.ToArray(); - - int rdIndex = op.Rd.Index; - - Operand GetDest() - { - if (rdIndex > RegisterConsts.RegisterZeroIndex) - { - return Const(0); - } - - return Register(rdIndex++, RegisterType.Gpr); - } - - int handle = op.Immediate; - - for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) - { - if ((compMask & 1) != 0) - { - Operand dest = GetDest(); - - TextureOperation operation = new TextureOperation( - Instruction.TextureSample, - type, - flags, - handle, - compIndex, - dest, - sources); - - context.Add(operation); - } - } - } - - public static void Txq(EmitterContext context) - { - Txq(context, bindless: false); - } - - public static void Txq_B(EmitterContext context) - { - Txq(context, bindless: true); - } - - private static void Txq(EmitterContext context, bool bindless) - { - OpCodeTex op = (OpCodeTex)context.CurrOp; - - if (op.Rd.IsRZ) - { - return; - } - - TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6); - - //TODO: Validate and use property. - Instruction inst = Instruction.TextureSize; - - TextureType type = TextureType.Texture2D; - - TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None; - - int raIndex = op.Ra.Index; - - Operand Ra() - { - if (raIndex > RegisterConsts.RegisterZeroIndex) - { - return Const(0); - } - - return context.Copy(Register(raIndex++, RegisterType.Gpr)); - } - - List sourcesList = new List(); - - if (bindless) - { - sourcesList.Add(Ra()); - } - - sourcesList.Add(Ra()); - - Operand[] sources = sourcesList.ToArray(); - - int rdIndex = op.Rd.Index; - - Operand GetDest() - { - if (rdIndex > RegisterConsts.RegisterZeroIndex) - { - return Const(0); - } - - return Register(rdIndex++, RegisterType.Gpr); - } - - int handle = !bindless ? op.Immediate : 0; - - for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) - { - if ((compMask & 1) != 0) - { - Operand dest = GetDest(); - - TextureOperation operation = new TextureOperation( - inst, - type, - flags, - handle, - compIndex, - dest, - sources); - - context.Add(operation); - } - } - } - - private static void Tex(EmitterContext context, TextureFlags flags) - { - OpCodeTexture op = (OpCodeTexture)context.CurrOp; - - bool isBindless = (flags & TextureFlags.Bindless) != 0; - bool intCoords = (flags & TextureFlags.IntCoords) != 0; - - if (op.Rd.IsRZ) - { - return; - } - - 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)); - } - - Operand arrayIndex = op.IsArray ? Ra() : null; - - List sourcesList = new List(); - - if (isBindless) - { - sourcesList.Add(Rb()); - } - - TextureType type = GetTextureType(op.Dimensions); - - int coordsCount = type.GetCoordsCount(); - - for (int index = 0; index < coordsCount; index++) - { - sourcesList.Add(Ra()); - } - - if (op.IsArray) - { - sourcesList.Add(arrayIndex); - - type |= TextureType.Array; - } - - bool hasLod = op.LodMode > TextureLodMode.LodZero; - - Operand lodValue = hasLod ? Rb() : ConstF(0); - - Operand packedOffs = op.HasOffset ? Rb() : null; - - if (op is OpCodeTex texOp && texOp.HasDepthCompare) - { - sourcesList.Add(Rb()); - } - - if (op.LodMode == TextureLodMode.LodZero || - op.LodMode == TextureLodMode.LodLevel || - op.LodMode == TextureLodMode.LodLevelA) - { - sourcesList.Add(lodValue); - - flags |= TextureFlags.LodLevel; - } - - if (op.HasOffset) - { - for (int index = 0; index < coordsCount; index++) - { - sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4))); - } - - flags |= TextureFlags.Offset; - } - - if (op.LodMode == TextureLodMode.LodBias || - op.LodMode == TextureLodMode.LodBiasA) - { - sourcesList.Add(lodValue); - - flags |= TextureFlags.LodBias; - } - - if (op is OpCodeTld tldOp && tldOp.IsMultisample) - { - sourcesList.Add(Rb()); - } - - Operand[] sources = sourcesList.ToArray(); - - int rdIndex = op.Rd.Index; - - Operand GetDest() - { - if (rdIndex > RegisterConsts.RegisterZeroIndex) - { - return Const(0); - } - - return Register(rdIndex++, RegisterType.Gpr); - } - - int handle = !isBindless ? op.Immediate : 0; - - for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) - { - if ((compMask & 1) != 0) - { - Operand dest = GetDest(); - - TextureOperation operation = new TextureOperation( - Instruction.TextureSample, - type, - flags, - handle, - compIndex, - dest, - sources); - - context.Add(operation); - } - } - } - - private static TextureType GetTextureType(TextureDimensions dimensions) - { - switch (dimensions) - { - case TextureDimensions.Texture1D: return TextureType.Texture1D; - case TextureDimensions.Texture2D: return TextureType.Texture2D; - case TextureDimensions.Texture3D: return TextureType.Texture3D; - case TextureDimensions.TextureCube: return TextureType.TextureCube; - } - - throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\"."); - } - - private static TextureType GetTextureType(TextureScalarType type) - { - switch (type) - { - case TextureScalarType.Texture1DLodZero: - return TextureType.Texture1D; - - case TextureScalarType.Texture2D: - case TextureScalarType.Texture2DLodZero: - case TextureScalarType.Texture2DLodLevel: - return TextureType.Texture2D; - - case TextureScalarType.Texture2DDepthCompare: - case TextureScalarType.Texture2DLodLevelDepthCompare: - case TextureScalarType.Texture2DLodZeroDepthCompare: - return TextureType.Texture2D | TextureType.Shadow; - - case TextureScalarType.Texture2DArray: - case TextureScalarType.Texture2DArrayLodZero: - return TextureType.Texture2D | TextureType.Array; - - case TextureScalarType.Texture2DArrayLodZeroDepthCompare: - return TextureType.Texture2D | TextureType.Array | TextureType.Shadow; - - case TextureScalarType.Texture3D: - case TextureScalarType.Texture3DLodZero: - return TextureType.Texture3D; - - case TextureScalarType.TextureCube: - case TextureScalarType.TextureCubeLodLevel: - return TextureType.TextureCube; - } - - throw new ArgumentException($"Invalid texture type \"{type}\"."); - } - - private static TextureType GetTextureType(TexelLoadScalarType type) - { - switch (type) - { - case TexelLoadScalarType.Texture1DLodZero: - case TexelLoadScalarType.Texture1DLodLevel: - return TextureType.Texture1D; - - case TexelLoadScalarType.Texture2DLodZero: - case TexelLoadScalarType.Texture2DLodZeroOffset: - case TexelLoadScalarType.Texture2DLodLevel: - case TexelLoadScalarType.Texture2DLodLevelOffset: - return TextureType.Texture2D; - - case TexelLoadScalarType.Texture2DLodZeroMultisample: - return TextureType.Texture2D | TextureType.Multisample; - - case TexelLoadScalarType.Texture3DLodZero: - return TextureType.Texture3D; - - case TexelLoadScalarType.Texture2DArrayLodZero: - return TextureType.Texture2D | TextureType.Array; - } - - throw new ArgumentException($"Invalid texture type \"{type}\"."); - } - - private static TextureFlags GetTextureFlags(TextureScalarType type) - { - switch (type) - { - case TextureScalarType.Texture1DLodZero: - case TextureScalarType.Texture2DLodZero: - case TextureScalarType.Texture2DLodLevel: - case TextureScalarType.Texture2DLodLevelDepthCompare: - case TextureScalarType.Texture2DLodZeroDepthCompare: - case TextureScalarType.Texture2DArrayLodZero: - case TextureScalarType.Texture2DArrayLodZeroDepthCompare: - case TextureScalarType.Texture3DLodZero: - case TextureScalarType.TextureCubeLodLevel: - return TextureFlags.LodLevel; - - case TextureScalarType.Texture2D: - case TextureScalarType.Texture2DDepthCompare: - case TextureScalarType.Texture2DArray: - case TextureScalarType.Texture3D: - case TextureScalarType.TextureCube: - return TextureFlags.None; - } - - throw new ArgumentException($"Invalid texture type \"{type}\"."); - } - - private static TextureFlags GetTextureFlags(TexelLoadScalarType type) - { - switch (type) - { - case TexelLoadScalarType.Texture1DLodZero: - case TexelLoadScalarType.Texture1DLodLevel: - case TexelLoadScalarType.Texture2DLodZero: - case TexelLoadScalarType.Texture2DLodLevel: - case TexelLoadScalarType.Texture2DLodZeroMultisample: - case TexelLoadScalarType.Texture3DLodZero: - case TexelLoadScalarType.Texture2DArrayLodZero: - return TextureFlags.LodLevel; - - case TexelLoadScalarType.Texture2DLodZeroOffset: - case TexelLoadScalarType.Texture2DLodLevelOffset: - return TextureFlags.LodLevel | TextureFlags.Offset; - } - - throw new ArgumentException($"Invalid texture type \"{type}\"."); - } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs new file mode 100644 index 0000000000..9b0f05db1c --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs @@ -0,0 +1,767 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; +using System; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void Tex(EmitterContext context) + { + Tex(context, TextureFlags.None); + } + + public static void Tex_B(EmitterContext context) + { + Tex(context, TextureFlags.Bindless); + } + + public static void Tld(EmitterContext context) + { + Tex(context, TextureFlags.IntCoords); + } + + public static void Tld_B(EmitterContext context) + { + Tex(context, TextureFlags.IntCoords | TextureFlags.Bindless); + } + + public static void Texs(EmitterContext context) + { + OpCodeTextureScalar op = (OpCodeTextureScalar)context.CurrOp; + + if (op.Rd0.IsRZ && op.Rd1.IsRZ) + { + return; + } + + List sourcesList = new List(); + + 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)); + } + + TextureType type; + TextureFlags flags; + + if (op is OpCodeTexs texsOp) + { + type = GetTextureType (texsOp.Type); + flags = GetTextureFlags(texsOp.Type); + + if ((type & TextureType.Array) != 0) + { + Operand arrayIndex = Ra(); + + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + + sourcesList.Add(arrayIndex); + + if ((type & TextureType.Shadow) != 0) + { + sourcesList.Add(Rb()); + } + + if ((flags & TextureFlags.LodLevel) != 0) + { + sourcesList.Add(ConstF(0)); + } + } + else + { + switch (texsOp.Type) + { + case TextureScalarType.Texture1DLodZero: + sourcesList.Add(Ra()); + break; + + case TextureScalarType.Texture2D: + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + break; + + case TextureScalarType.Texture2DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(ConstF(0)); + break; + + case TextureScalarType.Texture2DLodLevel: + case TextureScalarType.Texture2DDepthCompare: + case TextureScalarType.Texture3D: + case TextureScalarType.TextureCube: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + break; + + case TextureScalarType.Texture2DLodZeroDepthCompare: + case TextureScalarType.Texture3DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(ConstF(0)); + break; + + case TextureScalarType.Texture2DLodLevelDepthCompare: + case TextureScalarType.TextureCubeLodLevel: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(Rb()); + break; + } + } + } + else if (op is OpCodeTlds tldsOp) + { + type = GetTextureType (tldsOp.Type); + flags = GetTextureFlags(tldsOp.Type) | TextureFlags.IntCoords; + + switch (tldsOp.Type) + { + case TexelLoadScalarType.Texture1DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture1DLodLevel: + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + break; + + case TexelLoadScalarType.Texture2DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture2DLodZeroOffset: + case TexelLoadScalarType.Texture2DLodZeroMultisample: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Const(0)); + sourcesList.Add(Rb()); + break; + + case TexelLoadScalarType.Texture2DLodLevel: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + break; + + case TexelLoadScalarType.Texture3DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture2DArrayLodZero: + sourcesList.Add(Rb()); + sourcesList.Add(Rb()); + sourcesList.Add(Ra()); + sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture2DLodLevelOffset: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(Rb()); + break; + } + } + else if (op is OpCodeTld4s tld4sOp) + { + if (!(tld4sOp.HasDepthCompare || tld4sOp.HasOffset)) + { + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + } + else + { + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + } + + type = TextureType.Texture2D; + flags = TextureFlags.Gather; + + if (tld4sOp.HasDepthCompare) + { + sourcesList.Add(Rb()); + + type |= TextureType.Shadow; + } + + if (tld4sOp.HasOffset) + { + Operand packedOffs = Rb(); + + for (int index = 0; index < type.GetCoordsCount(); index++) + { + sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 8), Const(6))); + } + + flags |= TextureFlags.Offset; + } + + sourcesList.Add(Const(tld4sOp.GatherCompIndex)); + } + else + { + throw new InvalidOperationException($"Invalid opcode type \"{op.GetType().Name}\"."); + } + + Operand[] sources = sourcesList.ToArray(); + + Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) }; + Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) }; + + int destIncrement = 0; + + Operand GetDest() + { + int high = destIncrement >> 1; + int low = destIncrement & 1; + + destIncrement++; + + if (op.IsFp16) + { + return high != 0 + ? (rd1[low] = Local()) + : (rd0[low] = Local()); + } + else + { + int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index; + + if (rdIndex < RegisterConsts.RegisterZeroIndex) + { + rdIndex += low; + } + + return Register(rdIndex, RegisterType.Gpr); + } + } + + int handle = op.Immediate; + + for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + Operand dest = GetDest(); + + TextureOperation operation = new TextureOperation( + Instruction.TextureSample, + type, + flags, + handle, + compIndex, + dest, + sources); + + context.Add(operation); + } + } + + if (op.IsFp16) + { + context.Copy(Register(op.Rd0), context.PackHalf2x16(rd0[0], rd0[1])); + context.Copy(Register(op.Rd1), context.PackHalf2x16(rd1[0], rd1[1])); + } + } + + public static void Tld4(EmitterContext context) + { + OpCodeTld4 op = (OpCodeTld4)context.CurrOp; + + if (op.Rd.IsRZ) + { + return; + } + + 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)); + } + + Operand arrayIndex = op.IsArray ? Ra() : null; + + List sourcesList = new List(); + + TextureType type = GetTextureType(op.Dimensions); + + TextureFlags flags = TextureFlags.Gather; + + int coordsCount = type.GetCoordsCount(); + + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(Ra()); + } + + if (op.IsArray) + { + sourcesList.Add(arrayIndex); + + type |= TextureType.Array; + } + + Operand[] packedOffs = new Operand[2]; + + packedOffs[0] = op.Offset != TextureGatherOffset.None ? Rb() : null; + packedOffs[1] = op.Offset == TextureGatherOffset.Offsets ? Rb() : null; + + if (op.HasDepthCompare) + { + sourcesList.Add(Rb()); + } + + if (op.Offset != TextureGatherOffset.None) + { + int offsetTexelsCount = op.Offset == TextureGatherOffset.Offsets ? 4 : 1; + + for (int index = 0; index < coordsCount * offsetTexelsCount; index++) + { + Operand packed = packedOffs[(index >> 2) & 1]; + + sourcesList.Add(context.BitfieldExtractS32(packed, Const((index & 3) * 8), Const(6))); + } + + flags |= op.Offset == TextureGatherOffset.Offsets + ? TextureFlags.Offsets + : TextureFlags.Offset; + } + + sourcesList.Add(Const(op.GatherCompIndex)); + + Operand[] sources = sourcesList.ToArray(); + + int rdIndex = op.Rd.Index; + + Operand GetDest() + { + if (rdIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return Register(rdIndex++, RegisterType.Gpr); + } + + int handle = op.Immediate; + + for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + Operand dest = GetDest(); + + TextureOperation operation = new TextureOperation( + Instruction.TextureSample, + type, + flags, + handle, + compIndex, + dest, + sources); + + context.Add(operation); + } + } + } + + public static void Txq(EmitterContext context) + { + Txq(context, bindless: false); + } + + public static void Txq_B(EmitterContext context) + { + Txq(context, bindless: true); + } + + private static void Txq(EmitterContext context, bool bindless) + { + OpCodeTex op = (OpCodeTex)context.CurrOp; + + if (op.Rd.IsRZ) + { + return; + } + + TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6); + + //TODO: Validate and use property. + Instruction inst = Instruction.TextureSize; + + TextureType type = TextureType.Texture2D; + + TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None; + + int raIndex = op.Ra.Index; + + Operand Ra() + { + if (raIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(raIndex++, RegisterType.Gpr)); + } + + List sourcesList = new List(); + + if (bindless) + { + sourcesList.Add(Ra()); + } + + sourcesList.Add(Ra()); + + Operand[] sources = sourcesList.ToArray(); + + int rdIndex = op.Rd.Index; + + Operand GetDest() + { + if (rdIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return Register(rdIndex++, RegisterType.Gpr); + } + + int handle = !bindless ? op.Immediate : 0; + + for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + Operand dest = GetDest(); + + TextureOperation operation = new TextureOperation( + inst, + type, + flags, + handle, + compIndex, + dest, + sources); + + context.Add(operation); + } + } + } + + private static void Tex(EmitterContext context, TextureFlags flags) + { + OpCodeTexture op = (OpCodeTexture)context.CurrOp; + + bool isBindless = (flags & TextureFlags.Bindless) != 0; + bool intCoords = (flags & TextureFlags.IntCoords) != 0; + + if (op.Rd.IsRZ) + { + return; + } + + 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)); + } + + Operand arrayIndex = op.IsArray ? Ra() : null; + + List sourcesList = new List(); + + if (isBindless) + { + sourcesList.Add(Rb()); + } + + TextureType type = GetTextureType(op.Dimensions); + + int coordsCount = type.GetCoordsCount(); + + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(Ra()); + } + + if (op.IsArray) + { + sourcesList.Add(arrayIndex); + + type |= TextureType.Array; + } + + bool hasLod = op.LodMode > TextureLodMode.LodZero; + + Operand lodValue = hasLod ? Rb() : ConstF(0); + + Operand packedOffs = op.HasOffset ? Rb() : null; + + if (op is OpCodeTex texOp && texOp.HasDepthCompare) + { + sourcesList.Add(Rb()); + } + + if (op.LodMode == TextureLodMode.LodZero || + op.LodMode == TextureLodMode.LodLevel || + op.LodMode == TextureLodMode.LodLevelA) + { + sourcesList.Add(lodValue); + + flags |= TextureFlags.LodLevel; + } + + if (op.HasOffset) + { + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4))); + } + + flags |= TextureFlags.Offset; + } + + if (op.LodMode == TextureLodMode.LodBias || + op.LodMode == TextureLodMode.LodBiasA) + { + sourcesList.Add(lodValue); + + flags |= TextureFlags.LodBias; + } + + if (op is OpCodeTld tldOp && tldOp.IsMultisample) + { + sourcesList.Add(Rb()); + } + + Operand[] sources = sourcesList.ToArray(); + + int rdIndex = op.Rd.Index; + + Operand GetDest() + { + if (rdIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return Register(rdIndex++, RegisterType.Gpr); + } + + int handle = !isBindless ? op.Immediate : 0; + + for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + Operand dest = GetDest(); + + TextureOperation operation = new TextureOperation( + Instruction.TextureSample, + type, + flags, + handle, + compIndex, + dest, + sources); + + context.Add(operation); + } + } + } + + private static TextureType GetTextureType(TextureDimensions dimensions) + { + switch (dimensions) + { + case TextureDimensions.Texture1D: return TextureType.Texture1D; + case TextureDimensions.Texture2D: return TextureType.Texture2D; + case TextureDimensions.Texture3D: return TextureType.Texture3D; + case TextureDimensions.TextureCube: return TextureType.TextureCube; + } + + throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\"."); + } + + private static TextureType GetTextureType(TextureScalarType type) + { + switch (type) + { + case TextureScalarType.Texture1DLodZero: + return TextureType.Texture1D; + + case TextureScalarType.Texture2D: + case TextureScalarType.Texture2DLodZero: + case TextureScalarType.Texture2DLodLevel: + return TextureType.Texture2D; + + case TextureScalarType.Texture2DDepthCompare: + case TextureScalarType.Texture2DLodLevelDepthCompare: + case TextureScalarType.Texture2DLodZeroDepthCompare: + return TextureType.Texture2D | TextureType.Shadow; + + case TextureScalarType.Texture2DArray: + case TextureScalarType.Texture2DArrayLodZero: + return TextureType.Texture2D | TextureType.Array; + + case TextureScalarType.Texture2DArrayLodZeroDepthCompare: + return TextureType.Texture2D | TextureType.Array | TextureType.Shadow; + + case TextureScalarType.Texture3D: + case TextureScalarType.Texture3DLodZero: + return TextureType.Texture3D; + + case TextureScalarType.TextureCube: + case TextureScalarType.TextureCubeLodLevel: + return TextureType.TextureCube; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + + private static TextureType GetTextureType(TexelLoadScalarType type) + { + switch (type) + { + case TexelLoadScalarType.Texture1DLodZero: + case TexelLoadScalarType.Texture1DLodLevel: + return TextureType.Texture1D; + + case TexelLoadScalarType.Texture2DLodZero: + case TexelLoadScalarType.Texture2DLodZeroOffset: + case TexelLoadScalarType.Texture2DLodLevel: + case TexelLoadScalarType.Texture2DLodLevelOffset: + return TextureType.Texture2D; + + case TexelLoadScalarType.Texture2DLodZeroMultisample: + return TextureType.Texture2D | TextureType.Multisample; + + case TexelLoadScalarType.Texture3DLodZero: + return TextureType.Texture3D; + + case TexelLoadScalarType.Texture2DArrayLodZero: + return TextureType.Texture2D | TextureType.Array; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + + private static TextureFlags GetTextureFlags(TextureScalarType type) + { + switch (type) + { + case TextureScalarType.Texture1DLodZero: + case TextureScalarType.Texture2DLodZero: + case TextureScalarType.Texture2DLodLevel: + case TextureScalarType.Texture2DLodLevelDepthCompare: + case TextureScalarType.Texture2DLodZeroDepthCompare: + case TextureScalarType.Texture2DArrayLodZero: + case TextureScalarType.Texture2DArrayLodZeroDepthCompare: + case TextureScalarType.Texture3DLodZero: + case TextureScalarType.TextureCubeLodLevel: + return TextureFlags.LodLevel; + + case TextureScalarType.Texture2D: + case TextureScalarType.Texture2DDepthCompare: + case TextureScalarType.Texture2DArray: + case TextureScalarType.Texture3D: + case TextureScalarType.TextureCube: + return TextureFlags.None; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + + private static TextureFlags GetTextureFlags(TexelLoadScalarType type) + { + switch (type) + { + case TexelLoadScalarType.Texture1DLodZero: + case TexelLoadScalarType.Texture1DLodLevel: + case TexelLoadScalarType.Texture2DLodZero: + case TexelLoadScalarType.Texture2DLodLevel: + case TexelLoadScalarType.Texture2DLodZeroMultisample: + case TexelLoadScalarType.Texture3DLodZero: + case TexelLoadScalarType.Texture2DArrayLodZero: + return TextureFlags.LodLevel; + + case TexelLoadScalarType.Texture2DLodZeroOffset: + case TexelLoadScalarType.Texture2DLodLevelOffset: + return TextureFlags.LodLevel | TextureFlags.Offset; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + } +} \ No newline at end of file