forked from Mirror/Ryujinx
aef25980a7
* Salieri: Add blacklist system and blacklist shaders using bindless Currently the shader cache doesn't have the right format to support bindless textures correctly and may cache shaders that it cannot rebuild after host invalidation. This PR address the issue by blacklisting shaders using bindless textures. THis also support detection of already cached broken shader and handle removal of those. * Move to a feature flags design to avoid intrusive changes in the translator This remove the auto correct behaviour * Reduce diff on TranslationFlags * Reduce comma on last entry of TranslationFlags * Fix inverted logic and remove leftovers * remove debug edits oops
144 lines
4.7 KiB
C#
144 lines
4.7 KiB
C#
using Ryujinx.Graphics.Shader.Decoders;
|
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
|
using System.Collections.Generic;
|
|
|
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
|
using static Ryujinx.Graphics.Shader.Translation.Translator;
|
|
|
|
namespace Ryujinx.Graphics.Shader.Translation
|
|
{
|
|
public class TranslatorContext
|
|
{
|
|
private readonly Block[][] _cfg;
|
|
private ShaderConfig _config;
|
|
|
|
public ulong Address { get; }
|
|
|
|
public ShaderStage Stage => _config.Stage;
|
|
public int Size => _config.Size;
|
|
|
|
public FeatureFlags UsedFeatures => _config.UsedFeatures;
|
|
|
|
public HashSet<int> TextureHandlesForCache => _config.TextureHandlesForCache;
|
|
|
|
public IGpuAccessor GpuAccessor => _config.GpuAccessor;
|
|
|
|
internal TranslatorContext(ulong address, Block[][] cfg, ShaderConfig config)
|
|
{
|
|
Address = address;
|
|
_config = config;
|
|
_cfg = cfg;
|
|
}
|
|
|
|
private static bool IsUserAttribute(Operand operand)
|
|
{
|
|
return operand != null &&
|
|
operand.Type == OperandType.Attribute &&
|
|
operand.Value >= AttributeConsts.UserAttributeBase &&
|
|
operand.Value < AttributeConsts.UserAttributeEnd;
|
|
}
|
|
|
|
private static FunctionCode[] Combine(FunctionCode[] a, FunctionCode[] b)
|
|
{
|
|
// Here we combine two shaders.
|
|
// For shader A:
|
|
// - All user attribute stores on shader A are turned into copies to a
|
|
// temporary variable. It's assumed that shader B will consume them.
|
|
// - All return instructions are turned into branch instructions, the
|
|
// branch target being the start of the shader B code.
|
|
// For shader B:
|
|
// - All user attribute loads on shader B are turned into copies from a
|
|
// temporary variable, as long that attribute is written by shader A.
|
|
FunctionCode[] output = new FunctionCode[a.Length + b.Length - 1];
|
|
|
|
List<Operation> ops = new List<Operation>(a.Length + b.Length);
|
|
|
|
Operand[] temps = new Operand[AttributeConsts.UserAttributesCount * 4];
|
|
|
|
Operand lblB = Label();
|
|
|
|
for (int index = 0; index < a[0].Code.Length; index++)
|
|
{
|
|
Operation operation = a[0].Code[index];
|
|
|
|
if (IsUserAttribute(operation.Dest))
|
|
{
|
|
int tIndex = (operation.Dest.Value - AttributeConsts.UserAttributeBase) / 4;
|
|
|
|
Operand temp = temps[tIndex];
|
|
|
|
if (temp == null)
|
|
{
|
|
temp = Local();
|
|
|
|
temps[tIndex] = temp;
|
|
}
|
|
|
|
operation.Dest = temp;
|
|
}
|
|
|
|
if (operation.Inst == Instruction.Return)
|
|
{
|
|
ops.Add(new Operation(Instruction.Branch, lblB));
|
|
}
|
|
else
|
|
{
|
|
ops.Add(operation);
|
|
}
|
|
}
|
|
|
|
ops.Add(new Operation(Instruction.MarkLabel, lblB));
|
|
|
|
for (int index = 0; index < b[0].Code.Length; index++)
|
|
{
|
|
Operation operation = b[0].Code[index];
|
|
|
|
for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
|
|
{
|
|
Operand src = operation.GetSource(srcIndex);
|
|
|
|
if (IsUserAttribute(src))
|
|
{
|
|
Operand temp = temps[(src.Value - AttributeConsts.UserAttributeBase) / 4];
|
|
|
|
if (temp != null)
|
|
{
|
|
operation.SetSource(srcIndex, temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
ops.Add(operation);
|
|
}
|
|
|
|
output[0] = new FunctionCode(ops.ToArray());
|
|
|
|
for (int i = 1; i < a.Length; i++)
|
|
{
|
|
output[i] = a[i];
|
|
}
|
|
|
|
for (int i = 1; i < b.Length; i++)
|
|
{
|
|
output[a.Length + i - 1] = b[i];
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
public ShaderProgram Translate(out ShaderProgramInfo shaderProgramInfo, TranslatorContext other = null)
|
|
{
|
|
FunctionCode[] code = EmitShader(_cfg, _config);
|
|
|
|
if (other != null)
|
|
{
|
|
_config.SetUsedFeature(other._config.UsedFeatures);
|
|
TextureHandlesForCache.UnionWith(other.TextureHandlesForCache);
|
|
|
|
code = Combine(EmitShader(other._cfg, other._config), code);
|
|
}
|
|
|
|
return Translator.Translate(code, _config, out shaderProgramInfo);
|
|
}
|
|
}
|
|
}
|