Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
62585755fd | ||
|
56621615b1 | ||
|
2099a3e84b | ||
|
7d26e4ac7b | ||
|
8d41402fa6 | ||
|
5af8ce7c38 | ||
|
77c4291c34 | ||
|
6e92b7a378 | ||
|
9b852c7481 | ||
|
c40c3905e2 | ||
|
a6cd044f0f | ||
|
f5a1de6ac5 | ||
|
2aeb5b00e3 | ||
|
60ba7b71f2 | ||
|
7c1d2bbb98 | ||
|
beacf8c1c8 | ||
|
0dbe45ae37 | ||
|
2b50e52e48 | ||
|
49eadbc209 | ||
|
2df16ded9b | ||
|
e43390c723 | ||
|
5af1327068 | ||
|
88a8d1e567 | ||
|
bf77d1cab9 | ||
|
1ca0517c99 | ||
|
599d485bff | ||
|
60e16c15b6 | ||
|
2068445939 | ||
|
a4fc9f8050 | ||
|
5437d6cb13 | ||
|
7539e26144 | ||
|
1c3697b6a4 | ||
|
81f848e54f | ||
|
358a781639 | ||
|
45ce540b9b | ||
|
96bf7f8522 | ||
|
33e673ceb8 | ||
|
9c2500de5f | ||
|
dbe43c1719 | ||
|
f502cfaf62 | ||
|
1fd5cf2b4a | ||
|
814f75142e |
@@ -62,224 +62,225 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
_instTable = new InstructionInfo[(int)X86Instruction.Count];
|
_instTable = new InstructionInfo[(int)X86Instruction.Count];
|
||||||
|
|
||||||
// Name RM/R RM/I8 RM/I32 R/I64 R/RM Flags
|
// Name RM/R RM/I8 RM/I32 R/I64 R/RM Flags
|
||||||
Add(X86Instruction.Add, new InstructionInfo(0x00000001, 0x00000083, 0x00000081, BadOp, 0x00000003, InstructionFlags.None));
|
Add(X86Instruction.Add, new InstructionInfo(0x00000001, 0x00000083, 0x00000081, BadOp, 0x00000003, InstructionFlags.None));
|
||||||
Add(X86Instruction.Addpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Addpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Addps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex));
|
Add(X86Instruction.Addps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Addsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Addsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Addss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Addss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Aesdec, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38de, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Aesdec, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38de, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Aesdeclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38df, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Aesdeclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38df, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Aesenc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Aesenc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Aesenclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Aesenclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Aesimc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38db, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Aesimc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38db, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.And, new InstructionInfo(0x00000021, 0x04000083, 0x04000081, BadOp, 0x00000023, InstructionFlags.None));
|
Add(X86Instruction.And, new InstructionInfo(0x00000021, 0x04000083, 0x04000081, BadOp, 0x00000023, InstructionFlags.None));
|
||||||
Add(X86Instruction.Andnpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Andnpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Andnps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex));
|
Add(X86Instruction.Andnps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Andpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Andpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Andps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex));
|
Add(X86Instruction.Andps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Blendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3815, InstructionFlags.Prefix66));
|
Add(X86Instruction.Blendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3815, InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Blendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3814, InstructionFlags.Prefix66));
|
Add(X86Instruction.Blendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3814, InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Bsr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbd, InstructionFlags.None));
|
Add(X86Instruction.Bsr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbd, InstructionFlags.None));
|
||||||
Add(X86Instruction.Bswap, new InstructionInfo(0x00000fc8, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RegOnly));
|
Add(X86Instruction.Bswap, new InstructionInfo(0x00000fc8, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RegOnly));
|
||||||
Add(X86Instruction.Call, new InstructionInfo(0x020000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Call, new InstructionInfo(0x020000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Cmovcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f40, InstructionFlags.None));
|
Add(X86Instruction.Cmovcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f40, InstructionFlags.None));
|
||||||
Add(X86Instruction.Cmp, new InstructionInfo(0x00000039, 0x07000083, 0x07000081, BadOp, 0x0000003b, InstructionFlags.None));
|
Add(X86Instruction.Cmp, new InstructionInfo(0x00000039, 0x07000083, 0x07000081, BadOp, 0x0000003b, InstructionFlags.None));
|
||||||
Add(X86Instruction.Cmppd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Cmppd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Cmpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex));
|
Add(X86Instruction.Cmpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Cmpsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Cmpsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Cmpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Cmpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Cmpxchg, new InstructionInfo(0x00000fb1, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Cmpxchg, new InstructionInfo(0x00000fb1, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Cmpxchg16b, new InstructionInfo(0x01000fc7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RexW));
|
Add(X86Instruction.Cmpxchg16b, new InstructionInfo(0x01000fc7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RexW));
|
||||||
Add(X86Instruction.Cmpxchg8, new InstructionInfo(0x00000fb0, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Reg8Src));
|
Add(X86Instruction.Cmpxchg8, new InstructionInfo(0x00000fb0, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Reg8Src));
|
||||||
Add(X86Instruction.Comisd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Comisd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Comiss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex));
|
Add(X86Instruction.Comiss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Crc32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2));
|
Add(X86Instruction.Crc32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Crc32_16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2 | InstructionFlags.Prefix66));
|
Add(X86Instruction.Crc32_16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2 | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Crc32_8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f0, InstructionFlags.PrefixF2 | InstructionFlags.Reg8Src));
|
Add(X86Instruction.Crc32_8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f0, InstructionFlags.PrefixF2 | InstructionFlags.Reg8Src));
|
||||||
Add(X86Instruction.Cvtdq2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Cvtdq2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Cvtdq2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex));
|
Add(X86Instruction.Cvtdq2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Cvtpd2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Cvtpd2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Cvtpd2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Cvtpd2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Cvtps2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Cvtps2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Cvtps2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex));
|
Add(X86Instruction.Cvtps2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Cvtsd2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Cvtsd2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Cvtsd2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Cvtsd2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Cvtsi2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Cvtsi2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Cvtsi2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Cvtsi2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Cvtss2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Cvtss2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Cvtss2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Cvtss2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Div, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x060000f7, InstructionFlags.None));
|
Add(X86Instruction.Div, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x060000f7, InstructionFlags.None));
|
||||||
Add(X86Instruction.Divpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Divpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex));
|
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Divsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Divsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Divss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Divss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Haddpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Gf2p8affineqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3ace, InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Haddps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Haddpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None));
|
Add(X86Instruction.Haddps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Imul, new InstructionInfo(BadOp, 0x0000006b, 0x00000069, BadOp, 0x00000faf, InstructionFlags.None));
|
Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None));
|
||||||
Add(X86Instruction.Imul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x050000f7, InstructionFlags.None));
|
Add(X86Instruction.Imul, new InstructionInfo(BadOp, 0x0000006b, 0x00000069, BadOp, 0x00000faf, InstructionFlags.None));
|
||||||
Add(X86Instruction.Insertps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a21, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Imul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x050000f7, InstructionFlags.None));
|
||||||
Add(X86Instruction.Jmp, new InstructionInfo(0x040000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Insertps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a21, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Ldmxcsr, new InstructionInfo(0x02000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex));
|
Add(X86Instruction.Jmp, new InstructionInfo(0x040000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Lea, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x0000008d, InstructionFlags.None));
|
Add(X86Instruction.Ldmxcsr, new InstructionInfo(0x02000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Maxpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Lea, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x0000008d, InstructionFlags.None));
|
||||||
Add(X86Instruction.Maxps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex));
|
Add(X86Instruction.Maxpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Maxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Maxps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Maxss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Maxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Minpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Maxss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Minps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex));
|
Add(X86Instruction.Minpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Minsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Minps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Minss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Minsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Mov, new InstructionInfo(0x00000089, BadOp, 0x000000c7, 0x000000b8, 0x0000008b, InstructionFlags.None));
|
Add(X86Instruction.Minss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Mov16, new InstructionInfo(0x00000089, BadOp, 0x000000c7, BadOp, 0x0000008b, InstructionFlags.Prefix66));
|
Add(X86Instruction.Mov, new InstructionInfo(0x00000089, BadOp, 0x000000c7, 0x000000b8, 0x0000008b, InstructionFlags.None));
|
||||||
Add(X86Instruction.Mov8, new InstructionInfo(0x00000088, 0x000000c6, BadOp, BadOp, 0x0000008a, InstructionFlags.Reg8Src | InstructionFlags.Reg8Dest));
|
Add(X86Instruction.Mov16, new InstructionInfo(0x00000089, BadOp, 0x000000c7, BadOp, 0x0000008b, InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Movd, new InstructionInfo(0x00000f7e, BadOp, BadOp, BadOp, 0x00000f6e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Mov8, new InstructionInfo(0x00000088, 0x000000c6, BadOp, BadOp, 0x0000008a, InstructionFlags.Reg8Src | InstructionFlags.Reg8Dest));
|
||||||
Add(X86Instruction.Movdqu, new InstructionInfo(0x00000f7f, BadOp, BadOp, BadOp, 0x00000f6f, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Movd, new InstructionInfo(0x00000f7e, BadOp, BadOp, BadOp, 0x00000f6e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Movhlps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f12, InstructionFlags.Vex));
|
Add(X86Instruction.Movdqu, new InstructionInfo(0x00000f7f, BadOp, BadOp, BadOp, 0x00000f6f, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Movlhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f16, InstructionFlags.Vex));
|
Add(X86Instruction.Movhlps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f12, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Movq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Movlhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f16, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Movsd, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Movq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Movss, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Movsd, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Movsx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbf, InstructionFlags.None));
|
Add(X86Instruction.Movss, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Movsx32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000063, InstructionFlags.None));
|
Add(X86Instruction.Movsx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbf, InstructionFlags.None));
|
||||||
Add(X86Instruction.Movsx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbe, InstructionFlags.Reg8Src));
|
Add(X86Instruction.Movsx32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000063, InstructionFlags.None));
|
||||||
Add(X86Instruction.Movzx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb7, InstructionFlags.None));
|
Add(X86Instruction.Movsx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbe, InstructionFlags.Reg8Src));
|
||||||
Add(X86Instruction.Movzx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb6, InstructionFlags.Reg8Src));
|
Add(X86Instruction.Movzx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb7, InstructionFlags.None));
|
||||||
Add(X86Instruction.Mul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x040000f7, InstructionFlags.None));
|
Add(X86Instruction.Movzx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb6, InstructionFlags.Reg8Src));
|
||||||
Add(X86Instruction.Mulpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Mul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x040000f7, InstructionFlags.None));
|
||||||
Add(X86Instruction.Mulps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex));
|
Add(X86Instruction.Mulpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Mulsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Mulps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Mulss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Mulsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Neg, new InstructionInfo(0x030000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Mulss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Not, new InstructionInfo(0x020000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Neg, new InstructionInfo(0x030000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Or, new InstructionInfo(0x00000009, 0x01000083, 0x01000081, BadOp, 0x0000000b, InstructionFlags.None));
|
Add(X86Instruction.Not, new InstructionInfo(0x020000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Paddb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Or, new InstructionInfo(0x00000009, 0x01000083, 0x01000081, BadOp, 0x0000000b, InstructionFlags.None));
|
||||||
Add(X86Instruction.Paddd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffe, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Paddb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Paddq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd4, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Paddd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffe, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Paddw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Paddq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd4, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Palignr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Paddw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pand, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Palignr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pandn, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdf, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pand, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pavgb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe0, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pandn, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdf, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pavgw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pavgb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe0, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3810, InstructionFlags.Prefix66));
|
Add(X86Instruction.Pavgw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pclmulqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a44, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3810, InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pcmpeqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f74, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pclmulqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a44, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pcmpeqd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f76, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pcmpeqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f74, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pcmpeqq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3829, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pcmpeqd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f76, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pcmpeqw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f75, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pcmpeqq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3829, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pcmpgtb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f64, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pcmpeqw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f75, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pcmpgtd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f66, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pcmpgtb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f64, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pcmpgtq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3837, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pcmpgtd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f66, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pcmpgtw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f65, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pcmpgtq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3837, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pextrb, new InstructionInfo(0x000f3a14, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pcmpgtw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f65, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pextrd, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pextrb, new InstructionInfo(0x000f3a14, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pextrq, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pextrd, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pextrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc5, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pextrq, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pinsrb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a20, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pextrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc5, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pinsrd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pinsrb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a20, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pinsrq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pinsrd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pinsrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc4, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pinsrq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmaxsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pinsrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc4, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmaxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmaxsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmaxsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fee, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmaxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmaxub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fde, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmaxsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fee, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmaxud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmaxub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fde, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmaxuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmaxud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pminsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3838, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmaxuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pminsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3839, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pminsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3838, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pminsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fea, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pminsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3839, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pminub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fda, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pminsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fea, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pminud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pminub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fda, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pminuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pminud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmovsxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3820, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pminuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmovsxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3825, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmovsxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3820, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmovsxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3823, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmovsxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3825, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmovzxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3830, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmovsxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3823, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmovzxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3835, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmovzxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3830, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmovzxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3833, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmovzxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3835, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmulld, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3840, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmovzxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3833, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pmullw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd5, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pmulld, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3840, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pop, new InstructionInfo(0x0000008f, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Pmullw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd5, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Popcnt, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb8, InstructionFlags.PrefixF3));
|
Add(X86Instruction.Pop, new InstructionInfo(0x0000008f, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Por, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000feb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Popcnt, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb8, InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Pshufb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3800, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Por, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000feb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pshufd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f70, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pshufb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3800, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pslld, new InstructionInfo(BadOp, 0x06000f72, BadOp, BadOp, 0x00000ff2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pshufd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f70, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pslldq, new InstructionInfo(BadOp, 0x07000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pslld, new InstructionInfo(BadOp, 0x06000f72, BadOp, BadOp, 0x00000ff2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psllq, new InstructionInfo(BadOp, 0x06000f73, BadOp, BadOp, 0x00000ff3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Pslldq, new InstructionInfo(BadOp, 0x07000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psllw, new InstructionInfo(BadOp, 0x06000f71, BadOp, BadOp, 0x00000ff1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psllq, new InstructionInfo(BadOp, 0x06000f73, BadOp, BadOp, 0x00000ff3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psrad, new InstructionInfo(BadOp, 0x04000f72, BadOp, BadOp, 0x00000fe2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psllw, new InstructionInfo(BadOp, 0x06000f71, BadOp, BadOp, 0x00000ff1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psraw, new InstructionInfo(BadOp, 0x04000f71, BadOp, BadOp, 0x00000fe1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psrad, new InstructionInfo(BadOp, 0x04000f72, BadOp, BadOp, 0x00000fe2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psrld, new InstructionInfo(BadOp, 0x02000f72, BadOp, BadOp, 0x00000fd2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psraw, new InstructionInfo(BadOp, 0x04000f71, BadOp, BadOp, 0x00000fe1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psrlq, new InstructionInfo(BadOp, 0x02000f73, BadOp, BadOp, 0x00000fd3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psrld, new InstructionInfo(BadOp, 0x02000f72, BadOp, BadOp, 0x00000fd2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psrldq, new InstructionInfo(BadOp, 0x03000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psrlq, new InstructionInfo(BadOp, 0x02000f73, BadOp, BadOp, 0x00000fd3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psrlw, new InstructionInfo(BadOp, 0x02000f71, BadOp, BadOp, 0x00000fd1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psrldq, new InstructionInfo(BadOp, 0x03000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psubb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff8, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psrlw, new InstructionInfo(BadOp, 0x02000f71, BadOp, BadOp, 0x00000fd1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psubd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffa, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psubb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff8, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psubq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psubd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffa, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Psubw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff9, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psubq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Punpckhbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f68, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Psubw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff9, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Punpckhdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Punpckhbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f68, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Punpckhqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Punpckhdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Punpckhwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f69, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Punpckhqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Punpcklbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f60, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Punpckhwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f69, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Punpckldq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f62, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Punpcklbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f60, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Punpcklqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Punpckldq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f62, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Punpcklwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f61, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Punpcklqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Push, new InstructionInfo(BadOp, 0x0000006a, 0x00000068, BadOp, 0x060000ff, InstructionFlags.None));
|
Add(X86Instruction.Punpcklwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f61, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Pxor, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fef, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Push, new InstructionInfo(BadOp, 0x0000006a, 0x00000068, BadOp, 0x060000ff, InstructionFlags.None));
|
||||||
Add(X86Instruction.Rcpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex));
|
Add(X86Instruction.Pxor, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fef, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Rcpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Rcpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Ror, new InstructionInfo(0x010000d3, 0x010000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Rcpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Roundpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a09, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Ror, new InstructionInfo(0x010000d3, 0x010000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Roundps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a08, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Roundpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a09, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Roundsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Roundps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a08, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Roundss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Roundsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Rsqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex));
|
Add(X86Instruction.Roundss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Rsqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Rsqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Sar, new InstructionInfo(0x070000d3, 0x070000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Rsqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Setcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f90, InstructionFlags.Reg8Dest));
|
Add(X86Instruction.Sar, new InstructionInfo(0x070000d3, 0x070000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Sha256Msg1, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cc, InstructionFlags.None));
|
Add(X86Instruction.Setcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f90, InstructionFlags.Reg8Dest));
|
||||||
Add(X86Instruction.Sha256Msg2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cd, InstructionFlags.None));
|
Add(X86Instruction.Sha256Msg1, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cc, InstructionFlags.None));
|
||||||
Add(X86Instruction.Sha256Rnds2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cb, InstructionFlags.None));
|
Add(X86Instruction.Sha256Msg2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cd, InstructionFlags.None));
|
||||||
Add(X86Instruction.Shl, new InstructionInfo(0x040000d3, 0x040000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Sha256Rnds2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cb, InstructionFlags.None));
|
||||||
Add(X86Instruction.Shr, new InstructionInfo(0x050000d3, 0x050000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Shl, new InstructionInfo(0x040000d3, 0x040000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Shufpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Shr, new InstructionInfo(0x050000d3, 0x050000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Shufps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex));
|
Add(X86Instruction.Shufpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Sqrtpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Shufps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Sqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex));
|
Add(X86Instruction.Sqrtpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Sqrtsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Sqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Sqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Sqrtsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Stmxcsr, new InstructionInfo(0x03000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex));
|
Add(X86Instruction.Sqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Sub, new InstructionInfo(0x00000029, 0x05000083, 0x05000081, BadOp, 0x0000002b, InstructionFlags.None));
|
Add(X86Instruction.Stmxcsr, new InstructionInfo(0x03000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Subpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Sub, new InstructionInfo(0x00000029, 0x05000083, 0x05000081, BadOp, 0x0000002b, InstructionFlags.None));
|
||||||
Add(X86Instruction.Subps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex));
|
Add(X86Instruction.Subpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Subsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
Add(X86Instruction.Subps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Subss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
Add(X86Instruction.Subsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||||
Add(X86Instruction.Test, new InstructionInfo(0x00000085, BadOp, 0x000000f7, BadOp, BadOp, InstructionFlags.None));
|
Add(X86Instruction.Subss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||||
Add(X86Instruction.Unpckhpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Test, new InstructionInfo(0x00000085, BadOp, 0x000000f7, BadOp, BadOp, InstructionFlags.None));
|
||||||
Add(X86Instruction.Unpckhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex));
|
Add(X86Instruction.Unpckhpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Unpcklpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Unpckhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Unpcklps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex));
|
Add(X86Instruction.Unpcklpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vblendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Unpcklps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex));
|
||||||
Add(X86Instruction.Vblendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vblendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vcvtph2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3813, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vblendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vcvtps2ph, new InstructionInfo(0x000f3a1d, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vcvtph2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3813, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vfmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b8, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vcvtps2ph, new InstructionInfo(0x000f3a1d, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vfmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
Add(X86Instruction.Vfmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b8, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vfmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vfmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
||||||
Add(X86Instruction.Vfmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
Add(X86Instruction.Vfmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vfmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vfmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
||||||
Add(X86Instruction.Vfnmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vfmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vfnmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
Add(X86Instruction.Vfnmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vfnmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vfnmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
||||||
Add(X86Instruction.Vfnmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
Add(X86Instruction.Vfnmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Vfnmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vfnmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
||||||
Add(X86Instruction.Vpblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Vfnmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Xor, new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp, 0x00000033, InstructionFlags.None));
|
Add(X86Instruction.Vpblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
Add(X86Instruction.Xorpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
Add(X86Instruction.Xor, new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp, 0x00000033, InstructionFlags.None));
|
||||||
Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex));
|
Add(X86Instruction.Xorpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||||
|
Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex));
|
||||||
|
|
||||||
static void Add(X86Instruction inst, in InstructionInfo info)
|
static void Add(X86Instruction inst, in InstructionInfo info)
|
||||||
{
|
{
|
||||||
|
@@ -20,8 +20,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
if (maxNum >= 7)
|
if (maxNum >= 7)
|
||||||
{
|
{
|
||||||
(_, int ebx7, _, _) = X86Base.CpuId(0x00000007, 0x00000000);
|
(_, int ebx7, int ecx7, _) = X86Base.CpuId(0x00000007, 0x00000000);
|
||||||
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
|
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
|
||||||
|
FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,9 +55,16 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Sha = 1 << 29
|
Sha = 1 << 29
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum FeatureFlags7Ecx
|
||||||
|
{
|
||||||
|
Gfni = 1 << 8,
|
||||||
|
}
|
||||||
|
|
||||||
public static FeatureFlags1Edx FeatureInfo1Edx { get; }
|
public static FeatureFlags1Edx FeatureInfo1Edx { get; }
|
||||||
public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
|
public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
|
||||||
public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
|
public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
|
||||||
|
public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0;
|
||||||
|
|
||||||
public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
|
public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
|
||||||
public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2);
|
public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2);
|
||||||
@@ -72,6 +80,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
|
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
|
||||||
public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
|
public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
|
||||||
public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
|
public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
|
||||||
|
public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni);
|
||||||
|
|
||||||
public static bool ForceLegacySse { get; set; }
|
public static bool ForceLegacySse { get; set; }
|
||||||
|
|
||||||
|
@@ -13,176 +13,177 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
|
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
|
||||||
|
|
||||||
Add(Intrinsic.X86Addpd, new IntrinsicInfo(X86Instruction.Addpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Addpd, new IntrinsicInfo(X86Instruction.Addpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Addps, new IntrinsicInfo(X86Instruction.Addps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Addps, new IntrinsicInfo(X86Instruction.Addps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Addsd, new IntrinsicInfo(X86Instruction.Addsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Addsd, new IntrinsicInfo(X86Instruction.Addsd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Addss, new IntrinsicInfo(X86Instruction.Addss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Addss, new IntrinsicInfo(X86Instruction.Addss, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Aesdec, new IntrinsicInfo(X86Instruction.Aesdec, IntrinsicType.Binary));
|
Add(Intrinsic.X86Aesdec, new IntrinsicInfo(X86Instruction.Aesdec, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Aesdeclast, new IntrinsicInfo(X86Instruction.Aesdeclast, IntrinsicType.Binary));
|
Add(Intrinsic.X86Aesdeclast, new IntrinsicInfo(X86Instruction.Aesdeclast, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Aesenc, new IntrinsicInfo(X86Instruction.Aesenc, IntrinsicType.Binary));
|
Add(Intrinsic.X86Aesenc, new IntrinsicInfo(X86Instruction.Aesenc, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Aesenclast, new IntrinsicInfo(X86Instruction.Aesenclast, IntrinsicType.Binary));
|
Add(Intrinsic.X86Aesenclast, new IntrinsicInfo(X86Instruction.Aesenclast, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Aesimc, new IntrinsicInfo(X86Instruction.Aesimc, IntrinsicType.Unary));
|
Add(Intrinsic.X86Aesimc, new IntrinsicInfo(X86Instruction.Aesimc, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Andnpd, new IntrinsicInfo(X86Instruction.Andnpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Andnpd, new IntrinsicInfo(X86Instruction.Andnpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Andnps, new IntrinsicInfo(X86Instruction.Andnps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Andnps, new IntrinsicInfo(X86Instruction.Andnps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Andpd, new IntrinsicInfo(X86Instruction.Andpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Andpd, new IntrinsicInfo(X86Instruction.Andpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Andps, new IntrinsicInfo(X86Instruction.Andps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Andps, new IntrinsicInfo(X86Instruction.Andps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Blendvpd, new IntrinsicInfo(X86Instruction.Blendvpd, IntrinsicType.Ternary));
|
Add(Intrinsic.X86Blendvpd, new IntrinsicInfo(X86Instruction.Blendvpd, IntrinsicType.Ternary));
|
||||||
Add(Intrinsic.X86Blendvps, new IntrinsicInfo(X86Instruction.Blendvps, IntrinsicType.Ternary));
|
Add(Intrinsic.X86Blendvps, new IntrinsicInfo(X86Instruction.Blendvps, IntrinsicType.Ternary));
|
||||||
Add(Intrinsic.X86Cmppd, new IntrinsicInfo(X86Instruction.Cmppd, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Cmppd, new IntrinsicInfo(X86Instruction.Cmppd, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Cmpps, new IntrinsicInfo(X86Instruction.Cmpps, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Cmpps, new IntrinsicInfo(X86Instruction.Cmpps, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Cmpsd, new IntrinsicInfo(X86Instruction.Cmpsd, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Cmpsd, new IntrinsicInfo(X86Instruction.Cmpsd, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Cmpss, new IntrinsicInfo(X86Instruction.Cmpss, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Cmpss, new IntrinsicInfo(X86Instruction.Cmpss, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Comisdeq, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
Add(Intrinsic.X86Comisdeq, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
||||||
Add(Intrinsic.X86Comisdge, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
Add(Intrinsic.X86Comisdge, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
||||||
Add(Intrinsic.X86Comisdlt, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
Add(Intrinsic.X86Comisdlt, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
||||||
Add(Intrinsic.X86Comisseq, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
Add(Intrinsic.X86Comisseq, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
||||||
Add(Intrinsic.X86Comissge, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
Add(Intrinsic.X86Comissge, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
||||||
Add(Intrinsic.X86Comisslt, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
Add(Intrinsic.X86Comisslt, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
||||||
Add(Intrinsic.X86Crc32, new IntrinsicInfo(X86Instruction.Crc32, IntrinsicType.Crc32));
|
Add(Intrinsic.X86Crc32, new IntrinsicInfo(X86Instruction.Crc32, IntrinsicType.Crc32));
|
||||||
Add(Intrinsic.X86Crc32_16, new IntrinsicInfo(X86Instruction.Crc32_16, IntrinsicType.Crc32));
|
Add(Intrinsic.X86Crc32_16, new IntrinsicInfo(X86Instruction.Crc32_16, IntrinsicType.Crc32));
|
||||||
Add(Intrinsic.X86Crc32_8, new IntrinsicInfo(X86Instruction.Crc32_8, IntrinsicType.Crc32));
|
Add(Intrinsic.X86Crc32_8, new IntrinsicInfo(X86Instruction.Crc32_8, IntrinsicType.Crc32));
|
||||||
Add(Intrinsic.X86Cvtdq2pd, new IntrinsicInfo(X86Instruction.Cvtdq2pd, IntrinsicType.Unary));
|
Add(Intrinsic.X86Cvtdq2pd, new IntrinsicInfo(X86Instruction.Cvtdq2pd, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Cvtdq2ps, new IntrinsicInfo(X86Instruction.Cvtdq2ps, IntrinsicType.Unary));
|
Add(Intrinsic.X86Cvtdq2ps, new IntrinsicInfo(X86Instruction.Cvtdq2ps, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Cvtpd2dq, new IntrinsicInfo(X86Instruction.Cvtpd2dq, IntrinsicType.Unary));
|
Add(Intrinsic.X86Cvtpd2dq, new IntrinsicInfo(X86Instruction.Cvtpd2dq, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Cvtpd2ps, new IntrinsicInfo(X86Instruction.Cvtpd2ps, IntrinsicType.Unary));
|
Add(Intrinsic.X86Cvtpd2ps, new IntrinsicInfo(X86Instruction.Cvtpd2ps, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Cvtps2dq, new IntrinsicInfo(X86Instruction.Cvtps2dq, IntrinsicType.Unary));
|
Add(Intrinsic.X86Cvtps2dq, new IntrinsicInfo(X86Instruction.Cvtps2dq, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Cvtps2pd, new IntrinsicInfo(X86Instruction.Cvtps2pd, IntrinsicType.Unary));
|
Add(Intrinsic.X86Cvtps2pd, new IntrinsicInfo(X86Instruction.Cvtps2pd, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Cvtsd2si, new IntrinsicInfo(X86Instruction.Cvtsd2si, IntrinsicType.UnaryToGpr));
|
Add(Intrinsic.X86Cvtsd2si, new IntrinsicInfo(X86Instruction.Cvtsd2si, IntrinsicType.UnaryToGpr));
|
||||||
Add(Intrinsic.X86Cvtsd2ss, new IntrinsicInfo(X86Instruction.Cvtsd2ss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Cvtsd2ss, new IntrinsicInfo(X86Instruction.Cvtsd2ss, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Cvtsi2sd, new IntrinsicInfo(X86Instruction.Cvtsi2sd, IntrinsicType.BinaryGpr));
|
Add(Intrinsic.X86Cvtsi2sd, new IntrinsicInfo(X86Instruction.Cvtsi2sd, IntrinsicType.BinaryGpr));
|
||||||
Add(Intrinsic.X86Cvtsi2si, new IntrinsicInfo(X86Instruction.Movd, IntrinsicType.UnaryToGpr));
|
Add(Intrinsic.X86Cvtsi2si, new IntrinsicInfo(X86Instruction.Movd, IntrinsicType.UnaryToGpr));
|
||||||
Add(Intrinsic.X86Cvtsi2ss, new IntrinsicInfo(X86Instruction.Cvtsi2ss, IntrinsicType.BinaryGpr));
|
Add(Intrinsic.X86Cvtsi2ss, new IntrinsicInfo(X86Instruction.Cvtsi2ss, IntrinsicType.BinaryGpr));
|
||||||
Add(Intrinsic.X86Cvtss2sd, new IntrinsicInfo(X86Instruction.Cvtss2sd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Cvtss2sd, new IntrinsicInfo(X86Instruction.Cvtss2sd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Cvtss2si, new IntrinsicInfo(X86Instruction.Cvtss2si, IntrinsicType.UnaryToGpr));
|
Add(Intrinsic.X86Cvtss2si, new IntrinsicInfo(X86Instruction.Cvtss2si, IntrinsicType.UnaryToGpr));
|
||||||
Add(Intrinsic.X86Divpd, new IntrinsicInfo(X86Instruction.Divpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Divpd, new IntrinsicInfo(X86Instruction.Divpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Divss, new IntrinsicInfo(X86Instruction.Divss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Divss, new IntrinsicInfo(X86Instruction.Divss, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Haddpd, new IntrinsicInfo(X86Instruction.Haddpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Gf2p8affineqb, new IntrinsicInfo(X86Instruction.Gf2p8affineqb, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Haddpd, new IntrinsicInfo(X86Instruction.Haddpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Maxpd, new IntrinsicInfo(X86Instruction.Maxpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Maxps, new IntrinsicInfo(X86Instruction.Maxps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Maxpd, new IntrinsicInfo(X86Instruction.Maxpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Maxsd, new IntrinsicInfo(X86Instruction.Maxsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Maxps, new IntrinsicInfo(X86Instruction.Maxps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Maxss, new IntrinsicInfo(X86Instruction.Maxss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Maxsd, new IntrinsicInfo(X86Instruction.Maxsd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Minpd, new IntrinsicInfo(X86Instruction.Minpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Maxss, new IntrinsicInfo(X86Instruction.Maxss, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Minps, new IntrinsicInfo(X86Instruction.Minps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Minpd, new IntrinsicInfo(X86Instruction.Minpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Minsd, new IntrinsicInfo(X86Instruction.Minsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Minps, new IntrinsicInfo(X86Instruction.Minps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Minss, new IntrinsicInfo(X86Instruction.Minss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Minsd, new IntrinsicInfo(X86Instruction.Minsd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Movhlps, new IntrinsicInfo(X86Instruction.Movhlps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Minss, new IntrinsicInfo(X86Instruction.Minss, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Movlhps, new IntrinsicInfo(X86Instruction.Movlhps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Movhlps, new IntrinsicInfo(X86Instruction.Movhlps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Movss, new IntrinsicInfo(X86Instruction.Movss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Movlhps, new IntrinsicInfo(X86Instruction.Movlhps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Mulpd, new IntrinsicInfo(X86Instruction.Mulpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Movss, new IntrinsicInfo(X86Instruction.Movss, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Mulps, new IntrinsicInfo(X86Instruction.Mulps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Mulpd, new IntrinsicInfo(X86Instruction.Mulpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Mulsd, new IntrinsicInfo(X86Instruction.Mulsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Mulps, new IntrinsicInfo(X86Instruction.Mulps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Mulss, new IntrinsicInfo(X86Instruction.Mulss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Mulsd, new IntrinsicInfo(X86Instruction.Mulsd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Mxcsrmb, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Mask bits.
|
Add(Intrinsic.X86Mulss, new IntrinsicInfo(X86Instruction.Mulss, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Mxcsrub, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Unmask bits.
|
Add(Intrinsic.X86Mxcsrmb, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Mask bits.
|
||||||
Add(Intrinsic.X86Paddb, new IntrinsicInfo(X86Instruction.Paddb, IntrinsicType.Binary));
|
Add(Intrinsic.X86Mxcsrub, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Unmask bits.
|
||||||
Add(Intrinsic.X86Paddd, new IntrinsicInfo(X86Instruction.Paddd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Paddb, new IntrinsicInfo(X86Instruction.Paddb, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Paddq, new IntrinsicInfo(X86Instruction.Paddq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Paddd, new IntrinsicInfo(X86Instruction.Paddd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Paddw, new IntrinsicInfo(X86Instruction.Paddw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Paddq, new IntrinsicInfo(X86Instruction.Paddq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Palignr, new IntrinsicInfo(X86Instruction.Palignr, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Paddw, new IntrinsicInfo(X86Instruction.Paddw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pand, new IntrinsicInfo(X86Instruction.Pand, IntrinsicType.Binary));
|
Add(Intrinsic.X86Palignr, new IntrinsicInfo(X86Instruction.Palignr, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Pandn, new IntrinsicInfo(X86Instruction.Pandn, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pand, new IntrinsicInfo(X86Instruction.Pand, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pavgb, new IntrinsicInfo(X86Instruction.Pavgb, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pandn, new IntrinsicInfo(X86Instruction.Pandn, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pavgw, new IntrinsicInfo(X86Instruction.Pavgw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pavgb, new IntrinsicInfo(X86Instruction.Pavgb, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pblendvb, new IntrinsicInfo(X86Instruction.Pblendvb, IntrinsicType.Ternary));
|
Add(Intrinsic.X86Pavgw, new IntrinsicInfo(X86Instruction.Pavgw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pclmulqdq, new IntrinsicInfo(X86Instruction.Pclmulqdq, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Pblendvb, new IntrinsicInfo(X86Instruction.Pblendvb, IntrinsicType.Ternary));
|
||||||
Add(Intrinsic.X86Pcmpeqb, new IntrinsicInfo(X86Instruction.Pcmpeqb, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pclmulqdq, new IntrinsicInfo(X86Instruction.Pclmulqdq, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Pcmpeqd, new IntrinsicInfo(X86Instruction.Pcmpeqd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pcmpeqb, new IntrinsicInfo(X86Instruction.Pcmpeqb, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pcmpeqq, new IntrinsicInfo(X86Instruction.Pcmpeqq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pcmpeqd, new IntrinsicInfo(X86Instruction.Pcmpeqd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pcmpeqw, new IntrinsicInfo(X86Instruction.Pcmpeqw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pcmpeqq, new IntrinsicInfo(X86Instruction.Pcmpeqq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pcmpgtb, new IntrinsicInfo(X86Instruction.Pcmpgtb, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pcmpeqw, new IntrinsicInfo(X86Instruction.Pcmpeqw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pcmpgtd, new IntrinsicInfo(X86Instruction.Pcmpgtd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pcmpgtb, new IntrinsicInfo(X86Instruction.Pcmpgtb, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pcmpgtq, new IntrinsicInfo(X86Instruction.Pcmpgtq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pcmpgtd, new IntrinsicInfo(X86Instruction.Pcmpgtd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pcmpgtw, new IntrinsicInfo(X86Instruction.Pcmpgtw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pcmpgtq, new IntrinsicInfo(X86Instruction.Pcmpgtq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pmaxsb, new IntrinsicInfo(X86Instruction.Pmaxsb, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pcmpgtw, new IntrinsicInfo(X86Instruction.Pcmpgtw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pmaxsd, new IntrinsicInfo(X86Instruction.Pmaxsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pmaxsb, new IntrinsicInfo(X86Instruction.Pmaxsb, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pmaxsw, new IntrinsicInfo(X86Instruction.Pmaxsw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pmaxsd, new IntrinsicInfo(X86Instruction.Pmaxsd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pmaxub, new IntrinsicInfo(X86Instruction.Pmaxub, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pmaxsw, new IntrinsicInfo(X86Instruction.Pmaxsw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pmaxud, new IntrinsicInfo(X86Instruction.Pmaxud, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pmaxub, new IntrinsicInfo(X86Instruction.Pmaxub, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pmaxuw, new IntrinsicInfo(X86Instruction.Pmaxuw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pmaxud, new IntrinsicInfo(X86Instruction.Pmaxud, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pminsb, new IntrinsicInfo(X86Instruction.Pminsb, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pmaxuw, new IntrinsicInfo(X86Instruction.Pmaxuw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pminsd, new IntrinsicInfo(X86Instruction.Pminsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pminsb, new IntrinsicInfo(X86Instruction.Pminsb, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pminsw, new IntrinsicInfo(X86Instruction.Pminsw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pminsd, new IntrinsicInfo(X86Instruction.Pminsd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pminub, new IntrinsicInfo(X86Instruction.Pminub, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pminsw, new IntrinsicInfo(X86Instruction.Pminsw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pminud, new IntrinsicInfo(X86Instruction.Pminud, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pminub, new IntrinsicInfo(X86Instruction.Pminub, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pminuw, new IntrinsicInfo(X86Instruction.Pminuw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pminud, new IntrinsicInfo(X86Instruction.Pminud, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pmovsxbw, new IntrinsicInfo(X86Instruction.Pmovsxbw, IntrinsicType.Unary));
|
Add(Intrinsic.X86Pminuw, new IntrinsicInfo(X86Instruction.Pminuw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pmovsxdq, new IntrinsicInfo(X86Instruction.Pmovsxdq, IntrinsicType.Unary));
|
Add(Intrinsic.X86Pmovsxbw, new IntrinsicInfo(X86Instruction.Pmovsxbw, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Pmovsxwd, new IntrinsicInfo(X86Instruction.Pmovsxwd, IntrinsicType.Unary));
|
Add(Intrinsic.X86Pmovsxdq, new IntrinsicInfo(X86Instruction.Pmovsxdq, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Pmovzxbw, new IntrinsicInfo(X86Instruction.Pmovzxbw, IntrinsicType.Unary));
|
Add(Intrinsic.X86Pmovsxwd, new IntrinsicInfo(X86Instruction.Pmovsxwd, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Pmovzxdq, new IntrinsicInfo(X86Instruction.Pmovzxdq, IntrinsicType.Unary));
|
Add(Intrinsic.X86Pmovzxbw, new IntrinsicInfo(X86Instruction.Pmovzxbw, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Pmovzxwd, new IntrinsicInfo(X86Instruction.Pmovzxwd, IntrinsicType.Unary));
|
Add(Intrinsic.X86Pmovzxdq, new IntrinsicInfo(X86Instruction.Pmovzxdq, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Pmulld, new IntrinsicInfo(X86Instruction.Pmulld, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pmovzxwd, new IntrinsicInfo(X86Instruction.Pmovzxwd, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Pmullw, new IntrinsicInfo(X86Instruction.Pmullw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pmulld, new IntrinsicInfo(X86Instruction.Pmulld, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Popcnt, new IntrinsicInfo(X86Instruction.Popcnt, IntrinsicType.PopCount));
|
Add(Intrinsic.X86Pmullw, new IntrinsicInfo(X86Instruction.Pmullw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Por, new IntrinsicInfo(X86Instruction.Por, IntrinsicType.Binary));
|
Add(Intrinsic.X86Popcnt, new IntrinsicInfo(X86Instruction.Popcnt, IntrinsicType.PopCount));
|
||||||
Add(Intrinsic.X86Pshufb, new IntrinsicInfo(X86Instruction.Pshufb, IntrinsicType.Binary));
|
Add(Intrinsic.X86Por, new IntrinsicInfo(X86Instruction.Por, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pshufd, new IntrinsicInfo(X86Instruction.Pshufd, IntrinsicType.BinaryImm));
|
Add(Intrinsic.X86Pshufb, new IntrinsicInfo(X86Instruction.Pshufb, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pslld, new IntrinsicInfo(X86Instruction.Pslld, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pshufd, new IntrinsicInfo(X86Instruction.Pshufd, IntrinsicType.BinaryImm));
|
||||||
Add(Intrinsic.X86Pslldq, new IntrinsicInfo(X86Instruction.Pslldq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pslld, new IntrinsicInfo(X86Instruction.Pslld, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psllq, new IntrinsicInfo(X86Instruction.Psllq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Pslldq, new IntrinsicInfo(X86Instruction.Pslldq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psllw, new IntrinsicInfo(X86Instruction.Psllw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psllq, new IntrinsicInfo(X86Instruction.Psllq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psrad, new IntrinsicInfo(X86Instruction.Psrad, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psllw, new IntrinsicInfo(X86Instruction.Psllw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psraw, new IntrinsicInfo(X86Instruction.Psraw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psrad, new IntrinsicInfo(X86Instruction.Psrad, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psrld, new IntrinsicInfo(X86Instruction.Psrld, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psraw, new IntrinsicInfo(X86Instruction.Psraw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psrlq, new IntrinsicInfo(X86Instruction.Psrlq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psrld, new IntrinsicInfo(X86Instruction.Psrld, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psrldq, new IntrinsicInfo(X86Instruction.Psrldq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psrlq, new IntrinsicInfo(X86Instruction.Psrlq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psrlw, new IntrinsicInfo(X86Instruction.Psrlw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psrldq, new IntrinsicInfo(X86Instruction.Psrldq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psubb, new IntrinsicInfo(X86Instruction.Psubb, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psrlw, new IntrinsicInfo(X86Instruction.Psrlw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psubd, new IntrinsicInfo(X86Instruction.Psubd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psubb, new IntrinsicInfo(X86Instruction.Psubb, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psubq, new IntrinsicInfo(X86Instruction.Psubq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psubd, new IntrinsicInfo(X86Instruction.Psubd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Psubw, new IntrinsicInfo(X86Instruction.Psubw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psubq, new IntrinsicInfo(X86Instruction.Psubq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Punpckhbw, new IntrinsicInfo(X86Instruction.Punpckhbw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Psubw, new IntrinsicInfo(X86Instruction.Psubw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Punpckhdq, new IntrinsicInfo(X86Instruction.Punpckhdq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Punpckhbw, new IntrinsicInfo(X86Instruction.Punpckhbw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Punpckhqdq, new IntrinsicInfo(X86Instruction.Punpckhqdq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Punpckhdq, new IntrinsicInfo(X86Instruction.Punpckhdq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Punpckhwd, new IntrinsicInfo(X86Instruction.Punpckhwd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Punpckhqdq, new IntrinsicInfo(X86Instruction.Punpckhqdq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Punpcklbw, new IntrinsicInfo(X86Instruction.Punpcklbw, IntrinsicType.Binary));
|
Add(Intrinsic.X86Punpckhwd, new IntrinsicInfo(X86Instruction.Punpckhwd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Punpckldq, new IntrinsicInfo(X86Instruction.Punpckldq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Punpcklbw, new IntrinsicInfo(X86Instruction.Punpcklbw, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Punpcklqdq, new IntrinsicInfo(X86Instruction.Punpcklqdq, IntrinsicType.Binary));
|
Add(Intrinsic.X86Punpckldq, new IntrinsicInfo(X86Instruction.Punpckldq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Punpcklwd, new IntrinsicInfo(X86Instruction.Punpcklwd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Punpcklqdq, new IntrinsicInfo(X86Instruction.Punpcklqdq, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Pxor, new IntrinsicInfo(X86Instruction.Pxor, IntrinsicType.Binary));
|
Add(Intrinsic.X86Punpcklwd, new IntrinsicInfo(X86Instruction.Punpcklwd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Rcpps, new IntrinsicInfo(X86Instruction.Rcpps, IntrinsicType.Unary));
|
Add(Intrinsic.X86Pxor, new IntrinsicInfo(X86Instruction.Pxor, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Rcpss, new IntrinsicInfo(X86Instruction.Rcpss, IntrinsicType.Unary));
|
Add(Intrinsic.X86Rcpps, new IntrinsicInfo(X86Instruction.Rcpps, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Roundpd, new IntrinsicInfo(X86Instruction.Roundpd, IntrinsicType.BinaryImm));
|
Add(Intrinsic.X86Rcpss, new IntrinsicInfo(X86Instruction.Rcpss, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Roundps, new IntrinsicInfo(X86Instruction.Roundps, IntrinsicType.BinaryImm));
|
Add(Intrinsic.X86Roundpd, new IntrinsicInfo(X86Instruction.Roundpd, IntrinsicType.BinaryImm));
|
||||||
Add(Intrinsic.X86Roundsd, new IntrinsicInfo(X86Instruction.Roundsd, IntrinsicType.BinaryImm));
|
Add(Intrinsic.X86Roundps, new IntrinsicInfo(X86Instruction.Roundps, IntrinsicType.BinaryImm));
|
||||||
Add(Intrinsic.X86Roundss, new IntrinsicInfo(X86Instruction.Roundss, IntrinsicType.BinaryImm));
|
Add(Intrinsic.X86Roundsd, new IntrinsicInfo(X86Instruction.Roundsd, IntrinsicType.BinaryImm));
|
||||||
Add(Intrinsic.X86Rsqrtps, new IntrinsicInfo(X86Instruction.Rsqrtps, IntrinsicType.Unary));
|
Add(Intrinsic.X86Roundss, new IntrinsicInfo(X86Instruction.Roundss, IntrinsicType.BinaryImm));
|
||||||
Add(Intrinsic.X86Rsqrtss, new IntrinsicInfo(X86Instruction.Rsqrtss, IntrinsicType.Unary));
|
Add(Intrinsic.X86Rsqrtps, new IntrinsicInfo(X86Instruction.Rsqrtps, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Sha256Msg1, new IntrinsicInfo(X86Instruction.Sha256Msg1, IntrinsicType.Binary));
|
Add(Intrinsic.X86Rsqrtss, new IntrinsicInfo(X86Instruction.Rsqrtss, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Sha256Msg2, new IntrinsicInfo(X86Instruction.Sha256Msg2, IntrinsicType.Binary));
|
Add(Intrinsic.X86Sha256Msg1, new IntrinsicInfo(X86Instruction.Sha256Msg1, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Sha256Rnds2, new IntrinsicInfo(X86Instruction.Sha256Rnds2, IntrinsicType.Ternary));
|
Add(Intrinsic.X86Sha256Msg2, new IntrinsicInfo(X86Instruction.Sha256Msg2, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Shufpd, new IntrinsicInfo(X86Instruction.Shufpd, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Sha256Rnds2, new IntrinsicInfo(X86Instruction.Sha256Rnds2, IntrinsicType.Ternary));
|
||||||
Add(Intrinsic.X86Shufps, new IntrinsicInfo(X86Instruction.Shufps, IntrinsicType.TernaryImm));
|
Add(Intrinsic.X86Shufpd, new IntrinsicInfo(X86Instruction.Shufpd, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Sqrtpd, new IntrinsicInfo(X86Instruction.Sqrtpd, IntrinsicType.Unary));
|
Add(Intrinsic.X86Shufps, new IntrinsicInfo(X86Instruction.Shufps, IntrinsicType.TernaryImm));
|
||||||
Add(Intrinsic.X86Sqrtps, new IntrinsicInfo(X86Instruction.Sqrtps, IntrinsicType.Unary));
|
Add(Intrinsic.X86Sqrtpd, new IntrinsicInfo(X86Instruction.Sqrtpd, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Sqrtsd, new IntrinsicInfo(X86Instruction.Sqrtsd, IntrinsicType.Unary));
|
Add(Intrinsic.X86Sqrtps, new IntrinsicInfo(X86Instruction.Sqrtps, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Sqrtss, new IntrinsicInfo(X86Instruction.Sqrtss, IntrinsicType.Unary));
|
Add(Intrinsic.X86Sqrtsd, new IntrinsicInfo(X86Instruction.Sqrtsd, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Subpd, new IntrinsicInfo(X86Instruction.Subpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Sqrtss, new IntrinsicInfo(X86Instruction.Sqrtss, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Subps, new IntrinsicInfo(X86Instruction.Subps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Subpd, new IntrinsicInfo(X86Instruction.Subpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Subsd, new IntrinsicInfo(X86Instruction.Subsd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Subps, new IntrinsicInfo(X86Instruction.Subps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Subss, new IntrinsicInfo(X86Instruction.Subss, IntrinsicType.Binary));
|
Add(Intrinsic.X86Subsd, new IntrinsicInfo(X86Instruction.Subsd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Unpckhpd, new IntrinsicInfo(X86Instruction.Unpckhpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Subss, new IntrinsicInfo(X86Instruction.Subss, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Unpckhps, new IntrinsicInfo(X86Instruction.Unpckhps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Unpckhpd, new IntrinsicInfo(X86Instruction.Unpckhpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Unpcklpd, new IntrinsicInfo(X86Instruction.Unpcklpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Unpckhps, new IntrinsicInfo(X86Instruction.Unpckhps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Unpcklps, new IntrinsicInfo(X86Instruction.Unpcklps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Unpcklpd, new IntrinsicInfo(X86Instruction.Unpcklpd, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Vcvtph2ps, new IntrinsicInfo(X86Instruction.Vcvtph2ps, IntrinsicType.Unary));
|
Add(Intrinsic.X86Unpcklps, new IntrinsicInfo(X86Instruction.Unpcklps, IntrinsicType.Binary));
|
||||||
Add(Intrinsic.X86Vcvtps2ph, new IntrinsicInfo(X86Instruction.Vcvtps2ph, IntrinsicType.BinaryImm));
|
Add(Intrinsic.X86Vcvtph2ps, new IntrinsicInfo(X86Instruction.Vcvtph2ps, IntrinsicType.Unary));
|
||||||
Add(Intrinsic.X86Vfmadd231ps, new IntrinsicInfo(X86Instruction.Vfmadd231ps, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vcvtps2ph, new IntrinsicInfo(X86Instruction.Vcvtps2ph, IntrinsicType.BinaryImm));
|
||||||
Add(Intrinsic.X86Vfmadd231sd, new IntrinsicInfo(X86Instruction.Vfmadd231sd, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfmadd231ps, new IntrinsicInfo(X86Instruction.Vfmadd231ps, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Vfmadd231ss, new IntrinsicInfo(X86Instruction.Vfmadd231ss, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfmadd231sd, new IntrinsicInfo(X86Instruction.Vfmadd231sd, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Vfmsub231sd, new IntrinsicInfo(X86Instruction.Vfmsub231sd, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfmadd231ss, new IntrinsicInfo(X86Instruction.Vfmadd231ss, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Vfmsub231ss, new IntrinsicInfo(X86Instruction.Vfmsub231ss, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfmsub231sd, new IntrinsicInfo(X86Instruction.Vfmsub231sd, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Vfnmadd231ps, new IntrinsicInfo(X86Instruction.Vfnmadd231ps, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfmsub231ss, new IntrinsicInfo(X86Instruction.Vfmsub231ss, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Vfnmadd231sd, new IntrinsicInfo(X86Instruction.Vfnmadd231sd, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfnmadd231ps, new IntrinsicInfo(X86Instruction.Vfnmadd231ps, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Vfnmadd231ss, new IntrinsicInfo(X86Instruction.Vfnmadd231ss, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfnmadd231sd, new IntrinsicInfo(X86Instruction.Vfnmadd231sd, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Vfnmsub231sd, new IntrinsicInfo(X86Instruction.Vfnmsub231sd, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfnmadd231ss, new IntrinsicInfo(X86Instruction.Vfnmadd231ss, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Vfnmsub231ss, new IntrinsicInfo(X86Instruction.Vfnmsub231ss, IntrinsicType.Fma));
|
Add(Intrinsic.X86Vfnmsub231sd, new IntrinsicInfo(X86Instruction.Vfnmsub231sd, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary));
|
Add(Intrinsic.X86Vfnmsub231ss, new IntrinsicInfo(X86Instruction.Vfnmsub231ss, IntrinsicType.Fma));
|
||||||
Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary));
|
Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary));
|
||||||
|
Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Add(Intrinsic intrin, IntrinsicInfo info)
|
private static void Add(Intrinsic intrin, IntrinsicInfo info)
|
||||||
|
@@ -54,6 +54,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Divps,
|
Divps,
|
||||||
Divsd,
|
Divsd,
|
||||||
Divss,
|
Divss,
|
||||||
|
Gf2p8affineqb,
|
||||||
Haddpd,
|
Haddpd,
|
||||||
Haddps,
|
Haddps,
|
||||||
Idiv,
|
Idiv,
|
||||||
|
44
ARMeilleure/Decoders/OpCode32SimdCvtTB.cs
Normal file
44
ARMeilleure/Decoders/OpCode32SimdCvtTB.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32SimdCvtTB : OpCode32, IOpCode32Simd
|
||||||
|
{
|
||||||
|
public int Vd { get; }
|
||||||
|
public int Vm { get; }
|
||||||
|
public bool Op { get; } // Convert to Half / Convert from Half
|
||||||
|
public bool T { get; } // Top / Bottom
|
||||||
|
public int Size { get; } // Double / Single
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtTB(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtTB(inst, address, opCode, true);
|
||||||
|
|
||||||
|
public OpCode32SimdCvtTB(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
|
Op = ((opCode >> 16) & 0x1) != 0;
|
||||||
|
T = ((opCode >> 7) & 0x1) != 0;
|
||||||
|
Size = ((opCode >> 8) & 0x1);
|
||||||
|
|
||||||
|
RegisterSize = Size == 1 ? RegisterSize.Int64 : RegisterSize.Int32;
|
||||||
|
|
||||||
|
if (Size == 1)
|
||||||
|
{
|
||||||
|
if (Op)
|
||||||
|
{
|
||||||
|
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
|
||||||
|
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
|
||||||
|
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
|
||||||
|
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -828,6 +828,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetVfp("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // FP32 to int.
|
SetVfp("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // FP32 to int.
|
||||||
SetVfp("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // Int to FP32.
|
SetVfp("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // Int to FP32.
|
||||||
SetVfp("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // The many FP32 to int encodings (fp).
|
SetVfp("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // The many FP32 to int encodings (fp).
|
||||||
|
SetVfp("<<<<11101x11001xxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_TB, OpCode32SimdCvtTB.Create, OpCode32SimdCvtTB.CreateT32);
|
||||||
SetVfp("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
SetVfp("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetVfp("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create, OpCode32SimdDupGP.CreateT32);
|
SetVfp("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create, OpCode32SimdDupGP.CreateT32);
|
||||||
SetVfp("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
SetVfp("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
@@ -726,7 +726,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
||||||
{
|
{
|
||||||
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)), op1, op2);
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -774,7 +774,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
||||||
{
|
{
|
||||||
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)), op1, op2);
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -900,7 +900,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
||||||
{
|
{
|
||||||
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)), op1, op2);
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -948,7 +948,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
||||||
{
|
{
|
||||||
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)), op1, op2);
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1617,53 +1617,47 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Frinta_S(ArmEmitterContext context)
|
public static void Frinta_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitScalarUnaryOpF(context, (op1) =>
|
if (Optimizations.UseSse41)
|
||||||
{
|
{
|
||||||
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
|
EmitSse41ScalarRoundOpF(context, FPRoundingMode.ToNearestAway);
|
||||||
});
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitScalarUnaryOpF(context, (op1) =>
|
||||||
|
{
|
||||||
|
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Frinta_V(ArmEmitterContext context)
|
public static void Frinta_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitVectorUnaryOpF(context, (op1) =>
|
if (Optimizations.UseSse41)
|
||||||
{
|
{
|
||||||
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
|
EmitSse41VectorRoundOpF(context, FPRoundingMode.ToNearestAway);
|
||||||
});
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpF(context, (op1) =>
|
||||||
|
{
|
||||||
|
return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Frinti_S(ArmEmitterContext context)
|
public static void Frinti_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
|
||||||
|
|
||||||
EmitScalarUnaryOpF(context, (op1) =>
|
EmitScalarUnaryOpF(context, (op1) =>
|
||||||
{
|
{
|
||||||
if (op.Size == 0)
|
return EmitRoundByRMode(context, op1);
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
|
|
||||||
}
|
|
||||||
else /* if (op.Size == 1) */
|
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Frinti_V(ArmEmitterContext context)
|
public static void Frinti_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
|
||||||
|
|
||||||
int sizeF = op.Size & 1;
|
|
||||||
|
|
||||||
EmitVectorUnaryOpF(context, (op1) =>
|
EmitVectorUnaryOpF(context, (op1) =>
|
||||||
{
|
{
|
||||||
if (sizeF == 0)
|
return EmitRoundByRMode(context, op1);
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
|
|
||||||
}
|
|
||||||
else /* if (sizeF == 1) */
|
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1759,37 +1753,17 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Frintx_S(ArmEmitterContext context)
|
public static void Frintx_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
|
||||||
|
|
||||||
EmitScalarUnaryOpF(context, (op1) =>
|
EmitScalarUnaryOpF(context, (op1) =>
|
||||||
{
|
{
|
||||||
if (op.Size == 0)
|
return EmitRoundByRMode(context, op1);
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
|
|
||||||
}
|
|
||||||
else /* if (op.Size == 1) */
|
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Frintx_V(ArmEmitterContext context)
|
public static void Frintx_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
|
||||||
|
|
||||||
int sizeF = op.Size & 1;
|
|
||||||
|
|
||||||
EmitVectorUnaryOpF(context, (op1) =>
|
EmitVectorUnaryOpF(context, (op1) =>
|
||||||
{
|
{
|
||||||
if (sizeF == 0)
|
return EmitRoundByRMode(context, op1);
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
|
|
||||||
}
|
|
||||||
else /* if (sizeF == 1) */
|
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3556,9 +3530,18 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundsd : Intrinsic.X86Roundss;
|
Operand res;
|
||||||
|
|
||||||
Operand res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundsd : Intrinsic.X86Roundss;
|
||||||
|
|
||||||
|
res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = EmitSse41RoundToNearestWithTiesToAwayOpF(context, n, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
if ((op.Size & 1) != 0)
|
if ((op.Size & 1) != 0)
|
||||||
{
|
{
|
||||||
@@ -3578,9 +3561,18 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundpd : Intrinsic.X86Roundps;
|
Operand res;
|
||||||
|
|
||||||
Operand res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundpd : Intrinsic.X86Roundps;
|
||||||
|
|
||||||
|
res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = EmitSse41RoundToNearestWithTiesToAwayOpF(context, n, scalar: false);
|
||||||
|
}
|
||||||
|
|
||||||
if (op.RegisterSize == RegisterSize.Simd64)
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
{
|
{
|
||||||
|
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||||
@@ -178,37 +177,20 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero)
|
private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero)
|
||||||
{
|
{
|
||||||
Operand one = Const(1);
|
|
||||||
if (zero)
|
if (zero)
|
||||||
{
|
{
|
||||||
EmitVectorUnaryOpF32(context, (m) =>
|
EmitVectorUnaryOpF32(context, (m) =>
|
||||||
{
|
{
|
||||||
OperandType type = m.Type;
|
Operand zeroOp = m.Type == OperandType.FP64 ? ConstF(0.0d) : ConstF(0.0f);
|
||||||
|
|
||||||
if (type == OperandType.FP64)
|
return EmitSoftFloatCallDefaultFpscr(context, name, m, zeroOp);
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFloat64).GetMethod(name), m, ConstF(0.0d), one);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFloat32).GetMethod(name), m, ConstF(0.0f), one);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EmitVectorBinaryOpF32(context, (n, m) =>
|
EmitVectorBinaryOpF32(context, (n, m) =>
|
||||||
{
|
{
|
||||||
OperandType type = n.Type;
|
return EmitSoftFloatCallDefaultFpscr(context, name, n, m);
|
||||||
|
|
||||||
if (type == OperandType.FP64)
|
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFloat64).GetMethod(name), n, m, one);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return context.Call(typeof(SoftFloat32).GetMethod(name), n, m, one);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -357,11 +339,7 @@ namespace ARMeilleure.Instructions
|
|||||||
me = ExtractScalar(context, type, op.Vm);
|
me = ExtractScalar(context, type, op.Vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodInfo info = sizeF != 0
|
Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs));
|
||||||
? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare))
|
|
||||||
: typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare));
|
|
||||||
|
|
||||||
Operand nzcv = context.Call(info, ne, me, Const(signalNaNs));
|
|
||||||
|
|
||||||
EmitSetFpscrNzcv(context, nzcv);
|
EmitSetFpscrNzcv(context, nzcv);
|
||||||
}
|
}
|
||||||
|
@@ -76,7 +76,9 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0);
|
Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0);
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
res = context.ZeroExtend16(OperandType.I64, res);
|
res = context.ZeroExtend16(OperandType.I64, res);
|
||||||
|
|
||||||
@@ -98,7 +100,9 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
|
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
|
Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||||
}
|
}
|
||||||
@@ -120,7 +124,9 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0);
|
Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0);
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne);
|
Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
res = context.ZeroExtend16(OperandType.I64, res);
|
res = context.ZeroExtend16(OperandType.I64, res);
|
||||||
|
|
||||||
@@ -143,7 +149,9 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
|
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne);
|
Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||||
}
|
}
|
||||||
@@ -156,32 +164,74 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Fcvtas_Gp(ArmEmitterContext context)
|
public static void Fcvtas_Gp(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41Fcvts_Gp(context, FPRoundingMode.ToNearestAway, isFixed: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtas_S(ArmEmitterContext context)
|
public static void Fcvtas_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: true);
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearestAway, scalar: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtas_V(ArmEmitterContext context)
|
public static void Fcvtas_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: false);
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearestAway, scalar: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtau_Gp(ArmEmitterContext context)
|
public static void Fcvtau_Gp(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitFcvt_u_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41Fcvtu_Gp(context, FPRoundingMode.ToNearestAway, isFixed: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitFcvt_u_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtau_S(ArmEmitterContext context)
|
public static void Fcvtau_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: true);
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearestAway, scalar: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtau_V(ArmEmitterContext context)
|
public static void Fcvtau_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: false);
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearestAway, scalar: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtl_V(ArmEmitterContext context)
|
public static void Fcvtl_V(ArmEmitterContext context)
|
||||||
@@ -224,7 +274,9 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1);
|
Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1);
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
|
Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
res = context.VectorInsert(res, e, index);
|
res = context.VectorInsert(res, e, index);
|
||||||
}
|
}
|
||||||
@@ -333,7 +385,9 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
if (sizeF == 0)
|
if (sizeF == 0)
|
||||||
{
|
{
|
||||||
|
context.StoreToContext();
|
||||||
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
e = context.ZeroExtend16(OperandType.I64, e);
|
e = context.ZeroExtend16(OperandType.I64, e);
|
||||||
|
|
||||||
@@ -1211,7 +1265,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulps, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulps, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
|
||||||
|
}
|
||||||
|
|
||||||
Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes);
|
Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes);
|
||||||
|
|
||||||
@@ -1253,7 +1314,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
|
||||||
|
}
|
||||||
|
|
||||||
Operand nLong = EmitSse2CvtDoubleToInt64OpF(context, nRes, scalar);
|
Operand nLong = EmitSse2CvtDoubleToInt64OpF(context, nRes, scalar);
|
||||||
|
|
||||||
@@ -1302,7 +1370,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulps, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulps, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
@@ -1357,7 +1432,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
@@ -1412,7 +1494,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
|
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
|
||||||
? context.AddIntrinsicInt (Intrinsic.X86Cvtss2si, nRes)
|
? context.AddIntrinsicInt (Intrinsic.X86Cvtss2si, nRes)
|
||||||
@@ -1452,7 +1541,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
|
Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32
|
||||||
? context.AddIntrinsicInt (Intrinsic.X86Cvtsd2si, nRes)
|
? context.AddIntrinsicInt (Intrinsic.X86Cvtsd2si, nRes)
|
||||||
@@ -1500,7 +1596,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
@@ -1555,7 +1658,14 @@ namespace ARMeilleure.Instructions
|
|||||||
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
|
nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
|
@@ -161,34 +161,15 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Operand toConvert = ExtractScalar(context, floatSize, op.Vm);
|
Operand toConvert = ExtractScalar(context, floatSize, op.Vm);
|
||||||
|
|
||||||
Operand asInteger;
|
|
||||||
|
|
||||||
// TODO: Fast Path.
|
// TODO: Fast Path.
|
||||||
if (roundWithFpscr)
|
if (roundWithFpscr)
|
||||||
{
|
{
|
||||||
MethodInfo info;
|
toConvert = EmitRoundByRMode(context, toConvert);
|
||||||
|
|
||||||
if (floatSize == OperandType.FP64)
|
|
||||||
{
|
|
||||||
info = unsigned
|
|
||||||
? typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))
|
|
||||||
: typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
info = unsigned
|
|
||||||
? typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))
|
|
||||||
: typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32));
|
|
||||||
}
|
|
||||||
|
|
||||||
asInteger = context.Call(info, toConvert);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Round towards zero.
|
|
||||||
asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Round towards zero.
|
||||||
|
Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
|
||||||
|
|
||||||
InsertScalar(context, op.Vd, asInteger);
|
InsertScalar(context, op.Vd, asInteger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,6 +203,9 @@ namespace ARMeilleure.Instructions
|
|||||||
FPRoundingMode roundMode;
|
FPRoundingMode roundMode;
|
||||||
switch (rm)
|
switch (rm)
|
||||||
{
|
{
|
||||||
|
case 0b00:
|
||||||
|
roundMode = FPRoundingMode.ToNearestAway;
|
||||||
|
break;
|
||||||
case 0b01:
|
case 0b01:
|
||||||
roundMode = FPRoundingMode.ToNearest;
|
roundMode = FPRoundingMode.ToNearest;
|
||||||
break;
|
break;
|
||||||
@@ -247,7 +231,7 @@ namespace ARMeilleure.Instructions
|
|||||||
bool unsigned = op.Opc == 0;
|
bool unsigned = op.Opc == 0;
|
||||||
int rm = op.Opc2 & 3;
|
int rm = op.Opc2 & 3;
|
||||||
|
|
||||||
if (Optimizations.UseSse41 && rm != 0b00)
|
if (Optimizations.UseSse41)
|
||||||
{
|
{
|
||||||
EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned);
|
EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned);
|
||||||
}
|
}
|
||||||
@@ -271,14 +255,80 @@ namespace ARMeilleure.Instructions
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand asInteger;
|
Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
|
||||||
|
|
||||||
asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
|
|
||||||
|
|
||||||
InsertScalar(context, op.Vd, asInteger);
|
InsertScalar(context, op.Vd, asInteger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Vcvt_TB(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32SimdCvtTB op = (OpCode32SimdCvtTB)context.CurrOp;
|
||||||
|
|
||||||
|
if (Optimizations.UseF16c)
|
||||||
|
{
|
||||||
|
Debug.Assert(!Optimizations.ForceLegacySse);
|
||||||
|
|
||||||
|
if (op.Op)
|
||||||
|
{
|
||||||
|
Operand res = ExtractScalar(context, op.Size == 1 ? OperandType.FP64 : OperandType.FP32, op.Vm);
|
||||||
|
if (op.Size == 1)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), res);
|
||||||
|
}
|
||||||
|
res = context.AddIntrinsic(Intrinsic.X86Vcvtps2ph, res, Const(X86GetRoundControl(FPRoundingMode.ToNearest)));
|
||||||
|
res = context.VectorExtract16(res, 0);
|
||||||
|
InsertScalar16(context, op.Vd, op.T, res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand res = context.VectorCreateScalar(ExtractScalar16(context, op.Vm, op.T));
|
||||||
|
res = context.AddIntrinsic(Intrinsic.X86Vcvtph2ps, res);
|
||||||
|
if (op.Size == 1)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), res);
|
||||||
|
}
|
||||||
|
res = context.VectorExtract(op.Size == 1 ? OperandType.I64 : OperandType.I32, res, 0);
|
||||||
|
InsertScalar(context, op.Vd, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (op.Op)
|
||||||
|
{
|
||||||
|
// Convert to half.
|
||||||
|
|
||||||
|
Operand src = ExtractScalar(context, op.Size == 1 ? OperandType.FP64 : OperandType.FP32, op.Vm);
|
||||||
|
|
||||||
|
MethodInfo method = op.Size == 1
|
||||||
|
? typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert))
|
||||||
|
: typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert));
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
|
Operand res = context.Call(method, src);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
|
InsertScalar16(context, op.Vd, op.T, res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert from half.
|
||||||
|
|
||||||
|
Operand src = ExtractScalar16(context, op.Vm, op.T);
|
||||||
|
|
||||||
|
MethodInfo method = op.Size == 1
|
||||||
|
? typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert))
|
||||||
|
: typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert));
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
|
Operand res = context.Call(method, src);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
|
InsertScalar(context, op.Vd, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VRINTA/M/N/P (floating-point).
|
// VRINTA/M/N/P (floating-point).
|
||||||
public static void Vrint_RM(ArmEmitterContext context)
|
public static void Vrint_RM(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
@@ -288,15 +338,21 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
int rm = op.Opc2 & 3;
|
int rm = op.Opc2 & 3;
|
||||||
|
|
||||||
if (Optimizations.UseSse2 && rm != 0b00)
|
if (Optimizations.UseSse41)
|
||||||
{
|
{
|
||||||
EmitScalarUnaryOpSimd32(context, (m) =>
|
EmitScalarUnaryOpSimd32(context, (m) =>
|
||||||
{
|
{
|
||||||
Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd;
|
|
||||||
|
|
||||||
FPRoundingMode roundMode = RMToRoundMode(rm);
|
FPRoundingMode roundMode = RMToRoundMode(rm);
|
||||||
|
|
||||||
return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd;
|
||||||
|
return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return EmitSse41RoundToNearestWithTiesToAwayOpF(context, m, scalar: true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -326,7 +382,17 @@ namespace ARMeilleure.Instructions
|
|||||||
// VRINTA (vector).
|
// VRINTA (vector).
|
||||||
public static void Vrinta_V(ArmEmitterContext context)
|
public static void Vrinta_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m));
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||||
|
{
|
||||||
|
return EmitSse41RoundToNearestWithTiesToAwayOpF(context, m, scalar: false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VRINTM (vector).
|
// VRINTM (vector).
|
||||||
@@ -399,15 +465,9 @@ namespace ARMeilleure.Instructions
|
|||||||
// VRINTX (floating-point).
|
// VRINTX (floating-point).
|
||||||
public static void Vrintx_S(ArmEmitterContext context)
|
public static void Vrintx_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
|
||||||
|
|
||||||
bool doubleSize = (op.Size & 1) == 1;
|
|
||||||
string methodName = doubleSize ? nameof(SoftFallback.Round) : nameof(SoftFallback.RoundF);
|
|
||||||
|
|
||||||
EmitScalarUnaryOpF32(context, (op1) =>
|
EmitScalarUnaryOpF32(context, (op1) =>
|
||||||
{
|
{
|
||||||
MethodInfo info = typeof(SoftFallback).GetMethod(methodName);
|
return EmitRoundByRMode(context, op1);
|
||||||
return context.Call(info, op1);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,7 +500,14 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ));
|
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ));
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
|
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
@@ -491,7 +558,14 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ));
|
Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ));
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
|
nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n);
|
||||||
|
|
||||||
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
if (roundMode != FPRoundingMode.ToNearestAway)
|
||||||
|
{
|
||||||
|
nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nRes = EmitSse41RoundToNearestWithTiesToAwayOpF(context, nRes, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
|
@@ -33,6 +33,14 @@ namespace ARMeilleure.Instructions
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static readonly long ZeroMask = 128L << 56 | 128L << 48 | 128L << 40 | 128L << 32 | 128L << 24 | 128L << 16 | 128L << 8 | 128L << 0;
|
public static readonly long ZeroMask = 128L << 56 | 128L << 48 | 128L << 40 | 128L << 32 | 128L << 24 | 128L << 16 | 128L << 8 | 128L << 0;
|
||||||
|
|
||||||
|
public static ulong X86GetGf2p8LogicalShiftLeft(int shift)
|
||||||
|
{
|
||||||
|
ulong identity = (0b00000001UL << 56) | (0b00000010UL << 48) | (0b00000100UL << 40) | (0b00001000UL << 32) |
|
||||||
|
(0b00010000UL << 24) | (0b00100000UL << 16) | (0b01000000UL << 8) | (0b10000000UL << 0);
|
||||||
|
|
||||||
|
return shift >= 0 ? identity >> (shift * 8) : identity << (-shift * 8);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "X86 SSE Intrinsics"
|
#region "X86 SSE Intrinsics"
|
||||||
@@ -243,6 +251,46 @@ namespace ARMeilleure.Instructions
|
|||||||
throw new ArgumentException($"Invalid rounding mode \"{roundMode}\".");
|
throw new ArgumentException($"Invalid rounding mode \"{roundMode}\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operand EmitSse41RoundToNearestWithTiesToAwayOpF(ArmEmitterContext context, Operand n, bool scalar)
|
||||||
|
{
|
||||||
|
Debug.Assert(n.Type == OperandType.V128);
|
||||||
|
|
||||||
|
Operand nCopy = context.Copy(n);
|
||||||
|
|
||||||
|
Operand rC = Const(X86GetRoundControl(FPRoundingMode.TowardsZero));
|
||||||
|
|
||||||
|
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
if ((op.Size & 1) == 0)
|
||||||
|
{
|
||||||
|
Operand signMask = scalar ? X86GetScalar(context, int.MinValue) : X86GetAllElements(context, int.MinValue);
|
||||||
|
signMask = context.AddIntrinsic(Intrinsic.X86Pand, signMask, nCopy);
|
||||||
|
|
||||||
|
// 0x3EFFFFFF == BitConverter.SingleToInt32Bits(0.5f) - 1
|
||||||
|
Operand valueMask = scalar ? X86GetScalar(context, 0x3EFFFFFF) : X86GetAllElements(context, 0x3EFFFFFF);
|
||||||
|
valueMask = context.AddIntrinsic(Intrinsic.X86Por, valueMask, signMask);
|
||||||
|
|
||||||
|
nCopy = context.AddIntrinsic(scalar ? Intrinsic.X86Addss : Intrinsic.X86Addps, nCopy, valueMask);
|
||||||
|
|
||||||
|
nCopy = context.AddIntrinsic(scalar ? Intrinsic.X86Roundss : Intrinsic.X86Roundps, nCopy, rC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand signMask = scalar ? X86GetScalar(context, long.MinValue) : X86GetAllElements(context, long.MinValue);
|
||||||
|
signMask = context.AddIntrinsic(Intrinsic.X86Pand, signMask, nCopy);
|
||||||
|
|
||||||
|
// 0x3FDFFFFFFFFFFFFFL == BitConverter.DoubleToInt64Bits(0.5d) - 1L
|
||||||
|
Operand valueMask = scalar ? X86GetScalar(context, 0x3FDFFFFFFFFFFFFFL) : X86GetAllElements(context, 0x3FDFFFFFFFFFFFFFL);
|
||||||
|
valueMask = context.AddIntrinsic(Intrinsic.X86Por, valueMask, signMask);
|
||||||
|
|
||||||
|
nCopy = context.AddIntrinsic(scalar ? Intrinsic.X86Addsd : Intrinsic.X86Addpd, nCopy, valueMask);
|
||||||
|
|
||||||
|
nCopy = context.AddIntrinsic(scalar ? Intrinsic.X86Roundsd : Intrinsic.X86Roundpd, nCopy, rC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nCopy;
|
||||||
|
}
|
||||||
|
|
||||||
public static Operand EmitCountSetBits8(ArmEmitterContext context, Operand op) // "size" is 8 (SIMD&FP Inst.).
|
public static Operand EmitCountSetBits8(ArmEmitterContext context, Operand op) // "size" is 8 (SIMD&FP Inst.).
|
||||||
{
|
{
|
||||||
Debug.Assert(op.Type == OperandType.I32 || op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I32 || op.Type == OperandType.I64);
|
||||||
@@ -361,6 +409,54 @@ namespace ARMeilleure.Instructions
|
|||||||
return context.Call(info, n, Const((int)roundMode));
|
return context.Call(info, n, Const((int)roundMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operand EmitGetRoundingMode(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
Operand rMode = context.ShiftLeft(GetFpFlag(FPState.RMode1Flag), Const(1));
|
||||||
|
rMode = context.BitwiseOr(rMode, GetFpFlag(FPState.RMode0Flag));
|
||||||
|
|
||||||
|
return rMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Operand EmitRoundByRMode(ArmEmitterContext context, Operand op)
|
||||||
|
{
|
||||||
|
Debug.Assert(op.Type == OperandType.FP32 || op.Type == OperandType.FP64);
|
||||||
|
|
||||||
|
Operand lbl1 = Label();
|
||||||
|
Operand lbl2 = Label();
|
||||||
|
Operand lbl3 = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand rN = Const((int)FPRoundingMode.ToNearest);
|
||||||
|
Operand rP = Const((int)FPRoundingMode.TowardsPlusInfinity);
|
||||||
|
Operand rM = Const((int)FPRoundingMode.TowardsMinusInfinity);
|
||||||
|
|
||||||
|
Operand res = context.AllocateLocal(op.Type);
|
||||||
|
|
||||||
|
Operand rMode = EmitGetRoundingMode(context);
|
||||||
|
|
||||||
|
context.BranchIf(lbl1, rMode, rN, Comparison.NotEqual);
|
||||||
|
context.Copy(res, EmitRoundMathCall(context, MidpointRounding.ToEven, op));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lbl1);
|
||||||
|
context.BranchIf(lbl2, rMode, rP, Comparison.NotEqual);
|
||||||
|
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Ceiling), op));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lbl2);
|
||||||
|
context.BranchIf(lbl3, rMode, rM, Comparison.NotEqual);
|
||||||
|
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Floor), op));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lbl3);
|
||||||
|
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Truncate), op));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs)
|
public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs)
|
||||||
{
|
{
|
||||||
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
|
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
|
||||||
@@ -369,7 +465,11 @@ namespace ARMeilleure.Instructions
|
|||||||
? typeof(SoftFloat32).GetMethod(name)
|
? typeof(SoftFloat32).GetMethod(name)
|
||||||
: typeof(SoftFloat64).GetMethod(name);
|
: typeof(SoftFloat64).GetMethod(name);
|
||||||
|
|
||||||
return context.Call(info, callArgs);
|
context.StoreToContext();
|
||||||
|
Operand res = context.Call(info, callArgs);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit)
|
public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit)
|
||||||
@@ -1269,7 +1369,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void EmitSseOrAvxEnterFtzAndDazModesOpF(ArmEmitterContext context, out Operand isTrue)
|
public static void EmitSseOrAvxEnterFtzAndDazModesOpF(ArmEmitterContext context, out Operand isTrue)
|
||||||
{
|
{
|
||||||
isTrue = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
|
isTrue = GetFpFlag(FPState.FzFlag);
|
||||||
|
|
||||||
Operand lblTrue = Label();
|
Operand lblTrue = Label();
|
||||||
context.BranchIfFalse(lblTrue, isTrue);
|
context.BranchIfFalse(lblTrue, isTrue);
|
||||||
@@ -1281,9 +1381,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default)
|
public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default)
|
||||||
{
|
{
|
||||||
isTrue = isTrue == default
|
isTrue = isTrue == default ? GetFpFlag(FPState.FzFlag) : isTrue;
|
||||||
? context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)))
|
|
||||||
: isTrue;
|
|
||||||
|
|
||||||
Operand lblTrue = Label();
|
Operand lblTrue = Label();
|
||||||
context.BranchIfFalse(lblTrue, isTrue);
|
context.BranchIfFalse(lblTrue, isTrue);
|
||||||
@@ -1552,13 +1650,13 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual);
|
context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual);
|
||||||
context.Copy(res, maxT);
|
context.Copy(res, maxT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl1);
|
context.MarkLabel(lbl1);
|
||||||
context.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual);
|
||||||
context.Copy(res, minT);
|
context.Copy(res, minT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1583,7 +1681,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI);
|
context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI);
|
||||||
context.Copy(res, maxT);
|
context.Copy(res, maxT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1610,13 +1708,13 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual);
|
context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual);
|
||||||
context.Copy(res, maxT);
|
context.Copy(res, maxT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl1);
|
context.MarkLabel(lbl1);
|
||||||
context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual);
|
||||||
context.Copy(res, minT);
|
context.Copy(res, minT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1641,7 +1739,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI);
|
context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI);
|
||||||
context.Copy(res, maxT);
|
context.Copy(res, maxT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1663,7 +1761,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIf(lblEnd, op, minL, Comparison.NotEqual);
|
context.BranchIf(lblEnd, op, minL, Comparison.NotEqual);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1691,7 +1789,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
|
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
|
||||||
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1713,7 +1811,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
|
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
|
||||||
context.Copy(res, maxUL);
|
context.Copy(res, maxUL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1741,7 +1839,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
|
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
|
||||||
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1763,7 +1861,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
|
context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
|
||||||
context.Copy(res, zeroL);
|
context.Copy(res, zeroL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1790,19 +1888,19 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add);
|
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add);
|
||||||
context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl1);
|
context.MarkLabel(lbl1);
|
||||||
context.BranchIf(lbl2, op2, zeroL, Comparison.Less);
|
context.BranchIf(lbl2, op2, zeroL, Comparison.Less);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl2);
|
context.MarkLabel(lbl2);
|
||||||
context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI);
|
context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -1828,14 +1926,14 @@ namespace ARMeilleure.Instructions
|
|||||||
context.BranchIf(lbl1, op1, zeroL, Comparison.Less);
|
context.BranchIf(lbl1, op1, zeroL, Comparison.Less);
|
||||||
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
|
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
|
||||||
context.Copy(res, maxUL);
|
context.Copy(res, maxUL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl1);
|
context.MarkLabel(lbl1);
|
||||||
context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
|
context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
|
||||||
context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual);
|
||||||
context.Copy(res, zeroL);
|
context.Copy(res, zeroL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
|
@@ -70,6 +70,22 @@ namespace ARMeilleure.Instructions
|
|||||||
context.Copy(vec, insert);
|
context.Copy(vec, insert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operand ExtractScalar16(ArmEmitterContext context, int reg, bool top)
|
||||||
|
{
|
||||||
|
return context.VectorExtract16(GetVecA32(reg >> 2), ((reg & 3) << 1) | (top ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InsertScalar16(ArmEmitterContext context, int reg, bool top, Operand value)
|
||||||
|
{
|
||||||
|
Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.I32);
|
||||||
|
|
||||||
|
Operand vec, insert;
|
||||||
|
vec = GetVecA32(reg >> 2);
|
||||||
|
insert = context.VectorInsert16(vec, value, ((reg & 3) << 1) | (top ? 1 : 0));
|
||||||
|
|
||||||
|
context.Copy(vec, insert);
|
||||||
|
}
|
||||||
|
|
||||||
public static Operand ExtractElement(ArmEmitterContext context, int reg, int size, bool signed)
|
public static Operand ExtractElement(ArmEmitterContext context, int reg, int size, bool signed)
|
||||||
{
|
{
|
||||||
return EmitVectorExtract32(context, reg >> (4 - size), reg & ((16 >> size) - 1), size, signed);
|
return EmitVectorExtract32(context, reg >> (4 - size), reg & ((16 >> size) - 1), size, signed);
|
||||||
@@ -1181,7 +1197,11 @@ namespace ARMeilleure.Instructions
|
|||||||
Array.Resize(ref callArgs, callArgs.Length + 1);
|
Array.Resize(ref callArgs, callArgs.Length + 1);
|
||||||
callArgs[callArgs.Length - 1] = Const(1);
|
callArgs[callArgs.Length - 1] = Const(1);
|
||||||
|
|
||||||
return context.Call(info, callArgs);
|
context.StoreToContext();
|
||||||
|
Operand res = context.Call(info, callArgs);
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size)
|
public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size)
|
||||||
|
@@ -336,20 +336,45 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
Operand res = context.VectorZero();
|
if (Optimizations.UseGfni)
|
||||||
|
|
||||||
int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8;
|
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
|
||||||
{
|
{
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, index, 0);
|
const long bitMatrix =
|
||||||
|
(0b10000000L << 56) |
|
||||||
|
(0b01000000L << 48) |
|
||||||
|
(0b00100000L << 40) |
|
||||||
|
(0b00010000L << 32) |
|
||||||
|
(0b00001000L << 24) |
|
||||||
|
(0b00000100L << 16) |
|
||||||
|
(0b00000010L << 8) |
|
||||||
|
(0b00000001L << 0);
|
||||||
|
|
||||||
Operand de = EmitReverseBits8Op(context, ne);
|
Operand vBitMatrix = X86GetAllElements(context, bitMatrix);
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, de, index, 0);
|
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, GetVec(op.Rn), vBitMatrix, Const(0));
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand res = context.VectorZero();
|
||||||
|
int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8;
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
for (int index = 0; index < elems; index++)
|
||||||
|
{
|
||||||
|
Operand ne = EmitVectorExtractZx(context, op.Rn, index, 0);
|
||||||
|
|
||||||
|
Operand de = EmitReverseBits8Op(context, ne);
|
||||||
|
|
||||||
|
res = EmitVectorInsert(context, res, de, index, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op)
|
private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op)
|
||||||
|
@@ -88,8 +88,35 @@ namespace ARMeilleure.Instructions
|
|||||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||||
|
|
||||||
int shift = GetImmShl(op);
|
int shift = GetImmShl(op);
|
||||||
|
int eSize = 8 << op.Size;
|
||||||
|
|
||||||
if (Optimizations.UseSse2 && op.Size > 0)
|
if (shift >= eSize)
|
||||||
|
{
|
||||||
|
if ((op.RegisterSize == RegisterSize.Simd64))
|
||||||
|
{
|
||||||
|
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseGfni && op.Size == 0)
|
||||||
|
{
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(shift);
|
||||||
|
|
||||||
|
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||||
{
|
{
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
@@ -396,10 +423,40 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||||
|
|
||||||
if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
int shift = GetImmShr(op);
|
||||||
{
|
|
||||||
int shift = GetImmShr(op);
|
|
||||||
|
|
||||||
|
if (Optimizations.UseGfni && op.Size == 0)
|
||||||
|
{
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
ulong bitMatrix;
|
||||||
|
|
||||||
|
if (shift < 8)
|
||||||
|
{
|
||||||
|
bitMatrix = X86GetGf2p8LogicalShiftLeft(-shift);
|
||||||
|
|
||||||
|
// Extend sign-bit
|
||||||
|
bitMatrix |= 0x8080808080808080UL >> (64 - shift * 8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Replicate sign-bit into all bits
|
||||||
|
bitMatrix = 0x8080808080808080UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||||
|
{
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
Intrinsic sraInst = X86PsraInstruction[op.Size];
|
Intrinsic sraInst = X86PsraInstruction[op.Size];
|
||||||
@@ -929,10 +986,44 @@ namespace ARMeilleure.Instructions
|
|||||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||||
|
|
||||||
int shift = GetImmShl(op);
|
int shift = GetImmShl(op);
|
||||||
|
int eSize = 8 << op.Size;
|
||||||
|
|
||||||
ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL;
|
ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL;
|
||||||
|
|
||||||
if (Optimizations.UseSse2 && op.Size > 0)
|
if (shift >= eSize)
|
||||||
|
{
|
||||||
|
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||||
|
{
|
||||||
|
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseGfni && op.Size == 0)
|
||||||
|
{
|
||||||
|
Operand d = GetVec(op.Rd);
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(shift);
|
||||||
|
|
||||||
|
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||||
|
|
||||||
|
Operand nShifted = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||||
|
|
||||||
|
Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]);
|
||||||
|
|
||||||
|
Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask);
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked);
|
||||||
|
|
||||||
|
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(d, res);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||||
{
|
{
|
||||||
Operand d = GetVec(op.Rd);
|
Operand d = GetVec(op.Rd);
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
@@ -988,7 +1079,40 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
ulong mask = (ulong.MaxValue << (eSize - shift)) & (ulong.MaxValue >> (64 - eSize));
|
ulong mask = (ulong.MaxValue << (eSize - shift)) & (ulong.MaxValue >> (64 - eSize));
|
||||||
|
|
||||||
if (Optimizations.UseSse2 && op.Size > 0)
|
if (shift >= eSize)
|
||||||
|
{
|
||||||
|
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||||
|
{
|
||||||
|
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseGfni && op.Size == 0)
|
||||||
|
{
|
||||||
|
Operand d = GetVec(op.Rd);
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(-shift);
|
||||||
|
|
||||||
|
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||||
|
|
||||||
|
Operand nShifted = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||||
|
|
||||||
|
Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]);
|
||||||
|
|
||||||
|
Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask);
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked);
|
||||||
|
|
||||||
|
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(d, res);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||||
{
|
{
|
||||||
Operand d = GetVec(op.Rd);
|
Operand d = GetVec(op.Rd);
|
||||||
Operand n = GetVec(op.Rn);
|
Operand n = GetVec(op.Rn);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using ARMeilleure.Decoders;
|
using ARMeilleure.Decoders;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -378,7 +379,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt));
|
context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt));
|
||||||
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||||
|
|
||||||
context.MarkLabel(lblNoSat);
|
context.MarkLabel(lblNoSat);
|
||||||
|
|
||||||
|
@@ -31,8 +31,8 @@ namespace ARMeilleure.Instructions
|
|||||||
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
||||||
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
||||||
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
||||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
case 0b11_011_0100_0100_000: EmitGetFpcr(context); return;
|
||||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
case 0b11_011_0100_0100_001: EmitGetFpsr(context); return;
|
||||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
||||||
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
|
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
|
||||||
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
||||||
@@ -53,9 +53,9 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
switch (GetPackedId(op))
|
switch (GetPackedId(op))
|
||||||
{
|
{
|
||||||
case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
|
case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
|
||||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)); break;
|
case 0b11_011_0100_0100_000: EmitSetFpcr(context); return;
|
||||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)); break;
|
case 0b11_011_0100_0100_001: EmitSetFpsr(context); return;
|
||||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;
|
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;
|
||||||
|
|
||||||
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||||
@@ -121,39 +121,91 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
||||||
Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
|
nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
|
||||||
Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
|
nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
|
||||||
Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
|
nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
|
||||||
|
|
||||||
Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
|
SetIntOrZR(context, op.Rt, nzcv);
|
||||||
|
}
|
||||||
|
|
||||||
SetIntOrZR(context, op.Rt, nzcvSh);
|
private static void EmitGetFpcr(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
|
Operand fpcr = Const(0);
|
||||||
|
|
||||||
|
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||||
|
{
|
||||||
|
if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
|
||||||
|
{
|
||||||
|
fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetIntOrZR(context, op.Rt, fpcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitGetFpsr(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
|
Operand fpsr = Const(0);
|
||||||
|
|
||||||
|
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||||
|
{
|
||||||
|
if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
|
||||||
|
{
|
||||||
|
fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetIntOrZR(context, op.Rt, fpsr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitSetNzcv(ArmEmitterContext context)
|
private static void EmitSetNzcv(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
Operand t = GetIntOrZR(context, op.Rt);
|
Operand nzcv = GetIntOrZR(context, op.Rt);
|
||||||
t = context.ConvertI64ToI32(t);
|
nzcv = context.ConvertI64ToI32(nzcv);
|
||||||
|
|
||||||
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
|
SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1)));
|
||||||
v = context.BitwiseAnd (v, Const(1));
|
SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1)));
|
||||||
|
SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1)));
|
||||||
|
SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1)));
|
||||||
|
}
|
||||||
|
|
||||||
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
|
private static void EmitSetFpcr(ArmEmitterContext context)
|
||||||
c = context.BitwiseAnd (c, Const(1));
|
{
|
||||||
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
|
Operand fpcr = GetIntOrZR(context, op.Rt);
|
||||||
z = context.BitwiseAnd (z, Const(1));
|
fpcr = context.ConvertI64ToI32(fpcr);
|
||||||
|
|
||||||
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
|
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||||
n = context.BitwiseAnd (n, Const(1));
|
{
|
||||||
|
if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
|
||||||
|
{
|
||||||
|
SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), Const(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SetFlag(context, PState.VFlag, v);
|
private static void EmitSetFpsr(ArmEmitterContext context)
|
||||||
SetFlag(context, PState.CFlag, c);
|
{
|
||||||
SetFlag(context, PState.ZFlag, z);
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
SetFlag(context, PState.NFlag, n);
|
|
||||||
|
Operand fpsr = GetIntOrZR(context, op.Rt);
|
||||||
|
fpsr = context.ConvertI64ToI32(fpsr);
|
||||||
|
|
||||||
|
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||||
|
{
|
||||||
|
if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
|
||||||
|
{
|
||||||
|
SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -169,14 +169,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
Operand spsr = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
||||||
Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
|
spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
|
||||||
Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
|
spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
|
||||||
Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
|
spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
|
||||||
Operand qSh = context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag));
|
spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag)));
|
||||||
|
|
||||||
Operand spsr = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
|
|
||||||
spsr = context.BitwiseOr(spsr, qSh);
|
|
||||||
|
|
||||||
// TODO: Remaining flags.
|
// TODO: Remaining flags.
|
||||||
|
|
||||||
@@ -200,8 +197,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
EmitSetNzcv(context, value);
|
EmitSetNzcv(context, value);
|
||||||
|
|
||||||
Operand q = context.ShiftRightUI(value, Const((int)PState.QFlag));
|
Operand q = context.BitwiseAnd(context.ShiftRightUI(value, Const((int)PState.QFlag)), Const(1));
|
||||||
q = context.BitwiseAnd(q, Const(1));
|
|
||||||
|
|
||||||
SetFlag(context, PState.QFlag, q);
|
SetFlag(context, PState.QFlag, q);
|
||||||
}
|
}
|
||||||
@@ -284,17 +280,10 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
|
private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
|
||||||
{
|
{
|
||||||
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
|
Operand v = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.VFlag)), Const(1));
|
||||||
v = context.BitwiseAnd(v, Const(1));
|
Operand c = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.CFlag)), Const(1));
|
||||||
|
Operand z = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.ZFlag)), Const(1));
|
||||||
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
|
Operand n = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.NFlag)), Const(1));
|
||||||
c = context.BitwiseAnd(c, Const(1));
|
|
||||||
|
|
||||||
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
|
|
||||||
z = context.BitwiseAnd(z, Const(1));
|
|
||||||
|
|
||||||
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
|
|
||||||
n = context.BitwiseAnd(n, Const(1));
|
|
||||||
|
|
||||||
SetFlag(context, PState.VFlag, v);
|
SetFlag(context, PState.VFlag, v);
|
||||||
SetFlag(context, PState.CFlag, c);
|
SetFlag(context, PState.CFlag, c);
|
||||||
@@ -306,42 +295,32 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
|
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
|
||||||
|
|
||||||
Operand vSh = context.ShiftLeft(GetFpFlag(FPState.VFlag), Const((int)FPState.VFlag));
|
Operand fpscr = Const(0);
|
||||||
Operand cSh = context.ShiftLeft(GetFpFlag(FPState.CFlag), Const((int)FPState.CFlag));
|
|
||||||
Operand zSh = context.ShiftLeft(GetFpFlag(FPState.ZFlag), Const((int)FPState.ZFlag));
|
|
||||||
Operand nSh = context.ShiftLeft(GetFpFlag(FPState.NFlag), Const((int)FPState.NFlag));
|
|
||||||
|
|
||||||
Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
|
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||||
|
{
|
||||||
|
if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag)))
|
||||||
|
{
|
||||||
|
fpscr = context.BitwiseOr(fpscr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Operand fpscr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr)));
|
SetIntA32(context, op.Rt, fpscr);
|
||||||
|
|
||||||
SetIntA32(context, op.Rt, context.BitwiseOr(nzcvSh, fpscr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitSetFpscr(ArmEmitterContext context)
|
private static void EmitSetFpscr(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
|
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
|
||||||
|
|
||||||
Operand t = GetIntA32(context, op.Rt);
|
Operand fpscr = GetIntA32(context, op.Rt);
|
||||||
|
|
||||||
Operand v = context.ShiftRightUI(t, Const((int)FPState.VFlag));
|
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||||
v = context.BitwiseAnd(v, Const(1));
|
{
|
||||||
|
if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag)))
|
||||||
Operand c = context.ShiftRightUI(t, Const((int)FPState.CFlag));
|
{
|
||||||
c = context.BitwiseAnd(c, Const(1));
|
SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpscr, Const(flag)), Const(1)));
|
||||||
|
}
|
||||||
Operand z = context.ShiftRightUI(t, Const((int)FPState.ZFlag));
|
}
|
||||||
z = context.BitwiseAnd(z, Const(1));
|
|
||||||
|
|
||||||
Operand n = context.ShiftRightUI(t, Const((int)FPState.NFlag));
|
|
||||||
n = context.BitwiseAnd(n, Const(1));
|
|
||||||
|
|
||||||
SetFpFlag(context, FPState.VFlag, v);
|
|
||||||
SetFpFlag(context, FPState.CFlag, c);
|
|
||||||
SetFpFlag(context, FPState.ZFlag, z);
|
|
||||||
SetFpFlag(context, FPState.NFlag, n);
|
|
||||||
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr)), t);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -72,29 +72,6 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)GetContext().DczidEl0;
|
return (ulong)GetContext().DczidEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ulong GetFpcr()
|
|
||||||
{
|
|
||||||
return (ulong)GetContext().Fpcr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool GetFpcrFz()
|
|
||||||
{
|
|
||||||
return (GetContext().Fpcr & FPCR.Fz) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ulong GetFpsr()
|
|
||||||
{
|
|
||||||
return (ulong)GetContext().Fpsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint GetFpscr()
|
|
||||||
{
|
|
||||||
ExecutionContext context = GetContext();
|
|
||||||
|
|
||||||
return (uint)(context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) |
|
|
||||||
(uint)(context.Fpcr & FPCR.A32Mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ulong GetTpidrEl0()
|
public static ulong GetTpidrEl0()
|
||||||
{
|
{
|
||||||
return (ulong)GetContext().TpidrEl0;
|
return (ulong)GetContext().TpidrEl0;
|
||||||
@@ -130,29 +107,6 @@ namespace ARMeilleure.Instructions
|
|||||||
return GetContext().CntvctEl0;
|
return GetContext().CntvctEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetFpcr(ulong value)
|
|
||||||
{
|
|
||||||
GetContext().Fpcr = (FPCR)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetFpsr(ulong value)
|
|
||||||
{
|
|
||||||
GetContext().Fpsr = (FPSR)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetFpsrQc()
|
|
||||||
{
|
|
||||||
GetContext().Fpsr |= FPSR.Qc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetFpscr(uint fpscr)
|
|
||||||
{
|
|
||||||
ExecutionContext context = GetContext();
|
|
||||||
|
|
||||||
context.Fpsr = FPSR.A32Mask & (FPSR)fpscr;
|
|
||||||
context.Fpcr = FPCR.A32Mask & (FPCR)fpscr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetTpidrEl0(ulong value)
|
public static void SetTpidrEl0(ulong value)
|
||||||
{
|
{
|
||||||
GetContext().TpidrEl0 = (long)value;
|
GetContext().TpidrEl0 = (long)value;
|
||||||
|
@@ -91,76 +91,6 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Rounding"
|
|
||||||
public static double Round(double value)
|
|
||||||
{
|
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
|
||||||
|
|
||||||
FPRoundingMode roundMode = context.Fpcr.GetRoundingMode();
|
|
||||||
|
|
||||||
if (roundMode == FPRoundingMode.ToNearest)
|
|
||||||
{
|
|
||||||
return Math.Round(value); // even
|
|
||||||
}
|
|
||||||
else if (roundMode == FPRoundingMode.TowardsPlusInfinity)
|
|
||||||
{
|
|
||||||
return Math.Ceiling(value);
|
|
||||||
}
|
|
||||||
else if (roundMode == FPRoundingMode.TowardsMinusInfinity)
|
|
||||||
{
|
|
||||||
return Math.Floor(value);
|
|
||||||
}
|
|
||||||
else /* if (roundMode == FPRoundingMode.TowardsZero) */
|
|
||||||
{
|
|
||||||
return Math.Truncate(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float RoundF(float value)
|
|
||||||
{
|
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
|
||||||
|
|
||||||
FPRoundingMode roundMode = context.Fpcr.GetRoundingMode();
|
|
||||||
|
|
||||||
if (roundMode == FPRoundingMode.ToNearest)
|
|
||||||
{
|
|
||||||
return MathF.Round(value); // even
|
|
||||||
}
|
|
||||||
else if (roundMode == FPRoundingMode.TowardsPlusInfinity)
|
|
||||||
{
|
|
||||||
return MathF.Ceiling(value);
|
|
||||||
}
|
|
||||||
else if (roundMode == FPRoundingMode.TowardsMinusInfinity)
|
|
||||||
{
|
|
||||||
return MathF.Floor(value);
|
|
||||||
}
|
|
||||||
else /* if (roundMode == FPRoundingMode.TowardsZero) */
|
|
||||||
{
|
|
||||||
return MathF.Truncate(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int FloatToInt32(float value)
|
|
||||||
{
|
|
||||||
return SatF32ToS32(RoundF(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int DoubleToInt32(double value)
|
|
||||||
{
|
|
||||||
return SatF64ToS32(Round(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint FloatToUInt32(float value)
|
|
||||||
{
|
|
||||||
return SatF32ToU32(RoundF(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint DoubleToUInt32(double value)
|
|
||||||
{
|
|
||||||
return SatF64ToU32(Round(value));
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region "Saturation"
|
#region "Saturation"
|
||||||
public static int SatF32ToS32(float value)
|
public static int SatF32ToS32(float value)
|
||||||
{
|
{
|
||||||
|
@@ -12,8 +12,8 @@ namespace ARMeilleure.Instructions
|
|||||||
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
|
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static readonly byte[] RecipEstimateTable;
|
public static readonly byte[] RecipEstimateTable;
|
||||||
internal static readonly byte[] RecipSqrtEstimateTable;
|
public static readonly byte[] RecipSqrtEstimateTable;
|
||||||
|
|
||||||
private static byte[] BuildRecipEstimateTable()
|
private static byte[] BuildRecipEstimateTable()
|
||||||
{
|
{
|
||||||
@@ -94,6 +94,13 @@ namespace ARMeilleure.Instructions
|
|||||||
context.Fpsr |= (FPSR)(1 << (int)exc);
|
context.Fpsr |= (FPSR)(1 << (int)exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
|
||||||
|
{
|
||||||
|
const int RModeShift = 22;
|
||||||
|
|
||||||
|
return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SoftFloat16
|
static class SoftFloat16
|
||||||
|
@@ -47,6 +47,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
X86Divps,
|
X86Divps,
|
||||||
X86Divsd,
|
X86Divsd,
|
||||||
X86Divss,
|
X86Divss,
|
||||||
|
X86Gf2p8affineqb,
|
||||||
X86Haddpd,
|
X86Haddpd,
|
||||||
X86Haddps,
|
X86Haddps,
|
||||||
X86Insertps,
|
X86Insertps,
|
||||||
|
@@ -22,6 +22,7 @@ namespace ARMeilleure
|
|||||||
public static bool UseAesniIfAvailable { get; set; } = true;
|
public static bool UseAesniIfAvailable { get; set; } = true;
|
||||||
public static bool UsePclmulqdqIfAvailable { get; set; } = true;
|
public static bool UsePclmulqdqIfAvailable { get; set; } = true;
|
||||||
public static bool UseShaIfAvailable { get; set; } = true;
|
public static bool UseShaIfAvailable { get; set; } = true;
|
||||||
|
public static bool UseGfniIfAvailable { get; set; } = true;
|
||||||
|
|
||||||
public static bool ForceLegacySse
|
public static bool ForceLegacySse
|
||||||
{
|
{
|
||||||
@@ -42,5 +43,6 @@ namespace ARMeilleure
|
|||||||
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
||||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
||||||
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
||||||
|
internal static bool UseGfni => UseGfniIfAvailable && HardwareCapabilities.SupportsGfni;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -36,10 +36,25 @@ namespace ARMeilleure.State
|
|||||||
set => _nativeContext.SetPstate(value);
|
set => _nativeContext.SetPstate(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FPCR Fpcr { get; set; }
|
public FPSR Fpsr
|
||||||
public FPSR Fpsr { get; set; }
|
{
|
||||||
|
get => (FPSR)_nativeContext.GetFPState((uint)FPSR.Mask);
|
||||||
|
set => _nativeContext.SetFPState((uint)value, (uint)FPSR.Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FPCR Fpcr
|
||||||
|
{
|
||||||
|
get => (FPCR)_nativeContext.GetFPState((uint)FPCR.Mask);
|
||||||
|
set => _nativeContext.SetFPState((uint)value, (uint)FPCR.Mask);
|
||||||
|
}
|
||||||
public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz;
|
public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz;
|
||||||
|
|
||||||
|
public FPSCR Fpscr
|
||||||
|
{
|
||||||
|
get => (FPSCR)_nativeContext.GetFPState((uint)FPSCR.Mask);
|
||||||
|
set => _nativeContext.SetFPState((uint)value, (uint)FPSCR.Mask);
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsAarch32 { get; set; }
|
public bool IsAarch32 { get; set; }
|
||||||
|
|
||||||
internal ExecutionMode ExecutionMode
|
internal ExecutionMode ExecutionMode
|
||||||
|
@@ -5,21 +5,18 @@ namespace ARMeilleure.State
|
|||||||
[Flags]
|
[Flags]
|
||||||
public enum FPCR : uint
|
public enum FPCR : uint
|
||||||
{
|
{
|
||||||
|
Ioe = 1u << 8,
|
||||||
|
Dze = 1u << 9,
|
||||||
|
Ofe = 1u << 10,
|
||||||
Ufe = 1u << 11,
|
Ufe = 1u << 11,
|
||||||
|
Ixe = 1u << 12,
|
||||||
|
Ide = 1u << 15,
|
||||||
|
RMode0 = 1u << 22,
|
||||||
|
RMode1 = 1u << 23,
|
||||||
Fz = 1u << 24,
|
Fz = 1u << 24,
|
||||||
Dn = 1u << 25,
|
Dn = 1u << 25,
|
||||||
Ahp = 1u << 26,
|
Ahp = 1u << 26,
|
||||||
|
|
||||||
A32Mask = 0x07FF9F00u
|
Mask = Ahp | Dn | Fz | RMode1 | RMode0 | Ide | Ixe | Ufe | Ofe | Dze | Ioe // 0x07C09F00u
|
||||||
}
|
|
||||||
|
|
||||||
public static class FPCRExtensions
|
|
||||||
{
|
|
||||||
private const int RModeShift = 22;
|
|
||||||
|
|
||||||
public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
|
|
||||||
{
|
|
||||||
return (FPRoundingMode)(((int)fpcr >> RModeShift) & 3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,9 +2,10 @@ namespace ARMeilleure.State
|
|||||||
{
|
{
|
||||||
public enum FPRoundingMode
|
public enum FPRoundingMode
|
||||||
{
|
{
|
||||||
ToNearest = 0,
|
ToNearest = 0, // With ties to even.
|
||||||
TowardsPlusInfinity = 1,
|
TowardsPlusInfinity = 1,
|
||||||
TowardsMinusInfinity = 2,
|
TowardsMinusInfinity = 2,
|
||||||
TowardsZero = 3
|
TowardsZero = 3,
|
||||||
|
ToNearestAway = 4 // With ties to away.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
ARMeilleure/State/FPSCR.cs
Normal file
15
ARMeilleure/State/FPSCR.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ARMeilleure.State
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum FPSCR : uint
|
||||||
|
{
|
||||||
|
V = 1u << 28,
|
||||||
|
C = 1u << 29,
|
||||||
|
Z = 1u << 30,
|
||||||
|
N = 1u << 31,
|
||||||
|
|
||||||
|
Mask = N | Z | C | V | FPSR.Mask | FPCR.Mask // 0xFFC09F9Fu
|
||||||
|
}
|
||||||
|
}
|
@@ -5,11 +5,14 @@ namespace ARMeilleure.State
|
|||||||
[Flags]
|
[Flags]
|
||||||
public enum FPSR : uint
|
public enum FPSR : uint
|
||||||
{
|
{
|
||||||
|
Ioc = 1u << 0,
|
||||||
|
Dzc = 1u << 1,
|
||||||
|
Ofc = 1u << 2,
|
||||||
Ufc = 1u << 3,
|
Ufc = 1u << 3,
|
||||||
Qc = 1u << 27,
|
Ixc = 1u << 4,
|
||||||
|
Idc = 1u << 7,
|
||||||
|
Qc = 1u << 27,
|
||||||
|
|
||||||
Nzcv = (1u << 31) | (1u << 30) | (1u << 29) | (1u << 28),
|
Mask = Qc | Idc | Ixc | Ufc | Ofc | Dzc | Ioc // 0x0800009Fu
|
||||||
|
|
||||||
A32Mask = 0xF800009Fu
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,9 +2,30 @@
|
|||||||
{
|
{
|
||||||
public enum FPState
|
public enum FPState
|
||||||
{
|
{
|
||||||
|
// FPSR Flags.
|
||||||
|
IocFlag = 0,
|
||||||
|
DzcFlag = 1,
|
||||||
|
OfcFlag = 2,
|
||||||
|
UfcFlag = 3,
|
||||||
|
IxcFlag = 4,
|
||||||
|
IdcFlag = 7,
|
||||||
|
QcFlag = 27,
|
||||||
VFlag = 28,
|
VFlag = 28,
|
||||||
CFlag = 29,
|
CFlag = 29,
|
||||||
ZFlag = 30,
|
ZFlag = 30,
|
||||||
NFlag = 31
|
NFlag = 31,
|
||||||
|
|
||||||
|
// FPCR Flags.
|
||||||
|
IoeFlag = 8,
|
||||||
|
DzeFlag = 9,
|
||||||
|
OfeFlag = 10,
|
||||||
|
UfeFlag = 11,
|
||||||
|
IxeFlag = 12,
|
||||||
|
IdeFlag = 15,
|
||||||
|
RMode0Flag = 22,
|
||||||
|
RMode1Flag = 23,
|
||||||
|
FzFlag = 24,
|
||||||
|
DnFlag = 25,
|
||||||
|
AhpFlag = 26
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -140,6 +140,34 @@ namespace ARMeilleure.State
|
|||||||
GetStorage().FpFlags[(int)flag] = value ? 1u : 0u;
|
GetStorage().FpFlags[(int)flag] = value ? 1u : 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public unsafe uint GetFPState(uint mask = uint.MaxValue)
|
||||||
|
{
|
||||||
|
uint value = 0;
|
||||||
|
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||||
|
{
|
||||||
|
uint bit = 1u << flag;
|
||||||
|
|
||||||
|
if ((mask & bit) == bit)
|
||||||
|
{
|
||||||
|
value |= GetStorage().FpFlags[flag] != 0 ? bit : 0u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void SetFPState(uint value, uint mask = uint.MaxValue)
|
||||||
|
{
|
||||||
|
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||||
|
{
|
||||||
|
uint bit = 1u << flag;
|
||||||
|
|
||||||
|
if ((mask & bit) == bit)
|
||||||
|
{
|
||||||
|
GetStorage().FpFlags[flag] = (value & bit) == bit ? 1u : 0u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int GetCounter() => GetStorage().Counter;
|
public int GetCounter() => GetStorage().Counter;
|
||||||
public void SetCounter(int value) => GetStorage().Counter = value;
|
public void SetCounter(int value) => GetStorage().Counter = value;
|
||||||
|
|
||||||
|
@@ -109,10 +109,6 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
|
||||||
@@ -124,10 +120,6 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
||||||
@@ -151,12 +143,8 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))); // A32 only.
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
|
||||||
@@ -165,8 +153,6 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)));
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)));
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
|
||||||
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 3700; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 3713; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
@@ -951,7 +951,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return new FeatureInfo(
|
return new FeatureInfo(
|
||||||
(uint)HardwareCapabilities.FeatureInfo1Ecx,
|
(uint)HardwareCapabilities.FeatureInfo1Ecx,
|
||||||
(uint)HardwareCapabilities.FeatureInfo1Edx,
|
(uint)HardwareCapabilities.FeatureInfo1Edx,
|
||||||
(uint)HardwareCapabilities.FeatureInfo7Ebx);
|
(uint)HardwareCapabilities.FeatureInfo7Ebx,
|
||||||
|
(uint)HardwareCapabilities.FeatureInfo7Ecx);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte GetMemoryManagerMode()
|
private static byte GetMemoryManagerMode()
|
||||||
@@ -971,7 +972,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return osPlatform;
|
return osPlatform;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 54*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 58*/)]
|
||||||
private struct OuterHeader
|
private struct OuterHeader
|
||||||
{
|
{
|
||||||
public ulong Magic;
|
public ulong Magic;
|
||||||
@@ -1002,8 +1003,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 12*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 16*/)]
|
||||||
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2);
|
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2, uint FeatureInfo3);
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
||||||
private struct InnerHeader
|
private struct InnerHeader
|
||||||
|
@@ -455,13 +455,16 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
// If rejit is running, stop it as it may be trying to rejit a function on the invalidated region.
|
|
||||||
ClearRejitQueue(allowRequeue: true);
|
|
||||||
|
|
||||||
ulong[] overlapAddresses = Array.Empty<ulong>();
|
ulong[] overlapAddresses = Array.Empty<ulong>();
|
||||||
|
|
||||||
int overlapsCount = Functions.GetOverlaps(address, size, ref overlapAddresses);
|
int overlapsCount = Functions.GetOverlaps(address, size, ref overlapAddresses);
|
||||||
|
|
||||||
|
if (overlapsCount != 0)
|
||||||
|
{
|
||||||
|
// If rejit is running, stop it as it may be trying to rejit a function on the invalidated region.
|
||||||
|
ClearRejitQueue(allowRequeue: true);
|
||||||
|
}
|
||||||
|
|
||||||
for (int index = 0; index < overlapsCount; index++)
|
for (int index = 0; index < overlapsCount; index++)
|
||||||
{
|
{
|
||||||
ulong overlapAddress = overlapAddresses[index];
|
ulong overlapAddress = overlapAddresses[index];
|
||||||
|
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
As of September 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,400 boot past menus and into gameplay, with roughly 2,700 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
|
As of October 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,500 boot past menus and into gameplay, with roughly 3,000 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
|
||||||
Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
@@ -58,6 +58,8 @@ namespace Ryujinx.Ava
|
|||||||
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
||||||
private const int TargetFps = 60;
|
private const int TargetFps = 60;
|
||||||
|
|
||||||
|
private const float VolumeDelta = 0.05f;
|
||||||
|
|
||||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||||
|
|
||||||
private readonly long _ticksPerFrame;
|
private readonly long _ticksPerFrame;
|
||||||
@@ -73,6 +75,7 @@ namespace Ryujinx.Ava
|
|||||||
private bool _isStopped;
|
private bool _isStopped;
|
||||||
private bool _isActive;
|
private bool _isActive;
|
||||||
private long _lastCursorMoveTime;
|
private long _lastCursorMoveTime;
|
||||||
|
private float _newVolume;
|
||||||
private long _ticks = 0;
|
private long _ticks = 0;
|
||||||
|
|
||||||
private KeyboardHotkeyState _prevHotkeyState;
|
private KeyboardHotkeyState _prevHotkeyState;
|
||||||
@@ -1003,6 +1006,18 @@ namespace Ryujinx.Ava
|
|||||||
GraphicsConfig.ResScale =
|
GraphicsConfig.ResScale =
|
||||||
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
|
(MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1;
|
||||||
break;
|
break;
|
||||||
|
case KeyboardHotkeyState.VolumeUp:
|
||||||
|
_newVolume = MathF.Round((Device.GetVolume() + VolumeDelta), 2);
|
||||||
|
Device.SetVolume(_newVolume);
|
||||||
|
|
||||||
|
_parent.ViewModel.Volume = Device.GetVolume();
|
||||||
|
break;
|
||||||
|
case KeyboardHotkeyState.VolumeDown:
|
||||||
|
_newVolume = MathF.Round((Device.GetVolume() - VolumeDelta), 2);
|
||||||
|
Device.SetVolume(_newVolume);
|
||||||
|
|
||||||
|
_parent.ViewModel.Volume = Device.GetVolume();
|
||||||
|
break;
|
||||||
case KeyboardHotkeyState.None:
|
case KeyboardHotkeyState.None:
|
||||||
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
(_keyboardInterface as AvaloniaKeyboard).Clear();
|
||||||
break;
|
break;
|
||||||
@@ -1068,6 +1083,14 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
state = KeyboardHotkeyState.ResScaleDown;
|
state = KeyboardHotkeyState.ResScaleDown;
|
||||||
}
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeUp))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.VolumeUp;
|
||||||
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VolumeDown))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.VolumeDown;
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@@ -574,12 +574,12 @@
|
|||||||
"Discard": "Discard",
|
"Discard": "Discard",
|
||||||
"UserProfilesSetProfileImage": "Set Profile Image",
|
"UserProfilesSetProfileImage": "Set Profile Image",
|
||||||
"UserProfileEmptyNameError": "Name is required",
|
"UserProfileEmptyNameError": "Name is required",
|
||||||
"UserProfileNoImageError": "Profile image must be set",
|
"UserProfileNoImageError": "Profile image must be set",
|
||||||
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
|
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
|
||||||
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
||||||
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
||||||
"UserProfilesName": "Name:",
|
"UserProfilesName": "Name:",
|
||||||
"UserProfilesUserId" : "User Id:",
|
"UserProfilesUserId": "User Id:",
|
||||||
"SettingsTabGraphicsBackend": "Graphics Backend",
|
"SettingsTabGraphicsBackend": "Graphics Backend",
|
||||||
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
|
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
|
||||||
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
|
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
|
||||||
@@ -589,5 +589,8 @@
|
|||||||
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
||||||
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
|
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
|
||||||
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
||||||
|
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||||
|
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||||
|
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||||
"VolumeShort": "Vol"
|
"VolumeShort": "Vol"
|
||||||
}
|
}
|
||||||
|
@@ -588,5 +588,9 @@
|
|||||||
"SettingsTabGraphicsPreferredGpuTooltip": "Wybierz kartę graficzną, która będzie używana z backendem graficznym Vulkan.\n\nNie wpływa na GPU używane przez OpenGL.\n\nW razie wątpliwości ustaw flagę GPU jako \"dGPU\". Jeśli żadnej nie ma, pozostaw nietknięte.",
|
"SettingsTabGraphicsPreferredGpuTooltip": "Wybierz kartę graficzną, która będzie używana z backendem graficznym Vulkan.\n\nNie wpływa na GPU używane przez OpenGL.\n\nW razie wątpliwości ustaw flagę GPU jako \"dGPU\". Jeśli żadnej nie ma, pozostaw nietknięte.",
|
||||||
"SettingsAppRequiredRestartMessage": "Wymagane Zrestartowanie Ryujinx",
|
"SettingsAppRequiredRestartMessage": "Wymagane Zrestartowanie Ryujinx",
|
||||||
"SettingsGpuBackendRestartMessage": "Zmieniono ustawienia Backendu Graficznego lub GPU. Będzie to wymagało ponownego uruchomienia",
|
"SettingsGpuBackendRestartMessage": "Zmieniono ustawienia Backendu Graficznego lub GPU. Będzie to wymagało ponownego uruchomienia",
|
||||||
"SettingsGpuBackendRestartSubMessage": "Czy chcesz zrestartować teraz?"
|
"SettingsGpuBackendRestartSubMessage": "Czy chcesz zrestartować teraz?",
|
||||||
|
"RyujinxUpdaterMessage": "Czy chcesz zaktualizować Ryujinx do najnowszej wersji?",
|
||||||
|
"SettingsTabHotkeysVolumeUpHotkey": "Zwiększ Głośność:",
|
||||||
|
"SettingsTabHotkeysVolumeDownHotkey": "Zmniejsz Głośność:",
|
||||||
|
"VolumeShort": "Głoś"
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
Pause,
|
Pause,
|
||||||
ToggleMute,
|
ToggleMute,
|
||||||
ResScaleUp,
|
ResScaleUp,
|
||||||
ResScaleDown
|
ResScaleDown,
|
||||||
|
VolumeUp,
|
||||||
|
VolumeDown
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,6 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
using ICSharpCode.SharpZipLib.GZip;
|
using ICSharpCode.SharpZipLib.GZip;
|
||||||
using ICSharpCode.SharpZipLib.Tar;
|
using ICSharpCode.SharpZipLib.Tar;
|
||||||
using ICSharpCode.SharpZipLib.Zip;
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
@@ -11,11 +13,13 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -40,6 +44,8 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
|
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
|
||||||
|
|
||||||
|
public static bool UpdateSuccessful { get; private set; }
|
||||||
|
|
||||||
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
||||||
{
|
{
|
||||||
if (Running)
|
if (Running)
|
||||||
@@ -198,11 +204,18 @@ namespace Ryujinx.Modules
|
|||||||
_buildSize = -1;
|
_buildSize = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
// Show a message asking the user if they want to update
|
// Show a message asking the user if they want to update
|
||||||
UpdaterWindow updateDialog = new(mainWindow, newVersion, _buildUrl);
|
var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||||
await updateDialog.ShowDialog(mainWindow);
|
LocaleManager.Instance["RyujinxUpdaterMessage"],
|
||||||
|
$"{Program.Version} -> {newVersion}");
|
||||||
|
|
||||||
|
if (shouldUpdate)
|
||||||
|
{
|
||||||
|
UpdateRyujinx(mainWindow, _buildUrl);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +229,10 @@ namespace Ryujinx.Modules
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateRyujinx(UpdaterWindow updateDialog, string downloadUrl)
|
public static async void UpdateRyujinx(Window parent, string downloadUrl)
|
||||||
{
|
{
|
||||||
|
UpdateSuccessful = false;
|
||||||
|
|
||||||
// Empty update dir, although it shouldn't ever have anything inside it
|
// Empty update dir, although it shouldn't ever have anything inside it
|
||||||
if (Directory.Exists(UpdateDir))
|
if (Directory.Exists(UpdateDir))
|
||||||
{
|
{
|
||||||
@@ -228,25 +243,56 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
||||||
|
|
||||||
// Download the update .zip
|
var taskDialog = new TaskDialog()
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterDownloading"];
|
{
|
||||||
updateDialog.ProgressBar.Value = 0;
|
Header = LocaleManager.Instance["RyujinxUpdater"],
|
||||||
updateDialog.ProgressBar.Maximum = 100;
|
SubHeader = LocaleManager.Instance["UpdaterDownloading"],
|
||||||
|
IconSource = new SymbolIconSource { Symbol = Symbol.Download },
|
||||||
|
Buttons = { },
|
||||||
|
ShowProgressBar = true
|
||||||
|
};
|
||||||
|
|
||||||
Task.Run(() =>
|
taskDialog.XamlRoot = parent;
|
||||||
|
|
||||||
|
taskDialog.Opened += (s, e) =>
|
||||||
{
|
{
|
||||||
if (_buildSize >= 0)
|
if (_buildSize >= 0)
|
||||||
{
|
{
|
||||||
DoUpdateWithMultipleThreads(updateDialog, downloadUrl, updateFile);
|
DoUpdateWithMultipleThreads(taskDialog, downloadUrl, updateFile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
await taskDialog.ShowAsync(true);
|
||||||
|
|
||||||
|
if (UpdateSuccessful)
|
||||||
|
{
|
||||||
|
var shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
|
||||||
|
LocaleManager.Instance["DialogUpdaterCompleteMessage"],
|
||||||
|
LocaleManager.Instance["DialogUpdaterRestartMessage"]);
|
||||||
|
|
||||||
|
if (shouldRestart)
|
||||||
|
{
|
||||||
|
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
||||||
|
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
||||||
|
var ryuArg = Environment.GetCommandLineArgs().Skip(1);
|
||||||
|
|
||||||
|
if (!OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
chmod(ryuExe, Convert.ToUInt32("0777", 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
Process.Start(ryuExe, ryuArg);
|
||||||
|
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DoUpdateWithMultipleThreads(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
private static void DoUpdateWithMultipleThreads(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||||
{
|
{
|
||||||
// Multi-Threaded Updater
|
// Multi-Threaded Updater
|
||||||
long chunkSize = _buildSize / ConnectionCount;
|
long chunkSize = _buildSize / ConnectionCount;
|
||||||
@@ -290,7 +336,7 @@ namespace Ryujinx.Modules
|
|||||||
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
||||||
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
||||||
|
|
||||||
updateDialog.ProgressBar.Value = totalProgressPercentage / ConnectionCount;
|
taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal);
|
||||||
};
|
};
|
||||||
|
|
||||||
client.DownloadDataCompleted += (_, args) =>
|
client.DownloadDataCompleted += (_, args) =>
|
||||||
@@ -301,6 +347,8 @@ namespace Ryujinx.Modules
|
|||||||
{
|
{
|
||||||
webClients[index].Dispose();
|
webClients[index].Dispose();
|
||||||
|
|
||||||
|
taskDialog.Hide();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,14 +368,14 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
InstallUpdate(updateDialog, updateFile);
|
InstallUpdate(taskDialog, updateFile);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, e.Message);
|
Logger.Warning?.Print(LogClass.Application, e.Message);
|
||||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||||
|
|
||||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -348,7 +396,7 @@ namespace Ryujinx.Modules
|
|||||||
webClients[j].CancelAsync();
|
webClients[j].CancelAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -356,7 +404,7 @@ namespace Ryujinx.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DoUpdateWithSingleThreadWorker(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
private static void DoUpdateWithSingleThreadWorker(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||||
{
|
{
|
||||||
using (HttpClient client = new HttpClient())
|
using (HttpClient client = new HttpClient())
|
||||||
{
|
{
|
||||||
@@ -384,19 +432,26 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
byteWritten += readSize;
|
byteWritten += readSize;
|
||||||
|
|
||||||
updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100;
|
taskDialog.SetProgressBarState(GetPercentage(byteWritten, totalBytes), TaskDialogProgressState.Normal);
|
||||||
|
|
||||||
updateFileStream.Write(buffer, 0, readSize);
|
updateFileStream.Write(buffer, 0, readSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallUpdate(updateDialog, updateFile);
|
InstallUpdate(taskDialog, updateFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DoUpdateWithSingleThread(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static double GetPercentage(double value, double max)
|
||||||
{
|
{
|
||||||
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(updateDialog, downloadUrl, updateFile));
|
return max == 0 ? 0 : value / max * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DoUpdateWithSingleThread(TaskDialog taskDialog, string downloadUrl, string updateFile)
|
||||||
|
{
|
||||||
|
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(taskDialog, downloadUrl, updateFile));
|
||||||
worker.Name = "Updater.SingleThreadWorker";
|
worker.Name = "Updater.SingleThreadWorker";
|
||||||
worker.Start();
|
worker.Start();
|
||||||
}
|
}
|
||||||
@@ -414,11 +469,11 @@ namespace Ryujinx.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async void InstallUpdate(UpdaterWindow updateDialog, string updateFile)
|
private static async void InstallUpdate(TaskDialog taskDialog, string updateFile)
|
||||||
{
|
{
|
||||||
// Extract Update
|
// Extract Update
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterExtracting"];
|
taskDialog.SubHeader = LocaleManager.Instance["UpdaterExtracting"];
|
||||||
updateDialog.ProgressBar.Value = 0;
|
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||||
|
|
||||||
if (OperatingSystem.IsLinux())
|
if (OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
@@ -426,8 +481,6 @@ namespace Ryujinx.Modules
|
|||||||
using (Stream gzipStream = new GZipInputStream(inStream))
|
using (Stream gzipStream = new GZipInputStream(inStream))
|
||||||
using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII))
|
using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII))
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Maximum = inStream.Length;
|
|
||||||
|
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
TarEntry tarEntry;
|
TarEntry tarEntry;
|
||||||
@@ -450,12 +503,12 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Value += entry.Size;
|
taskDialog.SetProgressBarState(GetPercentage(entry.Size, inStream.Length), TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
updateDialog.ProgressBar.Value = inStream.Length;
|
taskDialog.SetProgressBarState(100, TaskDialogProgressState.Normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -463,12 +516,12 @@ namespace Ryujinx.Modules
|
|||||||
using (Stream inStream = File.OpenRead(updateFile))
|
using (Stream inStream = File.OpenRead(updateFile))
|
||||||
using (ZipFile zipFile = new ZipFile(inStream))
|
using (ZipFile zipFile = new ZipFile(inStream))
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Maximum = zipFile.Count;
|
|
||||||
|
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
double count = 0;
|
||||||
foreach (ZipEntry zipEntry in zipFile)
|
foreach (ZipEntry zipEntry in zipFile)
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
if (zipEntry.IsDirectory) continue;
|
if (zipEntry.IsDirectory) continue;
|
||||||
|
|
||||||
string outPath = Path.Combine(UpdateDir, zipEntry.Name);
|
string outPath = Path.Combine(UpdateDir, zipEntry.Name);
|
||||||
@@ -485,7 +538,7 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Value++;
|
taskDialog.SetProgressBarState(GetPercentage(count, zipFile.Count), TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -497,22 +550,23 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
||||||
|
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterRenaming"];
|
taskDialog.SubHeader = LocaleManager.Instance["UpdaterRenaming"];
|
||||||
updateDialog.ProgressBar.Value = 0;
|
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||||
updateDialog.ProgressBar.Maximum = allFiles.Count;
|
|
||||||
|
|
||||||
// Replace old files
|
// Replace old files
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
double count = 0;
|
||||||
foreach (string file in allFiles)
|
foreach (string file in allFiles)
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Move(file, file + ".ryuold");
|
File.Move(file, file + ".ryuold");
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
updateDialog.ProgressBar.Value++;
|
taskDialog.SetProgressBarState(GetPercentage(count, allFiles.Count), TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -523,23 +577,20 @@ namespace Ryujinx.Modules
|
|||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterAddingFiles"];
|
taskDialog.SubHeader = LocaleManager.Instance["UpdaterAddingFiles"];
|
||||||
updateDialog.ProgressBar.Value = 0;
|
taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
|
||||||
updateDialog.ProgressBar.Maximum = Directory.GetFiles(UpdatePublishDir, "*", SearchOption.AllDirectories).Length;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
MoveAllFilesOver(UpdatePublishDir, HomeDir, updateDialog);
|
MoveAllFilesOver(UpdatePublishDir, HomeDir, taskDialog);
|
||||||
});
|
});
|
||||||
|
|
||||||
Directory.Delete(UpdateDir, true);
|
Directory.Delete(UpdateDir, true);
|
||||||
|
|
||||||
SetUnixPermissions();
|
SetUnixPermissions();
|
||||||
|
|
||||||
updateDialog.MainText.Text = LocaleManager.Instance["DialogUpdaterCompleteMessage"];
|
UpdateSuccessful = true;
|
||||||
updateDialog.SecondaryText.Text = LocaleManager.Instance["DialogUpdaterRestartMessage"];
|
|
||||||
|
|
||||||
updateDialog.ProgressBar.IsVisible = false;
|
taskDialog.Hide();
|
||||||
updateDialog.ButtonBox.IsVisible = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
@@ -618,8 +669,9 @@ namespace Ryujinx.Modules
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MoveAllFilesOver(string root, string dest, UpdaterWindow dialog)
|
private static void MoveAllFilesOver(string root, string dest, TaskDialog taskDialog)
|
||||||
{
|
{
|
||||||
|
var total = Directory.GetFiles(root, "*", SearchOption.AllDirectories).Length;
|
||||||
foreach (string directory in Directory.GetDirectories(root))
|
foreach (string directory in Directory.GetDirectories(root))
|
||||||
{
|
{
|
||||||
string dirName = Path.GetFileName(directory);
|
string dirName = Path.GetFileName(directory);
|
||||||
@@ -629,16 +681,18 @@ namespace Ryujinx.Modules
|
|||||||
Directory.CreateDirectory(Path.Combine(dest, dirName));
|
Directory.CreateDirectory(Path.Combine(dest, dirName));
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveAllFilesOver(directory, Path.Combine(dest, dirName), dialog);
|
MoveAllFilesOver(directory, Path.Combine(dest, dirName), taskDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double count = 0;
|
||||||
foreach (string file in Directory.GetFiles(root))
|
foreach (string file in Directory.GetFiles(root))
|
||||||
{
|
{
|
||||||
|
count++;
|
||||||
File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true);
|
File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true);
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
dialog.ProgressBar.Value++;
|
taskDialog.SetProgressBarState(GetPercentage(count, total), TaskDialogProgressState.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -295,8 +295,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
if (_validTzRegions.Contains(location))
|
if (_validTzRegions.Contains(location))
|
||||||
{
|
{
|
||||||
TimeZone = location;
|
TimeZone = location;
|
||||||
|
|
||||||
OnPropertyChanged(nameof(TimeZone));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,6 @@
|
|||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
Title="Ryujinx - About"
|
|
||||||
Width="850"
|
Width="850"
|
||||||
Height="550"
|
Height="550"
|
||||||
MinWidth="500"
|
MinWidth="500"
|
||||||
|
@@ -164,7 +164,7 @@
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
CommandParameter="pl_PL"
|
CommandParameter="pl_PL"
|
||||||
Header="Polish" />
|
Header="Polski" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{ReflectionBinding ChangeLanguage}"
|
Command="{ReflectionBinding ChangeLanguage}"
|
||||||
CommandParameter="ru_RU"
|
CommandParameter="ru_RU"
|
||||||
|
@@ -257,6 +257,22 @@
|
|||||||
TextAlignment="Center" />
|
TextAlignment="Center" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" />
|
||||||
|
<ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}"
|
||||||
|
TextAlignment="Center" />
|
||||||
|
</ToggleButton>
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
@@ -37,7 +37,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Load();
|
Load();
|
||||||
|
|
||||||
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()));
|
FuncMultiValueConverter<string, string> converter = new(parts => string.Format("{0} {1} {2}", parts.ToArray()).Trim());
|
||||||
MultiBinding tzMultiBinding = new() { Converter = converter };
|
MultiBinding tzMultiBinding = new() { Converter = converter };
|
||||||
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
tzMultiBinding.Bindings.Add(new Binding("UtcDifference"));
|
||||||
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
tzMultiBinding.Bindings.Add(new Binding("Location"));
|
||||||
|
@@ -1,66 +0,0 @@
|
|||||||
<window:StyleableWindow
|
|
||||||
x:Class="Ryujinx.Ava.Ui.Windows.UpdaterWindow"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
|
||||||
Title="Ryujinx Updater"
|
|
||||||
Width="500"
|
|
||||||
Height="500"
|
|
||||||
MinWidth="500"
|
|
||||||
MinHeight="500"
|
|
||||||
d:DesignHeight="350"
|
|
||||||
d:DesignWidth="400"
|
|
||||||
CanResize="False"
|
|
||||||
SizeToContent="Height"
|
|
||||||
WindowStartupLocation="CenterOwner"
|
|
||||||
mc:Ignorable="d">
|
|
||||||
<Grid
|
|
||||||
Margin="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TextBlock
|
|
||||||
Name="MainText"
|
|
||||||
Grid.Row="1"
|
|
||||||
Height="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
<TextBlock
|
|
||||||
Name="SecondaryText"
|
|
||||||
Grid.Row="2"
|
|
||||||
Height="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
TextAlignment="Center" />
|
|
||||||
<ProgressBar
|
|
||||||
Name="ProgressBar"
|
|
||||||
Grid.Row="3"
|
|
||||||
Margin="20"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
IsVisible="False"
|
|
||||||
Maximum="100"
|
|
||||||
Minimum="0" />
|
|
||||||
<StackPanel
|
|
||||||
Name="ButtonBox"
|
|
||||||
Grid.Row="4"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
IsVisible="False"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Spacing="20">
|
|
||||||
<Button MinWidth="50" Command="{Binding YesPressed}">
|
|
||||||
<TextBlock Text="{locale:Locale InputDialogYes}" TextAlignment="Center" />
|
|
||||||
</Button>
|
|
||||||
<Button MinWidth="50" Command="{Binding NoPressed}">
|
|
||||||
<TextBlock Text="{locale:Locale InputDialogNo}" TextAlignment="Center" />
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</window:StyleableWindow>
|
|
@@ -1,73 +0,0 @@
|
|||||||
using Ryujinx.Ava.Common.Locale;
|
|
||||||
using Ryujinx.Modules;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Windows
|
|
||||||
{
|
|
||||||
public partial class UpdaterWindow : StyleableWindow
|
|
||||||
{
|
|
||||||
private readonly string _buildUrl;
|
|
||||||
private readonly MainWindow _mainWindow;
|
|
||||||
private readonly Version _newVersion;
|
|
||||||
private bool _restartQuery;
|
|
||||||
|
|
||||||
public UpdaterWindow()
|
|
||||||
{
|
|
||||||
DataContext = this;
|
|
||||||
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
Title = LocaleManager.Instance["RyujinxUpdater"];
|
|
||||||
}
|
|
||||||
|
|
||||||
public UpdaterWindow(MainWindow mainWindow, Version newVersion, string buildUrl) : this()
|
|
||||||
{
|
|
||||||
_mainWindow = mainWindow;
|
|
||||||
_newVersion = newVersion;
|
|
||||||
_buildUrl = buildUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
|
||||||
private static extern int chmod(string path, uint mode);
|
|
||||||
|
|
||||||
public void YesPressed()
|
|
||||||
{
|
|
||||||
if (_restartQuery)
|
|
||||||
{
|
|
||||||
string ryuName = OperatingSystem.IsWindows() ? "Ryujinx.Ava.exe" : "Ryujinx.Ava";
|
|
||||||
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
|
||||||
string ryuArg = string.Join(" ", Environment.GetCommandLineArgs().AsEnumerable().Skip(1).ToArray());
|
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows())
|
|
||||||
{
|
|
||||||
chmod(ryuExe, 0777);
|
|
||||||
}
|
|
||||||
|
|
||||||
Process.Start(ryuExe, ryuArg);
|
|
||||||
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ButtonBox.IsVisible = false;
|
|
||||||
ProgressBar.IsVisible = true;
|
|
||||||
|
|
||||||
SecondaryText.Text = "";
|
|
||||||
_restartQuery = true;
|
|
||||||
|
|
||||||
Updater.UpdateRyujinx(this, _buildUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void NoPressed()
|
|
||||||
{
|
|
||||||
_mainWindow.UpdateMenuItem.IsEnabled = true;
|
|
||||||
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -9,5 +9,7 @@
|
|||||||
public Key ToggleMute { get; set; }
|
public Key ToggleMute { get; set; }
|
||||||
public Key ResScaleUp { get; set; }
|
public Key ResScaleUp { get; set; }
|
||||||
public Key ResScaleDown { get; set; }
|
public Key ResScaleDown { get; set; }
|
||||||
|
public Key VolumeUp { get; set; }
|
||||||
|
public Key VolumeDown { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,6 +30,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
ServiceBsd,
|
ServiceBsd,
|
||||||
ServiceBtm,
|
ServiceBtm,
|
||||||
ServiceCaps,
|
ServiceCaps,
|
||||||
|
ServiceFatal,
|
||||||
ServiceFriend,
|
ServiceFriend,
|
||||||
ServiceFs,
|
ServiceFs,
|
||||||
ServiceHid,
|
ServiceHid,
|
||||||
|
89
Ryujinx.Common/Memory/SpanOrArray.cs
Normal file
89
Ryujinx.Common/Memory/SpanOrArray.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Memory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A struct that can represent both a Span and Array.
|
||||||
|
/// This is useful to keep the Array representation when possible to avoid copies.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Element Type</typeparam>
|
||||||
|
public ref struct SpanOrArray<T> where T : unmanaged
|
||||||
|
{
|
||||||
|
public readonly T[] Array;
|
||||||
|
public readonly ReadOnlySpan<T> Span;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new SpanOrArray from an array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">Array to store</param>
|
||||||
|
public SpanOrArray(T[] array)
|
||||||
|
{
|
||||||
|
Array = array;
|
||||||
|
Span = ReadOnlySpan<T>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new SpanOrArray from a readonly span.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">Span to store</param>
|
||||||
|
public SpanOrArray(ReadOnlySpan<T> span)
|
||||||
|
{
|
||||||
|
Array = null;
|
||||||
|
Span = span;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return the contained array, or convert the span if necessary.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array containing the data</returns>
|
||||||
|
public T[] ToArray()
|
||||||
|
{
|
||||||
|
return Array ?? Span.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return a ReadOnlySpan from either the array or ReadOnlySpan.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A ReadOnlySpan containing the data</returns>
|
||||||
|
public ReadOnlySpan<T> AsSpan()
|
||||||
|
{
|
||||||
|
return Array ?? Span;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast an array to a SpanOrArray.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">Source array</param>
|
||||||
|
public static implicit operator SpanOrArray<T>(T[] array)
|
||||||
|
{
|
||||||
|
return new SpanOrArray<T>(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast a ReadOnlySpan to a SpanOrArray.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">Source ReadOnlySpan</param>
|
||||||
|
public static implicit operator SpanOrArray<T>(ReadOnlySpan<T> span)
|
||||||
|
{
|
||||||
|
return new SpanOrArray<T>(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast a Span to a SpanOrArray.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">Source Span</param>
|
||||||
|
public static implicit operator SpanOrArray<T>(Span<T> span)
|
||||||
|
{
|
||||||
|
return new SpanOrArray<T>(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast a SpanOrArray to a ReadOnlySpan
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="spanOrArray">Source SpanOrArray</param>
|
||||||
|
public static implicit operator ReadOnlySpan<T>(SpanOrArray<T> spanOrArray)
|
||||||
|
{
|
||||||
|
return spanOrArray.AsSpan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -129,7 +129,7 @@ namespace Ryujinx.Common
|
|||||||
|
|
||||||
private static (Assembly, string) ResolveManifestPath(string filename)
|
private static (Assembly, string) ResolveManifestPath(string filename)
|
||||||
{
|
{
|
||||||
var segments = filename.Split(new[] { '/' }, 2, StringSplitOptions.RemoveEmptyEntries);
|
var segments = filename.Split('/', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
if (segments.Length >= 2)
|
if (segments.Length >= 2)
|
||||||
{
|
{
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Common.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.GAL
|
||||||
@@ -17,9 +18,9 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
ReadOnlySpan<byte> GetData();
|
ReadOnlySpan<byte> GetData();
|
||||||
ReadOnlySpan<byte> GetData(int layer, int level);
|
ReadOnlySpan<byte> GetData(int layer, int level);
|
||||||
|
|
||||||
void SetData(ReadOnlySpan<byte> data);
|
void SetData(SpanOrArray<byte> data);
|
||||||
void SetData(ReadOnlySpan<byte> data, int layer, int level);
|
void SetData(SpanOrArray<byte> data, int layer, int level);
|
||||||
void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region);
|
void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region);
|
||||||
void SetStorage(BufferRange buffer);
|
void SetStorage(BufferRange buffer);
|
||||||
void Release();
|
void Release();
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
|
||||||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -107,19 +108,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data.ToArray()));
|
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data.ToArray()));
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level);
|
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level);
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level, region);
|
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level, region);
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
|
@@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
|
|
||||||
if (target != null)
|
if (target != null)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<byte> data;
|
byte[] data;
|
||||||
if (srcLinear)
|
if (srcLinear)
|
||||||
{
|
{
|
||||||
data = LayoutConverter.ConvertLinearStridedToLinear(
|
data = LayoutConverter.ConvertLinearStridedToLinear(
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
@@ -136,11 +137,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public LinkedListNode<Texture> CacheNode { get; set; }
|
public LinkedListNode<Texture> CacheNode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event to fire when texture data is disposed.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<Texture> Disposed;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Physical memory ranges where the texture data is located.
|
/// Physical memory ranges where the texture data is located.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -720,9 +716,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data = ConvertToHostCompatibleFormat(data);
|
SpanOrArray<byte> result = ConvertToHostCompatibleFormat(data);
|
||||||
|
|
||||||
HostTexture.SetData(data);
|
HostTexture.SetData(result);
|
||||||
|
|
||||||
_hasData = true;
|
_hasData = true;
|
||||||
}
|
}
|
||||||
@@ -731,7 +727,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// Uploads new texture data to the host GPU.
|
/// Uploads new texture data to the host GPU.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">New data</param>
|
/// <param name="data">New data</param>
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
BlacklistScale();
|
BlacklistScale();
|
||||||
|
|
||||||
@@ -750,7 +746,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="data">New data</param>
|
/// <param name="data">New data</param>
|
||||||
/// <param name="layer">Target layer</param>
|
/// <param name="layer">Target layer</param>
|
||||||
/// <param name="level">Target level</param>
|
/// <param name="level">Target level</param>
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
BlacklistScale();
|
BlacklistScale();
|
||||||
|
|
||||||
@@ -786,7 +782,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="level">Mip level to convert</param>
|
/// <param name="level">Mip level to convert</param>
|
||||||
/// <param name="single">True to convert a single slice</param>
|
/// <param name="single">True to convert a single slice</param>
|
||||||
/// <returns>Converted data</returns>
|
/// <returns>Converted data</returns>
|
||||||
public ReadOnlySpan<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
|
public SpanOrArray<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
|
||||||
{
|
{
|
||||||
int width = Info.Width;
|
int width = Info.Width;
|
||||||
int height = Info.Height;
|
int height = Info.Height;
|
||||||
@@ -799,9 +795,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
height = Math.Max(height >> level, 1);
|
height = Math.Max(height >> level, 1);
|
||||||
depth = Math.Max(depth >> level, 1);
|
depth = Math.Max(depth >> level, 1);
|
||||||
|
|
||||||
|
SpanOrArray<byte> result;
|
||||||
|
|
||||||
if (Info.IsLinear)
|
if (Info.IsLinear)
|
||||||
{
|
{
|
||||||
data = LayoutConverter.ConvertLinearStridedToLinear(
|
result = LayoutConverter.ConvertLinearStridedToLinear(
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
Info.FormatInfo.BlockWidth,
|
Info.FormatInfo.BlockWidth,
|
||||||
@@ -813,7 +811,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data = LayoutConverter.ConvertBlockLinearToLinear(
|
result = LayoutConverter.ConvertBlockLinearToLinear(
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
depth,
|
depth,
|
||||||
@@ -836,7 +834,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
|
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
|
||||||
{
|
{
|
||||||
if (!AstcDecoder.TryDecodeToRgba8P(
|
if (!AstcDecoder.TryDecodeToRgba8P(
|
||||||
data.ToArray(),
|
result.ToArray(),
|
||||||
Info.FormatInfo.BlockWidth,
|
Info.FormatInfo.BlockWidth,
|
||||||
Info.FormatInfo.BlockHeight,
|
Info.FormatInfo.BlockHeight,
|
||||||
width,
|
width,
|
||||||
@@ -856,11 +854,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
decoded = BCnEncoder.EncodeBC7(decoded, width, height, depth, levels, layers);
|
decoded = BCnEncoder.EncodeBC7(decoded, width, height, depth, levels, layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
data = decoded;
|
result = decoded;
|
||||||
}
|
}
|
||||||
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
||||||
{
|
{
|
||||||
data = PixelConverter.ConvertR4G4ToR4G4B4A4(data);
|
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
|
||||||
}
|
}
|
||||||
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
||||||
{
|
{
|
||||||
@@ -868,36 +866,36 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
case Format.Bc1RgbaSrgb:
|
case Format.Bc1RgbaSrgb:
|
||||||
case Format.Bc1RgbaUnorm:
|
case Format.Bc1RgbaUnorm:
|
||||||
data = BCnDecoder.DecodeBC1(data, width, height, depth, levels, layers);
|
result = BCnDecoder.DecodeBC1(result, width, height, depth, levels, layers);
|
||||||
break;
|
break;
|
||||||
case Format.Bc2Srgb:
|
case Format.Bc2Srgb:
|
||||||
case Format.Bc2Unorm:
|
case Format.Bc2Unorm:
|
||||||
data = BCnDecoder.DecodeBC2(data, width, height, depth, levels, layers);
|
result = BCnDecoder.DecodeBC2(result, width, height, depth, levels, layers);
|
||||||
break;
|
break;
|
||||||
case Format.Bc3Srgb:
|
case Format.Bc3Srgb:
|
||||||
case Format.Bc3Unorm:
|
case Format.Bc3Unorm:
|
||||||
data = BCnDecoder.DecodeBC3(data, width, height, depth, levels, layers);
|
result = BCnDecoder.DecodeBC3(result, width, height, depth, levels, layers);
|
||||||
break;
|
break;
|
||||||
case Format.Bc4Snorm:
|
case Format.Bc4Snorm:
|
||||||
case Format.Bc4Unorm:
|
case Format.Bc4Unorm:
|
||||||
data = BCnDecoder.DecodeBC4(data, width, height, depth, levels, layers, Format == Format.Bc4Snorm);
|
result = BCnDecoder.DecodeBC4(result, width, height, depth, levels, layers, Format == Format.Bc4Snorm);
|
||||||
break;
|
break;
|
||||||
case Format.Bc5Snorm:
|
case Format.Bc5Snorm:
|
||||||
case Format.Bc5Unorm:
|
case Format.Bc5Unorm:
|
||||||
data = BCnDecoder.DecodeBC5(data, width, height, depth, levels, layers, Format == Format.Bc5Snorm);
|
result = BCnDecoder.DecodeBC5(result, width, height, depth, levels, layers, Format == Format.Bc5Snorm);
|
||||||
break;
|
break;
|
||||||
case Format.Bc6HSfloat:
|
case Format.Bc6HSfloat:
|
||||||
case Format.Bc6HUfloat:
|
case Format.Bc6HUfloat:
|
||||||
data = BCnDecoder.DecodeBC6(data, width, height, depth, levels, layers, Format == Format.Bc6HSfloat);
|
result = BCnDecoder.DecodeBC6(result, width, height, depth, levels, layers, Format == Format.Bc6HSfloat);
|
||||||
break;
|
break;
|
||||||
case Format.Bc7Srgb:
|
case Format.Bc7Srgb:
|
||||||
case Format.Bc7Unorm:
|
case Format.Bc7Unorm:
|
||||||
data = BCnDecoder.DecodeBC7(data, width, height, depth, levels, layers);
|
result = BCnDecoder.DecodeBC7(result, width, height, depth, levels, layers);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1445,7 +1443,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
DisposeTextures();
|
DisposeTextures();
|
||||||
|
|
||||||
HostTexture = hostTexture;
|
HostTexture = hostTexture;
|
||||||
InvalidatedSequence++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1600,6 +1597,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void DisposeTextures()
|
private void DisposeTextures()
|
||||||
{
|
{
|
||||||
|
InvalidatedSequence++;
|
||||||
|
|
||||||
_currentData = null;
|
_currentData = null;
|
||||||
HostTexture.Release();
|
HostTexture.Release();
|
||||||
|
|
||||||
@@ -1634,8 +1633,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
DisposeTextures();
|
DisposeTextures();
|
||||||
|
|
||||||
Disposed?.Invoke(this);
|
|
||||||
|
|
||||||
if (Group.Storage == this)
|
if (Group.Storage == this)
|
||||||
{
|
{
|
||||||
Group.Dispose();
|
Group.Dispose();
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Cpu.Tracking;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Cpu.Tracking;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
@@ -348,9 +349,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
|
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
|
||||||
|
|
||||||
data = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel, true);
|
SpanOrArray<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel, true);
|
||||||
|
|
||||||
Storage.SetData(data, info.BaseLayer, info.BaseLevel);
|
Storage.SetData(result, info.BaseLayer, info.BaseLevel);
|
||||||
|
|
||||||
offsetIndex++;
|
offsetIndex++;
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 3697;
|
private const uint CodeGenVersion = 3759;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@@ -123,7 +123,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
/// <param name="releaseCallback">Texture release callback</param>
|
/// <param name="releaseCallback">Texture release callback</param>
|
||||||
/// <param name="userObj">User defined object passed to the release callback</param>
|
/// <param name="userObj">User defined object passed to the release callback</param>
|
||||||
/// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
|
/// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
|
||||||
public void EnqueueFrameThreadSafe(
|
/// <returns>True if the frame was added to the queue, false otherwise</returns>
|
||||||
|
public bool EnqueueFrameThreadSafe(
|
||||||
ulong pid,
|
ulong pid,
|
||||||
ulong address,
|
ulong address,
|
||||||
int width,
|
int width,
|
||||||
@@ -140,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
{
|
{
|
||||||
if (!_context.PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
|
if (!_context.PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);
|
FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);
|
||||||
@@ -184,6 +185,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
acquireCallback,
|
acquireCallback,
|
||||||
releaseCallback,
|
releaseCallback,
|
||||||
userObj));
|
userObj));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -48,17 +49,19 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
return GetData();
|
return GetData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
Buffer.SetData(_buffer, _bufferOffset, data.Slice(0, Math.Min(data.Length, _bufferSize)));
|
var dataSpan = data.AsSpan();
|
||||||
|
|
||||||
|
Buffer.SetData(_buffer, _bufferOffset, dataSpan.Slice(0, Math.Min(dataSpan.Length, _bufferSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -317,32 +318,36 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
|
var dataSpan = data.AsSpan();
|
||||||
|
|
||||||
if (Format == Format.S8UintD24Unorm)
|
if (Format == Format.S8UintD24Unorm)
|
||||||
{
|
{
|
||||||
data = FormatConverter.ConvertS8D24ToD24S8(data);
|
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte* ptr = data)
|
fixed (byte* ptr = dataSpan)
|
||||||
{
|
{
|
||||||
ReadFrom((IntPtr)ptr, data.Length);
|
ReadFrom((IntPtr)ptr, dataSpan.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
|
var dataSpan = data.AsSpan();
|
||||||
|
|
||||||
if (Format == Format.S8UintD24Unorm)
|
if (Format == Format.S8UintD24Unorm)
|
||||||
{
|
{
|
||||||
data = FormatConverter.ConvertS8D24ToD24S8(data);
|
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte* ptr = data)
|
fixed (byte* ptr = dataSpan)
|
||||||
{
|
{
|
||||||
int width = Math.Max(Info.Width >> level, 1);
|
int width = Math.Max(Info.Width >> level, 1);
|
||||||
int height = Math.Max(Info.Height >> level, 1);
|
int height = Math.Max(Info.Height >> level, 1);
|
||||||
@@ -352,11 +357,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
|
var dataSpan = data.AsSpan();
|
||||||
|
|
||||||
if (Format == Format.S8UintD24Unorm)
|
if (Format == Format.S8UintD24Unorm)
|
||||||
{
|
{
|
||||||
data = FormatConverter.ConvertS8D24ToD24S8(data);
|
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
||||||
@@ -364,7 +371,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte* ptr = data)
|
fixed (byte* ptr = dataSpan)
|
||||||
{
|
{
|
||||||
ReadFrom2D(
|
ReadFrom2D(
|
||||||
(IntPtr)ptr,
|
(IntPtr)ptr,
|
||||||
|
@@ -2,6 +2,7 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
@@ -163,9 +164,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
}
|
}
|
||||||
else if (context.Config.Stage == ShaderStage.TessellationEvaluation)
|
else if (context.Config.Stage == ShaderStage.TessellationEvaluation)
|
||||||
{
|
{
|
||||||
|
bool tessCw = context.Config.GpuAccessor.QueryTessCw();
|
||||||
|
|
||||||
|
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||||
|
{
|
||||||
|
// We invert the front face on Vulkan backend, so we need to do that here aswell.
|
||||||
|
tessCw = !tessCw;
|
||||||
|
}
|
||||||
|
|
||||||
string patchType = context.Config.GpuAccessor.QueryTessPatchType().ToGlsl();
|
string patchType = context.Config.GpuAccessor.QueryTessPatchType().ToGlsl();
|
||||||
string spacing = context.Config.GpuAccessor.QueryTessSpacing().ToGlsl();
|
string spacing = context.Config.GpuAccessor.QueryTessSpacing().ToGlsl();
|
||||||
string windingOrder = context.Config.GpuAccessor.QueryTessCw() ? "cw" : "ccw";
|
string windingOrder = tessCw ? "cw" : "ccw";
|
||||||
|
|
||||||
context.AppendLine($"layout ({patchType}, {spacing}, {windingOrder}) in;");
|
context.AppendLine($"layout ({patchType}, {spacing}, {windingOrder}) in;");
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
@@ -185,14 +194,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.Config.UsedInputAttributesPerPatch != 0)
|
if (context.Config.UsedInputAttributesPerPatch.Count != 0)
|
||||||
{
|
{
|
||||||
DeclareInputAttributesPerPatch(context, context.Config.UsedInputAttributesPerPatch);
|
DeclareInputAttributesPerPatch(context, context.Config.UsedInputAttributesPerPatch);
|
||||||
|
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.Config.UsedOutputAttributesPerPatch != 0)
|
if (context.Config.UsedOutputAttributesPerPatch.Count != 0)
|
||||||
{
|
{
|
||||||
DeclareUsedOutputAttributesPerPatch(context, context.Config.UsedOutputAttributesPerPatch);
|
DeclareUsedOutputAttributesPerPatch(context, context.Config.UsedOutputAttributesPerPatch);
|
||||||
|
|
||||||
@@ -248,7 +257,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements);
|
DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements);
|
||||||
|
|
||||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling))
|
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling) && scaleElements != 0)
|
||||||
{
|
{
|
||||||
AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
|
AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
@@ -509,13 +518,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareInputAttributesPerPatch(CodeGenContext context, int usedAttributes)
|
private static void DeclareInputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||||
{
|
{
|
||||||
while (usedAttributes != 0)
|
foreach (int attr in attrs.OrderBy(x => x))
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
DeclareInputAttributePerPatch(context, attr);
|
||||||
DeclareInputAttributePerPatch(context, index);
|
|
||||||
usedAttributes &= ~(1 << index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,16 +573,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
private static void DeclareInputAttributePerPatch(CodeGenContext context, int attr)
|
private static void DeclareInputAttributePerPatch(CodeGenContext context, int attr)
|
||||||
{
|
{
|
||||||
string layout = string.Empty;
|
int location = context.Config.GetPerPatchAttributeLocation(attr);
|
||||||
|
|
||||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
|
||||||
{
|
|
||||||
layout = $"layout (location = {32 + attr}) ";
|
|
||||||
}
|
|
||||||
|
|
||||||
string name = $"{DefaultNames.PerPatchAttributePrefix}{attr}";
|
string name = $"{DefaultNames.PerPatchAttributePrefix}{attr}";
|
||||||
|
|
||||||
context.AppendLine($"{layout}patch in vec4 {name};");
|
context.AppendLine($"layout (location = {location}) patch in vec4 {name};");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||||||
@@ -624,28 +625,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, int usedAttributes)
|
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||||
{
|
{
|
||||||
while (usedAttributes != 0)
|
foreach (int attr in attrs.OrderBy(x => x))
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
DeclareOutputAttributePerPatch(context, attr);
|
||||||
DeclareOutputAttributePerPatch(context, index);
|
|
||||||
usedAttributes &= ~(1 << index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareOutputAttributePerPatch(CodeGenContext context, int attr)
|
private static void DeclareOutputAttributePerPatch(CodeGenContext context, int attr)
|
||||||
{
|
{
|
||||||
string layout = string.Empty;
|
int location = context.Config.GetPerPatchAttributeLocation(attr);
|
||||||
|
|
||||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
|
||||||
{
|
|
||||||
layout = $"layout (location = {32 + attr}) ";
|
|
||||||
}
|
|
||||||
|
|
||||||
string name = $"{DefaultNames.PerPatchAttributePrefix}{attr}";
|
string name = $"{DefaultNames.PerPatchAttributePrefix}{attr}";
|
||||||
|
|
||||||
context.AppendLine($"{layout}patch out vec4 {name};");
|
context.AppendLine($"layout (location = {location}) patch out vec4 {name};");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
|
private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
|
||||||
|
@@ -28,33 +28,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
private static Dictionary<int, BuiltInAttribute> _builtInAttributes = new Dictionary<int, BuiltInAttribute>()
|
private static Dictionary<int, BuiltInAttribute> _builtInAttributes = new Dictionary<int, BuiltInAttribute>()
|
||||||
{
|
{
|
||||||
{ AttributeConsts.TessLevelOuter0, new BuiltInAttribute("gl_TessLevelOuter[0]", VariableType.F32) },
|
{ AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", VariableType.S32) },
|
||||||
{ AttributeConsts.TessLevelOuter1, new BuiltInAttribute("gl_TessLevelOuter[1]", VariableType.F32) },
|
{ AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", VariableType.F32) },
|
||||||
{ AttributeConsts.TessLevelOuter2, new BuiltInAttribute("gl_TessLevelOuter[2]", VariableType.F32) },
|
{ AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", VariableType.F32) },
|
||||||
{ AttributeConsts.TessLevelOuter3, new BuiltInAttribute("gl_TessLevelOuter[3]", VariableType.F32) },
|
{ AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", VariableType.F32) },
|
||||||
{ AttributeConsts.TessLevelInner0, new BuiltInAttribute("gl_TessLevelInner[0]", VariableType.F32) },
|
{ AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", VariableType.F32) },
|
||||||
{ AttributeConsts.TessLevelInner1, new BuiltInAttribute("gl_TessLevelInner[1]", VariableType.F32) },
|
{ AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", VariableType.F32) },
|
||||||
{ AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", VariableType.S32) },
|
{ AttributeConsts.ClipDistance0, new BuiltInAttribute("gl_ClipDistance[0]", VariableType.F32) },
|
||||||
{ AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", VariableType.F32) },
|
{ AttributeConsts.ClipDistance1, new BuiltInAttribute("gl_ClipDistance[1]", VariableType.F32) },
|
||||||
{ AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", VariableType.F32) },
|
{ AttributeConsts.ClipDistance2, new BuiltInAttribute("gl_ClipDistance[2]", VariableType.F32) },
|
||||||
{ AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", VariableType.F32) },
|
{ AttributeConsts.ClipDistance3, new BuiltInAttribute("gl_ClipDistance[3]", VariableType.F32) },
|
||||||
{ AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", VariableType.F32) },
|
{ AttributeConsts.ClipDistance4, new BuiltInAttribute("gl_ClipDistance[4]", VariableType.F32) },
|
||||||
{ AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", VariableType.F32) },
|
{ AttributeConsts.ClipDistance5, new BuiltInAttribute("gl_ClipDistance[5]", VariableType.F32) },
|
||||||
{ AttributeConsts.ClipDistance0, new BuiltInAttribute("gl_ClipDistance[0]", VariableType.F32) },
|
{ AttributeConsts.ClipDistance6, new BuiltInAttribute("gl_ClipDistance[6]", VariableType.F32) },
|
||||||
{ AttributeConsts.ClipDistance1, new BuiltInAttribute("gl_ClipDistance[1]", VariableType.F32) },
|
{ AttributeConsts.ClipDistance7, new BuiltInAttribute("gl_ClipDistance[7]", VariableType.F32) },
|
||||||
{ AttributeConsts.ClipDistance2, new BuiltInAttribute("gl_ClipDistance[2]", VariableType.F32) },
|
{ AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", VariableType.F32) },
|
||||||
{ AttributeConsts.ClipDistance3, new BuiltInAttribute("gl_ClipDistance[3]", VariableType.F32) },
|
{ AttributeConsts.PointCoordY, new BuiltInAttribute("gl_PointCoord.y", VariableType.F32) },
|
||||||
{ AttributeConsts.ClipDistance4, new BuiltInAttribute("gl_ClipDistance[4]", VariableType.F32) },
|
{ AttributeConsts.TessCoordX, new BuiltInAttribute("gl_TessCoord.x", VariableType.F32) },
|
||||||
{ AttributeConsts.ClipDistance5, new BuiltInAttribute("gl_ClipDistance[5]", VariableType.F32) },
|
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) },
|
||||||
{ AttributeConsts.ClipDistance6, new BuiltInAttribute("gl_ClipDistance[6]", VariableType.F32) },
|
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", VariableType.S32) },
|
||||||
{ AttributeConsts.ClipDistance7, new BuiltInAttribute("gl_ClipDistance[7]", VariableType.F32) },
|
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) },
|
||||||
{ AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", VariableType.F32) },
|
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
|
||||||
{ 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("gl_InstanceID", VariableType.S32) },
|
|
||||||
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) },
|
|
||||||
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
|
|
||||||
|
|
||||||
// Special.
|
// Special.
|
||||||
{ AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) },
|
{ AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) },
|
||||||
@@ -170,7 +164,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
value &= AttributeConsts.Mask & ~3;
|
value &= AttributeConsts.Mask & ~3;
|
||||||
char swzMask = GetSwizzleMask((value >> 2) & 3);
|
char swzMask = GetSwizzleMask((value >> 2) & 3);
|
||||||
|
|
||||||
if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
if (perPatch)
|
||||||
|
{
|
||||||
|
if (value >= AttributeConsts.UserAttributePerPatchBase && value < AttributeConsts.UserAttributePerPatchEnd)
|
||||||
|
{
|
||||||
|
value -= AttributeConsts.UserAttributePerPatchBase;
|
||||||
|
|
||||||
|
return $"{DefaultNames.PerPatchAttributePrefix}{(value >> 4)}.{swzMask}";
|
||||||
|
}
|
||||||
|
else if (value < AttributeConsts.UserAttributePerPatchBase)
|
||||||
|
{
|
||||||
|
return value switch
|
||||||
|
{
|
||||||
|
AttributeConsts.TessLevelOuter0 => "gl_TessLevelOuter[0]",
|
||||||
|
AttributeConsts.TessLevelOuter1 => "gl_TessLevelOuter[1]",
|
||||||
|
AttributeConsts.TessLevelOuter2 => "gl_TessLevelOuter[2]",
|
||||||
|
AttributeConsts.TessLevelOuter3 => "gl_TessLevelOuter[3]",
|
||||||
|
AttributeConsts.TessLevelInner0 => "gl_TessLevelInner[0]",
|
||||||
|
AttributeConsts.TessLevelInner1 => "gl_TessLevelInner[1]",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
||||||
{
|
{
|
||||||
value -= AttributeConsts.UserAttributeBase;
|
value -= AttributeConsts.UserAttributeBase;
|
||||||
|
|
||||||
@@ -180,11 +196,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
bool indexable = config.UsedFeatures.HasFlag(isOutAttr ? FeatureFlags.OaIndexing : FeatureFlags.IaIndexing);
|
bool indexable = config.UsedFeatures.HasFlag(isOutAttr ? FeatureFlags.OaIndexing : FeatureFlags.IaIndexing);
|
||||||
|
|
||||||
if (!indexable && perPatch)
|
|
||||||
{
|
|
||||||
prefix = DefaultNames.PerPatchAttributePrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indexable)
|
if (indexable)
|
||||||
{
|
{
|
||||||
string name = prefix;
|
string name = prefix;
|
||||||
@@ -202,7 +213,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
{
|
{
|
||||||
string name = $"{prefix}{(value >> 4)}_{swzMask}";
|
string name = $"{prefix}{(value >> 4)}_{swzMask}";
|
||||||
|
|
||||||
if (!perPatch && AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||||
{
|
{
|
||||||
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
||||||
}
|
}
|
||||||
@@ -213,7 +224,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
{
|
{
|
||||||
string name = $"{prefix}{(value >> 4)}";
|
string name = $"{prefix}{(value >> 4)}";
|
||||||
|
|
||||||
if (!perPatch && AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||||
{
|
{
|
||||||
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
||||||
}
|
}
|
||||||
@@ -277,7 +288,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
string name = builtInAttr.Name;
|
string name = builtInAttr.Name;
|
||||||
|
|
||||||
if (!perPatch && AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr) && AttributeInfo.IsArrayBuiltIn(value))
|
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr) && AttributeInfo.IsArrayBuiltIn(value))
|
||||||
{
|
{
|
||||||
name = isOutAttr ? $"gl_out[gl_InvocationID].{name}" : $"gl_in[{indexExpr}].{name}";
|
name = isOutAttr ? $"gl_out[gl_InvocationID].{name}" : $"gl_in[{indexExpr}].{name}";
|
||||||
}
|
}
|
||||||
|
@@ -382,17 +382,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
public Instruction GetAttributePerPatchElemPointer(int attr, bool isOutAttr, out AggregateType elemType)
|
public Instruction GetAttributePerPatchElemPointer(int attr, bool isOutAttr, out AggregateType elemType)
|
||||||
{
|
{
|
||||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||||
var attrInfo = AttributeInfo.From(Config, attr, isOutAttr);
|
var attrInfo = AttributeInfo.FromPatch(Config, attr, isOutAttr);
|
||||||
|
|
||||||
int attrOffset = attrInfo.BaseValue;
|
int attrOffset = attrInfo.BaseValue;
|
||||||
Instruction ioVariable;
|
Instruction ioVariable = isOutAttr ? OutputsPerPatch[attrOffset] : InputsPerPatch[attrOffset];
|
||||||
|
|
||||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
|
||||||
|
|
||||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||||
|
|
||||||
ioVariable = isOutAttr ? OutputsPerPatch[attrOffset] : InputsPerPatch[attrOffset];
|
|
||||||
|
|
||||||
if ((attrInfo.Type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
if ((attrInfo.Type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
||||||
{
|
{
|
||||||
return ioVariable;
|
return ioVariable;
|
||||||
@@ -404,7 +400,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
public Instruction GetAttributePerPatch(AggregateType type, int attr, bool isOutAttr)
|
public Instruction GetAttributePerPatch(AggregateType type, int attr, bool isOutAttr)
|
||||||
{
|
{
|
||||||
if (!AttributeInfo.Validate(Config, attr, isOutAttr: false))
|
if (!AttributeInfo.ValidatePerPatch(Config, attr, isOutAttr: false))
|
||||||
{
|
{
|
||||||
return GetConstant(type, new AstOperand(IrOperandType.Constant, 0));
|
return GetConstant(type, new AstOperand(IrOperandType.Constant, 0));
|
||||||
}
|
}
|
||||||
|
@@ -403,7 +403,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
foreach (int attr in inputs)
|
foreach (int attr in inputs)
|
||||||
{
|
{
|
||||||
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: false))
|
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: false, perPatch))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -459,7 +459,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
foreach (int attr in outputs)
|
foreach (int attr in outputs)
|
||||||
{
|
{
|
||||||
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: true))
|
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: true, perPatch))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -519,7 +519,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
? (isOutAttr ? context.OutputsPerPatch : context.InputsPerPatch)
|
? (isOutAttr ? context.OutputsPerPatch : context.InputsPerPatch)
|
||||||
: (isOutAttr ? context.Outputs : context.Inputs);
|
: (isOutAttr ? context.Outputs : context.Inputs);
|
||||||
|
|
||||||
var attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr);
|
var attrInfo = perPatch
|
||||||
|
? AttributeInfo.FromPatch(context.Config, attr, isOutAttr)
|
||||||
|
: AttributeInfo.From(context.Config, attr, isOutAttr);
|
||||||
|
|
||||||
if (dict.ContainsKey(attrInfo.BaseValue))
|
if (dict.ContainsKey(attrInfo.BaseValue))
|
||||||
{
|
{
|
||||||
@@ -544,11 +546,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
var spvType = context.TypePointer(storageClass, attrType);
|
var spvType = context.TypePointer(storageClass, attrType);
|
||||||
var spvVar = context.Variable(spvType, storageClass);
|
var spvVar = context.Variable(spvType, storageClass);
|
||||||
|
|
||||||
if (perPatch)
|
|
||||||
{
|
|
||||||
context.Decorate(spvVar, Decoration.Patch);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (builtInPassthrough)
|
if (builtInPassthrough)
|
||||||
{
|
{
|
||||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||||
@@ -556,6 +553,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
if (attrInfo.IsBuiltin)
|
if (attrInfo.IsBuiltin)
|
||||||
{
|
{
|
||||||
|
if (perPatch)
|
||||||
|
{
|
||||||
|
context.Decorate(spvVar, Decoration.Patch);
|
||||||
|
}
|
||||||
|
|
||||||
context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
|
context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
|
||||||
|
|
||||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
||||||
@@ -569,6 +571,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (perPatch)
|
||||||
|
{
|
||||||
|
context.Decorate(spvVar, Decoration.Patch);
|
||||||
|
|
||||||
|
int location = context.Config.GetPerPatchAttributeLocation((attr - AttributeConsts.UserAttributePerPatchBase) / 16);
|
||||||
|
|
||||||
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||||
|
}
|
||||||
else if (isUserAttr)
|
else if (isUserAttr)
|
||||||
{
|
{
|
||||||
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
||||||
|
@@ -882,7 +882,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
||||||
{
|
{
|
||||||
int attrOffset = (baseAttr.Value & AttributeConsts.Mask) + (operand.Value << 2);
|
int attrOffset = (baseAttr.Value & AttributeConsts.Mask) + (operand.Value << 2);
|
||||||
return new OperationResult(resultType, context.GetAttribute(resultType, attrOffset, isOutAttr: false, index));
|
bool isOutAttr = (baseAttr.Value & AttributeConsts.LoadOutputMask) != 0;
|
||||||
|
return new OperationResult(resultType, context.GetAttribute(resultType, attrOffset, isOutAttr, index));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -191,7 +191,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.Config.GpuAccessor.QueryTessCw())
|
bool tessCw = context.Config.GpuAccessor.QueryTessCw();
|
||||||
|
|
||||||
|
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||||
|
{
|
||||||
|
// We invert the front face on Vulkan backend, so we need to do that here aswell.
|
||||||
|
tessCw = !tessCw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tessCw)
|
||||||
{
|
{
|
||||||
context.AddExecutionMode(spvFunc, ExecutionMode.VertexOrderCw);
|
context.AddExecutionMode(spvFunc, ExecutionMode.VertexOrderCw);
|
||||||
}
|
}
|
||||||
@@ -375,9 +383,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
}
|
}
|
||||||
else if (dest.Type == OperandType.Attribute || dest.Type == OperandType.AttributePerPatch)
|
else if (dest.Type == OperandType.Attribute || dest.Type == OperandType.AttributePerPatch)
|
||||||
{
|
{
|
||||||
if (AttributeInfo.Validate(context.Config, dest.Value, isOutAttr: true))
|
bool perPatch = dest.Type == OperandType.AttributePerPatch;
|
||||||
|
|
||||||
|
if (AttributeInfo.Validate(context.Config, dest.Value, isOutAttr: true, perPatch))
|
||||||
{
|
{
|
||||||
bool perPatch = dest.Type == OperandType.AttributePerPatch;
|
|
||||||
AggregateType elemType;
|
AggregateType elemType;
|
||||||
|
|
||||||
var elemPointer = perPatch
|
var elemPointer = perPatch
|
||||||
|
@@ -306,18 +306,36 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
for (int elemIndex = 0; elemIndex < count; elemIndex++)
|
for (int elemIndex = 0; elemIndex < count; elemIndex++)
|
||||||
{
|
{
|
||||||
int attr = offset + elemIndex * 4;
|
int attr = offset + elemIndex * 4;
|
||||||
if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
|
||||||
|
if (perPatch)
|
||||||
|
{
|
||||||
|
if (attr >= AttributeConsts.UserAttributePerPatchBase && attr < AttributeConsts.UserAttributePerPatchEnd)
|
||||||
|
{
|
||||||
|
int userAttr = attr - AttributeConsts.UserAttributePerPatchBase;
|
||||||
|
int index = userAttr / 16;
|
||||||
|
|
||||||
|
if (isStore)
|
||||||
|
{
|
||||||
|
config.SetOutputUserAttributePerPatch(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
config.SetInputUserAttributePerPatch(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
||||||
{
|
{
|
||||||
int userAttr = attr - AttributeConsts.UserAttributeBase;
|
int userAttr = attr - AttributeConsts.UserAttributeBase;
|
||||||
int index = userAttr / 16;
|
int index = userAttr / 16;
|
||||||
|
|
||||||
if (isStore)
|
if (isStore)
|
||||||
{
|
{
|
||||||
config.SetOutputUserAttribute(index, perPatch);
|
config.SetOutputUserAttribute(index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
config.SetInputUserAttribute(index, (userAttr >> 2) & 3, perPatch);
|
config.SetInputUserAttribute(index, (userAttr >> 2) & 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,6 +377,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
|
|
||||||
if (lastOp.Name == InstName.Brx && block.Successors.Count == (hasNext ? 1 : 0))
|
if (lastOp.Name == InstName.Brx && block.Successors.Count == (hasNext ? 1 : 0))
|
||||||
{
|
{
|
||||||
|
HashSet<ulong> visited = new HashSet<ulong>();
|
||||||
|
|
||||||
InstBrx opBrx = new InstBrx(lastOp.RawOpCode);
|
InstBrx opBrx = new InstBrx(lastOp.RawOpCode);
|
||||||
ulong baseOffset = lastOp.GetAbsoluteAddress();
|
ulong baseOffset = lastOp.GetAbsoluteAddress();
|
||||||
|
|
||||||
@@ -374,9 +394,14 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
for (int i = 0; i < cbOffsetsCount; i++)
|
for (int i = 0; i < cbOffsetsCount; i++)
|
||||||
{
|
{
|
||||||
uint targetOffset = config.ConstantBuffer1Read(cbBaseOffset + i * 4);
|
uint targetOffset = config.ConstantBuffer1Read(cbBaseOffset + i * 4);
|
||||||
Block target = getBlock(baseOffset + targetOffset);
|
ulong targetAddress = baseOffset + targetOffset;
|
||||||
target.Predecessors.Add(block);
|
|
||||||
block.Successors.Add(target);
|
if (visited.Add(targetAddress))
|
||||||
|
{
|
||||||
|
Block target = getBlock(targetAddress);
|
||||||
|
target.Predecessors.Add(block);
|
||||||
|
block.Successors.Add(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -279,16 +279,16 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
Add("1110101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB2, InstEmit.SuatomB2, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
|
Add("1110101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB2, InstEmit.SuatomB2, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc);
|
||||||
Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB, InstEmit.SuatomCasB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.SPd);
|
Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB, InstEmit.SuatomCasB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.Rc | InstProps.SPd);
|
||||||
Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas, InstEmit.SuatomCas, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.SPd);
|
Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas, InstEmit.SuatomCas, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.SPd);
|
||||||
Add("111010110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB, InstEmit.SuldDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
Add("1110101100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB, InstEmit.SuldDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
||||||
Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD, InstEmit.SuldD, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD, InstEmit.SuldD, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
||||||
Add("11101011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB, InstEmit.SuldB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
Add("1110101100000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB, InstEmit.SuldB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.SPd | InstProps.TexB);
|
||||||
Add("11101011000x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld, InstEmit.Suld, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
Add("1110101100001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld, InstEmit.Suld, InstProps.Rd | InstProps.Ra | InstProps.SPd | InstProps.Tex);
|
||||||
Add("111010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB, InstEmit.SuredB, InstProps.Rd | InstProps.Ra | InstProps.Rc);
|
Add("1110101101010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB, InstEmit.SuredB, InstProps.Rd | InstProps.Ra | InstProps.Rc);
|
||||||
Add("1110101101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sured, InstEmit.Sured, InstProps.Rd | InstProps.Ra);
|
Add("1110101101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sured, InstEmit.Sured, InstProps.Rd | InstProps.Ra);
|
||||||
Add("111010110011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustDB, InstEmit.SustDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
Add("1110101100110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustDB, InstEmit.SustDB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
||||||
Add("1110101100111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustD, InstEmit.SustD, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
Add("1110101100111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustD, InstEmit.SustD, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
||||||
Add("11101011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustB, InstEmit.SustB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
Add("1110101100100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustB, InstEmit.SustB, InstProps.Rd | InstProps.Ra | InstProps.Rc | InstProps.TexB);
|
||||||
Add("11101011001x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust, InstEmit.Sust, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
Add("1110101100101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust, InstEmit.Sust, InstProps.Rd | InstProps.Ra | InstProps.Tex);
|
||||||
Add("1111000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sync, InstEmit.Sync, InstProps.Bra);
|
Add("1111000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sync, InstEmit.Sync, InstProps.Bra);
|
||||||
Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex, InstEmit.Tex, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
|
Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex, InstEmit.Tex, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.Tex);
|
||||||
Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB, InstEmit.TexB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
|
Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB, InstEmit.TexB, InstProps.Rd | InstProps.Ra | InstProps.Rb | InstProps.TPd | InstProps.TexB);
|
||||||
|
@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
|
|
||||||
context.FlagAttributeRead(offset);
|
context.FlagAttributeRead(offset);
|
||||||
|
|
||||||
if (op.O)
|
if (op.O && CanLoadOutput(offset))
|
||||||
{
|
{
|
||||||
offset |= AttributeConsts.LoadOutputMask;
|
offset |= AttributeConsts.LoadOutputMask;
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
|
|
||||||
context.FlagAttributeRead(offset);
|
context.FlagAttributeRead(offset);
|
||||||
|
|
||||||
if (op.O)
|
if (op.O && CanLoadOutput(offset))
|
||||||
{
|
{
|
||||||
offset |= AttributeConsts.LoadOutputMask;
|
offset |= AttributeConsts.LoadOutputMask;
|
||||||
}
|
}
|
||||||
@@ -241,6 +241,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool CanLoadOutput(int attr)
|
||||||
|
{
|
||||||
|
return attr != AttributeConsts.TessCoordX && attr != AttributeConsts.TessCoordY;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool TryFixedFuncToUserAttributeIpa(EmitterContext context, int attr, out Operand selectedAttr)
|
private static bool TryFixedFuncToUserAttributeIpa(EmitterContext context, int attr, out Operand selectedAttr)
|
||||||
{
|
{
|
||||||
if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.BackColorDiffuseR)
|
if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.BackColorDiffuseR)
|
||||||
|
@@ -41,24 +41,82 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
|
|
||||||
Operand address = context.IAdd(Register(op.SrcA, RegisterType.Gpr), Const(offset));
|
Operand address = context.IAdd(Register(op.SrcA, RegisterType.Gpr), Const(offset));
|
||||||
|
|
||||||
// Sorting the target addresses in descending order improves the code,
|
var targets = context.CurrBlock.Successors.Skip(startIndex);
|
||||||
// since it will always check the most distant targets first, then the
|
|
||||||
// near ones. This can be easily transformed into if/else statements.
|
|
||||||
var sortedTargets = context.CurrBlock.Successors.Skip(startIndex).OrderByDescending(x => x.Address);
|
|
||||||
|
|
||||||
Block lastTarget = sortedTargets.LastOrDefault();
|
bool allTargetsSinglePred = true;
|
||||||
|
int total = context.CurrBlock.Successors.Count - startIndex;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
foreach (Block possibleTarget in sortedTargets)
|
foreach (var target in targets.OrderBy(x => x.Address))
|
||||||
{
|
{
|
||||||
Operand label = context.GetLabel(possibleTarget.Address);
|
if (++count < total && (target.Predecessors.Count > 1 || target.Address <= context.CurrBlock.Address))
|
||||||
|
|
||||||
if (possibleTarget != lastTarget)
|
|
||||||
{
|
{
|
||||||
context.BranchIfTrue(label, context.ICompareEqual(address, Const((int)possibleTarget.Address)));
|
allTargetsSinglePred = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (allTargetsSinglePred)
|
||||||
|
{
|
||||||
|
// Chain blocks, each target block will check if the BRX target address
|
||||||
|
// matches its own address, if not, it jumps to the next target which will do the same check,
|
||||||
|
// until it reaches the last possible target, which executed unconditionally.
|
||||||
|
// We can only do this if the BRX block is the only predecessor of all target blocks.
|
||||||
|
// Additionally, this is not supported for blocks located before the current block,
|
||||||
|
// since it will be too late to insert a label, but this is something that can be improved
|
||||||
|
// in the future if necessary.
|
||||||
|
|
||||||
|
var sortedTargets = targets.OrderBy(x => x.Address);
|
||||||
|
|
||||||
|
Block currentTarget = null;
|
||||||
|
ulong firstTargetAddress = 0;
|
||||||
|
|
||||||
|
foreach (Block nextTarget in sortedTargets)
|
||||||
{
|
{
|
||||||
context.Branch(label);
|
if (currentTarget != null)
|
||||||
|
{
|
||||||
|
if (currentTarget.Address != nextTarget.Address)
|
||||||
|
{
|
||||||
|
context.SetBrxTarget(currentTarget.Address, address, (int)currentTarget.Address, nextTarget.Address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
firstTargetAddress = nextTarget.Address;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTarget = nextTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Branch(context.GetLabel(firstTargetAddress));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Emit the branches sequentially.
|
||||||
|
// This generates slightly worse code, but should work for all cases.
|
||||||
|
|
||||||
|
var sortedTargets = targets.OrderByDescending(x => x.Address);
|
||||||
|
ulong lastTargetAddress = ulong.MaxValue;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
foreach (Block target in sortedTargets)
|
||||||
|
{
|
||||||
|
Operand label = context.GetLabel(target.Address);
|
||||||
|
|
||||||
|
if (++count < total)
|
||||||
|
{
|
||||||
|
if (target.Address != lastTargetAddress)
|
||||||
|
{
|
||||||
|
context.BranchIfTrue(label, context.ICompareEqual(address, Const((int)target.Address)));
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTargetAddress = target.Address;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Branch(label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
{
|
{
|
||||||
InstSuldB op = context.GetOp<InstSuldB>();
|
InstSuldB op = context.GetOp<InstSuldB>();
|
||||||
|
|
||||||
EmitSuld(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: true);
|
EmitSuld(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, op.SrcC, useComponents: true, false, isBindless: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Suld(EmitterContext context)
|
public static void Suld(EmitterContext context)
|
||||||
|
@@ -97,7 +97,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
|||||||
if (src1.Type == OperandType.Constant && src2.Type == OperandType.Constant)
|
if (src1.Type == OperandType.Constant && src2.Type == OperandType.Constant)
|
||||||
{
|
{
|
||||||
int attrOffset = (src1.Value & AttributeConsts.Mask) + (src2.Value << 2);
|
int attrOffset = (src1.Value & AttributeConsts.Mask) + (src2.Value << 2);
|
||||||
context.Info.Inputs.Add(attrOffset);
|
|
||||||
|
if ((src1.Value & AttributeConsts.LoadOutputMask) != 0)
|
||||||
|
{
|
||||||
|
context.Info.Outputs.Add(attrOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Info.Inputs.Add(attrOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,6 +54,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public const int UserAttributeBase = 0x80;
|
public const int UserAttributeBase = 0x80;
|
||||||
public const int UserAttributeEnd = UserAttributeBase + UserAttributesCount * 16;
|
public const int UserAttributeEnd = UserAttributeBase + UserAttributesCount * 16;
|
||||||
|
|
||||||
|
public const int UserAttributePerPatchBase = 0x18;
|
||||||
|
public const int UserAttributePerPatchEnd = 0x200;
|
||||||
|
|
||||||
public const int LoadOutputMask = 1 << 30;
|
public const int LoadOutputMask = 1 << 30;
|
||||||
public const int Mask = 0x3fffffff;
|
public const int Mask = 0x3fffffff;
|
||||||
|
|
||||||
|
@@ -4,36 +4,30 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{
|
{
|
||||||
struct AttributeInfo
|
struct AttributeInfo
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<int, AttributeInfo> BuiltInAttributes = new Dictionary<int, AttributeInfo>()
|
private static readonly Dictionary<int, AttributeInfo> _builtInAttributes = new Dictionary<int, AttributeInfo>()
|
||||||
{
|
{
|
||||||
{ AttributeConsts.TessLevelOuter0, new AttributeInfo(AttributeConsts.TessLevelOuter0, 0, 4, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.Layer, new AttributeInfo(AttributeConsts.Layer, 0, 1, AggregateType.S32) },
|
||||||
{ AttributeConsts.TessLevelOuter1, new AttributeInfo(AttributeConsts.TessLevelOuter0, 1, 4, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.ViewportIndex, new AttributeInfo(AttributeConsts.ViewportIndex, 0, 1, AggregateType.S32) },
|
||||||
{ AttributeConsts.TessLevelOuter2, new AttributeInfo(AttributeConsts.TessLevelOuter0, 2, 4, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.PointSize, new AttributeInfo(AttributeConsts.PointSize, 0, 1, AggregateType.FP32) },
|
||||||
{ AttributeConsts.TessLevelOuter3, new AttributeInfo(AttributeConsts.TessLevelOuter0, 3, 4, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.PositionX, new AttributeInfo(AttributeConsts.PositionX, 0, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||||
{ AttributeConsts.TessLevelInner0, new AttributeInfo(AttributeConsts.TessLevelInner0, 0, 2, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.PositionY, new AttributeInfo(AttributeConsts.PositionX, 1, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||||
{ AttributeConsts.TessLevelInner1, new AttributeInfo(AttributeConsts.TessLevelInner0, 1, 2, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.PositionZ, new AttributeInfo(AttributeConsts.PositionX, 2, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||||
{ AttributeConsts.Layer, new AttributeInfo(AttributeConsts.Layer, 0, 1, AggregateType.S32) },
|
{ AttributeConsts.PositionW, new AttributeInfo(AttributeConsts.PositionX, 3, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||||
{ AttributeConsts.ViewportIndex, new AttributeInfo(AttributeConsts.ViewportIndex, 0, 1, AggregateType.S32) },
|
{ AttributeConsts.ClipDistance0, new AttributeInfo(AttributeConsts.ClipDistance0, 0, 8, AggregateType.Array | AggregateType.FP32) },
|
||||||
{ AttributeConsts.PointSize, new AttributeInfo(AttributeConsts.PointSize, 0, 1, AggregateType.FP32) },
|
{ AttributeConsts.ClipDistance1, new AttributeInfo(AttributeConsts.ClipDistance0, 1, 8, AggregateType.Array | AggregateType.FP32) },
|
||||||
{ AttributeConsts.PositionX, new AttributeInfo(AttributeConsts.PositionX, 0, 4, AggregateType.Vector | AggregateType.FP32) },
|
{ AttributeConsts.ClipDistance2, new AttributeInfo(AttributeConsts.ClipDistance0, 2, 8, AggregateType.Array | AggregateType.FP32) },
|
||||||
{ AttributeConsts.PositionY, new AttributeInfo(AttributeConsts.PositionX, 1, 4, AggregateType.Vector | AggregateType.FP32) },
|
{ AttributeConsts.ClipDistance3, new AttributeInfo(AttributeConsts.ClipDistance0, 3, 8, AggregateType.Array | AggregateType.FP32) },
|
||||||
{ AttributeConsts.PositionZ, new AttributeInfo(AttributeConsts.PositionX, 2, 4, AggregateType.Vector | AggregateType.FP32) },
|
{ AttributeConsts.ClipDistance4, new AttributeInfo(AttributeConsts.ClipDistance0, 4, 8, AggregateType.Array | AggregateType.FP32) },
|
||||||
{ AttributeConsts.PositionW, new AttributeInfo(AttributeConsts.PositionX, 3, 4, AggregateType.Vector | AggregateType.FP32) },
|
{ AttributeConsts.ClipDistance5, new AttributeInfo(AttributeConsts.ClipDistance0, 5, 8, AggregateType.Array | AggregateType.FP32) },
|
||||||
{ AttributeConsts.ClipDistance0, new AttributeInfo(AttributeConsts.ClipDistance0, 0, 8, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.ClipDistance6, new AttributeInfo(AttributeConsts.ClipDistance0, 6, 8, AggregateType.Array | AggregateType.FP32) },
|
||||||
{ AttributeConsts.ClipDistance1, new AttributeInfo(AttributeConsts.ClipDistance0, 1, 8, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.ClipDistance7, new AttributeInfo(AttributeConsts.ClipDistance0, 7, 8, AggregateType.Array | AggregateType.FP32) },
|
||||||
{ AttributeConsts.ClipDistance2, new AttributeInfo(AttributeConsts.ClipDistance0, 2, 8, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.PointCoordX, new AttributeInfo(AttributeConsts.PointCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||||
{ AttributeConsts.ClipDistance3, new AttributeInfo(AttributeConsts.ClipDistance0, 3, 8, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.PointCoordY, new AttributeInfo(AttributeConsts.PointCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||||
{ AttributeConsts.ClipDistance4, new AttributeInfo(AttributeConsts.ClipDistance0, 4, 8, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.TessCoordX, new AttributeInfo(AttributeConsts.TessCoordX, 0, 3, AggregateType.Vector | AggregateType.FP32) },
|
||||||
{ AttributeConsts.ClipDistance5, new AttributeInfo(AttributeConsts.ClipDistance0, 5, 8, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.TessCoordY, new AttributeInfo(AttributeConsts.TessCoordX, 1, 3, AggregateType.Vector | AggregateType.FP32) },
|
||||||
{ AttributeConsts.ClipDistance6, new AttributeInfo(AttributeConsts.ClipDistance0, 6, 8, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.InstanceId, new AttributeInfo(AttributeConsts.InstanceId, 0, 1, AggregateType.S32) },
|
||||||
{ AttributeConsts.ClipDistance7, new AttributeInfo(AttributeConsts.ClipDistance0, 7, 8, AggregateType.Array | AggregateType.FP32) },
|
{ AttributeConsts.VertexId, new AttributeInfo(AttributeConsts.VertexId, 0, 1, AggregateType.S32) },
|
||||||
{ AttributeConsts.PointCoordX, new AttributeInfo(AttributeConsts.PointCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
|
{ AttributeConsts.FrontFacing, new AttributeInfo(AttributeConsts.FrontFacing, 0, 1, AggregateType.Bool) },
|
||||||
{ AttributeConsts.PointCoordY, new AttributeInfo(AttributeConsts.PointCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
|
|
||||||
{ AttributeConsts.TessCoordX, new AttributeInfo(AttributeConsts.TessCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
|
|
||||||
{ AttributeConsts.TessCoordY, new AttributeInfo(AttributeConsts.TessCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
|
|
||||||
{ AttributeConsts.InstanceId, new AttributeInfo(AttributeConsts.InstanceId, 0, 1, AggregateType.S32) },
|
|
||||||
{ AttributeConsts.VertexId, new AttributeInfo(AttributeConsts.VertexId, 0, 1, AggregateType.S32) },
|
|
||||||
{ AttributeConsts.FrontFacing, new AttributeInfo(AttributeConsts.FrontFacing, 0, 1, AggregateType.Bool) },
|
|
||||||
|
|
||||||
// Special.
|
// Special.
|
||||||
{ AttributeConsts.FragmentOutputDepth, new AttributeInfo(AttributeConsts.FragmentOutputDepth, 0, 1, AggregateType.FP32) },
|
{ AttributeConsts.FragmentOutputDepth, new AttributeInfo(AttributeConsts.FragmentOutputDepth, 0, 1, AggregateType.FP32) },
|
||||||
@@ -55,6 +49,16 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{ AttributeConsts.LtMask, new AttributeInfo(AttributeConsts.LtMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
|
{ AttributeConsts.LtMask, new AttributeInfo(AttributeConsts.LtMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<int, AttributeInfo> _builtInAttributesPerPatch = new Dictionary<int, AttributeInfo>()
|
||||||
|
{
|
||||||
|
{ AttributeConsts.TessLevelOuter0, new AttributeInfo(AttributeConsts.TessLevelOuter0, 0, 4, AggregateType.Array | AggregateType.FP32) },
|
||||||
|
{ AttributeConsts.TessLevelOuter1, new AttributeInfo(AttributeConsts.TessLevelOuter0, 1, 4, AggregateType.Array | AggregateType.FP32) },
|
||||||
|
{ AttributeConsts.TessLevelOuter2, new AttributeInfo(AttributeConsts.TessLevelOuter0, 2, 4, AggregateType.Array | AggregateType.FP32) },
|
||||||
|
{ AttributeConsts.TessLevelOuter3, new AttributeInfo(AttributeConsts.TessLevelOuter0, 3, 4, AggregateType.Array | AggregateType.FP32) },
|
||||||
|
{ AttributeConsts.TessLevelInner0, new AttributeInfo(AttributeConsts.TessLevelInner0, 0, 2, AggregateType.Array | AggregateType.FP32) },
|
||||||
|
{ AttributeConsts.TessLevelInner1, new AttributeInfo(AttributeConsts.TessLevelInner0, 1, 2, AggregateType.Array | AggregateType.FP32) },
|
||||||
|
};
|
||||||
|
|
||||||
public int BaseValue { get; }
|
public int BaseValue { get; }
|
||||||
public int Value { get; }
|
public int Value { get; }
|
||||||
public int Length { get; }
|
public int Length { get; }
|
||||||
@@ -76,6 +80,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
return (Value - BaseValue) / 4;
|
return (Value - BaseValue) / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool Validate(ShaderConfig config, int value, bool isOutAttr, bool perPatch)
|
||||||
|
{
|
||||||
|
return perPatch ? ValidatePerPatch(config, value, isOutAttr) : Validate(config, value, isOutAttr);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
|
public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
|
||||||
{
|
{
|
||||||
if (value == AttributeConsts.ViewportIndex && !config.GpuAccessor.QueryHostSupportsViewportIndex())
|
if (value == AttributeConsts.ViewportIndex && !config.GpuAccessor.QueryHostSupportsViewportIndex())
|
||||||
@@ -86,6 +95,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
return From(config, value, isOutAttr).IsValid;
|
return From(config, value, isOutAttr).IsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool ValidatePerPatch(ShaderConfig config, int value, bool isOutAttr)
|
||||||
|
{
|
||||||
|
return FromPatch(config, value, isOutAttr).IsValid;
|
||||||
|
}
|
||||||
|
|
||||||
public static AttributeInfo From(ShaderConfig config, int value, bool isOutAttr)
|
public static AttributeInfo From(ShaderConfig config, int value, bool isOutAttr)
|
||||||
{
|
{
|
||||||
value &= ~3;
|
value &= ~3;
|
||||||
@@ -115,7 +129,24 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{
|
{
|
||||||
return new AttributeInfo(value, 0, 1, AggregateType.FP32);
|
return new AttributeInfo(value, 0, 1, AggregateType.FP32);
|
||||||
}
|
}
|
||||||
else if (BuiltInAttributes.TryGetValue(value, out AttributeInfo info))
|
else if (_builtInAttributes.TryGetValue(value, out AttributeInfo info))
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AttributeInfo(value, 0, 0, AggregateType.Invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AttributeInfo FromPatch(ShaderConfig config, int value, bool isOutAttr)
|
||||||
|
{
|
||||||
|
value &= ~3;
|
||||||
|
|
||||||
|
if (value >= AttributeConsts.UserAttributePerPatchBase && value < AttributeConsts.UserAttributePerPatchEnd)
|
||||||
|
{
|
||||||
|
int offset = (value - AttributeConsts.UserAttributePerPatchBase) & 0xf;
|
||||||
|
return new AttributeInfo(value - offset, offset >> 2, 4, AggregateType.Vector | AggregateType.FP32, false);
|
||||||
|
}
|
||||||
|
else if (_builtInAttributesPerPatch.TryGetValue(value, out AttributeInfo info))
|
||||||
{
|
{
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
@@ -21,8 +21,33 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
public int OperationsCount => _operations.Count;
|
public int OperationsCount => _operations.Count;
|
||||||
|
|
||||||
|
private struct BrxTarget
|
||||||
|
{
|
||||||
|
public readonly Operand Selector;
|
||||||
|
public readonly int ExpectedValue;
|
||||||
|
public readonly ulong NextTargetAddress;
|
||||||
|
|
||||||
|
public BrxTarget(Operand selector, int expectedValue, ulong nextTargetAddress)
|
||||||
|
{
|
||||||
|
Selector = selector;
|
||||||
|
ExpectedValue = expectedValue;
|
||||||
|
NextTargetAddress = nextTargetAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BlockLabel
|
||||||
|
{
|
||||||
|
public readonly Operand Label;
|
||||||
|
public BrxTarget BrxTarget;
|
||||||
|
|
||||||
|
public BlockLabel(Operand label)
|
||||||
|
{
|
||||||
|
Label = label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly List<Operation> _operations;
|
private readonly List<Operation> _operations;
|
||||||
private readonly Dictionary<ulong, Operand> _labels;
|
private readonly Dictionary<ulong, BlockLabel> _labels;
|
||||||
|
|
||||||
public EmitterContext(DecodedProgram program, ShaderConfig config, bool isNonMain)
|
public EmitterContext(DecodedProgram program, ShaderConfig config, bool isNonMain)
|
||||||
{
|
{
|
||||||
@@ -30,7 +55,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
Config = config;
|
Config = config;
|
||||||
IsNonMain = isNonMain;
|
IsNonMain = isNonMain;
|
||||||
_operations = new List<Operation>();
|
_operations = new List<Operation>();
|
||||||
_labels = new Dictionary<ulong, Operand>();
|
_labels = new Dictionary<ulong, BlockLabel>();
|
||||||
|
|
||||||
EmitStart();
|
EmitStart();
|
||||||
}
|
}
|
||||||
@@ -158,14 +183,40 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
public Operand GetLabel(ulong address)
|
public Operand GetLabel(ulong address)
|
||||||
{
|
{
|
||||||
if (!_labels.TryGetValue(address, out Operand label))
|
return EnsureBlockLabel(address).Label;
|
||||||
{
|
}
|
||||||
label = Label();
|
|
||||||
|
|
||||||
_labels.Add(address, label);
|
public void SetBrxTarget(ulong address, Operand selector, int targetValue, ulong nextTargetAddress)
|
||||||
|
{
|
||||||
|
BlockLabel blockLabel = EnsureBlockLabel(address);
|
||||||
|
Debug.Assert(blockLabel.BrxTarget.Selector == null);
|
||||||
|
blockLabel.BrxTarget = new BrxTarget(selector, targetValue, nextTargetAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnterBlock(ulong address)
|
||||||
|
{
|
||||||
|
BlockLabel blockLabel = EnsureBlockLabel(address);
|
||||||
|
|
||||||
|
MarkLabel(blockLabel.Label);
|
||||||
|
|
||||||
|
BrxTarget brxTarget = blockLabel.BrxTarget;
|
||||||
|
|
||||||
|
if (brxTarget.Selector != null)
|
||||||
|
{
|
||||||
|
this.BranchIfFalse(GetLabel(brxTarget.NextTargetAddress), this.ICompareEqual(brxTarget.Selector, Const(brxTarget.ExpectedValue)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockLabel EnsureBlockLabel(ulong address)
|
||||||
|
{
|
||||||
|
if (!_labels.TryGetValue(address, out BlockLabel blockLabel))
|
||||||
|
{
|
||||||
|
blockLabel = new BlockLabel(Label());
|
||||||
|
|
||||||
|
_labels.Add(address, blockLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return label;
|
return blockLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PrepareForVertexReturn()
|
public void PrepareForVertexReturn()
|
||||||
@@ -261,7 +312,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(passthroughAttributes);
|
int index = BitOperations.TrailingZeroCount(passthroughAttributes);
|
||||||
WriteOutput(AttributeConsts.UserAttributeBase + index * 16, primIndex);
|
WriteOutput(AttributeConsts.UserAttributeBase + index * 16, primIndex);
|
||||||
Config.SetOutputUserAttribute(index, perPatch: false);
|
Config.SetOutputUserAttribute(index);
|
||||||
passthroughAttributes &= ~(1 << index);
|
passthroughAttributes &= ~(1 << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +415,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
|
bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
|
||||||
if (targetEnabled)
|
if (targetEnabled)
|
||||||
{
|
{
|
||||||
Config.SetOutputUserAttribute(rtIndex, perPatch: false);
|
Config.SetOutputUserAttribute(rtIndex);
|
||||||
regIndexBase += 4;
|
regIndexBase += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,16 +50,16 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public bool NextUsesFixedFuncAttributes { get; private set; }
|
public bool NextUsesFixedFuncAttributes { get; private set; }
|
||||||
public int UsedInputAttributes { get; private set; }
|
public int UsedInputAttributes { get; private set; }
|
||||||
public int UsedOutputAttributes { get; private set; }
|
public int UsedOutputAttributes { get; private set; }
|
||||||
public int UsedInputAttributesPerPatch { get; private set; }
|
public HashSet<int> UsedInputAttributesPerPatch { get; }
|
||||||
public int UsedOutputAttributesPerPatch { get; private set; }
|
public HashSet<int> UsedOutputAttributesPerPatch { get; }
|
||||||
|
public HashSet<int> NextUsedInputAttributesPerPatch { get; private set; }
|
||||||
public int PassthroughAttributes { get; private set; }
|
public int PassthroughAttributes { get; private set; }
|
||||||
private int _nextUsedInputAttributes;
|
private int _nextUsedInputAttributes;
|
||||||
private int _thisUsedInputAttributes;
|
private int _thisUsedInputAttributes;
|
||||||
|
private Dictionary<int, int> _perPatchAttributeLocations;
|
||||||
|
|
||||||
public UInt128 NextInputAttributesComponents { get; private set; }
|
public UInt128 NextInputAttributesComponents { get; private set; }
|
||||||
public UInt128 ThisInputAttributesComponents { get; private set; }
|
public UInt128 ThisInputAttributesComponents { get; private set; }
|
||||||
public UInt128 NextInputAttributesPerPatchComponents { get; private set; }
|
|
||||||
public UInt128 ThisInputAttributesPerPatchComponents { get; private set; }
|
|
||||||
|
|
||||||
private int _usedConstantBuffers;
|
private int _usedConstantBuffers;
|
||||||
private int _usedStorageBuffers;
|
private int _usedStorageBuffers;
|
||||||
@@ -119,9 +119,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationOptions options)
|
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationOptions options)
|
||||||
{
|
{
|
||||||
Stage = ShaderStage.Compute;
|
Stage = ShaderStage.Compute;
|
||||||
GpuAccessor = gpuAccessor;
|
GpuAccessor = gpuAccessor;
|
||||||
Options = options;
|
Options = options;
|
||||||
|
|
||||||
|
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||||
|
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||||
|
|
||||||
_usedTextures = new Dictionary<TextureInfo, TextureMeta>();
|
_usedTextures = new Dictionary<TextureInfo, TextureMeta>();
|
||||||
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
|
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
|
||||||
}
|
}
|
||||||
@@ -244,49 +248,71 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
UsedOutputAttributes |= 1 << index;
|
UsedOutputAttributes |= 1 << index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetInputUserAttribute(int index, int component, bool perPatch)
|
public void SetInputUserAttribute(int index, int component)
|
||||||
{
|
{
|
||||||
if (perPatch)
|
int mask = 1 << index;
|
||||||
{
|
|
||||||
UsedInputAttributesPerPatch |= 1 << index;
|
|
||||||
ThisInputAttributesPerPatchComponents |= UInt128.Pow2(index * 4 + component);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int mask = 1 << index;
|
|
||||||
|
|
||||||
UsedInputAttributes |= mask;
|
UsedInputAttributes |= mask;
|
||||||
_thisUsedInputAttributes |= mask;
|
_thisUsedInputAttributes |= mask;
|
||||||
ThisInputAttributesComponents |= UInt128.Pow2(index * 4 + component);
|
ThisInputAttributesComponents |= UInt128.Pow2(index * 4 + component);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetOutputUserAttribute(int index, bool perPatch)
|
public void SetInputUserAttributePerPatch(int index)
|
||||||
{
|
{
|
||||||
if (perPatch)
|
UsedInputAttributesPerPatch.Add(index);
|
||||||
{
|
}
|
||||||
UsedOutputAttributesPerPatch |= 1 << index;
|
|
||||||
}
|
public void SetOutputUserAttribute(int index)
|
||||||
else
|
{
|
||||||
{
|
UsedOutputAttributes |= 1 << index;
|
||||||
UsedOutputAttributes |= 1 << index;
|
}
|
||||||
}
|
|
||||||
|
public void SetOutputUserAttributePerPatch(int index)
|
||||||
|
{
|
||||||
|
UsedOutputAttributesPerPatch.Add(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MergeFromtNextStage(ShaderConfig config)
|
public void MergeFromtNextStage(ShaderConfig config)
|
||||||
{
|
{
|
||||||
NextInputAttributesComponents = config.ThisInputAttributesComponents;
|
NextInputAttributesComponents = config.ThisInputAttributesComponents;
|
||||||
NextInputAttributesPerPatchComponents = config.ThisInputAttributesPerPatchComponents;
|
NextUsedInputAttributesPerPatch = config.UsedInputAttributesPerPatch;
|
||||||
NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr);
|
NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr);
|
||||||
MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch);
|
MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch);
|
||||||
|
|
||||||
|
if (UsedOutputAttributesPerPatch.Count != 0)
|
||||||
|
{
|
||||||
|
// Regular and per-patch input/output locations can't overlap,
|
||||||
|
// so we must assign on our location using unused regular input/output locations.
|
||||||
|
|
||||||
|
Dictionary<int, int> locationsMap = new Dictionary<int, int>();
|
||||||
|
|
||||||
|
int freeMask = ~UsedOutputAttributes;
|
||||||
|
|
||||||
|
foreach (int attr in UsedOutputAttributesPerPatch)
|
||||||
|
{
|
||||||
|
int location = BitOperations.TrailingZeroCount(freeMask);
|
||||||
|
if (location == 32)
|
||||||
|
{
|
||||||
|
config.GpuAccessor.Log($"No enough free locations for patch input/output 0x{attr:X}.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
locationsMap.Add(attr, location);
|
||||||
|
freeMask &= ~(1 << location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both stages must agree on the locations, so use the same "map" for both.
|
||||||
|
_perPatchAttributeLocations = locationsMap;
|
||||||
|
config._perPatchAttributeLocations = locationsMap;
|
||||||
|
}
|
||||||
|
|
||||||
if (config.Stage != ShaderStage.Fragment)
|
if (config.Stage != ShaderStage.Fragment)
|
||||||
{
|
{
|
||||||
LastInVertexPipeline = false;
|
LastInVertexPipeline = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MergeOutputUserAttributes(int mask, int maskPerPatch)
|
public void MergeOutputUserAttributes(int mask, IEnumerable<int> perPatch)
|
||||||
{
|
{
|
||||||
_nextUsedInputAttributes = mask;
|
_nextUsedInputAttributes = mask;
|
||||||
|
|
||||||
@@ -297,10 +323,20 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
UsedOutputAttributes |= mask;
|
UsedOutputAttributes |= mask;
|
||||||
UsedOutputAttributesPerPatch |= maskPerPatch;
|
UsedOutputAttributesPerPatch.UnionWith(perPatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetPerPatchAttributeLocation(int index)
|
||||||
|
{
|
||||||
|
if (_perPatchAttributeLocations == null || !_perPatchAttributeLocations.TryGetValue(index, out int location))
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsUsedOutputAttribute(int attr)
|
public bool IsUsedOutputAttribute(int attr)
|
||||||
{
|
{
|
||||||
// The check for fixed function attributes on the next stage is conservative,
|
// The check for fixed function attributes on the next stage is conservative,
|
||||||
|
@@ -162,7 +162,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{
|
{
|
||||||
context.CurrBlock = block;
|
context.CurrBlock = block;
|
||||||
|
|
||||||
context.MarkLabel(context.GetLabel(block.Address));
|
context.EnterBlock(block.Address);
|
||||||
|
|
||||||
EmitOps(context, block);
|
EmitOps(context, block);
|
||||||
}
|
}
|
||||||
@@ -204,14 +204,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
InitializeOutputComponent(context, AttributeConsts.UserAttributeBase + index * 4, perPatch: false);
|
InitializeOutputComponent(context, AttributeConsts.UserAttributeBase + index * 4, perPatch: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 usedAttributesPerPatch = context.Config.NextInputAttributesPerPatchComponents;
|
if (context.Config.NextUsedInputAttributesPerPatch != null)
|
||||||
while (usedAttributesPerPatch != UInt128.Zero)
|
|
||||||
{
|
{
|
||||||
int index = usedAttributesPerPatch.TrailingZeroCount();
|
foreach (int vecIndex in context.Config.NextUsedInputAttributesPerPatch.OrderBy(x => x))
|
||||||
|
{
|
||||||
InitializeOutputComponent(context, AttributeConsts.UserAttributeBase + index * 4, perPatch: true);
|
InitializeOutput(context, AttributeConsts.UserAttributePerPatchBase + vecIndex * 16, perPatch: true);
|
||||||
|
}
|
||||||
usedAttributesPerPatch &= ~UInt128.Pow2(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.NextUsesFixedFuncAttributes)
|
if (config.NextUsesFixedFuncAttributes)
|
||||||
@@ -236,7 +234,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
for (int c = 0; c < 4; c++)
|
for (int c = 0; c < 4; c++)
|
||||||
{
|
{
|
||||||
int attrOffset = baseAttr + c * 4;
|
int attrOffset = baseAttr + c * 4;
|
||||||
context.Copy(perPatch ? AttributePerPatch(attrOffset) : Attribute(attrOffset), ConstF(c == 3 ? 1f : 0f));
|
InitializeOutputComponent(context, attrOffset, perPatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using Ryujinx.Graphics.Shader.Decoders;
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
using static Ryujinx.Graphics.Shader.Translation.Translator;
|
using static Ryujinx.Graphics.Shader.Translation.Translator;
|
||||||
@@ -137,7 +138,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
if (other != null)
|
if (other != null)
|
||||||
{
|
{
|
||||||
other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, 0);
|
other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, Enumerable.Empty<int>());
|
||||||
|
|
||||||
FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
|
FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
|
||||||
|
|
||||||
|
@@ -93,7 +93,7 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Span<byte> ConvertBlockLinearToLinear(
|
public static byte[] ConvertBlockLinearToLinear(
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
int depth,
|
int depth,
|
||||||
@@ -119,7 +119,7 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
blockHeight,
|
blockHeight,
|
||||||
bytesPerPixel);
|
bytesPerPixel);
|
||||||
|
|
||||||
Span<byte> output = new byte[outSize];
|
byte[] output = new byte[outSize];
|
||||||
|
|
||||||
int outOffs = 0;
|
int outOffs = 0;
|
||||||
|
|
||||||
@@ -246,7 +246,7 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Span<byte> ConvertLinearStridedToLinear(
|
public static byte[] ConvertLinearStridedToLinear(
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
int blockWidth,
|
int blockWidth,
|
||||||
@@ -262,14 +262,15 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);
|
int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);
|
||||||
lineSize = Math.Min(lineSize, outStride);
|
lineSize = Math.Min(lineSize, outStride);
|
||||||
|
|
||||||
Span<byte> output = new byte[h * outStride];
|
byte[] output = new byte[h * outStride];
|
||||||
|
Span<byte> outSpan = output;
|
||||||
|
|
||||||
int outOffs = 0;
|
int outOffs = 0;
|
||||||
int inOffs = 0;
|
int inOffs = 0;
|
||||||
|
|
||||||
for (int y = 0; y < h; y++)
|
for (int y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
data.Slice(inOffs, lineSize).CopyTo(output.Slice(outOffs, lineSize));
|
data.Slice(inOffs, lineSize).CopyTo(outSpan.Slice(outOffs, lineSize));
|
||||||
|
|
||||||
inOffs += stride;
|
inOffs += stride;
|
||||||
outOffs += outStride;
|
outOffs += outStride;
|
||||||
|
@@ -109,12 +109,34 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (isWrite)
|
if (isWrite)
|
||||||
{
|
{
|
||||||
_cachedConvertedBuffers.Clear();
|
SignalWrite(0, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _buffer;
|
return _buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, int offset, int size, bool isWrite = false)
|
||||||
|
{
|
||||||
|
if (isWrite)
|
||||||
|
{
|
||||||
|
SignalWrite(offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SignalWrite(int offset, int size)
|
||||||
|
{
|
||||||
|
if (offset == 0 && size == Size)
|
||||||
|
{
|
||||||
|
_cachedConvertedBuffers.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_cachedConvertedBuffers.ClearRange(offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public BufferHandle GetHandle()
|
public BufferHandle GetHandle()
|
||||||
{
|
{
|
||||||
var handle = _bufferHandle;
|
var handle = _bufferHandle;
|
||||||
@@ -183,6 +205,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
data.Slice(0, dataSize).CopyTo(new Span<byte>((void*)(_map + offset), dataSize));
|
data.Slice(0, dataSize).CopyTo(new Span<byte>((void*)(_map + offset), dataSize));
|
||||||
|
|
||||||
|
SignalWrite(offset, dataSize);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,7 +264,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
endRenderPass?.Invoke();
|
endRenderPass?.Invoke();
|
||||||
|
|
||||||
var dstBuffer = GetBuffer(cbs.CommandBuffer, true).Get(cbs, dstOffset, data.Length).Value;
|
var dstBuffer = GetBuffer(cbs.CommandBuffer, dstOffset, data.Length, true).Get(cbs, dstOffset, data.Length).Value;
|
||||||
|
|
||||||
InsertBufferBarrier(
|
InsertBufferBarrier(
|
||||||
_gd,
|
_gd,
|
||||||
@@ -362,9 +386,26 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_waitable.WaitForFences(_gd.Api, _device, offset, size);
|
_waitable.WaitForFences(_gd.Api, _device, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool BoundToRange(int offset, ref int size)
|
||||||
|
{
|
||||||
|
if (offset >= Size)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = Math.Min(Size - offset, size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
|
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
|
||||||
{
|
{
|
||||||
var key = new I8ToI16CacheKey();
|
if (!BoundToRange(offset, ref size))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = new I8ToI16CacheKey(_gd);
|
||||||
|
|
||||||
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
||||||
{
|
{
|
||||||
@@ -373,6 +414,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_gd.PipelineInternal.EndRenderPass();
|
_gd.PipelineInternal.EndRenderPass();
|
||||||
_gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size);
|
_gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size);
|
||||||
|
|
||||||
|
key.SetBuffer(holder.GetBuffer());
|
||||||
|
|
||||||
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,6 +424,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public Auto<DisposableBuffer> GetAlignedVertexBuffer(CommandBufferScoped cbs, int offset, int size, int stride, int alignment)
|
public Auto<DisposableBuffer> GetAlignedVertexBuffer(CommandBufferScoped cbs, int offset, int size, int stride, int alignment)
|
||||||
{
|
{
|
||||||
|
if (!BoundToRange(offset, ref size))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var key = new AlignedVertexBufferCacheKey(_gd, stride, alignment);
|
var key = new AlignedVertexBufferCacheKey(_gd, stride, alignment);
|
||||||
|
|
||||||
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
||||||
@@ -402,6 +450,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferTopologyConversion(CommandBufferScoped cbs, int offset, int size, IndexBufferPattern pattern, int indexSize)
|
public Auto<DisposableBuffer> GetBufferTopologyConversion(CommandBufferScoped cbs, int offset, int size, IndexBufferPattern pattern, int indexSize)
|
||||||
{
|
{
|
||||||
|
if (!BoundToRange(offset, ref size))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var key = new TopologyConversionCacheKey(_gd, pattern, indexSize);
|
var key = new TopologyConversionCacheKey(_gd, pattern, indexSize);
|
||||||
|
|
||||||
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
||||||
@@ -417,6 +470,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_gd.PipelineInternal.EndRenderPass();
|
_gd.PipelineInternal.EndRenderPass();
|
||||||
_gd.HelperShader.ConvertIndexBuffer(_gd, cbs, this, holder, pattern, indexSize, offset, indexCount);
|
_gd.HelperShader.ConvertIndexBuffer(_gd, cbs, this, holder, pattern, indexSize, offset, indexCount);
|
||||||
|
|
||||||
|
key.SetBuffer(holder.GetBuffer());
|
||||||
|
|
||||||
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,6 +38,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private readonly IdList<BufferHolder> _buffers;
|
private readonly IdList<BufferHolder> _buffers;
|
||||||
|
|
||||||
|
public int BufferCount { get; private set; }
|
||||||
|
|
||||||
public StagingBuffer StagingBuffer { get; }
|
public StagingBuffer StagingBuffer { get; }
|
||||||
|
|
||||||
public BufferManager(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device)
|
public BufferManager(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device)
|
||||||
@@ -56,6 +58,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return BufferHandle.Null;
|
return BufferHandle.Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BufferCount++;
|
||||||
|
|
||||||
ulong handle64 = (uint)_buffers.Add(holder);
|
ulong handle64 = (uint)_buffers.Add(holder);
|
||||||
|
|
||||||
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
||||||
@@ -120,6 +124,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, BufferHandle handle, int offset, int size, bool isWrite)
|
||||||
|
{
|
||||||
|
if (TryGetBuffer(handle, out var holder))
|
||||||
|
{
|
||||||
|
return holder.GetBuffer(commandBuffer, offset, size, isWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size)
|
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size)
|
||||||
{
|
{
|
||||||
if (TryGetBuffer(handle, out var holder))
|
if (TryGetBuffer(handle, out var holder))
|
||||||
|
@@ -24,6 +24,11 @@
|
|||||||
|
|
||||||
public void Add(int cbIndex, int offset, int size)
|
public void Add(int cbIndex, int offset, int size)
|
||||||
{
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Some usages can be out of bounds (vertex buffer on amd), so bound if necessary.
|
// Some usages can be out of bounds (vertex buffer on amd), so bound if necessary.
|
||||||
if (offset + size > _size)
|
if (offset + size > _size)
|
||||||
{
|
{
|
||||||
@@ -39,6 +44,11 @@
|
|||||||
|
|
||||||
public bool OverlapsWith(int cbIndex, int offset, int size)
|
public bool OverlapsWith(int cbIndex, int offset, int size)
|
||||||
{
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int cbBase = cbIndex * _bitsPerCb;
|
int cbBase = cbIndex * _bitsPerCb;
|
||||||
int start = cbBase + offset / _granularity;
|
int start = cbBase + offset / _granularity;
|
||||||
int end = cbBase + (offset + size - 1) / _granularity;
|
int end = cbBase + (offset + size - 1) / _granularity;
|
||||||
|
@@ -25,6 +25,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return other is I8ToI16CacheKey;
|
return other is I8ToI16CacheKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetBuffer(Auto<DisposableBuffer> buffer)
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_gd.PipelineInternal.DirtyIndexBuffer(_buffer);
|
_gd.PipelineInternal.DirtyIndexBuffer(_buffer);
|
||||||
@@ -160,6 +165,44 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClearRange(int offset, int size)
|
||||||
|
{
|
||||||
|
if (_ranges != null && _ranges.Count > 0)
|
||||||
|
{
|
||||||
|
int end = offset + size;
|
||||||
|
|
||||||
|
List<ulong> toRemove = null;
|
||||||
|
|
||||||
|
foreach (KeyValuePair<ulong, List<Entry>> range in _ranges)
|
||||||
|
{
|
||||||
|
(int rOffset, int rSize) = UnpackRange(range.Key);
|
||||||
|
|
||||||
|
int rEnd = rOffset + rSize;
|
||||||
|
|
||||||
|
if (rEnd > offset && rOffset < end)
|
||||||
|
{
|
||||||
|
List<Entry> entries = range.Value;
|
||||||
|
|
||||||
|
foreach (Entry entry in entries)
|
||||||
|
{
|
||||||
|
entry.Key.Dispose();
|
||||||
|
entry.Value.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
(toRemove ??= new List<ulong>()).Add(range.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toRemove != null)
|
||||||
|
{
|
||||||
|
foreach (ulong range in toRemove)
|
||||||
|
{
|
||||||
|
_ranges.Remove(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<Entry> GetEntries(int offset, int size)
|
private List<Entry> GetEntries(int offset, int size)
|
||||||
{
|
{
|
||||||
if (_ranges == null)
|
if (_ranges == null)
|
||||||
@@ -184,6 +227,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return (uint)offset | ((ulong)size << 32);
|
return (uint)offset | ((ulong)size << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static (int offset, int size) UnpackRange(ulong range)
|
||||||
|
{
|
||||||
|
return ((int)range, (int)(range >> 32));
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public int GetPrimitiveCount(int vertexCount)
|
public int GetPrimitiveCount(int vertexCount)
|
||||||
{
|
{
|
||||||
return Math.Max(0, ((vertexCount - BaseIndex) + IndexStride - 1) / IndexStride);
|
return Math.Max(0, (vertexCount - BaseIndex) / IndexStride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetConvertedCount(int indexCount)
|
public int GetConvertedCount(int indexCount)
|
||||||
|
@@ -49,7 +49,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int _);
|
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int bufferSize);
|
||||||
|
|
||||||
|
if (_offset >= bufferSize)
|
||||||
|
{
|
||||||
|
autoBuffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
offset = _offset;
|
offset = _offset;
|
||||||
size = _size;
|
size = _size;
|
||||||
|
@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
protected readonly AutoFlushCounter AutoFlush;
|
protected readonly AutoFlushCounter AutoFlush;
|
||||||
|
|
||||||
private PipelineDynamicState _dynamicState;
|
protected PipelineDynamicState DynamicState;
|
||||||
private PipelineState _newState;
|
private PipelineState _newState;
|
||||||
private bool _stateDirty;
|
private bool _stateDirty;
|
||||||
private GAL.PrimitiveTopology _topology;
|
private GAL.PrimitiveTopology _topology;
|
||||||
@@ -68,6 +68,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private bool _tfEnabled;
|
private bool _tfEnabled;
|
||||||
private bool _tfActive;
|
private bool _tfActive;
|
||||||
|
|
||||||
|
private PipelineColorBlendAttachmentState[] _storedBlend;
|
||||||
|
|
||||||
public ulong DrawCount { get; private set; }
|
public ulong DrawCount { get; private set; }
|
||||||
|
|
||||||
public unsafe PipelineBase(VulkanRenderer gd, Device device)
|
public unsafe PipelineBase(VulkanRenderer gd, Device device)
|
||||||
@@ -93,7 +95,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
using var emptyVb = gd.BufferManager.Create(gd, EmptyVbSize);
|
using var emptyVb = gd.BufferManager.Create(gd, EmptyVbSize);
|
||||||
emptyVb.SetData(0, new byte[EmptyVbSize]);
|
emptyVb.SetData(0, new byte[EmptyVbSize]);
|
||||||
_vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, EmptyVbSize, 0);
|
_vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, 0, EmptyVbSize, 0);
|
||||||
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
||||||
|
|
||||||
ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
|
ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
|
||||||
@@ -104,6 +106,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_newState.Initialize();
|
_newState.Initialize();
|
||||||
_newState.LineWidth = 1f;
|
_newState.LineWidth = 1f;
|
||||||
_newState.SamplesCount = 1;
|
_newState.SamplesCount = 1;
|
||||||
|
|
||||||
|
_storedBlend = new PipelineColorBlendAttachmentState[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
@@ -146,7 +150,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, true).Get(Cbs, offset, size).Value;
|
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, offset, size, true).Get(Cbs, offset, size).Value;
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
Gd,
|
Gd,
|
||||||
@@ -234,8 +238,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
var src = Gd.BufferManager.GetBuffer(CommandBuffer, source, false);
|
var src = Gd.BufferManager.GetBuffer(CommandBuffer, source, srcOffset, size, false);
|
||||||
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, true);
|
var dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, dstOffset, size, true);
|
||||||
|
|
||||||
BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
|
BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
|
||||||
}
|
}
|
||||||
@@ -384,7 +388,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var oldDepthTestEnable = _newState.DepthTestEnable;
|
var oldDepthTestEnable = _newState.DepthTestEnable;
|
||||||
var oldDepthWriteEnable = _newState.DepthWriteEnable;
|
var oldDepthWriteEnable = _newState.DepthWriteEnable;
|
||||||
var oldTopology = _newState.Topology;
|
var oldTopology = _newState.Topology;
|
||||||
var oldViewports = _dynamicState.Viewports;
|
var oldViewports = DynamicState.Viewports;
|
||||||
var oldViewportsCount = _newState.ViewportsCount;
|
var oldViewportsCount = _newState.ViewportsCount;
|
||||||
|
|
||||||
_newState.CullMode = CullModeFlags.CullModeNone;
|
_newState.CullMode = CullModeFlags.CullModeNone;
|
||||||
@@ -407,9 +411,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_newState.DepthWriteEnable = oldDepthWriteEnable;
|
_newState.DepthWriteEnable = oldDepthWriteEnable;
|
||||||
_newState.Topology = oldTopology;
|
_newState.Topology = oldTopology;
|
||||||
|
|
||||||
_dynamicState.Viewports = oldViewports;
|
DynamicState.Viewports = oldViewports;
|
||||||
_dynamicState.ViewportsCount = (int)oldViewportsCount;
|
DynamicState.ViewportsCount = (int)oldViewportsCount;
|
||||||
_dynamicState.SetViewportsDirty();
|
DynamicState.SetViewportsDirty();
|
||||||
|
|
||||||
_newState.ViewportsCount = oldViewportsCount;
|
_newState.ViewportsCount = oldViewportsCount;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
@@ -444,8 +448,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ResumeTransformFeedbackInternal();
|
ResumeTransformFeedbackInternal();
|
||||||
DrawCount++;
|
DrawCount++;
|
||||||
|
|
||||||
var buffer = Gd.BufferManager.GetBuffer(CommandBuffer, indirectBuffer.Handle, true).Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
var buffer = Gd.BufferManager
|
||||||
var countBuffer = Gd.BufferManager.GetBuffer(CommandBuffer, parameterBuffer.Handle, true).Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
.GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, true)
|
||||||
|
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
||||||
|
|
||||||
|
var countBuffer = Gd.BufferManager
|
||||||
|
.GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
|
||||||
|
.Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
||||||
|
|
||||||
Gd.DrawIndirectCountApi.CmdDrawIndirectCount(
|
Gd.DrawIndirectCountApi.CmdDrawIndirectCount(
|
||||||
CommandBuffer,
|
CommandBuffer,
|
||||||
@@ -474,8 +483,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ResumeTransformFeedbackInternal();
|
ResumeTransformFeedbackInternal();
|
||||||
DrawCount++;
|
DrawCount++;
|
||||||
|
|
||||||
var buffer = Gd.BufferManager.GetBuffer(CommandBuffer, indirectBuffer.Handle, true).Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
var buffer = Gd.BufferManager
|
||||||
var countBuffer = Gd.BufferManager.GetBuffer(CommandBuffer, parameterBuffer.Handle, true).Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
.GetBuffer(CommandBuffer, indirectBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
|
||||||
|
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
||||||
|
|
||||||
|
var countBuffer = Gd.BufferManager
|
||||||
|
.GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, true)
|
||||||
|
.Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
||||||
|
|
||||||
Gd.DrawIndirectCountApi.CmdDrawIndexedIndirectCount(
|
Gd.DrawIndirectCountApi.CmdDrawIndexedIndirectCount(
|
||||||
CommandBuffer,
|
CommandBuffer,
|
||||||
@@ -498,13 +512,28 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
|
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
|
||||||
|
|
||||||
vkBlend.BlendEnable = blend.Enable;
|
if (blend.Enable)
|
||||||
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
|
{
|
||||||
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
|
vkBlend.BlendEnable = blend.Enable;
|
||||||
vkBlend.ColorBlendOp = blend.ColorOp.Convert();
|
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
|
||||||
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
|
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
|
||||||
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
|
vkBlend.ColorBlendOp = blend.ColorOp.Convert();
|
||||||
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
|
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
|
||||||
|
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
|
||||||
|
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vkBlend = new PipelineColorBlendAttachmentState(
|
||||||
|
colorWriteMask: vkBlend.ColorWriteMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vkBlend.ColorWriteMask == 0)
|
||||||
|
{
|
||||||
|
_storedBlend[index] = vkBlend;
|
||||||
|
|
||||||
|
vkBlend = new PipelineColorBlendAttachmentState();
|
||||||
|
}
|
||||||
|
|
||||||
_newState.BlendConstantR = blend.BlendConstant.Red;
|
_newState.BlendConstantR = blend.BlendConstant.Red;
|
||||||
_newState.BlendConstantG = blend.BlendConstant.Green;
|
_newState.BlendConstantG = blend.BlendConstant.Green;
|
||||||
@@ -516,7 +545,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
|
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
|
||||||
{
|
{
|
||||||
_dynamicState.SetDepthBias(factor, units, clamp);
|
DynamicState.SetDepthBias(factor, units, clamp);
|
||||||
|
|
||||||
_newState.DepthBiasEnable = enables != 0;
|
_newState.DepthBiasEnable = enables != 0;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
@@ -669,8 +698,25 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
|
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
|
||||||
|
var newMask = (ColorComponentFlags)componentMask[i];
|
||||||
|
|
||||||
vkBlend.ColorWriteMask = (ColorComponentFlags)componentMask[i];
|
// When color write mask is 0, remove all blend state to help the pipeline cache.
|
||||||
|
// Restore it when the mask becomes non-zero.
|
||||||
|
if (vkBlend.ColorWriteMask != newMask)
|
||||||
|
{
|
||||||
|
if (newMask == 0)
|
||||||
|
{
|
||||||
|
_storedBlend[i] = vkBlend;
|
||||||
|
|
||||||
|
vkBlend = new PipelineColorBlendAttachmentState();
|
||||||
|
}
|
||||||
|
else if (vkBlend.ColorWriteMask == 0)
|
||||||
|
{
|
||||||
|
vkBlend = _storedBlend[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vkBlend.ColorWriteMask = newMask;
|
||||||
|
|
||||||
if (componentMask[i] != 0)
|
if (componentMask[i] != 0)
|
||||||
{
|
{
|
||||||
@@ -717,10 +763,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var offset = new Offset2D(region.X, region.Y);
|
var offset = new Offset2D(region.X, region.Y);
|
||||||
var extent = new Extent2D((uint)region.Width, (uint)region.Height);
|
var extent = new Extent2D((uint)region.Width, (uint)region.Height);
|
||||||
|
|
||||||
_dynamicState.SetScissor(i, new Rect2D(offset, extent));
|
DynamicState.SetScissor(i, new Rect2D(offset, extent));
|
||||||
}
|
}
|
||||||
|
|
||||||
_dynamicState.ScissorsCount = count;
|
DynamicState.ScissorsCount = count;
|
||||||
|
|
||||||
_newState.ScissorsCount = (uint)count;
|
_newState.ScissorsCount = (uint)count;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
@@ -728,7 +774,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void SetStencilTest(StencilTestDescriptor stencilTest)
|
public void SetStencilTest(StencilTestDescriptor stencilTest)
|
||||||
{
|
{
|
||||||
_dynamicState.SetStencilMasks(
|
DynamicState.SetStencilMasks(
|
||||||
(uint)stencilTest.BackFuncMask,
|
(uint)stencilTest.BackFuncMask,
|
||||||
(uint)stencilTest.BackMask,
|
(uint)stencilTest.BackMask,
|
||||||
(uint)stencilTest.BackFuncRef,
|
(uint)stencilTest.BackFuncRef,
|
||||||
@@ -777,7 +823,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (range.Handle != BufferHandle.Null)
|
if (range.Handle != BufferHandle.Null)
|
||||||
{
|
{
|
||||||
_transformFeedbackBuffers[i] = new BufferState(Gd.BufferManager.GetBuffer(CommandBuffer, range.Handle, true), range.Offset, range.Size);
|
_transformFeedbackBuffers[i] =
|
||||||
|
new BufferState(Gd.BufferManager.GetBuffer(CommandBuffer, range.Handle, range.Offset, range.Size, true), range.Offset, range.Size);
|
||||||
_transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
|
_transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -939,7 +986,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
var viewport = viewports[i];
|
var viewport = viewports[i];
|
||||||
|
|
||||||
_dynamicState.SetViewport(i, new Silk.NET.Vulkan.Viewport(
|
DynamicState.SetViewport(i, new Silk.NET.Vulkan.Viewport(
|
||||||
viewport.Region.X,
|
viewport.Region.X,
|
||||||
viewport.Region.Y,
|
viewport.Region.Y,
|
||||||
viewport.Region.Width == 0f ? 1f : viewport.Region.Width,
|
viewport.Region.Width == 0f ? 1f : viewport.Region.Width,
|
||||||
@@ -948,7 +995,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Clamp(viewport.DepthFar)));
|
Clamp(viewport.DepthFar)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_dynamicState.ViewportsCount = count;
|
DynamicState.ViewportsCount = count;
|
||||||
|
|
||||||
float disableTransformF = disableTransform ? 1.0f : 0.0f;
|
float disableTransformF = disableTransform ? 1.0f : 0.0f;
|
||||||
if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform)
|
if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform)
|
||||||
@@ -1027,7 +1074,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
||||||
|
|
||||||
_descriptorSetUpdater.SignalCommandBufferChange();
|
_descriptorSetUpdater.SignalCommandBufferChange();
|
||||||
_dynamicState.ForceAllDirty();
|
DynamicState.ForceAllDirty();
|
||||||
_currentPipelineHandle = 0;
|
_currentPipelineHandle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1165,7 +1212,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
|
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
|
||||||
{
|
{
|
||||||
_dynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||||
|
|
||||||
// Commit changes to the support buffer before drawing.
|
// Commit changes to the support buffer before drawing.
|
||||||
SupportBufferUpdater.Commit();
|
SupportBufferUpdater.Commit();
|
||||||
@@ -1196,7 +1243,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState);
|
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState);
|
||||||
|
|
||||||
_vertexBuffersDirty &= ~(1u << i);
|
_vertexBuffersDirty &= ~(1UL << i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -257,15 +257,23 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
var blend = state.BlendDescriptors[i];
|
var blend = state.BlendDescriptors[i];
|
||||||
|
|
||||||
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
if (blend.Enable && state.ColorWriteMask[i] != 0)
|
||||||
blend.Enable,
|
{
|
||||||
blend.ColorSrcFactor.Convert(),
|
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
||||||
blend.ColorDstFactor.Convert(),
|
blend.Enable,
|
||||||
blend.ColorOp.Convert(),
|
blend.ColorSrcFactor.Convert(),
|
||||||
blend.AlphaSrcFactor.Convert(),
|
blend.ColorDstFactor.Convert(),
|
||||||
blend.AlphaDstFactor.Convert(),
|
blend.ColorOp.Convert(),
|
||||||
blend.AlphaOp.Convert(),
|
blend.AlphaSrcFactor.Convert(),
|
||||||
(ColorComponentFlags)state.ColorWriteMask[i]);
|
blend.AlphaDstFactor.Convert(),
|
||||||
|
blend.AlphaOp.Convert(),
|
||||||
|
(ColorComponentFlags)state.ColorWriteMask[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
||||||
|
colorWriteMask: (ColorComponentFlags)state.ColorWriteMask[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxAttachmentIndex = 0;
|
int maxAttachmentIndex = 0;
|
||||||
|
@@ -204,6 +204,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
SignalCommandBufferChange();
|
SignalCommandBufferChange();
|
||||||
|
|
||||||
|
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FlushCommandsImpl()
|
public void FlushCommandsImpl()
|
||||||
|
@@ -64,6 +64,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
};
|
};
|
||||||
|
|
||||||
samplerCreateInfo.PNext = &customBorderColor;
|
samplerCreateInfo.PNext = &customBorderColor;
|
||||||
|
samplerCreateInfo.BorderColor = BorderColor.FloatCustomExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
gd.Api.CreateSampler(device, samplerCreateInfo, null, out var sampler).ThrowOnError();
|
gd.Api.CreateSampler(device, samplerCreateInfo, null, out var sampler).ThrowOnError();
|
||||||
|
@@ -9,17 +9,19 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
class Shader
|
class Shader : IDisposable
|
||||||
{
|
{
|
||||||
// The shaderc.net dependency's Options constructor and dispose are not thread safe.
|
// The shaderc.net dependency's Options constructor and dispose are not thread safe.
|
||||||
// Take this lock when using them.
|
// Take this lock when using them.
|
||||||
private static object _shaderOptionsLock = new object();
|
private static object _shaderOptionsLock = new object();
|
||||||
|
|
||||||
|
private static readonly IntPtr _ptrMainEntryPointName = Marshal.StringToHGlobalAnsi("main");
|
||||||
|
|
||||||
private readonly Vk _api;
|
private readonly Vk _api;
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
private readonly ShaderStageFlags _stage;
|
private readonly ShaderStageFlags _stage;
|
||||||
|
|
||||||
private IntPtr _entryPointName;
|
private bool _disposed;
|
||||||
private ShaderModule _module;
|
private ShaderModule _module;
|
||||||
|
|
||||||
public ShaderStageFlags StageFlags => _stage;
|
public ShaderStageFlags StageFlags => _stage;
|
||||||
@@ -39,7 +41,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
CompileStatus = ProgramLinkStatus.Incomplete;
|
CompileStatus = ProgramLinkStatus.Incomplete;
|
||||||
|
|
||||||
_stage = shaderSource.Stage.Convert();
|
_stage = shaderSource.Stage.Convert();
|
||||||
_entryPointName = Marshal.StringToHGlobalAnsi("main");
|
|
||||||
|
|
||||||
CompileTask = Task.Run(() =>
|
CompileTask = Task.Run(() =>
|
||||||
{
|
{
|
||||||
@@ -145,7 +146,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.PipelineShaderStageCreateInfo,
|
SType = StructureType.PipelineShaderStageCreateInfo,
|
||||||
Stage = _stage,
|
Stage = _stage,
|
||||||
Module = _module,
|
Module = _module,
|
||||||
PName = (byte*)_entryPointName
|
PName = (byte*)_ptrMainEntryPointName
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,11 +157,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public unsafe void Dispose()
|
public unsafe void Dispose()
|
||||||
{
|
{
|
||||||
if (_entryPointName != IntPtr.Zero)
|
if (!_disposed)
|
||||||
{
|
{
|
||||||
_api.DestroyShaderModule(_device, _module, null);
|
_api.DestroyShaderModule(_device, _module, null);
|
||||||
Marshal.FreeHGlobal(_entryPointName);
|
_disposed = true;
|
||||||
_entryPointName = IntPtr.Zero;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -87,7 +87,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private void PushDataImpl(CommandBufferScoped cbs, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
|
private void PushDataImpl(CommandBufferScoped cbs, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
var srcBuffer = _buffer.GetBuffer();
|
var srcBuffer = _buffer.GetBuffer();
|
||||||
var dstBuffer = dst.GetBuffer();
|
var dstBuffer = dst.GetBuffer(cbs.CommandBuffer, dstOffset, data.Length, true);
|
||||||
|
|
||||||
int offset = _freeOffset;
|
int offset = _freeOffset;
|
||||||
int capacity = BufferSize - offset;
|
int capacity = BufferSize - offset;
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -16,6 +17,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private Auto<DisposableBufferView> _bufferView;
|
private Auto<DisposableBufferView> _bufferView;
|
||||||
private Dictionary<GAL.Format, Auto<DisposableBufferView>> _selfManagedViews;
|
private Dictionary<GAL.Format, Auto<DisposableBufferView>> _selfManagedViews;
|
||||||
|
|
||||||
|
private int _bufferCount;
|
||||||
|
|
||||||
public int Width { get; }
|
public int Width { get; }
|
||||||
public int Height { get; }
|
public int Height { get; }
|
||||||
|
|
||||||
@@ -88,17 +91,17 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_bufferView = null;
|
_bufferView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
_gd.SetBufferData(_bufferHandle, _offset, data);
|
_gd.SetBufferData(_bufferHandle, _offset, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
@@ -107,7 +110,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (_bufferHandle == buffer.Handle &&
|
if (_bufferHandle == buffer.Handle &&
|
||||||
_offset == buffer.Offset &&
|
_offset == buffer.Offset &&
|
||||||
_size == buffer.Size)
|
_size == buffer.Size &&
|
||||||
|
_bufferCount == _gd.BufferManager.BufferCount)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -115,6 +119,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_bufferHandle = buffer.Handle;
|
_bufferHandle = buffer.Handle;
|
||||||
_offset = buffer.Offset;
|
_offset = buffer.Offset;
|
||||||
_size = buffer.Size;
|
_size = buffer.Size;
|
||||||
|
_bufferCount = _gd.BufferManager.BufferCount;
|
||||||
|
|
||||||
ReleaseImpl();
|
ReleaseImpl();
|
||||||
}
|
}
|
||||||
|
@@ -480,6 +480,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
if (--_viewsCount == 0)
|
if (--_viewsCount == 0)
|
||||||
{
|
{
|
||||||
_gd.PipelineInternal?.FlushCommandsIfWeightExceeding(_imageAuto, _size);
|
_gd.PipelineInternal?.FlushCommandsIfWeightExceeding(_imageAuto, _size);
|
||||||
|
|
||||||
|
Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -514,10 +515,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
dst.Info,
|
dst.Info,
|
||||||
srcRegion,
|
srcRegion,
|
||||||
dstRegion,
|
dstRegion,
|
||||||
src.FirstLevel,
|
|
||||||
dst.FirstLevel,
|
|
||||||
src.FirstLayer,
|
src.FirstLayer,
|
||||||
dst.FirstLayer,
|
dst.FirstLayer,
|
||||||
|
src.FirstLevel,
|
||||||
|
dst.FirstLevel,
|
||||||
layers,
|
layers,
|
||||||
levels,
|
levels,
|
||||||
linearFilter,
|
linearFilter,
|
||||||
@@ -873,17 +874,17 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return GetDataFromBuffer(result, size, result);
|
return GetDataFromBuffer(result, size, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data)
|
public void SetData(SpanOrArray<byte> data)
|
||||||
{
|
{
|
||||||
SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
|
SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
|
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||||
{
|
{
|
||||||
SetData(data, layer, level, 1, 1, singleSlice: true);
|
SetData(data, layer, level, 1, 1, singleSlice: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
{
|
{
|
||||||
SetData(data, layer, level, 1, 1, singleSlice: true, region);
|
SetData(data, layer, level, 1, 1, singleSlice: true, region);
|
||||||
}
|
}
|
||||||
|
@@ -57,37 +57,48 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
if (gd.NeedsVertexBufferAlignment(AttributeScalarAlignment, out int alignment) && (_stride % alignment) != 0)
|
if (gd.NeedsVertexBufferAlignment(AttributeScalarAlignment, out int alignment) && (_stride % alignment) != 0)
|
||||||
{
|
{
|
||||||
autoBuffer = gd.BufferManager.GetAlignedVertexBuffer(cbs, _handle, _offset, _size, _stride, alignment);
|
autoBuffer = gd.BufferManager.GetAlignedVertexBuffer(cbs, _handle, _offset, _size, _stride, alignment);
|
||||||
int stride = (_stride + (alignment - 1)) & -alignment;
|
|
||||||
|
|
||||||
var buffer = autoBuffer.Get(cbs, _offset, _size).Value;
|
if (autoBuffer != null)
|
||||||
|
{
|
||||||
|
int stride = (_stride + (alignment - 1)) & -alignment;
|
||||||
|
int newSize = (_size / _stride) * stride;
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsExtendedDynamicState)
|
var buffer = autoBuffer.Get(cbs, 0, newSize).Value;
|
||||||
{
|
|
||||||
gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
if (gd.Capabilities.SupportsExtendedDynamicState)
|
||||||
cbs.CommandBuffer,
|
{
|
||||||
binding,
|
gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
||||||
1,
|
cbs.CommandBuffer,
|
||||||
buffer,
|
binding,
|
||||||
0,
|
1,
|
||||||
(ulong)(_size / _stride) * (ulong)stride,
|
buffer,
|
||||||
(ulong)stride);
|
0,
|
||||||
}
|
(ulong)newSize,
|
||||||
else
|
(ulong)stride);
|
||||||
{
|
}
|
||||||
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0);
|
else
|
||||||
|
{
|
||||||
|
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buffer = autoBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffer = autoBuffer;
|
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
|
||||||
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int _);
|
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int size);
|
||||||
|
|
||||||
// The original stride must be reapplied in case it was rewritten.
|
// The original stride must be reapplied in case it was rewritten.
|
||||||
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
|
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
|
||||||
|
|
||||||
|
if (_offset >= size)
|
||||||
|
{
|
||||||
|
autoBuffer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -310,7 +310,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
internal TextureView CreateTextureView(TextureCreateInfo info, float scale)
|
internal TextureView CreateTextureView(TextureCreateInfo info, float scale)
|
||||||
{
|
{
|
||||||
// This should be disposed when all views are destroyed.
|
// This should be disposed when all views are destroyed.
|
||||||
using var storage = CreateTextureStorage(info, scale);
|
var storage = CreateTextureStorage(info, scale);
|
||||||
return storage.CreateView(info, 0, 0);
|
return storage.CreateView(info, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -918,7 +918,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return int.Parse(part.Substring(0, numberLength));
|
return int.Parse(part.AsSpan(0, numberLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ParseNumber(bool isSigned = false)
|
private string ParseNumber(bool isSigned = false)
|
||||||
|
@@ -2540,11 +2540,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
|
|
||||||
for (int attempt = 0; attempt < 8; attempt++)
|
for (int attempt = 0; attempt < 8; attempt++)
|
||||||
{
|
{
|
||||||
address = BitUtils.AlignDown(regionStart + GetRandomValue(0, aslrMaxOffset) * (ulong)alignment, alignment);
|
ulong aslrAddress = BitUtils.AlignDown(regionStart + GetRandomValue(0, aslrMaxOffset) * (ulong)alignment, alignment);
|
||||||
|
ulong aslrEndAddr = aslrAddress + totalNeededSize;
|
||||||
|
|
||||||
ulong endAddr = address + totalNeededSize;
|
KMemoryInfo info = _blockManager.FindBlock(aslrAddress).GetInfo();
|
||||||
|
|
||||||
KMemoryInfo info = _blockManager.FindBlock(address).GetInfo();
|
|
||||||
|
|
||||||
if (info.State != MemoryState.Unmapped)
|
if (info.State != MemoryState.Unmapped)
|
||||||
{
|
{
|
||||||
@@ -2554,11 +2553,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
ulong currBaseAddr = info.Address + reservedPagesCount * PageSize;
|
ulong currBaseAddr = info.Address + reservedPagesCount * PageSize;
|
||||||
ulong currEndAddr = info.Address + info.Size;
|
ulong currEndAddr = info.Address + info.Size;
|
||||||
|
|
||||||
if (address >= regionStart &&
|
if (aslrAddress >= regionStart &&
|
||||||
address >= currBaseAddr &&
|
aslrAddress >= currBaseAddr &&
|
||||||
endAddr - 1 <= regionEndAddr - 1 &&
|
aslrEndAddr - 1 <= regionEndAddr - 1 &&
|
||||||
endAddr - 1 <= currEndAddr - 1)
|
aslrEndAddr - 1 <= currEndAddr - 1)
|
||||||
{
|
{
|
||||||
|
address = aslrAddress;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2603,7 +2603,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
|
|
||||||
ulong totalNeededSize = reservedSize + neededPagesCount * PageSize;
|
ulong totalNeededSize = reservedSize + neededPagesCount * PageSize;
|
||||||
|
|
||||||
ulong regionEndAddr = regionStart + regionPagesCount * PageSize;
|
ulong regionEndAddr = (regionStart + regionPagesCount * PageSize) - 1;
|
||||||
|
|
||||||
KMemoryBlock currBlock = _blockManager.FindBlock(regionStart);
|
KMemoryBlock currBlock = _blockManager.FindBlock(regionStart);
|
||||||
|
|
||||||
|
@@ -22,7 +22,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
// outside of the AccountManager.
|
// outside of the AccountManager.
|
||||||
private readonly HorizonClient _horizonClient;
|
private readonly HorizonClient _horizonClient;
|
||||||
|
|
||||||
private ConcurrentDictionary<string, UserProfile> _profiles;
|
private readonly ConcurrentDictionary<string, UserProfile> _profiles;
|
||||||
|
private UserProfile[] _storedOpenedUsers;
|
||||||
|
|
||||||
public UserProfile LastOpenedUser { get; private set; }
|
public UserProfile LastOpenedUser { get; private set; }
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
_horizonClient = horizonClient;
|
_horizonClient = horizonClient;
|
||||||
|
|
||||||
_profiles = new ConcurrentDictionary<string, UserProfile>();
|
_profiles = new ConcurrentDictionary<string, UserProfile>();
|
||||||
|
_storedOpenedUsers = Array.Empty<UserProfile>();
|
||||||
|
|
||||||
_accountSaveDataManager = new AccountSaveDataManager(_profiles);
|
_accountSaveDataManager = new AccountSaveDataManager(_profiles);
|
||||||
|
|
||||||
@@ -44,9 +46,9 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UserId commandLineUserProfileOverride = default;
|
UserId commandLineUserProfileOverride = default;
|
||||||
if (!string.IsNullOrEmpty(initialProfileName))
|
if (!string.IsNullOrEmpty(initialProfileName))
|
||||||
{
|
{
|
||||||
commandLineUserProfileOverride = _profiles.Values.FirstOrDefault(x => x.Name == initialProfileName)?.UserId ?? default;
|
commandLineUserProfileOverride = _profiles.Values.FirstOrDefault(x => x.Name == initialProfileName)?.UserId ?? default;
|
||||||
if (commandLineUserProfileOverride.IsNull)
|
if (commandLineUserProfileOverride.IsNull)
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The command line specified profile named '{initialProfileName}' was not found");
|
Logger.Warning?.Print(LogClass.Application, $"The command line specified profile named '{initialProfileName}' was not found");
|
||||||
@@ -221,6 +223,16 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
return _profiles.Values.Where(x => x.AccountState == AccountState.Open);
|
return _profiles.Values.Where(x => x.AccountState == AccountState.Open);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal IEnumerable<UserProfile> GetStoredOpenedUsers()
|
||||||
|
{
|
||||||
|
return _storedOpenedUsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void StoreOpenedUsers()
|
||||||
|
{
|
||||||
|
_storedOpenedUsers = _profiles.Values.Where(x => x.AccountState == AccountState.Open).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
internal UserProfile GetFirst()
|
internal UserProfile GetFirst()
|
||||||
{
|
{
|
||||||
return _profiles.First().Value;
|
return _profiles.First().Value;
|
||||||
|
@@ -162,7 +162,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
|
|||||||
|
|
||||||
public ResultCode StoreOpenContext(ServiceCtx context)
|
public ResultCode StoreOpenContext(ServiceCtx context)
|
||||||
{
|
{
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
|
context.Device.System.AccountManager.StoreOpenedUsers();
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@@ -201,6 +201,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
|
||||||
|
{
|
||||||
|
return WriteUserList(context, context.Device.System.AccountManager.GetStoredOpenedUsers());
|
||||||
|
}
|
||||||
|
|
||||||
public ResultCode ListQualifiedUsers(ServiceCtx context)
|
public ResultCode ListQualifiedUsers(ServiceCtx context)
|
||||||
{
|
{
|
||||||
// TODO: Determine how users are "qualified". We assume all users are "qualified" for now.
|
// TODO: Determine how users are "qualified". We assume all users are "qualified" for now.
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
|
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
|
||||||
using Ryujinx.HLE.HOS.Services.Arp;
|
using Ryujinx.HLE.HOS.Services.Arp;
|
||||||
|
|
||||||
@@ -139,20 +138,21 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
return _applicationServiceServer.ClearSaveDataThumbnail(context);
|
return _applicationServiceServer.ClearSaveDataThumbnail(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CommandHipc(130)] // 5.0.0+
|
||||||
|
// LoadOpenContext(nn::account::Uid)
|
||||||
|
public ResultCode LoadOpenContext(ServiceCtx context)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandHipc(60)] // 5.0.0-5.1.0
|
||||||
[CommandHipc(131)] // 6.0.0+
|
[CommandHipc(131)] // 6.0.0+
|
||||||
// ListOpenContextStoredUsers() -> array<nn::account::Uid, 0xa>
|
// ListOpenContextStoredUsers() -> array<nn::account::Uid, 0xa>
|
||||||
public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
|
public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
return _applicationServiceServer.ListOpenContextStoredUsers(context);
|
||||||
ulong outputSize = context.Request.RecvListBuff[0].Size;
|
|
||||||
|
|
||||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
|
|
||||||
|
|
||||||
// TODO: This seems to write stored userids of the OpenContext in the buffer. We needs to determine them.
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(141)] // 6.0.0+
|
[CommandHipc(141)] // 6.0.0+
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user