From ed97109f980c4f77b99926f110d15efa14f901cf Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 14 Apr 2019 13:56:23 -0300 Subject: [PATCH] Misc. fixes on texture instructions --- .../Glsl/Instructions/InstGenMemory.cs | 86 ++++++++++++------- .../Shader/CodeGen/Glsl/NumberFormatter.cs | 10 +++ .../Shader/Decoders/OpCodeTable.cs | 4 +- Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs | 4 +- .../Shader/Decoders/OpCodeTexture.cs | 8 +- Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs | 10 ++- .../Shader/Decoders/OpCodeTld4.cs | 2 - .../Shader/Instructions/InstEmitTexture.cs | 45 +++++++--- 8 files changed, 111 insertions(+), 58 deletions(-) diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs index 9523a1184c..79f80057ff 100644 --- a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs @@ -34,8 +34,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions bool isMultisample = (texOp.Type & TextureType.Multisample) != 0; bool isShadow = (texOp.Type & TextureType.Shadow) != 0; - string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp); - string texCall = intCoords ? "texelFetch" : "texture"; if (isGather) @@ -56,6 +54,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions texCall += "Offsets"; } + string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp); + texCall += "(" + samplerName; int coordsCount = texOp.Type.GetCoordsCount(); @@ -69,6 +69,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions arrayIndexElem = pCount++; } + //The sampler 1D shadow overload expects a + //dummy value on the middle of the vector, who knows why... + bool hasDummy1DShadowElem = texOp.Type == (TextureType.Texture1D | TextureType.Shadow); + + if (hasDummy1DShadowElem) + { + pCount++; + } + if (isShadow && !isGather) { pCount++; @@ -97,42 +106,46 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions texCall += ", " + str; } - string AssembleVector(int count, VariableType type) + VariableType coordType = intCoords ? VariableType.S32 : VariableType.F32; + + string AssemblePVector(int count) { if (count > 1) { - string[] vecElems = new string[count]; + string[] elems = new string[count]; for (int index = 0; index < count; index++) { if (arrayIndexElem == index) { - arrayIndexElem = -1; + elems[index] = Src(VariableType.S32); - vecElems[index] = Src(VariableType.S32); - - if (type == VariableType.F32) + if (!intCoords) { - vecElems[index] = "float(" + vecElems[index] + ")"; + elems[index] = "float(" + elems[index] + ")"; } } + else if (index == 1 && hasDummy1DShadowElem) + { + elems[index] = NumberFormatter.FormatFloat(0); + } else { - vecElems[index] = Src(type); + elems[index] = Src(coordType); } } - string prefix = type == VariableType.F32 ? string.Empty : "i"; + string prefix = intCoords ? "i" : string.Empty; - return prefix + "vec" + count + "(" + string.Join(", ", vecElems) + ")"; + return prefix + "vec" + count + "(" + string.Join(", ", elems) + ")"; } else { - return Src(type); + return Src(coordType); } } - Append(AssembleVector(pCount, intCoords ? VariableType.S32 : VariableType.F32)); + Append(AssemblePVector(pCount)); if (hasExtraCompareArg) { @@ -143,33 +156,42 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions { Append(Src(VariableType.S32)); } - - if (hasLodLevel) + else if (hasLodLevel) { - Append(Src(intCoords ? VariableType.S32 : VariableType.F32)); + Append(Src(coordType)); + } + + string AssembleOffsetVector(int count) + { + if (count > 1) + { + string[] elems = new string[count]; + + for (int index = 0; index < count; index++) + { + elems[index] = Src(VariableType.S32); + } + + return "ivec" + count + "(" + string.Join(", ", elems) + ")"; + } + else + { + return Src(VariableType.S32); + } } if (hasOffset) { - Append(AssembleVector(coordsCount, VariableType.S32)); + Append(AssembleOffsetVector(coordsCount)); } else if (hasOffsets) { - const int gatherTexelsCount = 4; + texCall += $", ivec{coordsCount}[4]("; - texCall += $", ivec{coordsCount}[{gatherTexelsCount}]("; - - for (int index = 0; index < gatherTexelsCount; index++) - { - texCall += AssembleVector(coordsCount, VariableType.S32); - - if (index < gatherTexelsCount - 1) - { - texCall += ", "; - } - } - - texCall += ")"; + texCall += AssembleOffsetVector(coordsCount) + ", "; + texCall += AssembleOffsetVector(coordsCount) + ", "; + texCall += AssembleOffsetVector(coordsCount) + ", "; + texCall += AssembleOffsetVector(coordsCount) + ")"; } if (hasLodBias) diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs index 40827768d8..2ec44277c3 100644 --- a/Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs @@ -34,6 +34,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl return true; } + public static string FormatFloat(float value) + { + if (!TryFormatFloat(value, out string formatted)) + { + throw new ArgumentException("Failed to convert float value to string."); + } + + return formatted; + } + public static bool TryFormatFloat(float value, out string formatted) { if (float.IsNaN(value) || float.IsInfinity(value)) diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTable.cs index 5b8306cfd4..d588ce8ee8 100644 --- a/Ryujinx.Graphics/Shader/Decoders/OpCodeTable.cs +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTable.cs @@ -139,8 +139,8 @@ namespace Ryujinx.Graphics.Shader.Decoders Set("1101x00xxxxxxx", InstEmit.Texs, typeof(OpCodeTexs)); Set("1101x01xxxxxxx", InstEmit.Texs, typeof(OpCodeTlds)); Set("1101x11100xxxx", InstEmit.Texs, typeof(OpCodeTld4s)); - Set("1101110000111x", InstEmit.Tld, typeof(OpCodeTld)); - Set("1101110100111x", InstEmit.Tld_B, typeof(OpCodeTld)); + Set("11011100xx111x", InstEmit.Tld, typeof(OpCodeTld)); + Set("11011101xx111x", InstEmit.Tld_B, typeof(OpCodeTld)); Set("110010xxxx111x", InstEmit.Tld4, typeof(OpCodeTld4)); Set("1101111101001x", InstEmit.Txq, typeof(OpCodeTex)); Set("1101111101010x", InstEmit.Txq_B, typeof(OpCodeTex)); diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs index 75a28b3a7f..da8756b91c 100644 --- a/Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs @@ -4,11 +4,11 @@ namespace Ryujinx.Graphics.Shader.Decoders { class OpCodeTex : OpCodeTexture { - public bool HasDepthCompare { get; } - public OpCodeTex(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) { HasDepthCompare = opCode.Extract(50); + + HasOffset = opCode.Extract(54); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTexture.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTexture.cs index 2b617b6602..7a7e8f46e7 100644 --- a/Ryujinx.Graphics/Shader/Decoders/OpCodeTexture.cs +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTexture.cs @@ -16,10 +16,12 @@ namespace Ryujinx.Graphics.Shader.Decoders public int Immediate { get; } - public bool HasOffset { get; } - public TextureLodMode LodMode { get; protected set; } + public bool HasOffset { get; protected set; } + public bool HasDepthCompare { get; protected set; } + public bool IsMultisample { get; protected set; } + public OpCodeTexture(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) { Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr); @@ -34,8 +36,6 @@ namespace Ryujinx.Graphics.Shader.Decoders Immediate = opCode.Extract(36, 13); - HasOffset = opCode.Extract(54); - LodMode = (TextureLodMode)opCode.Extract(55, 3); } } diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs index e0846a05d9..61bd900b2d 100644 --- a/Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs @@ -4,13 +4,17 @@ namespace Ryujinx.Graphics.Shader.Decoders { class OpCodeTld : OpCodeTexture { - public bool IsMultisample { get; } - public OpCodeTld(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) { + HasOffset = opCode.Extract(35); + IsMultisample = opCode.Extract(50); - LodMode = (TextureLodMode)(opCode.Extract(55, 1) + TextureLodMode.LodZero); + bool isLL = opCode.Extract(55); + + LodMode = isLL + ? TextureLodMode.LodLevel + : TextureLodMode.LodZero; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4.cs index f5e1a80e5a..485edf936b 100644 --- a/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4.cs +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4.cs @@ -4,8 +4,6 @@ namespace Ryujinx.Graphics.Shader.Decoders { class OpCodeTld4 : OpCodeTexture { - public bool HasDepthCompare { get; } - public TextureGatherOffset Offset { get; } public int GatherCompIndex { get; } diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs index 9b0f05db1c..b69ff3beb4 100644 --- a/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs @@ -64,6 +64,16 @@ namespace Ryujinx.Graphics.Shader.Instructions return context.Copy(Register(rbIndex++, RegisterType.Gpr)); } + void AddTextureOffset(int coordsCount, int stride, int size) + { + Operand packedOffs = Rb(); + + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * stride), Const(size))); + } + } + TextureType type; TextureFlags flags; @@ -161,10 +171,14 @@ namespace Ryujinx.Graphics.Shader.Instructions break; case TexelLoadScalarType.Texture2DLodZeroOffset: - case TexelLoadScalarType.Texture2DLodZeroMultisample: sourcesList.Add(Ra()); sourcesList.Add(Ra()); sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture2DLodZeroMultisample: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); sourcesList.Add(Rb()); break; @@ -192,9 +206,13 @@ namespace Ryujinx.Graphics.Shader.Instructions sourcesList.Add(Ra()); sourcesList.Add(Ra()); sourcesList.Add(Rb()); - sourcesList.Add(Rb()); break; } + + if ((flags & TextureFlags.Offset) != 0) + { + AddTextureOffset(type.GetCoordsCount(), 4, 4); + } } else if (op is OpCodeTld4s tld4sOp) { @@ -221,12 +239,7 @@ namespace Ryujinx.Graphics.Shader.Instructions if (tld4sOp.HasOffset) { - Operand packedOffs = Rb(); - - for (int index = 0; index < type.GetCoordsCount(); index++) - { - sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 8), Const(6))); - } + AddTextureOffset(type.GetCoordsCount(), 8, 6); flags |= TextureFlags.Offset; } @@ -361,6 +374,8 @@ namespace Ryujinx.Graphics.Shader.Instructions if (op.HasDepthCompare) { sourcesList.Add(Rb()); + + type |= TextureType.Shadow; } if (op.Offset != TextureGatherOffset.None) @@ -568,14 +583,16 @@ namespace Ryujinx.Graphics.Shader.Instructions Operand packedOffs = op.HasOffset ? Rb() : null; - if (op is OpCodeTex texOp && texOp.HasDepthCompare) + if (op.HasDepthCompare) { sourcesList.Add(Rb()); + + type |= TextureType.Shadow; } - if (op.LodMode == TextureLodMode.LodZero || - op.LodMode == TextureLodMode.LodLevel || - op.LodMode == TextureLodMode.LodLevelA) + if ((op.LodMode == TextureLodMode.LodZero || + op.LodMode == TextureLodMode.LodLevel || + op.LodMode == TextureLodMode.LodLevelA) && !op.IsMultisample) { sourcesList.Add(lodValue); @@ -600,9 +617,11 @@ namespace Ryujinx.Graphics.Shader.Instructions flags |= TextureFlags.LodBias; } - if (op is OpCodeTld tldOp && tldOp.IsMultisample) + if (op.IsMultisample) { sourcesList.Add(Rb()); + + type |= TextureType.Multisample; } Operand[] sources = sourcesList.ToArray();