Support non-constant texture offsets on non-NVIDIA gpus
This commit is contained in:
parent
3323a3a042
commit
f2c85c5d58
11 changed files with 319 additions and 33 deletions
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
using static Ryujinx.Graphics.Shader.Translation.GlobalMemory;
|
||||
|
@ -23,13 +24,18 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
if (UsesGlobalMemory(operation.Inst))
|
||||
{
|
||||
node = LowerGlobal(node, config);
|
||||
node = RewriteGlobalAccess(node, config);
|
||||
}
|
||||
|
||||
if (!config.Capabilities.SupportsNonConstantTextureOffset && operation.Inst == Instruction.TextureSample)
|
||||
{
|
||||
node = RewriteTextureSample(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static LinkedListNode<INode> LowerGlobal(LinkedListNode<INode> node, ShaderConfig config)
|
||||
private static LinkedListNode<INode> RewriteGlobalAccess(LinkedListNode<INode> node, ShaderConfig config)
|
||||
{
|
||||
Operation operation = (Operation)node.Value;
|
||||
|
||||
|
@ -117,5 +123,217 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static LinkedListNode<INode> RewriteTextureSample(LinkedListNode<INode> node)
|
||||
{
|
||||
TextureOperation texOp = (TextureOperation)node.Value;
|
||||
|
||||
bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0;
|
||||
bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0;
|
||||
|
||||
if (!(hasOffset || hasOffsets))
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
||||
bool isGather = (texOp.Flags & TextureFlags.Gather) != 0;
|
||||
bool hasDerivatives = (texOp.Flags & TextureFlags.Derivatives) != 0;
|
||||
bool hasLodBias = (texOp.Flags & TextureFlags.LodBias) != 0;
|
||||
bool hasLodLevel = (texOp.Flags & TextureFlags.LodLevel) != 0;
|
||||
|
||||
bool isArray = (texOp.Type & SamplerType.Array) != 0;
|
||||
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
|
||||
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
|
||||
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
|
||||
|
||||
int coordsCount = texOp.Type.GetDimensions();
|
||||
|
||||
int offsetsCount = coordsCount * (hasOffsets ? 4 : 1);
|
||||
|
||||
Operand[] offsets = new Operand[offsetsCount];
|
||||
Operand[] sources = new Operand[texOp.SourcesCount - offsetsCount];
|
||||
|
||||
int srcIndex = 0;
|
||||
int dstIndex = 0;
|
||||
|
||||
int copyCount = 0;
|
||||
|
||||
if (isBindless || isIndexed)
|
||||
{
|
||||
copyCount++;
|
||||
}
|
||||
|
||||
Operand[] lodSources = new Operand[copyCount + coordsCount];
|
||||
|
||||
for (int index = 0; index < lodSources.Length; index++)
|
||||
{
|
||||
lodSources[index] = texOp.GetSource(index);
|
||||
}
|
||||
|
||||
copyCount += coordsCount;
|
||||
|
||||
if (isArray)
|
||||
{
|
||||
copyCount++;
|
||||
}
|
||||
|
||||
if (isShadow)
|
||||
{
|
||||
copyCount++;
|
||||
}
|
||||
|
||||
if (hasDerivatives)
|
||||
{
|
||||
copyCount += coordsCount * 2;
|
||||
}
|
||||
|
||||
if (isMultisample)
|
||||
{
|
||||
copyCount++;
|
||||
}
|
||||
else if (hasLodLevel)
|
||||
{
|
||||
copyCount++;
|
||||
}
|
||||
|
||||
for (int index = 0; index < copyCount; index++)
|
||||
{
|
||||
sources[dstIndex++] = texOp.GetSource(srcIndex++);
|
||||
}
|
||||
|
||||
bool areAllOffsetsConstant = true;
|
||||
|
||||
for (int index = 0; index < offsetsCount; index++)
|
||||
{
|
||||
Operand offset = texOp.GetSource(srcIndex++);
|
||||
|
||||
areAllOffsetsConstant &= offset.Type == OperandType.Constant;
|
||||
|
||||
offsets[index] = offset;
|
||||
}
|
||||
|
||||
if (areAllOffsetsConstant)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
if (hasLodBias)
|
||||
{
|
||||
sources[dstIndex++] = texOp.GetSource(srcIndex++);
|
||||
}
|
||||
|
||||
if (isGather && !isShadow)
|
||||
{
|
||||
sources[dstIndex++] = texOp.GetSource(srcIndex++);
|
||||
}
|
||||
|
||||
Operand Int(Operand value)
|
||||
{
|
||||
Operand res = Local();
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.ConvertFPToS32, res, value));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Operand Float(Operand value)
|
||||
{
|
||||
Operand res = Local();
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.ConvertS32ToFP, res, value));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Operand lod = Local();
|
||||
|
||||
node.List.AddBefore(node, new TextureOperation(
|
||||
Instruction.Lod,
|
||||
texOp.Type,
|
||||
texOp.Flags,
|
||||
texOp.Handle,
|
||||
1,
|
||||
lod,
|
||||
lodSources));
|
||||
|
||||
int coordsIndex = isBindless || isIndexed ? 1 : 0;
|
||||
|
||||
for (int index = 0; index < coordsCount; index++)
|
||||
{
|
||||
Operand coordSize = Local();
|
||||
|
||||
Operand[] texSizeSources;
|
||||
|
||||
if (isBindless || isIndexed)
|
||||
{
|
||||
texSizeSources = new Operand[] { sources[0], Int(lod) };
|
||||
}
|
||||
else
|
||||
{
|
||||
texSizeSources = new Operand[] { Int(lod) };
|
||||
}
|
||||
|
||||
node.List.AddBefore(node, new TextureOperation(
|
||||
Instruction.TextureSize,
|
||||
texOp.Type,
|
||||
texOp.Flags,
|
||||
texOp.Handle,
|
||||
index,
|
||||
coordSize,
|
||||
texSizeSources));
|
||||
|
||||
Operand offset = Local();
|
||||
|
||||
Operand intOffset = offsets[index + (hasOffsets ? texOp.Index * coordsCount : 0)];
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Divide, offset, Float(intOffset), Float(coordSize)));
|
||||
|
||||
Operand source = sources[coordsIndex + index];
|
||||
|
||||
Operand coordPlusOffset = Local();
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.FP | Instruction.Add, coordPlusOffset, source, offset));
|
||||
|
||||
sources[coordsIndex + index] = coordPlusOffset;
|
||||
}
|
||||
|
||||
int componentIndex;
|
||||
|
||||
if (isGather && !isShadow)
|
||||
{
|
||||
Operand gatherComponent = sources[dstIndex - 1];
|
||||
|
||||
Debug.Assert(gatherComponent.Type == OperandType.Constant);
|
||||
|
||||
componentIndex = gatherComponent.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
componentIndex = texOp.Index;
|
||||
}
|
||||
|
||||
TextureOperation newTexOp = new TextureOperation(
|
||||
Instruction.TextureSample,
|
||||
texOp.Type,
|
||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||
texOp.Handle,
|
||||
componentIndex,
|
||||
texOp.Dest,
|
||||
sources);
|
||||
|
||||
for (int index = 0; index < texOp.SourcesCount; index++)
|
||||
{
|
||||
texOp.SetSource(index, null);
|
||||
}
|
||||
|
||||
LinkedListNode<INode> oldNode = node;
|
||||
|
||||
node = node.List.AddBefore(node, newTexOp);
|
||||
|
||||
node.List.Remove(oldNode);
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue