HelperFunctionManager.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2. using System;
  3. using System.Collections.Generic;
  4. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  5. namespace Ryujinx.Graphics.Shader.Translation
  6. {
  7. class HelperFunctionManager
  8. {
  9. private readonly List<Function> _functionList;
  10. private readonly Dictionary<HelperFunctionName, int> _functionIds;
  11. private readonly ShaderStage _stage;
  12. public HelperFunctionManager(List<Function> functionList, ShaderStage stage)
  13. {
  14. _functionList = functionList;
  15. _functionIds = new Dictionary<HelperFunctionName, int>();
  16. _stage = stage;
  17. }
  18. public int GetOrCreateFunctionId(HelperFunctionName functionName)
  19. {
  20. if (_functionIds.TryGetValue(functionName, out int functionId))
  21. {
  22. return functionId;
  23. }
  24. Function function = GenerateFunction(functionName);
  25. functionId = _functionList.Count;
  26. _functionList.Add(function);
  27. _functionIds.Add(functionName, functionId);
  28. return functionId;
  29. }
  30. private Function GenerateFunction(HelperFunctionName functionName)
  31. {
  32. return functionName switch
  33. {
  34. HelperFunctionName.TexelFetchScale => GenerateTexelFetchScaleFunction(),
  35. HelperFunctionName.TextureSizeUnscale => GenerateTextureSizeUnscaleFunction(),
  36. _ => throw new ArgumentException($"Invalid function name {functionName}")
  37. };
  38. }
  39. private Function GenerateTexelFetchScaleFunction()
  40. {
  41. EmitterContext context = new EmitterContext();
  42. Operand input = Argument(0);
  43. Operand samplerIndex = Argument(1);
  44. Operand index = GetScaleIndex(context, samplerIndex);
  45. Operand scale = context.Load(StorageKind.ConstantBuffer, 0, Const((int)SupportBufferField.RenderScale), index);
  46. Operand scaleIsOne = context.FPCompareEqual(scale, ConstF(1f));
  47. Operand lblScaleNotOne = Label();
  48. context.BranchIfFalse(lblScaleNotOne, scaleIsOne);
  49. context.Return(input);
  50. context.MarkLabel(lblScaleNotOne);
  51. int inArgumentsCount;
  52. if (_stage == ShaderStage.Fragment)
  53. {
  54. Operand scaleIsLessThanZero = context.FPCompareLess(scale, ConstF(0f));
  55. Operand lblScaleGreaterOrEqualZero = Label();
  56. context.BranchIfFalse(lblScaleGreaterOrEqualZero, scaleIsLessThanZero);
  57. Operand negScale = context.FPNegate(scale);
  58. Operand inputScaled = context.FPMultiply(context.IConvertS32ToFP32(input), negScale);
  59. Operand fragCoordX = context.Load(StorageKind.Input, IoVariable.FragmentCoord, null, Const(0));
  60. Operand fragCoordY = context.Load(StorageKind.Input, IoVariable.FragmentCoord, null, Const(1));
  61. Operand fragCoord = context.ConditionalSelect(Argument(2), fragCoordY, fragCoordX);
  62. Operand inputBias = context.FPModulo(fragCoord, negScale);
  63. Operand inputWithBias = context.FPAdd(inputScaled, inputBias);
  64. context.Return(context.FP32ConvertToS32(inputWithBias));
  65. context.MarkLabel(lblScaleGreaterOrEqualZero);
  66. inArgumentsCount = 3;
  67. }
  68. else
  69. {
  70. inArgumentsCount = 2;
  71. }
  72. Operand inputScaled2 = context.FPMultiply(context.IConvertS32ToFP32(input), scale);
  73. context.Return(context.FP32ConvertToS32(inputScaled2));
  74. return new Function(ControlFlowGraph.Create(context.GetOperations()).Blocks, "TexelFetchScale", true, inArgumentsCount, 0);
  75. }
  76. private Function GenerateTextureSizeUnscaleFunction()
  77. {
  78. EmitterContext context = new EmitterContext();
  79. Operand input = Argument(0);
  80. Operand samplerIndex = Argument(1);
  81. Operand index = GetScaleIndex(context, samplerIndex);
  82. Operand scale = context.FPAbsolute(context.Load(StorageKind.ConstantBuffer, 0, Const((int)SupportBufferField.RenderScale), index));
  83. Operand scaleIsOne = context.FPCompareEqual(scale, ConstF(1f));
  84. Operand lblScaleNotOne = Label();
  85. context.BranchIfFalse(lblScaleNotOne, scaleIsOne);
  86. context.Return(input);
  87. context.MarkLabel(lblScaleNotOne);
  88. Operand inputUnscaled = context.FPDivide(context.IConvertS32ToFP32(input), scale);
  89. context.Return(context.FP32ConvertToS32(inputUnscaled));
  90. return new Function(ControlFlowGraph.Create(context.GetOperations()).Blocks, "TextureSizeUnscale", true, 2, 0);
  91. }
  92. private Operand GetScaleIndex(EmitterContext context, Operand index)
  93. {
  94. switch (_stage)
  95. {
  96. case ShaderStage.Vertex:
  97. Operand fragScaleCount = context.Load(StorageKind.ConstantBuffer, 0, Const((int)SupportBufferField.FragmentRenderScaleCount));
  98. return context.IAdd(Const(1), context.IAdd(index, fragScaleCount));
  99. default:
  100. return context.IAdd(Const(1), index);
  101. }
  102. }
  103. }
  104. }