Force reciprocal operation with value biased by constant to be precise on macOS (#5110)

* Force operations to be precise in some cases on SPIR-V

* Make it a bit more strict, add comments

* Shader cache version bump
This commit is contained in:
gdkchan 2023-05-26 15:19:37 -03:00 committed by GitHub
parent e6658c133c
commit 3b375525fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 67 additions and 14 deletions

View file

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2; private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 5102; private const uint CodeGenVersion = 5110;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View file

@ -2245,7 +2245,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{ {
var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2)); var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2));
if (!context.Config.GpuAccessor.QueryHostReducedPrecision()) if (!context.Config.GpuAccessor.QueryHostReducedPrecision() || operation.ForcePrecise)
{ {
context.Decorate(result, Decoration.NoContraction); context.Decorate(result, Decoration.NoContraction);
} }
@ -2256,7 +2256,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{ {
var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2)); var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2));
if (!context.Config.GpuAccessor.QueryHostReducedPrecision()) if (!context.Config.GpuAccessor.QueryHostReducedPrecision() || operation.ForcePrecise)
{ {
context.Decorate(result, Decoration.NoContraction); context.Decorate(result, Decoration.NoContraction);
} }
@ -2316,7 +2316,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{ {
var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2), context.GetFP64(src3)); var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2), context.GetFP64(src3));
if (!context.Config.GpuAccessor.QueryHostReducedPrecision()) if (!context.Config.GpuAccessor.QueryHostReducedPrecision() || operation.ForcePrecise)
{ {
context.Decorate(result, Decoration.NoContraction); context.Decorate(result, Decoration.NoContraction);
} }
@ -2327,7 +2327,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{ {
var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2), context.GetFP32(src3)); var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2), context.GetFP32(src3));
if (!context.Config.GpuAccessor.QueryHostReducedPrecision()) if (!context.Config.GpuAccessor.QueryHostReducedPrecision() || operation.ForcePrecise)
{ {
context.Decorate(result, Decoration.NoContraction); context.Decorate(result, Decoration.NoContraction);
} }

View file

@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public Instruction Inst { get; private set; } public Instruction Inst { get; private set; }
public StorageKind StorageKind { get; } public StorageKind StorageKind { get; }
public bool ForcePrecise { get; set; }
private Operand[] _dests; private Operand[] _dests;
public Operand Dest public Operand Dest

View file

@ -10,6 +10,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{ {
public Instruction Inst { get; } public Instruction Inst { get; }
public StorageKind StorageKind { get; } public StorageKind StorageKind { get; }
public bool ForcePrecise { get; }
public int Index { get; } public int Index { get; }
@ -17,10 +18,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
public int SourcesCount => _sources.Length; public int SourcesCount => _sources.Length;
public AstOperation(Instruction inst, StorageKind storageKind, IAstNode[] sources, int sourcesCount) public AstOperation(Instruction inst, StorageKind storageKind, bool forcePrecise, IAstNode[] sources, int sourcesCount)
{ {
Inst = inst; Inst = inst;
StorageKind = storageKind; StorageKind = storageKind;
ForcePrecise = forcePrecise;
_sources = sources; _sources = sources;
for (int index = 0; index < sources.Length; index++) for (int index = 0; index < sources.Length; index++)
@ -38,12 +40,18 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Index = 0; Index = 0;
} }
public AstOperation(Instruction inst, StorageKind storageKind, int index, IAstNode[] sources, int sourcesCount) : this(inst, storageKind, sources, sourcesCount) public AstOperation(
Instruction inst,
StorageKind storageKind,
bool forcePrecise,
int index,
IAstNode[] sources,
int sourcesCount) : this(inst, storageKind, forcePrecise, sources, sourcesCount)
{ {
Index = index; Index = index;
} }
public AstOperation(Instruction inst, params IAstNode[] sources) : this(inst, StorageKind.None, sources, sources.Length) public AstOperation(Instruction inst, params IAstNode[] sources) : this(inst, StorageKind.None, false, sources, sources.Length)
{ {
} }

View file

@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
int cbufSlot, int cbufSlot,
int handle, int handle,
int index, int index,
params IAstNode[] sources) : base(inst, StorageKind.None, index, sources, sources.Length) params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
{ {
Type = type; Type = type;
Format = format; Format = format;

View file

@ -156,7 +156,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
} }
else else
{ {
source = new AstOperation(inst, operation.StorageKind, operation.Index, sources, operation.SourcesCount); source = new AstOperation(
inst,
operation.StorageKind,
operation.ForcePrecise,
operation.Index,
sources,
operation.SourcesCount);
} }
AggregateType destElemType = destType; AggregateType destElemType = destType;
@ -179,7 +185,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
dest.VarType = destElemType; dest.VarType = destElemType;
context.AddNode(new AstAssignment(dest, new AstOperation(Instruction.VectorExtract, StorageKind.None, new[] { destVec, index }, 2))); context.AddNode(new AstAssignment(dest, new AstOperation(Instruction.VectorExtract, StorageKind.None, false, new[] { destVec, index }, 2)));
} }
} }
else if (operation.Dest != null) else if (operation.Dest != null)
@ -227,7 +233,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
} }
else if (!isCopy) else if (!isCopy)
{ {
source = new AstOperation(inst, operation.StorageKind, operation.Index, sources, operation.SourcesCount); source = new AstOperation(
inst,
operation.StorageKind,
operation.ForcePrecise,
operation.Index,
sources,
operation.SourcesCount);
} }
else else
{ {
@ -248,7 +260,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
} }
else else
{ {
context.AddNode(new AstOperation(inst, operation.StorageKind, operation.Index, sources, operation.SourcesCount)); context.AddNode(new AstOperation(
inst,
operation.StorageKind,
operation.ForcePrecise,
operation.Index,
sources,
operation.SourcesCount));
} }
// Those instructions needs to be emulated by using helper functions, // Those instructions needs to be emulated by using helper functions,

