Misc. fixes on texture instructions

This commit is contained in:
gdkchan 2019-04-14 13:56:23 -03:00
commit ed97109f98
8 changed files with 111 additions and 58 deletions

View file

@ -34,8 +34,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
bool isMultisample = (texOp.Type & TextureType.Multisample) != 0; bool isMultisample = (texOp.Type & TextureType.Multisample) != 0;
bool isShadow = (texOp.Type & TextureType.Shadow) != 0; bool isShadow = (texOp.Type & TextureType.Shadow) != 0;
string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp);
string texCall = intCoords ? "texelFetch" : "texture"; string texCall = intCoords ? "texelFetch" : "texture";
if (isGather) if (isGather)
@ -56,6 +54,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
texCall += "Offsets"; texCall += "Offsets";
} }
string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp);
texCall += "(" + samplerName; texCall += "(" + samplerName;
int coordsCount = texOp.Type.GetCoordsCount(); int coordsCount = texOp.Type.GetCoordsCount();
@ -69,6 +69,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
arrayIndexElem = pCount++; 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) if (isShadow && !isGather)
{ {
pCount++; pCount++;
@ -97,42 +106,46 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
texCall += ", " + str; texCall += ", " + str;
} }
string AssembleVector(int count, VariableType type) VariableType coordType = intCoords ? VariableType.S32 : VariableType.F32;
string AssemblePVector(int count)
{ {
if (count > 1) if (count > 1)
{ {
string[] vecElems = new string[count]; string[] elems = new string[count];
for (int index = 0; index < count; index++) for (int index = 0; index < count; index++)
{ {
if (arrayIndexElem == index) if (arrayIndexElem == index)
{ {
arrayIndexElem = -1; elems[index] = Src(VariableType.S32);
vecElems[index] = Src(VariableType.S32); if (!intCoords)
if (type == VariableType.F32)
{ {
vecElems[index] = "float(" + vecElems[index] + ")"; elems[index] = "float(" + elems[index] + ")";
} }
} }
else if (index == 1 && hasDummy1DShadowElem)
{
elems[index] = NumberFormatter.FormatFloat(0);
}
else 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 else
{ {
return Src(type); return Src(coordType);
} }
} }
Append(AssembleVector(pCount, intCoords ? VariableType.S32 : VariableType.F32)); Append(AssemblePVector(pCount));
if (hasExtraCompareArg) if (hasExtraCompareArg)
{ {
@ -143,33 +156,42 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{ {
Append(Src(VariableType.S32)); Append(Src(VariableType.S32));
} }
else if (hasLodLevel)
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) if (hasOffset)
{ {
Append(AssembleVector(coordsCount, VariableType.S32)); Append(AssembleOffsetVector(coordsCount));
} }
else if (hasOffsets) else if (hasOffsets)
{ {
const int gatherTexelsCount = 4; texCall += $", ivec{coordsCount}[4](";
texCall += $", ivec{coordsCount}[{gatherTexelsCount}]("; texCall += AssembleOffsetVector(coordsCount) + ", ";
texCall += AssembleOffsetVector(coordsCount) + ", ";
for (int index = 0; index < gatherTexelsCount; index++) texCall += AssembleOffsetVector(coordsCount) + ", ";
{ texCall += AssembleOffsetVector(coordsCount) + ")";
texCall += AssembleVector(coordsCount, VariableType.S32);
if (index < gatherTexelsCount - 1)
{
texCall += ", ";
}
}
texCall += ")";
} }
if (hasLodBias) if (hasLodBias)

View file

@ -34,6 +34,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return true; 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) public static bool TryFormatFloat(float value, out string formatted)
{ {
if (float.IsNaN(value) || float.IsInfinity(value)) if (float.IsNaN(value) || float.IsInfinity(value))

View file

@ -139,8 +139,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
Set("1101x00xxxxxxx", InstEmit.Texs, typeof(OpCodeTexs)); Set("1101x00xxxxxxx", InstEmit.Texs, typeof(OpCodeTexs));
Set("1101x01xxxxxxx", InstEmit.Texs, typeof(OpCodeTlds)); Set("1101x01xxxxxxx", InstEmit.Texs, typeof(OpCodeTlds));
Set("1101x11100xxxx", InstEmit.Texs, typeof(OpCodeTld4s)); Set("1101x11100xxxx", InstEmit.Texs, typeof(OpCodeTld4s));
Set("1101110000111x", InstEmit.Tld, typeof(OpCodeTld)); Set("11011100xx111x", InstEmit.Tld, typeof(OpCodeTld));
Set("1101110100111x", InstEmit.Tld_B, typeof(OpCodeTld)); Set("11011101xx111x", InstEmit.Tld_B, typeof(OpCodeTld));
Set("110010xxxx111x", InstEmit.Tld4, typeof(OpCodeTld4)); Set("110010xxxx111x", InstEmit.Tld4, typeof(OpCodeTld4));
Set("1101111101001x", InstEmit.Txq, typeof(OpCodeTex)); Set("1101111101001x", InstEmit.Txq, typeof(OpCodeTex));
Set("1101111101010x", InstEmit.Txq_B, typeof(OpCodeTex)); Set("1101111101010x", InstEmit.Txq_B, typeof(OpCodeTex));

View file

@ -4,11 +4,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
{ {
class OpCodeTex : OpCodeTexture class OpCodeTex : OpCodeTexture
{ {
public bool HasDepthCompare { get; }
public OpCodeTex(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) public OpCodeTex(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
{ {
HasDepthCompare = opCode.Extract(50); HasDepthCompare = opCode.Extract(50);
HasOffset = opCode.Extract(54);
} }
} }
} }

View file

@ -16,10 +16,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
public int Immediate { get; } public int Immediate { get; }
public bool HasOffset { get; }
public TextureLodMode LodMode { get; protected set; } 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) public OpCodeTexture(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
{ {
Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr); Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr);
@ -34,8 +36,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
Immediate = opCode.Extract(36, 13); Immediate = opCode.Extract(36, 13);
HasOffset = opCode.Extract(54);
LodMode = (TextureLodMode)opCode.Extract(55, 3); LodMode = (TextureLodMode)opCode.Extract(55, 3);
} }
} }

View file

@ -4,13 +4,17 @@ namespace Ryujinx.Graphics.Shader.Decoders
{ {
class OpCodeTld : OpCodeTexture class OpCodeTld : OpCodeTexture
{ {
public bool IsMultisample { get; }
public OpCodeTld(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) public OpCodeTld(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
{ {
HasOffset = opCode.Extract(35);
IsMultisample = opCode.Extract(50); IsMultisample = opCode.Extract(50);
LodMode = (TextureLodMode)(opCode.Extract(55, 1) + TextureLodMode.LodZero); bool isLL = opCode.Extract(55);
LodMode = isLL
? TextureLodMode.LodLevel
: TextureLodMode.LodZero;
} }
} }
} }

View file

@ -4,8 +4,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
{ {
class OpCodeTld4 : OpCodeTexture class OpCodeTld4 : OpCodeTexture
{ {
public bool HasDepthCompare { get; }
public TextureGatherOffset Offset { get; } public TextureGatherOffset Offset { get; }
public int GatherCompIndex { get; } public int GatherCompIndex { get; }

View file

@ -64,6 +64,16 @@ namespace Ryujinx.Graphics.Shader.Instructions
return context.Copy(Register(rbIndex++, RegisterType.Gpr)); 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; TextureType type;
TextureFlags flags; TextureFlags flags;
@ -161,10 +171,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
break; break;
case TexelLoadScalarType.Texture2DLodZeroOffset: case TexelLoadScalarType.Texture2DLodZeroOffset:
case TexelLoadScalarType.Texture2DLodZeroMultisample:
sourcesList.Add(Ra()); sourcesList.Add(Ra());
sourcesList.Add(Ra()); sourcesList.Add(Ra());
sourcesList.Add(Const(0)); sourcesList.Add(Const(0));
break;
case TexelLoadScalarType.Texture2DLodZeroMultisample:
sourcesList.Add(Ra());
sourcesList.Add(Ra());
sourcesList.Add(Rb()); sourcesList.Add(Rb());
break; break;
@ -192,9 +206,13 @@ namespace Ryujinx.Graphics.Shader.Instructions
sourcesList.Add(Ra()); sourcesList.Add(Ra());
sourcesList.Add(Ra()); sourcesList.Add(Ra());
sourcesList.Add(Rb()); sourcesList.Add(Rb());
sourcesList.Add(Rb());
break; break;
} }
if ((flags & TextureFlags.Offset) != 0)
{
AddTextureOffset(type.GetCoordsCount(), 4, 4);
}
} }
else if (op is OpCodeTld4s tld4sOp) else if (op is OpCodeTld4s tld4sOp)
{ {
@ -221,12 +239,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (tld4sOp.HasOffset) if (tld4sOp.HasOffset)
{ {
Operand packedOffs = Rb(); AddTextureOffset(type.GetCoordsCount(), 8, 6);
for (int index = 0; index < type.GetCoordsCount(); index++)
{
sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 8), Const(6)));
}
flags |= TextureFlags.Offset; flags |= TextureFlags.Offset;
} }
@ -361,6 +374,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (op.HasDepthCompare) if (op.HasDepthCompare)
{ {
sourcesList.Add(Rb()); sourcesList.Add(Rb());
type |= TextureType.Shadow;
} }
if (op.Offset != TextureGatherOffset.None) if (op.Offset != TextureGatherOffset.None)
@ -568,14 +583,16 @@ namespace Ryujinx.Graphics.Shader.Instructions
Operand packedOffs = op.HasOffset ? Rb() : null; Operand packedOffs = op.HasOffset ? Rb() : null;
if (op is OpCodeTex texOp && texOp.HasDepthCompare) if (op.HasDepthCompare)
{ {
sourcesList.Add(Rb()); sourcesList.Add(Rb());
type |= TextureType.Shadow;
} }
if (op.LodMode == TextureLodMode.LodZero || if ((op.LodMode == TextureLodMode.LodZero ||
op.LodMode == TextureLodMode.LodLevel || op.LodMode == TextureLodMode.LodLevel ||
op.LodMode == TextureLodMode.LodLevelA) op.LodMode == TextureLodMode.LodLevelA) && !op.IsMultisample)
{ {
sourcesList.Add(lodValue); sourcesList.Add(lodValue);
@ -600,9 +617,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
flags |= TextureFlags.LodBias; flags |= TextureFlags.LodBias;
} }
if (op is OpCodeTld tldOp && tldOp.IsMultisample) if (op.IsMultisample)
{ {
sourcesList.Add(Rb()); sourcesList.Add(Rb());
type |= TextureType.Multisample;
} }
Operand[] sources = sourcesList.ToArray(); Operand[] sources = sourcesList.ToArray();