ScalingHelpers.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2. using Ryujinx.Graphics.Shader.StructuredIr;
  3. using Ryujinx.Graphics.Shader.Translation;
  4. using static Spv.Specification;
  5. namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
  6. {
  7. using SpvInstruction = Spv.Generator.Instruction;
  8. static class ScalingHelpers
  9. {
  10. public static SpvInstruction ApplyScaling(
  11. CodeGenContext context,
  12. AstTextureOperation texOp,
  13. SpvInstruction vector,
  14. bool intCoords,
  15. bool isBindless,
  16. bool isIndexed,
  17. bool isArray,
  18. int pCount)
  19. {
  20. if (intCoords)
  21. {
  22. if (context.Config.Stage.SupportsRenderScale() &&
  23. !isBindless &&
  24. !isIndexed)
  25. {
  26. int index = texOp.Inst == Instruction.ImageLoad
  27. ? context.Config.GetTextureDescriptors().Length + context.Config.FindImageDescriptorIndex(texOp)
  28. : context.Config.FindTextureDescriptorIndex(texOp);
  29. if (pCount == 3 && isArray)
  30. {
  31. return ApplyScaling2DArray(context, vector, index);
  32. }
  33. else if (pCount == 2 && !isArray)
  34. {
  35. return ApplyScaling2D(context, vector, index);
  36. }
  37. }
  38. }
  39. return vector;
  40. }
  41. private static SpvInstruction ApplyScaling2DArray(CodeGenContext context, SpvInstruction vector, int index)
  42. {
  43. // The array index is not scaled, just x and y.
  44. var vectorXY = context.VectorShuffle(context.TypeVector(context.TypeS32(), 2), vector, vector, 0, 1);
  45. var vectorZ = context.CompositeExtract(context.TypeS32(), vector, 2);
  46. var vectorXYScaled = ApplyScaling2D(context, vectorXY, index);
  47. var vectorScaled = context.CompositeConstruct(context.TypeVector(context.TypeS32(), 3), vectorXYScaled, vectorZ);
  48. return vectorScaled;
  49. }
  50. private static SpvInstruction ApplyScaling2D(CodeGenContext context, SpvInstruction vector, int index)
  51. {
  52. var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32());
  53. var fieldIndex = context.Constant(context.TypeU32(), 4);
  54. var scaleIndex = context.Constant(context.TypeU32(), index);
  55. if (context.Config.Stage == ShaderStage.Vertex)
  56. {
  57. var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
  58. var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3));
  59. var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer);
  60. scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
  61. }
  62. scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));
  63. var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex);
  64. var scale = context.Load(context.TypeFP32(), scaleElemPointer);
  65. var ivector2Type = context.TypeVector(context.TypeS32(), 2);
  66. var localVector = context.CoordTemp;
  67. var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f));
  68. var mergeLabel = context.Label();
  69. if (context.Config.Stage == ShaderStage.Fragment)
  70. {
  71. var scaledInterpolatedLabel = context.Label();
  72. var scaledNoInterpolationLabel = context.Label();
  73. var needsInterpolation = context.FOrdLessThan(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 0f));
  74. context.SelectionMerge(mergeLabel, SelectionControlMask.MaskNone);
  75. context.BranchConditional(needsInterpolation, scaledInterpolatedLabel, scaledNoInterpolationLabel);
  76. // scale < 0.0
  77. context.AddLabel(scaledInterpolatedLabel);
  78. ApplyScalingInterpolated(context, localVector, vector, scale);
  79. context.Branch(mergeLabel);
  80. // scale >= 0.0
  81. context.AddLabel(scaledNoInterpolationLabel);
  82. ApplyScalingNoInterpolation(context, localVector, vector, scale);
  83. context.Branch(mergeLabel);
  84. context.AddLabel(mergeLabel);
  85. var passthroughLabel = context.Label();
  86. var finalMergeLabel = context.Label();
  87. context.SelectionMerge(finalMergeLabel, SelectionControlMask.MaskNone);
  88. context.BranchConditional(passthrough, passthroughLabel, finalMergeLabel);
  89. context.AddLabel(passthroughLabel);
  90. context.Store(localVector, vector);
  91. context.Branch(finalMergeLabel);
  92. context.AddLabel(finalMergeLabel);
  93. return context.Load(ivector2Type, localVector);
  94. }
  95. else
  96. {
  97. var passthroughLabel = context.Label();
  98. var scaledLabel = context.Label();
  99. context.SelectionMerge(mergeLabel, SelectionControlMask.MaskNone);
  100. context.BranchConditional(passthrough, passthroughLabel, scaledLabel);
  101. // scale == 1.0
  102. context.AddLabel(passthroughLabel);
  103. context.Store(localVector, vector);
  104. context.Branch(mergeLabel);
  105. // scale != 1.0
  106. context.AddLabel(scaledLabel);
  107. ApplyScalingNoInterpolation(context, localVector, vector, scale);
  108. context.Branch(mergeLabel);
  109. context.AddLabel(mergeLabel);
  110. return context.Load(ivector2Type, localVector);
  111. }
  112. }
  113. private static void ApplyScalingInterpolated(CodeGenContext context, SpvInstruction output, SpvInstruction vector, SpvInstruction scale)
  114. {
  115. var vector2Type = context.TypeVector(context.TypeFP32(), 2);
  116. var scaleNegated = context.FNegate(context.TypeFP32(), scale);
  117. var scaleVector = context.CompositeConstruct(vector2Type, scaleNegated, scaleNegated);
  118. var vectorFloat = context.ConvertSToF(vector2Type, vector);
  119. var vectorScaled = context.VectorTimesScalar(vector2Type, vectorFloat, scaleNegated);
  120. var fragCoordPointer = context.Inputs[AttributeConsts.PositionX];
  121. var fragCoord = context.Load(context.TypeVector(context.TypeFP32(), 4), fragCoordPointer);
  122. var fragCoordXY = context.VectorShuffle(vector2Type, fragCoord, fragCoord, 0, 1);
  123. var scaleMod = context.FMod(vector2Type, fragCoordXY, scaleVector);
  124. var vectorInterpolated = context.FAdd(vector2Type, vectorScaled, scaleMod);
  125. context.Store(output, context.ConvertFToS(context.TypeVector(context.TypeS32(), 2), vectorInterpolated));
  126. }
  127. private static void ApplyScalingNoInterpolation(CodeGenContext context, SpvInstruction output, SpvInstruction vector, SpvInstruction scale)
  128. {
  129. if (context.Config.Stage == ShaderStage.Vertex)
  130. {
  131. scale = context.GlslFAbs(context.TypeFP32(), scale);
  132. }
  133. var vector2Type = context.TypeVector(context.TypeFP32(), 2);
  134. var vectorFloat = context.ConvertSToF(vector2Type, vector);
  135. var vectorScaled = context.VectorTimesScalar(vector2Type, vectorFloat, scale);
  136. context.Store(output, context.ConvertFToS(context.TypeVector(context.TypeS32(), 2), vectorScaled));
  137. }
  138. public static SpvInstruction ApplyUnscaling(
  139. CodeGenContext context,
  140. AstTextureOperation texOp,
  141. SpvInstruction size,
  142. bool isBindless,
  143. bool isIndexed)
  144. {
  145. if (context.Config.Stage.SupportsRenderScale() &&
  146. !isBindless &&
  147. !isIndexed)
  148. {
  149. int index = context.Config.FindTextureDescriptorIndex(texOp);
  150. var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32());
  151. var fieldIndex = context.Constant(context.TypeU32(), 4);
  152. var scaleIndex = context.Constant(context.TypeU32(), index);
  153. if (context.Config.Stage == ShaderStage.Vertex)
  154. {
  155. var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
  156. var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3));
  157. var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer);
  158. scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
  159. }
  160. scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));
  161. var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex);
  162. var scale = context.GlslFAbs(context.TypeFP32(), context.Load(context.TypeFP32(), scaleElemPointer));
  163. var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f));
  164. var sizeFloat = context.ConvertSToF(context.TypeFP32(), size);
  165. var sizeUnscaled = context.FDiv(context.TypeFP32(), sizeFloat, scale);
  166. var sizeUnscaledInt = context.ConvertFToS(context.TypeS32(), sizeUnscaled);
  167. return context.Select(context.TypeS32(), passthrough, size, sizeUnscaledInt);
  168. }
  169. return size;
  170. }
  171. }
  172. }