View file

@ -319,7 +319,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
new AstOperand(OperandType.Constant, elemIndex) new AstOperand(OperandType.Constant, elemIndex)
}; };
return new AstOperation(Instruction.Load, StorageKind.ConstantBuffer, sources, sources.Length); return new AstOperation(Instruction.Load, StorageKind.ConstantBuffer, false, sources, sources.Length);
} }
return GetOperand(operand); return GetOperand(operand);

View file

@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public static void RunPass(HelperFunctionManager hfm, BasicBlock[] blocks, ShaderConfig config) public static void RunPass(HelperFunctionManager hfm, BasicBlock[] blocks, ShaderConfig config)
{ {
bool isVertexShader = config.Stage == ShaderStage.Vertex; bool isVertexShader = config.Stage == ShaderStage.Vertex;
bool isImpreciseFragmentShader = config.Stage == ShaderStage.Fragment && config.GpuAccessor.QueryHostReducedPrecision();
bool hasConstantBufferDrawParameters = config.GpuAccessor.QueryHasConstantBufferDrawParameters(); bool hasConstantBufferDrawParameters = config.GpuAccessor.QueryHasConstantBufferDrawParameters();
bool hasVectorIndexingBug = config.GpuAccessor.QueryHostHasVectorIndexingBug(); bool hasVectorIndexingBug = config.GpuAccessor.QueryHostHasVectorIndexingBug();
bool supportsSnormBufferTextureFormat = config.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat(); bool supportsSnormBufferTextureFormat = config.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat();
@ -45,6 +46,11 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
} }
if (isImpreciseFragmentShader)
{
EnableForcePreciseIfNeeded(operation);
}
if (hasVectorIndexingBug) if (hasVectorIndexingBug)
{ {
InsertVectorComponentSelect(node, config); InsertVectorComponentSelect(node, config);
@ -81,6 +87,25 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
} }
private static void EnableForcePreciseIfNeeded(Operation operation)
{
// There are some cases where a small bias is added to values to prevent division by zero.
// When operating with reduced precision, it is possible for this bias to get rounded to 0
// and cause a division by zero.
// To prevent that, we force those operations to be precise even if the host wants
// imprecise operations for performance.
if (operation.Inst == (Instruction.FP32 | Instruction.Divide) &&
operation.GetSource(0).Type == OperandType.Constant &&
operation.GetSource(0).AsFloat() == 1f &&
operation.GetSource(1).AsgOp is Operation addOp &&
addOp.Inst == (Instruction.FP32 | Instruction.Add) &&
addOp.GetSource(1).Type == OperandType.Constant)
{
addOp.ForcePrecise = true;
}
}
private static void InsertVectorComponentSelect(LinkedListNode<INode> node, ShaderConfig config) private static void InsertVectorComponentSelect(LinkedListNode<INode> node, ShaderConfig config)
{ {
Operation operation = (Operation)node.Value; Operation operation = (Operation)node.Value;