[GPU] Add more shader instructions, add support for rgb565 textures

This commit is contained in:
gdkchan 2018-04-10 16:50:32 -03:00
parent e9cfdef098
commit feb2680a6c
22 changed files with 817 additions and 238 deletions

View file

@ -31,40 +31,51 @@ namespace Ryujinx.Graphics.Gal.Shader
{
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
{
{ ShaderIrInst.And, GetAndExpr },
{ ShaderIrInst.Asr, GetAsrExpr },
{ ShaderIrInst.Band, GetBandExpr },
{ ShaderIrInst.Bnot, GetBnotExpr },
{ ShaderIrInst.Clt, GetCltExpr },
{ ShaderIrInst.Ceq, GetCeqExpr },
{ ShaderIrInst.Cle, GetCleExpr },
{ ShaderIrInst.Cgt, GetCgtExpr },
{ ShaderIrInst.Cne, GetCneExpr },
{ ShaderIrInst.Cge, GetCgeExpr },
{ ShaderIrInst.Exit, GetExitExpr },
{ ShaderIrInst.Fabs, GetFabsExpr },
{ ShaderIrInst.Fadd, GetFaddExpr },
{ ShaderIrInst.Fcos, GetFcosExpr },
{ ShaderIrInst.Fex2, GetFex2Expr },
{ ShaderIrInst.Ffma, GetFfmaExpr },
{ ShaderIrInst.Flg2, GetFlg2Expr },
{ ShaderIrInst.Fmul, GetFmulExpr },
{ ShaderIrInst.Fneg, GetFnegExpr },
{ ShaderIrInst.Frcp, GetFrcpExpr },
{ ShaderIrInst.Frsq, GetFrsqExpr },
{ ShaderIrInst.Fsin, GetFsinExpr },
{ ShaderIrInst.Ipa, GetIpaExpr },
{ ShaderIrInst.Kil, GetKilExpr },
{ ShaderIrInst.Lsr, GetLsrExpr },
{ ShaderIrInst.Not, GetNotExpr },
{ ShaderIrInst.Or, GetOrExpr },
{ ShaderIrInst.Stof, GetStofExpr },
{ ShaderIrInst.Utof, GetUtofExpr },
{ ShaderIrInst.Texr, GetTexrExpr },
{ ShaderIrInst.Texg, GetTexgExpr },
{ ShaderIrInst.Texb, GetTexbExpr },
{ ShaderIrInst.Texa, GetTexaExpr },
{ ShaderIrInst.Xor, GetXorExpr },
{ ShaderIrInst.And, GetAndExpr },
{ ShaderIrInst.Asr, GetAsrExpr },
{ ShaderIrInst.Band, GetBandExpr },
{ ShaderIrInst.Bnot, GetBnotExpr },
{ ShaderIrInst.Ceil, GetCeilExpr },
{ ShaderIrInst.Ceq, GetCeqExpr },
{ ShaderIrInst.Cge, GetCgeExpr },
{ ShaderIrInst.Cgt, GetCgtExpr },
{ ShaderIrInst.Clamp, GetClampExpr },
{ ShaderIrInst.Cle, GetCleExpr },
{ ShaderIrInst.Clt, GetCltExpr },
{ ShaderIrInst.Cne, GetCneExpr },
{ ShaderIrInst.Exit, GetExitExpr },
{ ShaderIrInst.Fabs, GetFabsExpr },
{ ShaderIrInst.Fadd, GetFaddExpr },
{ ShaderIrInst.Fceq, GetCeqExpr },
{ ShaderIrInst.Fcge, GetCgeExpr },
{ ShaderIrInst.Fcgt, GetCgtExpr },
{ ShaderIrInst.Fcle, GetCleExpr },
{ ShaderIrInst.Fclt, GetCltExpr },
{ ShaderIrInst.Fcne, GetCneExpr },
{ ShaderIrInst.Fcos, GetFcosExpr },
{ ShaderIrInst.Fex2, GetFex2Expr },
{ ShaderIrInst.Ffma, GetFfmaExpr },
{ ShaderIrInst.Flg2, GetFlg2Expr },
{ ShaderIrInst.Floor, GetFloorExpr },
{ ShaderIrInst.Fmul, GetFmulExpr },
{ ShaderIrInst.Fneg, GetFnegExpr },
{ ShaderIrInst.Frcp, GetFrcpExpr },
{ ShaderIrInst.Frsq, GetFrsqExpr },
{ ShaderIrInst.Fsin, GetFsinExpr },
{ ShaderIrInst.Ftos, GetFtosExpr },
{ ShaderIrInst.Ftou, GetFtouExpr },
{ ShaderIrInst.Ipa, GetIpaExpr },
{ ShaderIrInst.Kil, GetKilExpr },
{ ShaderIrInst.Lsr, GetLsrExpr },
{ ShaderIrInst.Not, GetNotExpr },
{ ShaderIrInst.Or, GetOrExpr },
{ ShaderIrInst.Stof, GetStofExpr },
{ ShaderIrInst.Texq, GetTexqExpr },
{ ShaderIrInst.Texs, GetTexsExpr },
{ ShaderIrInst.Trunc, GetTruncExpr },
{ ShaderIrInst.Txlf, GetTxlfExpr },
{ ShaderIrInst.Utof, GetUtofExpr },
{ ShaderIrInst.Xor, GetXorExpr }
};
}
@ -117,11 +128,21 @@ namespace Ryujinx.Graphics.Gal.Shader
private void PrintDeclInAttributes()
{
if (Decl.ShaderType == GalShaderType.Fragment)
{
SB.AppendLine("in vec4 " + GlslDecl.PositionOutAttrName + ";");
}
PrintDeclAttributes(Decl.InAttributes.Values, "in");
}
private void PrintDeclOutAttributes()
{
if (Decl.ShaderType == GalShaderType.Vertex)
{
SB.AppendLine("out vec4 " + GlslDecl.PositionOutAttrName + ";");
}
PrintDeclAttributes(Decl.OutAttributes.Values, "out");
}
@ -133,7 +154,7 @@ namespace Ryujinx.Graphics.Gal.Shader
{
if (DeclInfo.Index >= 0)
{
SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
SB.AppendLine("layout (location = " + DeclInfo.Index + ") " + InOut + " " + GetDecl(DeclInfo) + ";");
Count++;
}
@ -222,7 +243,14 @@ namespace Ryujinx.Graphics.Gal.Shader
if (Node is ShaderIrCond Cond)
{
string SubScopeName = "if (" + GetSrcExpr(Cond.Pred, true) + ")";
string IfExpr = GetSrcExpr(Cond.Pred, true);
if (Cond.Not)
{
IfExpr = "!(" + IfExpr + ")";
}
string SubScopeName = "if (" + IfExpr + ")";
PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
}
@ -236,6 +264,16 @@ namespace Ryujinx.Graphics.Gal.Shader
}
else if (Node is ShaderIrOp Op)
{
if (Op.Inst == ShaderIrInst.Exit)
{
//Do everything that needs to be done before
//the shader ends here.
if (Decl.ShaderType == GalShaderType.Vertex)
{
SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
}
}
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
}
else
@ -321,10 +359,9 @@ namespace Ryujinx.Graphics.Gal.Shader
return true;
case ShaderIrInst.Ipa:
case ShaderIrInst.Texr:
case ShaderIrInst.Texg:
case ShaderIrInst.Texb:
case ShaderIrInst.Texa:
case ShaderIrInst.Texq:
case ShaderIrInst.Texs:
case ShaderIrInst.Txlf:
return false;
}
@ -349,11 +386,6 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetName(ShaderIrOperAbuf Abuf)
{
if (Abuf.Offs == GlslDecl.GlPositionWAttr && Decl.ShaderType == GalShaderType.Fragment)
{
return "(1f / gl_FragCoord.w)";
}
if (Abuf.Offs == GlslDecl.VertexIdAttr)
{
return "gl_VertexID";
@ -437,6 +469,10 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!");
private string GetCeilExpr(ShaderIrOp Op) => GetUnaryCall(Op, "ceil");
private string GetClampExpr(ShaderIrOp Op) => GetTernaryCall(Op, "clamp");
private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<");
private string GetCeqExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "==");
private string GetCleExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<=");
@ -458,6 +494,8 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetFlg2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "log2");
private string GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor");
private string GetFmulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
private string GetFnegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
@ -468,6 +506,16 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetFsinExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sin");
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) => GetSrcExpr(Op.OperandA);
private string GetKilExpr(ShaderIrOp Op) => "discard";
@ -487,6 +535,54 @@ namespace Ryujinx.Graphics.Gal.Shader
return "float(" + GetOperExpr(Op, Op.OperandA) + ")";
}
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 "texture(" + Sampler + ", " + Coords + ")." + Ch;
}
private string GetTxlfExpr(ShaderIrOp Op)
{
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
string Sampler = GetTexSamplerName(Op);
string Coords = GetITexSamplerCoords(Op);
string Ch = "rgba".Substring(Meta.Elem, 1);
return "texelFetch(" + Sampler + ", " + Coords + ", 0)." + Ch;
}
private string GetTruncExpr(ShaderIrOp Op) => GetUnaryCall(Op, "trunc");
private string GetUtofExpr(ShaderIrOp Op)
{
return "float(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
@ -499,6 +595,13 @@ namespace Ryujinx.Graphics.Gal.Shader
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")";
}
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);
@ -517,16 +620,6 @@ namespace Ryujinx.Graphics.Gal.Shader
GetOperExpr(Op, Op.OperandC);
}
private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r');
private string GetTexgExpr(ShaderIrOp Op) => GetTexExpr(Op, 'g');
private string GetTexbExpr(ShaderIrOp Op) => GetTexExpr(Op, 'b');
private string GetTexaExpr(ShaderIrOp Op) => GetTexExpr(Op, 'a');
private string GetTexExpr(ShaderIrOp Op, char Ch)
{
return $"texture({GetTexSamplerName(Op)}, {GetTexSamplerCoords(Op)}).{Ch}";
}
private string GetTexSamplerName(ShaderIrOp Op)
{
ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
@ -547,6 +640,12 @@ namespace Ryujinx.Graphics.Gal.Shader
GetOperExpr(Op, Op.OperandB) + ")";
}
private string GetITexSamplerCoords(ShaderIrOp Op)
{
return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
GetOperExpr(Op, Op.OperandB) + ")";
}
private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper)
{
return GetExprWithCast(Op, Oper, GetSrcExpr(Oper));
@ -571,13 +670,31 @@ namespace Ryujinx.Graphics.Gal.Shader
throw new InvalidOperationException();
}
//For integer immediates being used as float,
//it's better (for readability) to just return the float value.
if (Src is ShaderIrOperImm Imm && DstType == OperType.F32)
switch (Src)
{
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
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;
}
return Value.ToString(CultureInfo.InvariantCulture) + "f";
case ShaderIrOperImm Imm:
{
//For integer immediates being used as float,
//it's better (for readability) to just return the float value.
if (DstType == OperType.F32)
{
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
return Value.ToString(CultureInfo.InvariantCulture) + "f";
}
break;
}
}
switch (DstType)
@ -592,12 +709,20 @@ namespace Ryujinx.Graphics.Gal.Shader
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: return OperType.F32;
case ShaderIrInst.Utof: return OperType.F32;
case ShaderIrInst.Stof:
case ShaderIrInst.Txlf:
case ShaderIrInst.Utof:
return OperType.F32;
case ShaderIrInst.Ftos:
case ShaderIrInst.Ftou:
return OperType.I32;
}
}