|
|
@@ -1,1679 +0,0 @@
|
|
|
-using OpenTK.Graphics.OpenGL;
|
|
|
-using Ryujinx.Graphics.Texture;
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
-using System.Globalization;
|
|
|
-using System.Linq;
|
|
|
-using System.Text;
|
|
|
-
|
|
|
-namespace Ryujinx.Graphics.Gal.Shader
|
|
|
-{
|
|
|
- public class GlslDecompiler
|
|
|
- {
|
|
|
- private delegate string GetInstExpr(ShaderIrOp op);
|
|
|
-
|
|
|
- private Dictionary<ShaderIrInst, GetInstExpr> _instsExpr;
|
|
|
-
|
|
|
- private enum OperType
|
|
|
- {
|
|
|
- Bool,
|
|
|
- F32,
|
|
|
- I32
|
|
|
- }
|
|
|
-
|
|
|
- private const string IdentationStr = " ";
|
|
|
-
|
|
|
- private const int MaxVertexInput = 3;
|
|
|
-
|
|
|
- private GlslDecl _decl;
|
|
|
-
|
|
|
- private ShaderHeader _header, _headerB;
|
|
|
-
|
|
|
- private ShaderIrBlock[] _blocks, _blocksB;
|
|
|
-
|
|
|
- private StringBuilder _sb;
|
|
|
-
|
|
|
- public int MaxUboSize { get; }
|
|
|
-
|
|
|
- private bool _isNvidiaDriver;
|
|
|
-
|
|
|
- public GlslDecompiler(int maxUboSize, bool isNvidiaDriver)
|
|
|
- {
|
|
|
- _instsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
|
|
- {
|
|
|
- { ShaderIrInst.Abs, GetAbsExpr },
|
|
|
- { ShaderIrInst.Add, GetAddExpr },
|
|
|
- { ShaderIrInst.And, GetAndExpr },
|
|
|
- { ShaderIrInst.Asr, GetAsrExpr },
|
|
|
- { ShaderIrInst.Band, GetBandExpr },
|
|
|
- { ShaderIrInst.Bnot, GetBnotExpr },
|
|
|
- { ShaderIrInst.Bor, GetBorExpr },
|
|
|
- { ShaderIrInst.Bxor, GetBxorExpr },
|
|
|
- { ShaderIrInst.Ceil, GetCeilExpr },
|
|
|
- { ShaderIrInst.Ceq, GetCeqExpr },
|
|
|
- { ShaderIrInst.Cge, GetCgeExpr },
|
|
|
- { ShaderIrInst.Cgt, GetCgtExpr },
|
|
|
- { ShaderIrInst.Clamps, GetClampsExpr },
|
|
|
- { ShaderIrInst.Clampu, GetClampuExpr },
|
|
|
- { ShaderIrInst.Cle, GetCleExpr },
|
|
|
- { ShaderIrInst.Clt, GetCltExpr },
|
|
|
- { ShaderIrInst.Cne, GetCneExpr },
|
|
|
- { ShaderIrInst.Cut, GetCutExpr },
|
|
|
- { ShaderIrInst.Exit, GetExitExpr },
|
|
|
- { ShaderIrInst.Fabs, GetAbsExpr },
|
|
|
- { ShaderIrInst.Fadd, GetAddExpr },
|
|
|
- { ShaderIrInst.Fceq, GetCeqExpr },
|
|
|
- { ShaderIrInst.Fcequ, GetCequExpr },
|
|
|
- { ShaderIrInst.Fcge, GetCgeExpr },
|
|
|
- { ShaderIrInst.Fcgeu, GetCgeuExpr },
|
|
|
- { ShaderIrInst.Fcgt, GetCgtExpr },
|
|
|
- { ShaderIrInst.Fcgtu, GetCgtuExpr },
|
|
|
- { ShaderIrInst.Fclamp, GetFclampExpr },
|
|
|
- { ShaderIrInst.Fcle, GetCleExpr },
|
|
|
- { ShaderIrInst.Fcleu, GetCleuExpr },
|
|
|
- { ShaderIrInst.Fclt, GetCltExpr },
|
|
|
- { ShaderIrInst.Fcltu, GetCltuExpr },
|
|
|
- { ShaderIrInst.Fcnan, GetCnanExpr },
|
|
|
- { ShaderIrInst.Fcne, GetCneExpr },
|
|
|
- { ShaderIrInst.Fcneu, GetCneuExpr },
|
|
|
- { ShaderIrInst.Fcnum, GetCnumExpr },
|
|
|
- { ShaderIrInst.Fcos, GetFcosExpr },
|
|
|
- { ShaderIrInst.Fex2, GetFex2Expr },
|
|
|
- { ShaderIrInst.Ffma, GetFfmaExpr },
|
|
|
- { ShaderIrInst.Flg2, GetFlg2Expr },
|
|
|
- { ShaderIrInst.Floor, GetFloorExpr },
|
|
|
- { ShaderIrInst.Fmax, GetMaxExpr },
|
|
|
- { ShaderIrInst.Fmin, GetMinExpr },
|
|
|
- { ShaderIrInst.Fmul, GetMulExpr },
|
|
|
- { ShaderIrInst.Fneg, GetNegExpr },
|
|
|
- { ShaderIrInst.Frcp, GetFrcpExpr },
|
|
|
- { ShaderIrInst.Frsq, GetFrsqExpr },
|
|
|
- { ShaderIrInst.Fsin, GetFsinExpr },
|
|
|
- { ShaderIrInst.Fsqrt, GetFsqrtExpr },
|
|
|
- { ShaderIrInst.Ftos, GetFtosExpr },
|
|
|
- { ShaderIrInst.Ftou, GetFtouExpr },
|
|
|
- { ShaderIrInst.Ipa, GetIpaExpr },
|
|
|
- { ShaderIrInst.Kil, GetKilExpr },
|
|
|
- { ShaderIrInst.Lsl, GetLslExpr },
|
|
|
- { ShaderIrInst.Lsr, GetLsrExpr },
|
|
|
- { ShaderIrInst.Max, GetMaxExpr },
|
|
|
- { ShaderIrInst.Min, GetMinExpr },
|
|
|
- { ShaderIrInst.Mul, GetMulExpr },
|
|
|
- { ShaderIrInst.Neg, GetNegExpr },
|
|
|
- { ShaderIrInst.Not, GetNotExpr },
|
|
|
- { ShaderIrInst.Or, GetOrExpr },
|
|
|
- { ShaderIrInst.Stof, GetStofExpr },
|
|
|
- { ShaderIrInst.Sub, GetSubExpr },
|
|
|
- { ShaderIrInst.Texb, GetTexbExpr },
|
|
|
- { ShaderIrInst.Texq, GetTexqExpr },
|
|
|
- { ShaderIrInst.Texs, GetTexsExpr },
|
|
|
- { ShaderIrInst.Tld4, GetTld4Expr },
|
|
|
- { ShaderIrInst.Trunc, GetTruncExpr },
|
|
|
- { ShaderIrInst.Txlf, GetTxlfExpr },
|
|
|
- { ShaderIrInst.Utof, GetUtofExpr },
|
|
|
- { ShaderIrInst.Xor, GetXorExpr }
|
|
|
- };
|
|
|
-
|
|
|
- MaxUboSize = maxUboSize / 16;
|
|
|
- _isNvidiaDriver = isNvidiaDriver;
|
|
|
- }
|
|
|
-
|
|
|
- public GlslProgram Decompile(
|
|
|
- IGalMemory memory,
|
|
|
- long vpAPosition,
|
|
|
- long vpBPosition,
|
|
|
- GalShaderType shaderType)
|
|
|
- {
|
|
|
- _header = new ShaderHeader(memory, vpAPosition);
|
|
|
- _headerB = new ShaderHeader(memory, vpBPosition);
|
|
|
-
|
|
|
- _blocks = ShaderDecoder.Decode(memory, vpAPosition);
|
|
|
- _blocksB = ShaderDecoder.Decode(memory, vpBPosition);
|
|
|
-
|
|
|
- GlslDecl declVpA = new GlslDecl(_blocks, shaderType, _header);
|
|
|
- GlslDecl declVpB = new GlslDecl(_blocksB, shaderType, _headerB);
|
|
|
-
|
|
|
- _decl = GlslDecl.Merge(declVpA, declVpB);
|
|
|
-
|
|
|
- return Decompile();
|
|
|
- }
|
|
|
-
|
|
|
- public GlslProgram Decompile(IGalMemory memory, long position, GalShaderType shaderType)
|
|
|
- {
|
|
|
- _header = new ShaderHeader(memory, position);
|
|
|
- _headerB = null;
|
|
|
-
|
|
|
- _blocks = ShaderDecoder.Decode(memory, position);
|
|
|
- _blocksB = null;
|
|
|
-
|
|
|
- _decl = new GlslDecl(_blocks, shaderType, _header);
|
|
|
-
|
|
|
- return Decompile();
|
|
|
- }
|
|
|
-
|
|
|
- private GlslProgram Decompile()
|
|
|
- {
|
|
|
- _sb = new StringBuilder();
|
|
|
-
|
|
|
- _sb.AppendLine("#version 410 core");
|
|
|
-
|
|
|
- PrintDeclHeader();
|
|
|
- PrintDeclTextures();
|
|
|
- PrintDeclUniforms();
|
|
|
- PrintDeclAttributes();
|
|
|
- PrintDeclInAttributes();
|
|
|
- PrintDeclOutAttributes();
|
|
|
- PrintDeclGprs();
|
|
|
- PrintDeclPreds();
|
|
|
- PrintDeclSsy();
|
|
|
-
|
|
|
- if (_blocksB != null)
|
|
|
- {
|
|
|
- PrintBlockScope(_blocks, GlslDecl.BasicBlockAName);
|
|
|
-
|
|
|
- _sb.AppendLine();
|
|
|
-
|
|
|
- PrintBlockScope(_blocksB, GlslDecl.BasicBlockBName);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- PrintBlockScope(_blocks, GlslDecl.BasicBlockName);
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine();
|
|
|
-
|
|
|
- PrintMain();
|
|
|
-
|
|
|
- string glslCode = _sb.ToString();
|
|
|
-
|
|
|
- List<ShaderDeclInfo> textureInfo = new List<ShaderDeclInfo>();
|
|
|
-
|
|
|
- textureInfo.AddRange(_decl.Textures.Values);
|
|
|
- textureInfo.AddRange(IterateCbTextures());
|
|
|
-
|
|
|
- return new GlslProgram(glslCode, textureInfo, _decl.Uniforms.Values);
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclHeader()
|
|
|
- {
|
|
|
- if (_decl.ShaderType == GalShaderType.Geometry)
|
|
|
- {
|
|
|
- int maxVertices = _header.MaxOutputVertexCount;
|
|
|
-
|
|
|
- string outputTopology;
|
|
|
-
|
|
|
- switch (_header.OutputTopology)
|
|
|
- {
|
|
|
- case ShaderHeader.PointList: outputTopology = "points"; break;
|
|
|
- case ShaderHeader.LineStrip: outputTopology = "line_strip"; break;
|
|
|
- case ShaderHeader.TriangleStrip: outputTopology = "triangle_strip"; break;
|
|
|
-
|
|
|
- default: throw new InvalidOperationException();
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine("#extension GL_ARB_enhanced_layouts : require");
|
|
|
-
|
|
|
- _sb.AppendLine();
|
|
|
-
|
|
|
- _sb.AppendLine("// Stubbed. Maxwell geometry shaders don't inform input geometry type");
|
|
|
-
|
|
|
- _sb.AppendLine("layout(triangles) in;" + Environment.NewLine);
|
|
|
-
|
|
|
- _sb.AppendLine($"layout({outputTopology}, max_vertices = {maxVertices}) out;");
|
|
|
-
|
|
|
- _sb.AppendLine();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private string GetSamplerType(TextureTarget textureTarget, bool hasShadow)
|
|
|
- {
|
|
|
- string result;
|
|
|
-
|
|
|
- switch (textureTarget)
|
|
|
- {
|
|
|
- case TextureTarget.Texture1D:
|
|
|
- result = "sampler1D";
|
|
|
- break;
|
|
|
- case TextureTarget.Texture2D:
|
|
|
- result = "sampler2D";
|
|
|
- break;
|
|
|
- case TextureTarget.Texture3D:
|
|
|
- result = "sampler3D";
|
|
|
- break;
|
|
|
- case TextureTarget.TextureCubeMap:
|
|
|
- result = "samplerCube";
|
|
|
- break;
|
|
|
- case TextureTarget.TextureRectangle:
|
|
|
- result = "sampler2DRect";
|
|
|
- break;
|
|
|
- case TextureTarget.Texture1DArray:
|
|
|
- result = "sampler1DArray";
|
|
|
- break;
|
|
|
- case TextureTarget.Texture2DArray:
|
|
|
- result = "sampler2DArray";
|
|
|
- break;
|
|
|
- case TextureTarget.TextureCubeMapArray:
|
|
|
- result = "samplerCubeArray";
|
|
|
- break;
|
|
|
- case TextureTarget.TextureBuffer:
|
|
|
- result = "samplerBuffer";
|
|
|
- break;
|
|
|
- case TextureTarget.Texture2DMultisample:
|
|
|
- result = "sampler2DMS";
|
|
|
- break;
|
|
|
- case TextureTarget.Texture2DMultisampleArray:
|
|
|
- result = "sampler2DMSArray";
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new NotSupportedException();
|
|
|
- }
|
|
|
-
|
|
|
- if (hasShadow)
|
|
|
- result += "Shadow";
|
|
|
-
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclTextures()
|
|
|
- {
|
|
|
- foreach (ShaderDeclInfo declInfo in IterateCbTextures())
|
|
|
- {
|
|
|
- TextureTarget target = ImageUtils.GetTextureTarget(declInfo.TextureTarget);
|
|
|
- _sb.AppendLine($"// {declInfo.TextureSuffix}");
|
|
|
- _sb.AppendLine("uniform " + GetSamplerType(target, (declInfo.TextureSuffix & TextureInstructionSuffix.Dc) != 0) + " " + declInfo.Name + ";");
|
|
|
- }
|
|
|
-
|
|
|
- foreach (ShaderDeclInfo declInfo in _decl.Textures.Values.OrderBy(DeclKeySelector))
|
|
|
- {
|
|
|
- TextureTarget target = ImageUtils.GetTextureTarget(declInfo.TextureTarget);
|
|
|
- _sb.AppendLine($"// {declInfo.TextureSuffix}");
|
|
|
- _sb.AppendLine("uniform " + GetSamplerType(target, (declInfo.TextureSuffix & TextureInstructionSuffix.Dc) != 0) + " " + declInfo.Name + ";");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private IEnumerable<ShaderDeclInfo> IterateCbTextures()
|
|
|
- {
|
|
|
- HashSet<string> names = new HashSet<string>();
|
|
|
-
|
|
|
- foreach (ShaderDeclInfo declInfo in _decl.CbTextures.Values.OrderBy(DeclKeySelector))
|
|
|
- {
|
|
|
- if (names.Add(declInfo.Name))
|
|
|
- {
|
|
|
- yield return declInfo;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclUniforms()
|
|
|
- {
|
|
|
- if (_decl.ShaderType == GalShaderType.Vertex)
|
|
|
- {
|
|
|
- //Memory layout here is [flip_x, flip_y, instance, unused]
|
|
|
- //It's using 4 bytes, not 8
|
|
|
-
|
|
|
- _sb.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + " {");
|
|
|
-
|
|
|
- _sb.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";");
|
|
|
-
|
|
|
- _sb.AppendLine(IdentationStr + "int " + GlslDecl.InstanceUniformName + ";");
|
|
|
-
|
|
|
- _sb.AppendLine("};");
|
|
|
- _sb.AppendLine();
|
|
|
- }
|
|
|
-
|
|
|
- foreach (ShaderDeclInfo declInfo in _decl.Uniforms.Values.OrderBy(DeclKeySelector))
|
|
|
- {
|
|
|
- _sb.AppendLine($"layout (std140) uniform {declInfo.Name} {{");
|
|
|
-
|
|
|
- _sb.AppendLine($"{IdentationStr}vec4 {declInfo.Name}_data[{MaxUboSize}];");
|
|
|
-
|
|
|
- _sb.AppendLine("};");
|
|
|
- }
|
|
|
-
|
|
|
- if (_decl.Uniforms.Count > 0)
|
|
|
- {
|
|
|
- _sb.AppendLine();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclAttributes()
|
|
|
- {
|
|
|
- string geometryArray = (_decl.ShaderType == GalShaderType.Geometry) ? "[" + MaxVertexInput + "]" : "";
|
|
|
-
|
|
|
- PrintDecls(_decl.Attributes, suffix: geometryArray);
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclInAttributes()
|
|
|
- {
|
|
|
- if (_decl.ShaderType == GalShaderType.Fragment)
|
|
|
- {
|
|
|
- _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") in vec4 " + GlslDecl.PositionOutAttrName + ";");
|
|
|
- }
|
|
|
-
|
|
|
- if (_decl.ShaderType == GalShaderType.Geometry)
|
|
|
- {
|
|
|
- if (_decl.InAttributes.Count > 0)
|
|
|
- {
|
|
|
- _sb.AppendLine("in Vertex {");
|
|
|
-
|
|
|
- foreach (ShaderDeclInfo declInfo in _decl.InAttributes.Values.OrderBy(DeclKeySelector))
|
|
|
- {
|
|
|
- if (declInfo.Index >= 0)
|
|
|
- {
|
|
|
- _sb.AppendLine(IdentationStr + "layout (location = " + declInfo.Index + ") vec4 " + declInfo.Name + "; ");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine("} block_in[];" + Environment.NewLine);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- PrintDeclAttributes(_decl.InAttributes.Values, "in");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclOutAttributes()
|
|
|
- {
|
|
|
- if (_decl.ShaderType == GalShaderType.Fragment)
|
|
|
- {
|
|
|
- int count = 0;
|
|
|
-
|
|
|
- for (int attachment = 0; attachment < 8; attachment++)
|
|
|
- {
|
|
|
- if (_header.OmapTargets[attachment].Enabled)
|
|
|
- {
|
|
|
- _sb.AppendLine("layout (location = " + attachment + ") out vec4 " + GlslDecl.FragmentOutputName + attachment + ";");
|
|
|
-
|
|
|
- count++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (count > 0)
|
|
|
- {
|
|
|
- _sb.AppendLine();
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";");
|
|
|
- _sb.AppendLine();
|
|
|
- }
|
|
|
-
|
|
|
- PrintDeclAttributes(_decl.OutAttributes.Values, "out");
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclAttributes(IEnumerable<ShaderDeclInfo> decls, string inOut)
|
|
|
- {
|
|
|
- int count = 0;
|
|
|
-
|
|
|
- foreach (ShaderDeclInfo declInfo in decls.OrderBy(DeclKeySelector))
|
|
|
- {
|
|
|
- if (declInfo.Index >= 0)
|
|
|
- {
|
|
|
- _sb.AppendLine("layout (location = " + declInfo.Index + ") " + inOut + " vec4 " + declInfo.Name + ";");
|
|
|
-
|
|
|
- count++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (count > 0)
|
|
|
- {
|
|
|
- _sb.AppendLine();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclGprs()
|
|
|
- {
|
|
|
- PrintDecls(_decl.Gprs);
|
|
|
- PrintDecls(_decl.GprsHalf);
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclPreds()
|
|
|
- {
|
|
|
- PrintDecls(_decl.Preds, "bool");
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDeclSsy()
|
|
|
- {
|
|
|
- _sb.AppendLine("uint " + GlslDecl.SsyCursorName + " = 0;");
|
|
|
-
|
|
|
- _sb.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine);
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintDecls(IReadOnlyDictionary<int, ShaderDeclInfo> dict, string customType = null, string suffix = "")
|
|
|
- {
|
|
|
- foreach (ShaderDeclInfo declInfo in dict.Values.OrderBy(DeclKeySelector))
|
|
|
- {
|
|
|
- string name;
|
|
|
-
|
|
|
- if (customType != null)
|
|
|
- {
|
|
|
- name = customType + " " + declInfo.Name + suffix + ";";
|
|
|
- }
|
|
|
- else if (declInfo.Name.Contains(GlslDecl.FragmentOutputName))
|
|
|
- {
|
|
|
- name = "layout (location = " + declInfo.Index / 4 + ") out vec4 " + declInfo.Name + suffix + ";";
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- name = GetDecl(declInfo) + suffix + ";";
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine(name);
|
|
|
- }
|
|
|
-
|
|
|
- if (dict.Count > 0)
|
|
|
- {
|
|
|
- _sb.AppendLine();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private int DeclKeySelector(ShaderDeclInfo declInfo)
|
|
|
- {
|
|
|
- return declInfo.Cbuf << 24 | declInfo.Index;
|
|
|
- }
|
|
|
-
|
|
|
- private string GetDecl(ShaderDeclInfo declInfo)
|
|
|
- {
|
|
|
- if (declInfo.Size == 4)
|
|
|
- {
|
|
|
- return "vec4 " + declInfo.Name;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return "float " + declInfo.Name;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintMain()
|
|
|
- {
|
|
|
- _sb.AppendLine("void main() {");
|
|
|
-
|
|
|
- foreach (KeyValuePair<int, ShaderDeclInfo> kv in _decl.InAttributes)
|
|
|
- {
|
|
|
- if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr))
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- ShaderDeclInfo declInfo = kv.Value;
|
|
|
-
|
|
|
- if (_decl.ShaderType == GalShaderType.Geometry)
|
|
|
- {
|
|
|
- for (int vertex = 0; vertex < MaxVertexInput; vertex++)
|
|
|
- {
|
|
|
- string dst = attr.Name + "[" + vertex + "]";
|
|
|
-
|
|
|
- string src = "block_in[" + vertex + "]." + declInfo.Name;
|
|
|
-
|
|
|
- _sb.AppendLine(IdentationStr + dst + " = " + src + ";");
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- _sb.AppendLine(IdentationStr + attr.Name + " = " + declInfo.Name + ";");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine(IdentationStr + "uint pc;");
|
|
|
-
|
|
|
- if (_blocksB != null)
|
|
|
- {
|
|
|
- PrintProgram(_blocks, GlslDecl.BasicBlockAName);
|
|
|
- PrintProgram(_blocksB, GlslDecl.BasicBlockBName);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- PrintProgram(_blocks, GlslDecl.BasicBlockName);
|
|
|
- }
|
|
|
-
|
|
|
- if (_decl.ShaderType != GalShaderType.Geometry)
|
|
|
- {
|
|
|
- PrintAttrToOutput();
|
|
|
- }
|
|
|
-
|
|
|
- if (_decl.ShaderType == GalShaderType.Fragment)
|
|
|
- {
|
|
|
- if (_header.OmapDepth)
|
|
|
- {
|
|
|
- _sb.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(_header.DepthRegister) + ";");
|
|
|
- }
|
|
|
-
|
|
|
- int gprIndex = 0;
|
|
|
-
|
|
|
- for (int attachment = 0; attachment < 8; attachment++)
|
|
|
- {
|
|
|
- string output = GlslDecl.FragmentOutputName + attachment;
|
|
|
-
|
|
|
- OmapTarget target = _header.OmapTargets[attachment];
|
|
|
-
|
|
|
- for (int component = 0; component < 4; component++)
|
|
|
- {
|
|
|
- if (target.ComponentEnabled(component))
|
|
|
- {
|
|
|
- _sb.AppendLine(IdentationStr + output + "[" + component + "] = " + GlslDecl.GetGprName(gprIndex) + ";");
|
|
|
-
|
|
|
- gprIndex++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine("}");
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintProgram(ShaderIrBlock[] blocks, string name)
|
|
|
- {
|
|
|
- const string ident1 = IdentationStr;
|
|
|
- const string ident2 = ident1 + IdentationStr;
|
|
|
- const string ident3 = ident2 + IdentationStr;
|
|
|
- const string ident4 = ident3 + IdentationStr;
|
|
|
-
|
|
|
- _sb.AppendLine(ident1 + "pc = " + GetBlockPosition(blocks[0]) + ";");
|
|
|
- _sb.AppendLine(ident1 + "do {");
|
|
|
- _sb.AppendLine(ident2 + "switch (pc) {");
|
|
|
-
|
|
|
- foreach (ShaderIrBlock block in blocks)
|
|
|
- {
|
|
|
- string functionName = block.Position.ToString("x8");
|
|
|
-
|
|
|
- _sb.AppendLine(ident3 + "case 0x" + functionName + ": pc = " + name + "_" + functionName + "(); break;");
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine(ident3 + "default:");
|
|
|
- _sb.AppendLine(ident4 + "pc = 0;");
|
|
|
- _sb.AppendLine(ident4 + "break;");
|
|
|
-
|
|
|
- _sb.AppendLine(ident2 + "}");
|
|
|
- _sb.AppendLine(ident1 + "} while (pc != 0);");
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintAttrToOutput(string identation = IdentationStr)
|
|
|
- {
|
|
|
- foreach (KeyValuePair<int, ShaderDeclInfo> kv in _decl.OutAttributes)
|
|
|
- {
|
|
|
- if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr))
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- ShaderDeclInfo declInfo = kv.Value;
|
|
|
-
|
|
|
- string name = attr.Name;
|
|
|
-
|
|
|
- if (_decl.ShaderType == GalShaderType.Geometry)
|
|
|
- {
|
|
|
- name += "[0]";
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine(identation + declInfo.Name + " = " + name + ";");
|
|
|
- }
|
|
|
-
|
|
|
- if (_decl.ShaderType == GalShaderType.Vertex)
|
|
|
- {
|
|
|
- _sb.AppendLine(identation + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";");
|
|
|
- }
|
|
|
-
|
|
|
- if (_decl.ShaderType != GalShaderType.Fragment)
|
|
|
- {
|
|
|
- _sb.AppendLine(identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
|
|
|
- _sb.AppendLine(identation + GlslDecl.PositionOutAttrName + ".w = 1;");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintBlockScope(ShaderIrBlock[] blocks, string name)
|
|
|
- {
|
|
|
- foreach (ShaderIrBlock block in blocks)
|
|
|
- {
|
|
|
- _sb.AppendLine("uint " + name + "_" + block.Position.ToString("x8") + "() {");
|
|
|
-
|
|
|
- PrintNodes(block, block.GetNodes());
|
|
|
-
|
|
|
- _sb.AppendLine("}" + Environment.NewLine);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintNodes(ShaderIrBlock block, ShaderIrNode[] nodes)
|
|
|
- {
|
|
|
- foreach (ShaderIrNode node in nodes)
|
|
|
- {
|
|
|
- PrintNode(block, node, IdentationStr);
|
|
|
- }
|
|
|
-
|
|
|
- if (nodes.Length == 0)
|
|
|
- {
|
|
|
- _sb.AppendLine(IdentationStr + "return 0u;");
|
|
|
-
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- ShaderIrNode last = nodes[nodes.Length - 1];
|
|
|
-
|
|
|
- bool unconditionalFlowChange = false;
|
|
|
-
|
|
|
- if (last is ShaderIrOp op)
|
|
|
- {
|
|
|
- switch (op.Inst)
|
|
|
- {
|
|
|
- case ShaderIrInst.Bra:
|
|
|
- case ShaderIrInst.Exit:
|
|
|
- case ShaderIrInst.Sync:
|
|
|
- unconditionalFlowChange = true;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!unconditionalFlowChange)
|
|
|
- {
|
|
|
- if (block.Next != null)
|
|
|
- {
|
|
|
- _sb.AppendLine(IdentationStr + "return " + GetBlockPosition(block.Next) + ";");
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- _sb.AppendLine(IdentationStr + "return 0u;");
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void PrintNode(ShaderIrBlock block, ShaderIrNode node, string identation)
|
|
|
- {
|
|
|
- if (node is ShaderIrCond cond)
|
|
|
- {
|
|
|
- string ifExpr = GetSrcExpr(cond.Pred, true);
|
|
|
-
|
|
|
- if (cond.Not)
|
|
|
- {
|
|
|
- ifExpr = "!(" + ifExpr + ")";
|
|
|
- }
|
|
|
-
|
|
|
- _sb.AppendLine(identation + "if (" + ifExpr + ") {");
|
|
|
-
|
|
|
- PrintNode(block, cond.Child, identation + IdentationStr);
|
|
|
-
|
|
|
- _sb.AppendLine(identation + "}");
|
|
|
- }
|
|
|
- else if (node is ShaderIrAsg asg)
|
|
|
- {
|
|
|
- if (IsValidOutOper(asg.Dst))
|
|
|
- {
|
|
|
- string expr = GetSrcExpr(asg.Src, true);
|
|
|
-
|
|
|
- expr = GetExprWithCast(asg.Dst, asg.Src, expr);
|
|
|
-
|
|
|
- _sb.AppendLine(identation + GetDstOperName(asg.Dst) + " = " + expr + ";");
|
|
|
- }
|
|
|
- }
|
|
|
- else if (node is ShaderIrOp op)
|
|
|
- {
|
|
|
- switch (op.Inst)
|
|
|
- {
|
|
|
- case ShaderIrInst.Bra:
|
|
|
- {
|
|
|
- _sb.AppendLine(identation + "return " + GetBlockPosition(block.Branch) + ";");
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- case ShaderIrInst.Emit:
|
|
|
- {
|
|
|
- PrintAttrToOutput(identation);
|
|
|
-
|
|
|
- _sb.AppendLine(identation + "EmitVertex();");
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- case ShaderIrInst.Ssy:
|
|
|
- {
|
|
|
- string stackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]";
|
|
|
-
|
|
|
- int targetPosition = (op.OperandA as ShaderIrOperImm).Value;
|
|
|
-
|
|
|
- string target = "0x" + targetPosition.ToString("x8") + "u";
|
|
|
-
|
|
|
- _sb.AppendLine(identation + stackIndex + " = " + target + ";");
|
|
|
-
|
|
|
- _sb.AppendLine(identation + GlslDecl.SsyCursorName + "++;");
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- case ShaderIrInst.Sync:
|
|
|
- {
|
|
|
- _sb.AppendLine(identation + GlslDecl.SsyCursorName + "--;");
|
|
|
-
|
|
|
- string target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]";
|
|
|
-
|
|
|
- _sb.AppendLine(identation + "return " + target + ";");
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- default:
|
|
|
- _sb.AppendLine(identation + GetSrcExpr(op, true) + ";");
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (node is ShaderIrCmnt cmnt)
|
|
|
- {
|
|
|
- _sb.AppendLine(identation + "// " + cmnt.Comment);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private bool IsValidOutOper(ShaderIrNode node)
|
|
|
- {
|
|
|
- if (node is ShaderIrOperGpr gpr && gpr.IsConst)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- else if (node is ShaderIrOperPred pred && pred.IsConst)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- private string GetDstOperName(ShaderIrNode node)
|
|
|
- {
|
|
|
- if (node is ShaderIrOperAbuf abuf)
|
|
|
- {
|
|
|
- return GetOutAbufName(abuf);
|
|
|
- }
|
|
|
- else if (node is ShaderIrOperGpr gpr)
|
|
|
- {
|
|
|
- return GetName(gpr);
|
|
|
- }
|
|
|
- else if (node is ShaderIrOperPred pred)
|
|
|
- {
|
|
|
- return GetName(pred);
|
|
|
- }
|
|
|
-
|
|
|
- throw new ArgumentException(nameof(node));
|
|
|
- }
|
|
|
-
|
|
|
- private string GetSrcExpr(ShaderIrNode node, bool entry = false)
|
|
|
- {
|
|
|
- switch (node)
|
|
|
- {
|
|
|
- case ShaderIrOperAbuf abuf: return GetName (abuf);
|
|
|
- case ShaderIrOperCbuf cbuf: return GetName (cbuf);
|
|
|
- case ShaderIrOperGpr gpr: return GetName (gpr);
|
|
|
- case ShaderIrOperImm imm: return GetValue(imm);
|
|
|
- case ShaderIrOperImmf immf: return GetValue(immf);
|
|
|
- case ShaderIrOperPred pred: return GetName (pred);
|
|
|
-
|
|
|
- case ShaderIrOp op:
|
|
|
- string expr;
|
|
|
-
|
|
|
- if (_instsExpr.TryGetValue(op.Inst, out GetInstExpr getExpr))
|
|
|
- {
|
|
|
- expr = getExpr(op);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- throw new NotImplementedException(op.Inst.ToString());
|
|
|
- }
|
|
|
-
|
|
|
- if (!entry && NeedsParentheses(op))
|
|
|
- {
|
|
|
- expr = "(" + expr + ")";
|
|
|
- }
|
|
|
-
|
|
|
- return expr;
|
|
|
-
|
|
|
- default: throw new ArgumentException(nameof(node));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private static bool NeedsParentheses(ShaderIrOp op)
|
|
|
- {
|
|
|
- switch (op.Inst)
|
|
|
- {
|
|
|
- case ShaderIrInst.Ipa:
|
|
|
- case ShaderIrInst.Texq:
|
|
|
- case ShaderIrInst.Texs:
|
|
|
- case ShaderIrInst.Tld4:
|
|
|
- case ShaderIrInst.Txlf:
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- private string GetName(ShaderIrOperCbuf cbuf)
|
|
|
- {
|
|
|
- if (!_decl.Uniforms.TryGetValue(cbuf.Index, out ShaderDeclInfo declInfo))
|
|
|
- {
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
-
|
|
|
- if (cbuf.Offs != null)
|
|
|
- {
|
|
|
- string offset = "floatBitsToInt(" + GetSrcExpr(cbuf.Offs) + ")";
|
|
|
-
|
|
|
- string index = "(" + cbuf.Pos * 4 + " + " + offset + ")";
|
|
|
-
|
|
|
- return $"{declInfo.Name}_data[{index} / 16][({index} / 4) % 4]";
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return $"{declInfo.Name}_data[{cbuf.Pos / 4}][{cbuf.Pos % 4}]";
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private string GetOutAbufName(ShaderIrOperAbuf abuf)
|
|
|
- {
|
|
|
- if (_decl.ShaderType == GalShaderType.Geometry)
|
|
|
- {
|
|
|
- switch (abuf.Offs)
|
|
|
- {
|
|
|
- case GlslDecl.LayerAttr: return "gl_Layer";
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return GetAttrTempName(abuf);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetName(ShaderIrOperAbuf abuf)
|
|
|
- {
|
|
|
- //Handle special scalar read-only attributes here.
|
|
|
- if (_decl.ShaderType == GalShaderType.Vertex)
|
|
|
- {
|
|
|
- switch (abuf.Offs)
|
|
|
- {
|
|
|
- case GlslDecl.VertexIdAttr: return "gl_VertexID";
|
|
|
- case GlslDecl.InstanceIdAttr: return GlslDecl.InstanceUniformName;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (_decl.ShaderType == GalShaderType.TessEvaluation)
|
|
|
- {
|
|
|
- switch (abuf.Offs)
|
|
|
- {
|
|
|
- case GlslDecl.TessCoordAttrX: return "gl_TessCoord.x";
|
|
|
- case GlslDecl.TessCoordAttrY: return "gl_TessCoord.y";
|
|
|
- case GlslDecl.TessCoordAttrZ: return "gl_TessCoord.z";
|
|
|
- }
|
|
|
- }
|
|
|
- else if (_decl.ShaderType == GalShaderType.Fragment)
|
|
|
- {
|
|
|
- switch (abuf.Offs)
|
|
|
- {
|
|
|
- case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x";
|
|
|
- case GlslDecl.PointCoordAttrY: return "gl_PointCoord.y";
|
|
|
- case GlslDecl.FaceAttr: return "(gl_FrontFacing ? -1 : 0)";
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return GetAttrTempName(abuf);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetAttrTempName(ShaderIrOperAbuf abuf)
|
|
|
- {
|
|
|
- int index = abuf.Offs >> 4;
|
|
|
- int elem = (abuf.Offs >> 2) & 3;
|
|
|
-
|
|
|
- string swizzle = "." + GetAttrSwizzle(elem);
|
|
|
-
|
|
|
- if (!_decl.Attributes.TryGetValue(index, out ShaderDeclInfo declInfo))
|
|
|
- {
|
|
|
- //Handle special vec4 attributes here
|
|
|
- //(for example, index 7 is always gl_Position).
|
|
|
- if (index == GlslDecl.GlPositionVec4Index)
|
|
|
- {
|
|
|
- string name =
|
|
|
- _decl.ShaderType != GalShaderType.Vertex &&
|
|
|
- _decl.ShaderType != GalShaderType.Geometry ? GlslDecl.PositionOutAttrName : "gl_Position";
|
|
|
-
|
|
|
- return name + swizzle;
|
|
|
- }
|
|
|
- else if (abuf.Offs == GlslDecl.PointSizeAttr)
|
|
|
- {
|
|
|
- return "gl_PointSize";
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (declInfo.Index >= 32)
|
|
|
- {
|
|
|
- throw new InvalidOperationException($"Shader attribute offset {abuf.Offs} is invalid.");
|
|
|
- }
|
|
|
-
|
|
|
- if (_decl.ShaderType == GalShaderType.Geometry)
|
|
|
- {
|
|
|
- string vertex = "floatBitsToInt(" + GetSrcExpr(abuf.Vertex) + ")";
|
|
|
-
|
|
|
- return declInfo.Name + "[" + vertex + "]" + swizzle;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return declInfo.Name + swizzle;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private string GetName(ShaderIrOperGpr gpr)
|
|
|
- {
|
|
|
- if (gpr.IsConst)
|
|
|
- {
|
|
|
- return "0";
|
|
|
- }
|
|
|
-
|
|
|
- if (gpr.RegisterSize == ShaderRegisterSize.Single)
|
|
|
- {
|
|
|
- return GetNameWithSwizzle(_decl.Gprs, gpr.Index);
|
|
|
- }
|
|
|
- else if (gpr.RegisterSize == ShaderRegisterSize.Half)
|
|
|
- {
|
|
|
- return GetNameWithSwizzle(_decl.GprsHalf, (gpr.Index << 1) | gpr.HalfPart);
|
|
|
- }
|
|
|
- else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */
|
|
|
- {
|
|
|
- throw new NotImplementedException("Double types are not supported.");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private string GetValue(ShaderIrOperImm imm)
|
|
|
- {
|
|
|
- //Only use hex is the value is too big and would likely be hard to read as int.
|
|
|
- if (imm.Value > 0xfff ||
|
|
|
- imm.Value < -0xfff)
|
|
|
- {
|
|
|
- return "0x" + imm.Value.ToString("x8", CultureInfo.InvariantCulture);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return GetIntConst(imm.Value);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private string GetValue(ShaderIrOperImmf immf)
|
|
|
- {
|
|
|
- return GetFloatConst(immf.Value);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetName(ShaderIrOperPred pred)
|
|
|
- {
|
|
|
- return pred.IsConst ? "true" : GetNameWithSwizzle(_decl.Preds, pred.Index);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetNameWithSwizzle(IReadOnlyDictionary<int, ShaderDeclInfo> dict, int index)
|
|
|
- {
|
|
|
- int vecIndex = index & ~3;
|
|
|
-
|
|
|
- if (dict.TryGetValue(vecIndex, out ShaderDeclInfo declInfo))
|
|
|
- {
|
|
|
- if (declInfo.Size > 1 && index < vecIndex + declInfo.Size)
|
|
|
- {
|
|
|
- return declInfo.Name + "." + GetAttrSwizzle(index & 3);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!dict.TryGetValue(index, out declInfo))
|
|
|
- {
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
-
|
|
|
- return declInfo.Name;
|
|
|
- }
|
|
|
-
|
|
|
- private string GetAttrSwizzle(int elem)
|
|
|
- {
|
|
|
- return "xyzw".Substring(elem, 1);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetAbsExpr(ShaderIrOp op) => GetUnaryCall(op, "abs");
|
|
|
-
|
|
|
- private string GetAddExpr(ShaderIrOp op) => GetBinaryExpr(op, "+");
|
|
|
-
|
|
|
- private string GetAndExpr(ShaderIrOp op) => GetBinaryExpr(op, "&");
|
|
|
-
|
|
|
- private string GetAsrExpr(ShaderIrOp op) => GetBinaryExpr(op, ">>");
|
|
|
-
|
|
|
- private string GetBandExpr(ShaderIrOp op) => GetBinaryExpr(op, "&&");
|
|
|
-
|
|
|
- private string GetBnotExpr(ShaderIrOp op) => GetUnaryExpr(op, "!");
|
|
|
-
|
|
|
- private string GetBorExpr(ShaderIrOp op) => GetBinaryExpr(op, "||");
|
|
|
-
|
|
|
- private string GetBxorExpr(ShaderIrOp op) => GetBinaryExpr(op, "^^");
|
|
|
-
|
|
|
- private string GetCeilExpr(ShaderIrOp op) => GetUnaryCall(op, "ceil");
|
|
|
-
|
|
|
- private string GetClampsExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- return "clamp(" + GetOperExpr(op, op.OperandA) + ", " +
|
|
|
- GetOperExpr(op, op.OperandB) + ", " +
|
|
|
- GetOperExpr(op, op.OperandC) + ")";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetClampuExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- return "int(clamp(uint(" + GetOperExpr(op, op.OperandA) + "), " +
|
|
|
- "uint(" + GetOperExpr(op, op.OperandB) + "), " +
|
|
|
- "uint(" + GetOperExpr(op, op.OperandC) + ")))";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetCeqExpr(ShaderIrOp op) => GetBinaryExpr(op, "==");
|
|
|
-
|
|
|
- private string GetCequExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "==");
|
|
|
-
|
|
|
- private string GetCgeExpr(ShaderIrOp op) => GetBinaryExpr(op, ">=");
|
|
|
-
|
|
|
- private string GetCgeuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, ">=");
|
|
|
-
|
|
|
- private string GetCgtExpr(ShaderIrOp op) => GetBinaryExpr(op, ">");
|
|
|
-
|
|
|
- private string GetCgtuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, ">");
|
|
|
-
|
|
|
- private string GetCleExpr(ShaderIrOp op) => GetBinaryExpr(op, "<=");
|
|
|
-
|
|
|
- private string GetCleuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "<=");
|
|
|
-
|
|
|
- private string GetCltExpr(ShaderIrOp op) => GetBinaryExpr(op, "<");
|
|
|
-
|
|
|
- private string GetCltuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "<");
|
|
|
-
|
|
|
- private string GetCnanExpr(ShaderIrOp op) => GetUnaryCall(op, "isnan");
|
|
|
-
|
|
|
- private string GetCneExpr(ShaderIrOp op) => GetBinaryExpr(op, "!=");
|
|
|
-
|
|
|
- private string GetCutExpr(ShaderIrOp op) => "EndPrimitive()";
|
|
|
-
|
|
|
- private string GetCneuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "!=");
|
|
|
-
|
|
|
- private string GetCnumExpr(ShaderIrOp op) => GetUnaryCall(op, "!isnan");
|
|
|
-
|
|
|
- private string GetExitExpr(ShaderIrOp op) => "return 0u";
|
|
|
-
|
|
|
- private string GetFcosExpr(ShaderIrOp op) => GetUnaryCall(op, "cos");
|
|
|
-
|
|
|
- private string GetFex2Expr(ShaderIrOp op) => GetUnaryCall(op, "exp2");
|
|
|
-
|
|
|
- private string GetFfmaExpr(ShaderIrOp op) => GetTernaryExpr(op, "*", "+");
|
|
|
-
|
|
|
- private string GetFclampExpr(ShaderIrOp op) => GetTernaryCall(op, "clamp");
|
|
|
-
|
|
|
- private string GetFlg2Expr(ShaderIrOp op) => GetUnaryCall(op, "log2");
|
|
|
-
|
|
|
- private string GetFloorExpr(ShaderIrOp op) => GetUnaryCall(op, "floor");
|
|
|
-
|
|
|
- private string GetFrcpExpr(ShaderIrOp op) => GetUnaryExpr(op, "1 / ");
|
|
|
-
|
|
|
- private string GetFrsqExpr(ShaderIrOp op) => GetUnaryCall(op, "inversesqrt");
|
|
|
-
|
|
|
- private string GetFsinExpr(ShaderIrOp op) => GetUnaryCall(op, "sin");
|
|
|
-
|
|
|
- private string GetFsqrtExpr(ShaderIrOp op) => GetUnaryCall(op, "sqrt");
|
|
|
-
|
|
|
- private string GetFtosExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- return "int(" + GetOperExpr(op, op.OperandA) + ")";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetFtouExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- return "int(uint(" + GetOperExpr(op, op.OperandA) + "))";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetIpaExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- ShaderIrMetaIpa meta = (ShaderIrMetaIpa)op.MetaData;
|
|
|
-
|
|
|
- ShaderIrOperAbuf abuf = (ShaderIrOperAbuf)op.OperandA;
|
|
|
-
|
|
|
- if (meta.Mode == ShaderIpaMode.Pass)
|
|
|
- {
|
|
|
- int index = abuf.Offs >> 4;
|
|
|
- int elem = (abuf.Offs >> 2) & 3;
|
|
|
-
|
|
|
- if (_decl.ShaderType == GalShaderType.Fragment && index == GlslDecl.GlPositionVec4Index)
|
|
|
- {
|
|
|
- switch (elem)
|
|
|
- {
|
|
|
- case 0: return "gl_FragCoord.x";
|
|
|
- case 1: return "gl_FragCoord.y";
|
|
|
- case 2: return "gl_FragCoord.z";
|
|
|
- case 3: return "1";
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return GetSrcExpr(op.OperandA);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetKilExpr(ShaderIrOp op) => "discard";
|
|
|
-
|
|
|
- private string GetLslExpr(ShaderIrOp op) => GetBinaryExpr(op, "<<");
|
|
|
- private string GetLsrExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- return "int(uint(" + GetOperExpr(op, op.OperandA) + ") >> " +
|
|
|
- GetOperExpr(op, op.OperandB) + ")";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetMaxExpr(ShaderIrOp op) => GetBinaryCall(op, "max");
|
|
|
- private string GetMinExpr(ShaderIrOp op) => GetBinaryCall(op, "min");
|
|
|
-
|
|
|
- private string GetMulExpr(ShaderIrOp op) => GetBinaryExpr(op, "*");
|
|
|
-
|
|
|
- private string GetNegExpr(ShaderIrOp op) => GetUnaryExpr(op, "-");
|
|
|
-
|
|
|
- private string GetNotExpr(ShaderIrOp op) => GetUnaryExpr(op, "~");
|
|
|
-
|
|
|
- private string GetOrExpr(ShaderIrOp op) => GetBinaryExpr(op, "|");
|
|
|
-
|
|
|
- private string GetStofExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- return "float(" + GetOperExpr(op, op.OperandA) + ")";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetSubExpr(ShaderIrOp op) => GetBinaryExpr(op, "-");
|
|
|
-
|
|
|
- private string GetTexbExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
|
|
-
|
|
|
- if (!_decl.CbTextures.TryGetValue(op, out ShaderDeclInfo declInfo))
|
|
|
- {
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
-
|
|
|
- string coords = GetTexSamplerCoords(op);
|
|
|
-
|
|
|
- string ch = "rgba".Substring(meta.Elem, 1);
|
|
|
-
|
|
|
- return GetTextureOperation(op, declInfo.Name, coords, ch);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTexqExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- ShaderIrMetaTexq meta = (ShaderIrMetaTexq)op.MetaData;
|
|
|
-
|
|
|
- string ch = "xyzw".Substring(meta.Elem, 1);
|
|
|
-
|
|
|
- if (meta.Info == ShaderTexqInfo.Dimension)
|
|
|
- {
|
|
|
- string sampler = GetTexSamplerName(op);
|
|
|
-
|
|
|
- string lod = GetOperExpr(op, op.OperandA); //???
|
|
|
-
|
|
|
- return "textureSize(" + sampler + ", " + lod + ")." + ch;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- throw new NotImplementedException(meta.Info.ToString());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTexsExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
|
|
-
|
|
|
- string sampler = GetTexSamplerName(op);
|
|
|
-
|
|
|
- string coords = GetTexSamplerCoords(op);
|
|
|
-
|
|
|
- string ch = "rgba".Substring(meta.Elem, 1);
|
|
|
-
|
|
|
- return GetTextureOperation(op, sampler, coords, ch);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTld4Expr(ShaderIrOp op)
|
|
|
- {
|
|
|
- ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
|
|
-
|
|
|
- string sampler = GetTexSamplerName(op);
|
|
|
-
|
|
|
- string coords = GetTexSamplerCoords(op);
|
|
|
-
|
|
|
- string ch = "rgba".Substring(meta.Elem, 1);
|
|
|
-
|
|
|
- return GetTextureGatherOperation(op, sampler, coords, ch);
|
|
|
- }
|
|
|
-
|
|
|
- // TODO: support AOFFI on non nvidia drivers
|
|
|
- private string GetTxlfExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- // TODO: Support all suffixes
|
|
|
- ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
|
|
-
|
|
|
- TextureInstructionSuffix suffix = meta.TextureInstructionSuffix;
|
|
|
-
|
|
|
- string sampler = GetTexSamplerName(op);
|
|
|
-
|
|
|
- string coords = GetITexSamplerCoords(op);
|
|
|
-
|
|
|
- string ch = "rgba".Substring(meta.Elem, 1);
|
|
|
-
|
|
|
- string lod = "0";
|
|
|
-
|
|
|
- if (meta.LevelOfDetail != null)
|
|
|
- {
|
|
|
- lod = GetOperExpr(op, meta.LevelOfDetail);
|
|
|
- }
|
|
|
-
|
|
|
- if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
|
|
|
- {
|
|
|
- string offset = GetTextureOffset(meta, GetOperExpr(op, meta.Offset));
|
|
|
- return "texelFetchOffset(" + sampler + ", " + coords + ", " + lod + ", " + offset + ")." + ch;
|
|
|
- }
|
|
|
-
|
|
|
- return "texelFetch(" + sampler + ", " + coords + ", " + lod + ")." + ch;
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTruncExpr(ShaderIrOp op) => GetUnaryCall(op, "trunc");
|
|
|
-
|
|
|
- private string GetUtofExpr(ShaderIrOp op)
|
|
|
- {
|
|
|
- return "float(uint(" + GetOperExpr(op, op.OperandA) + "))";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetXorExpr(ShaderIrOp op) => GetBinaryExpr(op, "^");
|
|
|
-
|
|
|
- private string GetUnaryCall(ShaderIrOp op, string funcName)
|
|
|
- {
|
|
|
- return funcName + "(" + GetOperExpr(op, op.OperandA) + ")";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetBinaryCall(ShaderIrOp op, string funcName)
|
|
|
- {
|
|
|
- return funcName + "(" + GetOperExpr(op, op.OperandA) + ", " +
|
|
|
- GetOperExpr(op, op.OperandB) + ")";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTernaryCall(ShaderIrOp op, string funcName)
|
|
|
- {
|
|
|
- return funcName + "(" + GetOperExpr(op, op.OperandA) + ", " +
|
|
|
- GetOperExpr(op, op.OperandB) + ", " +
|
|
|
- GetOperExpr(op, op.OperandC) + ")";
|
|
|
- }
|
|
|
-
|
|
|
- private string GetUnaryExpr(ShaderIrOp op, string opr)
|
|
|
- {
|
|
|
- return opr + GetOperExpr(op, op.OperandA);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetBinaryExpr(ShaderIrOp op, string opr)
|
|
|
- {
|
|
|
- return GetOperExpr(op, op.OperandA) + " " + opr + " " +
|
|
|
- GetOperExpr(op, op.OperandB);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetBinaryExprWithNaN(ShaderIrOp op, string opr)
|
|
|
- {
|
|
|
- string a = GetOperExpr(op, op.OperandA);
|
|
|
- string b = GetOperExpr(op, op.OperandB);
|
|
|
-
|
|
|
- string nanCheck =
|
|
|
- " || isnan(" + a + ")" +
|
|
|
- " || isnan(" + b + ")";
|
|
|
-
|
|
|
- return a + " " + opr + " " + b + nanCheck;
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTernaryExpr(ShaderIrOp op, string opr1, string opr2)
|
|
|
- {
|
|
|
- return GetOperExpr(op, op.OperandA) + " " + opr1 + " " +
|
|
|
- GetOperExpr(op, op.OperandB) + " " + opr2 + " " +
|
|
|
- GetOperExpr(op, op.OperandC);
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTexSamplerName(ShaderIrOp op)
|
|
|
- {
|
|
|
- ShaderIrOperImm node = (ShaderIrOperImm)op.OperandC;
|
|
|
-
|
|
|
- int handle = ((ShaderIrOperImm)op.OperandC).Value;
|
|
|
-
|
|
|
- if (!_decl.Textures.TryGetValue(handle, out ShaderDeclInfo declInfo))
|
|
|
- {
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
-
|
|
|
- return declInfo.Name;
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTexSamplerCoords(ShaderIrOp op)
|
|
|
- {
|
|
|
- ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
|
|
-
|
|
|
- bool hasDepth = (meta.TextureInstructionSuffix & TextureInstructionSuffix.Dc) != 0;
|
|
|
-
|
|
|
- int coords = ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget);
|
|
|
-
|
|
|
- bool isArray = ImageUtils.IsArray(meta.TextureTarget);
|
|
|
-
|
|
|
-
|
|
|
- string GetLastArgument(ShaderIrNode node)
|
|
|
- {
|
|
|
- string result = GetOperExpr(op, node);
|
|
|
-
|
|
|
- // array index is actually an integer so we need to pass it correctly
|
|
|
- if (isArray)
|
|
|
- {
|
|
|
- result = "float(floatBitsToInt(" + result + "))";
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- string lastArgument;
|
|
|
- string depthArgument = "";
|
|
|
-
|
|
|
- int vecSize = coords;
|
|
|
- if (hasDepth && op.Inst != ShaderIrInst.Tld4)
|
|
|
- {
|
|
|
- vecSize++;
|
|
|
- depthArgument = $", {GetOperExpr(op, meta.DepthCompare)}";
|
|
|
- }
|
|
|
-
|
|
|
- switch (coords)
|
|
|
- {
|
|
|
- case 1:
|
|
|
- if (hasDepth)
|
|
|
- {
|
|
|
- return $"vec3({GetOperExpr(op, meta.Coordinates[0])}, 0.0{depthArgument})";
|
|
|
- }
|
|
|
-
|
|
|
- return GetOperExpr(op, meta.Coordinates[0]);
|
|
|
- case 2:
|
|
|
- lastArgument = GetLastArgument(meta.Coordinates[1]);
|
|
|
-
|
|
|
- return $"vec{vecSize}({GetOperExpr(op, meta.Coordinates[0])}, {lastArgument}{depthArgument})";
|
|
|
- case 3:
|
|
|
- lastArgument = GetLastArgument(meta.Coordinates[2]);
|
|
|
-
|
|
|
- return $"vec{vecSize}({GetOperExpr(op, meta.Coordinates[0])}, {GetOperExpr(op, meta.Coordinates[1])}, {lastArgument}{depthArgument})";
|
|
|
- case 4:
|
|
|
- lastArgument = GetLastArgument(meta.Coordinates[3]);
|
|
|
-
|
|
|
- return $"vec4({GetOperExpr(op, meta.Coordinates[0])}, {GetOperExpr(op, meta.Coordinates[1])}, {GetOperExpr(op, meta.Coordinates[2])}, {lastArgument}){depthArgument}";
|
|
|
- default:
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- private string GetTextureOffset(ShaderIrMetaTex meta, string oper, int shift = 4, int mask = 0xF)
|
|
|
- {
|
|
|
- string GetOffset(string operation, int index)
|
|
|
- {
|
|
|
- return $"({operation} >> {index * shift}) & 0x{mask:x}";
|
|
|
- }
|
|
|
-
|
|
|
- int coords = ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget);
|
|
|
-
|
|
|
- if (ImageUtils.IsArray(meta.TextureTarget))
|
|
|
- coords -= 1;
|
|
|
-
|
|
|
- switch (coords)
|
|
|
- {
|
|
|
- case 1:
|
|
|
- return GetOffset(oper, 0);
|
|
|
- case 2:
|
|
|
- return "ivec2(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ")";
|
|
|
- case 3:
|
|
|
- return "ivec3(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ", " + GetOffset(oper, 2) + ")";
|
|
|
- case 4:
|
|
|
- return "ivec4(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ", " + GetOffset(oper, 2) + ", " + GetOffset(oper, 3) + ")";
|
|
|
- default:
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // TODO: support AOFFI on non nvidia drivers
|
|
|
- private string GetTextureGatherOperation(ShaderIrOp op, string sampler, string coords, string ch)
|
|
|
- {
|
|
|
- ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
|
|
-
|
|
|
- TextureInstructionSuffix suffix = meta.TextureInstructionSuffix;
|
|
|
-
|
|
|
- string chString = "." + ch;
|
|
|
-
|
|
|
- string comp = meta.Component.ToString();
|
|
|
-
|
|
|
- if ((suffix & TextureInstructionSuffix.Dc) != 0)
|
|
|
- {
|
|
|
- comp = GetOperExpr(op, meta.DepthCompare);
|
|
|
- }
|
|
|
-
|
|
|
- if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
|
|
|
- {
|
|
|
- string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))", 8, 0x3F);
|
|
|
-
|
|
|
- if ((suffix & TextureInstructionSuffix.Dc) != 0)
|
|
|
- {
|
|
|
- return "textureGatherOffset(" + sampler + ", " + coords + ", " + comp + ", " + offset + ")" + chString;
|
|
|
- }
|
|
|
-
|
|
|
- return "textureGatherOffset(" + sampler + ", " + coords + ", " + offset + ", " + comp + ")" + chString;
|
|
|
- }
|
|
|
- // TODO: Support PTP
|
|
|
- else if ((suffix & TextureInstructionSuffix.Ptp) != 0)
|
|
|
- {
|
|
|
- throw new NotImplementedException();
|
|
|
- }
|
|
|
-
|
|
|
- return "textureGather(" + sampler + ", " + coords + ", " + comp + ")" + chString;
|
|
|
- }
|
|
|
-
|
|
|
- // TODO: support AOFFI on non nvidia drivers
|
|
|
- private string GetTextureOperation(ShaderIrOp op, string sampler, string coords, string ch)
|
|
|
- {
|
|
|
- ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
|
|
-
|
|
|
- TextureInstructionSuffix suffix = meta.TextureInstructionSuffix;
|
|
|
-
|
|
|
- string chString = "." + ch;
|
|
|
-
|
|
|
- if ((suffix & TextureInstructionSuffix.Dc) != 0)
|
|
|
- {
|
|
|
- chString = "";
|
|
|
- }
|
|
|
-
|
|
|
- // TODO: Support LBA and LLA
|
|
|
- if ((suffix & TextureInstructionSuffix.Lz) != 0)
|
|
|
- {
|
|
|
- if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
|
|
|
- {
|
|
|
- string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))");
|
|
|
-
|
|
|
- return "textureLodOffset(" + sampler + ", " + coords + ", 0.0, " + offset + ")" + chString;
|
|
|
- }
|
|
|
-
|
|
|
- return "textureLod(" + sampler + ", " + coords + ", 0.0)" + chString;
|
|
|
- }
|
|
|
- else if ((suffix & TextureInstructionSuffix.Lb) != 0)
|
|
|
- {
|
|
|
- if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
|
|
|
- {
|
|
|
- string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))");
|
|
|
-
|
|
|
- return "textureOffset(" + sampler + ", " + coords + ", " + offset + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString;
|
|
|
- }
|
|
|
-
|
|
|
- return "texture(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString;
|
|
|
- }
|
|
|
- else if ((suffix & TextureInstructionSuffix.Ll) != 0)
|
|
|
- {
|
|
|
- if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
|
|
|
- {
|
|
|
- string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))");
|
|
|
-
|
|
|
- return "textureLodOffset(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ", " + offset + ")" + chString;
|
|
|
- }
|
|
|
-
|
|
|
- return "textureLod(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString;
|
|
|
- }
|
|
|
- else if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
|
|
|
- {
|
|
|
- string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))");
|
|
|
-
|
|
|
- return "textureOffset(" + sampler + ", " + coords + ", " + offset + ")" + chString;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return "texture(" + sampler + ", " + coords + ")" + chString;
|
|
|
- }
|
|
|
- throw new NotImplementedException($"Texture Suffix {meta.TextureInstructionSuffix} is not implemented");
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- private string GetITexSamplerCoords(ShaderIrOp op)
|
|
|
- {
|
|
|
- ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
|
|
-
|
|
|
- switch (ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget))
|
|
|
- {
|
|
|
- case 1:
|
|
|
- return GetOperExpr(op, meta.Coordinates[0]);
|
|
|
- case 2:
|
|
|
- return "ivec2(" + GetOperExpr(op, meta.Coordinates[0]) + ", " + GetOperExpr(op, meta.Coordinates[1]) + ")";
|
|
|
- case 3:
|
|
|
- return "ivec3(" + GetOperExpr(op, meta.Coordinates[0]) + ", " + GetOperExpr(op, meta.Coordinates[1]) + ", " + GetOperExpr(op, meta.Coordinates[2]) + ")";
|
|
|
- default:
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private string GetOperExpr(ShaderIrOp op, ShaderIrNode oper)
|
|
|
- {
|
|
|
- return GetExprWithCast(op, oper, GetSrcExpr(oper));
|
|
|
- }
|
|
|
-
|
|
|
- private static string GetExprWithCast(ShaderIrNode dst, ShaderIrNode src, string expr)
|
|
|
- {
|
|
|
- //Note: The "DstType" (of the cast) is the type that the operation
|
|
|
- //uses on the source operands, while the "SrcType" is the destination
|
|
|
- //type of the operand result (if it is a operation) or just the type
|
|
|
- //of the variable for registers/uniforms/attributes.
|
|
|
- OperType dstType = GetSrcNodeType(dst);
|
|
|
- OperType srcType = GetDstNodeType(src);
|
|
|
-
|
|
|
- if (dstType != srcType)
|
|
|
- {
|
|
|
- //Check for invalid casts
|
|
|
- //(like bool to int/float and others).
|
|
|
- if (srcType != OperType.F32 &&
|
|
|
- srcType != OperType.I32)
|
|
|
- {
|
|
|
- throw new InvalidOperationException();
|
|
|
- }
|
|
|
-
|
|
|
- switch (src)
|
|
|
- {
|
|
|
- case ShaderIrOperGpr gpr:
|
|
|
- {
|
|
|
- //When the Gpr is ZR, just return the 0 value directly,
|
|
|
- //since the float encoding for 0 is 0.
|
|
|
- if (gpr.IsConst)
|
|
|
- {
|
|
|
- return "0";
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- switch (dstType)
|
|
|
- {
|
|
|
- case OperType.F32: expr = "intBitsToFloat(" + expr + ")"; break;
|
|
|
- case OperType.I32: expr = "floatBitsToInt(" + expr + ")"; break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return expr;
|
|
|
- }
|
|
|
-
|
|
|
- private static string GetIntConst(int value)
|
|
|
- {
|
|
|
- string expr = value.ToString(CultureInfo.InvariantCulture);
|
|
|
-
|
|
|
- return value < 0 ? "(" + expr + ")" : expr;
|
|
|
- }
|
|
|
-
|
|
|
- private static string GetFloatConst(float value)
|
|
|
- {
|
|
|
- string expr = value.ToString(CultureInfo.InvariantCulture);
|
|
|
-
|
|
|
- return value < 0 ? "(" + expr + ")" : expr;
|
|
|
- }
|
|
|
-
|
|
|
- private static OperType GetDstNodeType(ShaderIrNode node)
|
|
|
- {
|
|
|
- //Special case instructions with the result type different
|
|
|
- //from the input types (like integer <-> float conversion) here.
|
|
|
- if (node is ShaderIrOp op)
|
|
|
- {
|
|
|
- switch (op.Inst)
|
|
|
- {
|
|
|
- case ShaderIrInst.Stof:
|
|
|
- case ShaderIrInst.Txlf:
|
|
|
- case ShaderIrInst.Utof:
|
|
|
- return OperType.F32;
|
|
|
-
|
|
|
- case ShaderIrInst.Ftos:
|
|
|
- case ShaderIrInst.Ftou:
|
|
|
- return OperType.I32;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return GetSrcNodeType(node);
|
|
|
- }
|
|
|
-
|
|
|
- private static OperType GetSrcNodeType(ShaderIrNode node)
|
|
|
- {
|
|
|
- switch (node)
|
|
|
- {
|
|
|
- case ShaderIrOperAbuf abuf:
|
|
|
- return abuf.Offs == GlslDecl.LayerAttr ||
|
|
|
- abuf.Offs == GlslDecl.InstanceIdAttr ||
|
|
|
- abuf.Offs == GlslDecl.VertexIdAttr ||
|
|
|
- abuf.Offs == GlslDecl.FaceAttr
|
|
|
- ? OperType.I32
|
|
|
- : OperType.F32;
|
|
|
-
|
|
|
- case ShaderIrOperCbuf cbuf: return OperType.F32;
|
|
|
- case ShaderIrOperGpr gpr: return OperType.F32;
|
|
|
- case ShaderIrOperImm imm: return OperType.I32;
|
|
|
- case ShaderIrOperImmf immf: return OperType.F32;
|
|
|
- case ShaderIrOperPred pred: return OperType.Bool;
|
|
|
-
|
|
|
- case ShaderIrOp op:
|
|
|
- if (op.Inst > ShaderIrInst.B_Start &&
|
|
|
- op.Inst < ShaderIrInst.B_End)
|
|
|
- {
|
|
|
- return OperType.Bool;
|
|
|
- }
|
|
|
- else if (op.Inst > ShaderIrInst.F_Start &&
|
|
|
- op.Inst < ShaderIrInst.F_End)
|
|
|
- {
|
|
|
- return OperType.F32;
|
|
|
- }
|
|
|
- else if (op.Inst > ShaderIrInst.I_Start &&
|
|
|
- op.Inst < ShaderIrInst.I_End)
|
|
|
- {
|
|
|
- return OperType.I32;
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- throw new ArgumentException(nameof(node));
|
|
|
- }
|
|
|
-
|
|
|
- private static string GetBlockPosition(ShaderIrBlock block)
|
|
|
- {
|
|
|
- if (block != null)
|
|
|
- {
|
|
|
- return "0x" + block.Position.ToString("x8") + "u";
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return "0u";
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|