diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2019-04-17 20:57:08 -0300 |
|---|---|---|
| committer | jduncanator <1518948+jduncanator@users.noreply.github.com> | 2019-04-18 09:57:08 +1000 |
| commit | 6b23a2c125b9c48b5ebea92716004ef68698bb0f (patch) | |
| tree | 69332df6fbbd8e2bddc522ba682fcc5c7a69e101 /Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs | |
| parent | b2e88b04a85b41cc60af3485d88c90429e84a218 (diff) | |
New shader translator implementation (#654)
* Start implementing a new shader translator
* Fix shift instructions and a typo
* Small refactoring on StructuredProgram, move RemovePhis method to a separate class
* Initial geometry shader support
* Implement TLD4
* Fix -- There's no negation on FMUL32I
* Add constant folding and algebraic simplification optimizations, nits
* Some leftovers from constant folding
* Avoid cast for constant assignments
* Add a branch elimination pass, and misc small fixes
* Remove redundant branches, add expression propagation and other improvements on the code
* Small leftovers -- add missing break and continue, remove unused properties, other improvements
* Add null check to handle empty block cases on block visitor
* Add HADD2 and HMUL2 half float shader instructions
* Optimize pack/unpack sequences, some fixes related to half float instructions
* Add TXQ, TLD, TLDS and TLD4S shader texture instructions, and some support for bindless textures, some refactoring on codegen
* Fix copy paste mistake that caused RZ to be ignored on the AST instruction
* Add workaround for conditional exit, and fix half float instruction with constant buffer
* Add missing 0.0 source for TLDS.LZ variants
* Simplify the switch for TLDS.LZ
* Texture instructions related fixes
* Implement the HFMA instruction, and some misc. fixes
* Enable constant folding on UnpackHalf2x16 instructions
* Refactor HFMA to use OpCode* for opcode decoding rather than on the helper methods
* Remove the old shader translator
* Remove ShaderDeclInfo and other unused things
* Add dual vertex shader support
* Add ShaderConfig, used to pass shader type and maximum cbuffer size
* Move and rename some instruction enums
* Move texture instructions into a separate file
* Move operand GetExpression and locals management to OperandManager
* Optimize opcode decoding using a simple list and binary search
* Add missing condition for do-while on goto elimination
* Misc. fixes on texture instructions
* Simplify TLDS switch
* Address PR feedback, and a nit
Diffstat (limited to 'Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs')
| -rw-r--r-- | Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs new file mode 100644 index 00000000..debba428 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs @@ -0,0 +1,239 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; +using System; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + class OperandManager + { + private static string[] _stagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" }; + + private struct BuiltInAttribute + { + public string Name { get; } + + public VariableType Type { get; } + + public BuiltInAttribute(string name, VariableType type) + { + Name = name; + Type = type; + } + } + + private static Dictionary<int, BuiltInAttribute> _builtInAttributes = + new Dictionary<int, BuiltInAttribute>() + { + { AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", VariableType.S32) }, + { AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", VariableType.F32) }, + { AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", VariableType.F32) }, + { AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", VariableType.F32) }, + { AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", VariableType.F32) }, + { AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", VariableType.F32) }, + { AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", VariableType.F32) }, + { AttributeConsts.PointCoordY, new BuiltInAttribute("gl_PointCoord.y", VariableType.F32) }, + { AttributeConsts.TessCoordX, new BuiltInAttribute("gl_TessCoord.x", VariableType.F32) }, + { AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) }, + { AttributeConsts.InstanceId, new BuiltInAttribute("instance", VariableType.S32) }, + { AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) }, + { AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) }, + { AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) } + }; + + private Dictionary<AstOperand, string> _locals; + + public OperandManager() + { + _locals = new Dictionary<AstOperand, string>(); + } + + public string DeclareLocal(AstOperand operand) + { + string name = $"{DefaultNames.LocalNamePrefix}_{_locals.Count}"; + + _locals.Add(operand, name); + + return name; + } + + public string GetExpression(AstOperand operand, GalShaderType shaderType) + { + switch (operand.Type) + { + case OperandType.Attribute: + return GetAttributeName(operand, shaderType); + + case OperandType.Constant: + return NumberFormatter.FormatInt(operand.Value); + + case OperandType.ConstantBuffer: + return GetConstantBufferName(operand, shaderType); + + case OperandType.LocalVariable: + return _locals[operand]; + + case OperandType.Undefined: + return DefaultNames.UndefinedName; + } + + throw new ArgumentException($"Invalid operand type \"{operand.Type}\"."); + } + + public static string GetConstantBufferName(AstOperand cbuf, GalShaderType shaderType) + { + string ubName = GetUbName(shaderType, cbuf.CbufSlot); + + ubName += "[" + (cbuf.CbufOffset >> 2) + "]"; + + return ubName + "." + GetSwizzleMask(cbuf.CbufOffset & 3); + } + + public static string GetConstantBufferName(IAstNode slot, string offsetExpr, GalShaderType shaderType) + { + //Non-constant slots are not supported. + //It is expected that upstream stages are never going to generate non-constant + //slot access. + AstOperand operand = (AstOperand)slot; + + string ubName = GetUbName(shaderType, operand.Value); + + string index0 = "[" + offsetExpr + " >> 4]"; + string index1 = "[" + offsetExpr + " >> 2 & 3]"; + + return ubName + index0 + index1; + } + + public static string GetOutAttributeName(AstOperand attr, GalShaderType shaderType) + { + return GetAttributeName(attr, shaderType, isOutAttr: true); + } + + private static string GetAttributeName(AstOperand attr, GalShaderType shaderType, bool isOutAttr = false) + { + int value = attr.Value; + + string swzMask = GetSwizzleMask((value >> 2) & 3); + + if (value >= AttributeConsts.UserAttributeBase && + value < AttributeConsts.UserAttributeEnd) + { + value -= AttributeConsts.UserAttributeBase; + + string prefix = isOutAttr + ? DefaultNames.OAttributePrefix + : DefaultNames.IAttributePrefix; + + string name = $"{prefix}{(value >> 4)}"; + + if (shaderType == GalShaderType.Geometry && !isOutAttr) + { + name += "[0]"; + } + + name += "." + swzMask; + + return name; + } + else + { + if (value >= AttributeConsts.FragmentOutputColorBase && + value < AttributeConsts.FragmentOutputColorEnd) + { + value -= AttributeConsts.FragmentOutputColorBase; + + return $"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}"; + } + else if (_builtInAttributes.TryGetValue(value & ~3, out BuiltInAttribute builtInAttr)) + { + //TODO: There must be a better way to handle this... + if (shaderType == GalShaderType.Fragment) + { + switch (value & ~3) + { + case AttributeConsts.PositionX: return "gl_FragCoord.x"; + case AttributeConsts.PositionY: return "gl_FragCoord.y"; + case AttributeConsts.PositionZ: return "gl_FragCoord.z"; + case AttributeConsts.PositionW: return "1.0"; + } + } + + string name = builtInAttr.Name; + + if (shaderType == GalShaderType.Geometry && !isOutAttr) + { + name = "gl_in[0]." + name; + } + + return name; + } + } + + return DefaultNames.UndefinedName; + } + + public static string GetUbName(GalShaderType shaderType, int slot) + { + string ubName = OperandManager.GetShaderStagePrefix(shaderType); + + ubName += "_" + DefaultNames.UniformNamePrefix + slot; + + return ubName + "_" + DefaultNames.UniformNameSuffix; + } + + public static string GetSamplerName(GalShaderType shaderType, AstTextureOperation texOp) + { + string suffix; + + if ((texOp.Flags & TextureFlags.Bindless) != 0) + { + AstOperand operand = texOp.GetSource(0) as AstOperand; + + suffix = "_cb" + operand.CbufSlot + "_" + operand.CbufOffset; + } + else + { + suffix = (texOp.Handle - 8).ToString(); + } + + return GetShaderStagePrefix(shaderType) + "_" + DefaultNames.SamplerNamePrefix + suffix; + } + + public static string GetShaderStagePrefix(GalShaderType shaderType) + { + return _stagePrefixes[(int)shaderType]; + } + + private static string GetSwizzleMask(int value) + { + return "xyzw".Substring(value, 1); + } + + public static VariableType GetNodeDestType(IAstNode node) + { + if (node is AstOperation operation) + { + return GetDestVarType(operation.Inst); + } + else if (node is AstOperand operand) + { + if (operand.Type == OperandType.Attribute) + { + if (_builtInAttributes.TryGetValue(operand.Value & ~3, out BuiltInAttribute builtInAttr)) + { + return builtInAttr.Type; + } + } + + return OperandInfo.GetVarType(operand); + } + else + { + throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\"."); + } + } + } +}
\ No newline at end of file |
