Merge pull request #1826 from adriadam10/feat/shader-ieee-minmax
feat(shader): follow IEEE_MODE in f32 min, max, min3, max3 and med3
This commit is contained in:
commit
aa258760dc
|
|
@ -289,8 +289,139 @@ constexpr std::uint32_t Expected[128][7] = {
|
|||
{0x00000000u, 0x3f800000u, 0x80000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u},
|
||||
{0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u}
|
||||
};
|
||||
constexpr std::uint32_t ExpectedIeee[128][7] = {
|
||||
{0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x80000000u, 0x00000000u},
|
||||
{0x00000000u, 0x3f800000u, 0xff800000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u},
|
||||
{0xc0400000u, 0x00000000u, 0xc0400000u, 0x3f800000u, 0x00000000u, 0xc0400000u, 0x00000000u},
|
||||
{0x00000000u, 0x7f800000u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0x00000000u, 0x7f800000u},
|
||||
{0xff800000u, 0x00000000u, 0xff800000u, 0x00000000u, 0xff800000u, 0xff800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xc0400000u, 0x00000000u, 0xc0400000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0xffc12345u, 0xffc12345u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x7f800000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u},
|
||||
{0x80000000u, 0x3f800000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x80000000u, 0x3f800000u},
|
||||
{0xc0400000u, 0x80000000u, 0xff800000u, 0x80000000u, 0xc0400000u, 0xc0400000u, 0x80000000u},
|
||||
{0x80000000u, 0x7f800000u, 0x80000000u, 0x7f800000u, 0x3f800000u, 0x80000000u, 0x7f800000u},
|
||||
{0xff800000u, 0x80000000u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xff800000u, 0x80000000u},
|
||||
{0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u},
|
||||
{0x80000000u, 0x80000000u, 0xc0400000u, 0x80000000u, 0xc0400000u, 0x80000000u, 0x80000000u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u},
|
||||
{0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u},
|
||||
{0x80000000u, 0x3f800000u, 0x80000000u, 0x7f800000u, 0x3f800000u, 0x80000000u, 0x3f800000u},
|
||||
{0x3f800000u, 0x3f800000u, 0x80000000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u},
|
||||
{0xc0400000u, 0x3f800000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0xc0400000u, 0x3f800000u},
|
||||
{0x3f800000u, 0x7f800000u, 0xff800000u, 0x7f800000u, 0x3f800000u, 0x3f800000u, 0x7f800000u},
|
||||
{0xff800000u, 0x3f800000u, 0xff800000u, 0x3f800000u, 0x3f800000u, 0xff800000u, 0x3f800000u},
|
||||
{0x3f800000u, 0x3f800000u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0x3f800000u, 0x3f800000u},
|
||||
{0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0xc0400000u, 0xc0400000u, 0xc0400000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0x00000000u, 0x00000000u, 0x00000000u, 0xffc12345u, 0xffc12345u},
|
||||
{0xc0400000u, 0x00000000u, 0xc0400000u, 0x00000000u, 0x00000000u, 0xc0400000u, 0x00000000u},
|
||||
{0xc0400000u, 0x80000000u, 0xc0400000u, 0x80000000u, 0xc0400000u, 0xc0400000u, 0x80000000u},
|
||||
{0xc0400000u, 0x3f800000u, 0xc0400000u, 0x7f800000u, 0x3f800000u, 0xc0400000u, 0x3f800000u},
|
||||
{0xc0400000u, 0xc0400000u, 0xc0400000u, 0x80000000u, 0xc0400000u, 0xc0400000u, 0xc0400000u},
|
||||
{0xc0400000u, 0x7f800000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0xc0400000u, 0x7f800000u},
|
||||
{0xff800000u, 0xc0400000u, 0xff800000u, 0xc0400000u, 0xff800000u, 0xff800000u, 0xc0400000u},
|
||||
{0xc0400000u, 0xc0400000u, 0xc0400000u, 0x3f800000u, 0xc0400000u, 0xc0400000u, 0xc0400000u},
|
||||
{0xc0400000u, 0xc0400000u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xc0400000u, 0xc0400000u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0xc0400000u, 0xc0400000u, 0xc0400000u, 0xffc12345u, 0xffc12345u},
|
||||
{0x00000000u, 0x7f800000u, 0xc0400000u, 0x7f800000u, 0x00000000u, 0x00000000u, 0x7f800000u},
|
||||
{0x80000000u, 0x7f800000u, 0x80000000u, 0x7f800000u, 0x00000000u, 0x80000000u, 0x7f800000u},
|
||||
{0x3f800000u, 0x7f800000u, 0x3f800000u, 0x7f800000u, 0x3f800000u, 0x3f800000u, 0x7f800000u},
|
||||
{0xc0400000u, 0x7f800000u, 0xc0400000u, 0x7f800000u, 0x7f800000u, 0xc0400000u, 0x7f800000u},
|
||||
{0x7f800000u, 0x7f800000u, 0x80000000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u},
|
||||
{0xff800000u, 0x7f800000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0xff800000u, 0x7f800000u},
|
||||
{0x7f800000u, 0x7f800000u, 0xff800000u, 0x7f800000u, 0xff800000u, 0x7f800000u, 0x7f800000u},
|
||||
{0x7f800000u, 0x7f800000u, 0x3f800000u, 0x7f800000u, 0x3f800000u, 0x7f800000u, 0x7f800000u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u},
|
||||
{0xff800000u, 0x00000000u, 0xff800000u, 0x00000000u, 0xff800000u, 0xff800000u, 0x00000000u},
|
||||
{0xff800000u, 0x80000000u, 0xff800000u, 0x80000000u, 0xc0400000u, 0xff800000u, 0x80000000u},
|
||||
{0xff800000u, 0x3f800000u, 0xff800000u, 0x3f800000u, 0x00000000u, 0xff800000u, 0x3f800000u},
|
||||
{0xff800000u, 0xc0400000u, 0xff800000u, 0xc0400000u, 0xff800000u, 0xff800000u, 0xc0400000u},
|
||||
{0xff800000u, 0x7f800000u, 0xff800000u, 0x7f800000u, 0x7f800000u, 0xff800000u, 0x7f800000u},
|
||||
{0xff800000u, 0xff800000u, 0xff800000u, 0x80000000u, 0xff800000u, 0xff800000u, 0xff800000u},
|
||||
{0xff800000u, 0xff800000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0xff800000u, 0xff800000u},
|
||||
{0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u},
|
||||
{0x00000000u, 0x00000000u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0x00000000u, 0x00000000u},
|
||||
{0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u},
|
||||
{0x3f800000u, 0x3f800000u, 0xc0400000u, 0x3f800000u, 0xc0400000u, 0x3f800000u, 0x3f800000u},
|
||||
{0xc0400000u, 0xc0400000u, 0xc0400000u, 0x00000000u, 0xc0400000u, 0xc0400000u, 0xc0400000u},
|
||||
{0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u},
|
||||
{0xff800000u, 0xff800000u, 0xff800000u, 0x7f800000u, 0xff800000u, 0xff800000u, 0xff800000u},
|
||||
{0x7fc12345u, 0x7fc12345u, 0x80000000u, 0x80000000u, 0x80000000u, 0x7fc12345u, 0x7fc12345u},
|
||||
{0x7fc12345u, 0x7fc12345u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc12345u, 0x7fc12345u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0xff800000u, 0xff800000u, 0xff800000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0xffc12345u, 0xffc12345u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x80000000u, 0x80000000u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0x80000000u, 0x80000000u},
|
||||
{0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u},
|
||||
{0xc0400000u, 0xc0400000u, 0xc0400000u, 0xc0400000u, 0xc0400000u, 0xc0400000u, 0xc0400000u},
|
||||
{0x7f800000u, 0x7f800000u, 0x00000000u, 0x7f800000u, 0x00000000u, 0x7f800000u, 0x7f800000u},
|
||||
{0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u},
|
||||
{0xffd54321u, 0xffd54321u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0xffd54321u, 0xffd54321u},
|
||||
{0xffd54321u, 0xffd54321u, 0x80000000u, 0x80000000u, 0x80000000u, 0xffd54321u, 0xffd54321u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0xff800000u, 0xff800000u, 0xff800000u, 0xffc12345u, 0xffc12345u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0xff800000u, 0xff800000u, 0xff800000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0xc0400000u, 0xc0400000u, 0xc0400000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x80000000u, 0x80000000u, 0x80000000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0xffc12345u, 0xffc12345u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0xff800000u, 0xff800000u, 0xff800000u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0xc0400000u, 0xc0400000u, 0xc0400000u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0x00000000u, 0x00000000u, 0x00000000u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0xffc12345u, 0xffc12345u},
|
||||
{0xffc12345u, 0xffc12345u, 0x80000000u, 0x80000000u, 0x80000000u, 0xffc12345u, 0xffc12345u},
|
||||
{0x3f800000u, 0x40200000u, 0x00000000u, 0x40200000u, 0x3f800000u, 0x3f800000u, 0x40200000u},
|
||||
{0x00800000u, 0x3f800000u, 0x00800000u, 0x3f800000u, 0x3f800000u, 0x00800000u, 0x3f800000u},
|
||||
{0xc0400000u, 0xbf800000u, 0xc0400000u, 0x00000000u, 0xbf800000u, 0xc0400000u, 0xbf800000u},
|
||||
{0xc0400000u, 0xbf800000u, 0xc0400000u, 0x3f800000u, 0xbf800000u, 0xc0400000u, 0xbf800000u},
|
||||
{0x7fc00000u, 0x7fc00000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x7fc00000u, 0x7fc00000u},
|
||||
{0xffc00000u, 0xffc00000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xffc00000u, 0xffc00000u},
|
||||
{0x7fc00001u, 0x7fc00001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x7fc00001u, 0x7fc00001u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xbf800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x7f800000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xff800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00001u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0x00000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x3f800000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0xbf800000u, 0x00000000u, 0x80000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x7f800000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0xff800000u, 0x00000000u, 0x80000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x80000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0xffc12345u, 0xffc12345u, 0xffc12345u, 0x80000000u, 0x00000000u},
|
||||
{0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u},
|
||||
{0x00000000u, 0x3f800000u, 0x80000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u},
|
||||
{0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u},
|
||||
};
|
||||
constexpr std::uint32_t Chunks = 4;
|
||||
std::uint32_t Chunk = 0;
|
||||
bool Ieee = false;
|
||||
constexpr const char* Names[7] = {
|
||||
"v_min_f32 v10, v4, v5",
|
||||
"v_max_f32 v11, v4, v5",
|
||||
|
|
@ -317,7 +448,7 @@ std::string Hex(std::uint32_t value) {
|
|||
}
|
||||
|
||||
void Expect(std::uint32_t tid, std::uint32_t actual, std::uint32_t expected, const char* name) {
|
||||
Require(actual == expected, std::string("f32 min max nan: row ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected));
|
||||
Require(actual == expected, std::string(Ieee ? "f32 min max nan, IEEE mode: row " : "f32 min max nan: row ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected));
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device) {
|
||||
|
|
@ -338,6 +469,7 @@ void Run(AgcDriver::VulkanDevice& device) {
|
|||
{0, 0, 0, 128}
|
||||
};
|
||||
request.useCache = false;
|
||||
if (Ieee) request.context.floatMode = ShaderRecompiler::ShaderFloatMode{0xf0u, true, true, false};
|
||||
const auto result = ShaderRecompiler::Recompile(request);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
|
|
@ -348,7 +480,7 @@ void Check() {
|
|||
const std::uint32_t* in = &Input[tid * Inputs];
|
||||
const std::uint32_t* out = &Output[tid * Results];
|
||||
for (std::uint32_t i = 0; i < 7; ++i) {
|
||||
Expect(Chunk * Threads + tid, out[i], Expected[Chunk * Threads + tid][i], Names[i]);
|
||||
Expect(Chunk * Threads + tid, out[i], (Ieee ? ExpectedIeee : Expected)[Chunk * Threads + tid][i], Names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -359,9 +491,12 @@ int main() {
|
|||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
for (Chunk = 0; Chunk < Chunks; ++Chunk) {
|
||||
Run(*device);
|
||||
Check();
|
||||
for (const bool ieee : {false, true}) {
|
||||
Ieee = ieee;
|
||||
for (Chunk = 0; Chunk < Chunks; ++Chunk) {
|
||||
Run(*device);
|
||||
Check();
|
||||
}
|
||||
}
|
||||
std::puts("f32 min max nan tests passed");
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ IrProgram PrepareResourceProgram(const RecompileRequest& request) {
|
|||
translateOptions.userDataCount = static_cast<std::uint32_t>(request.context.userData.size());
|
||||
translateOptions.scratchDwords = request.context.compute.has_value() ? request.context.compute->scratchDwords : 0u;
|
||||
translateOptions.fragmentShaderBarycentricEnabled = request.target.fragmentShaderBarycentricEnabled;
|
||||
translateOptions.floatMode = request.context.floatMode;
|
||||
translateOptions.inputInfo = inputInfo;
|
||||
|
||||
constexpr InstructionTranslator translator;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "Optimization/ShaderStageInputInfo.hpp"
|
||||
#include "Translation/EmbeddedVertexFetch.hpp"
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace ShaderRecompiler {
|
||||
|
||||
|
|
@ -31,6 +32,7 @@ struct TranslateOptions {
|
|||
std::uint32_t scratchDwords = 0;
|
||||
std::uint64_t shaderHash = 0;
|
||||
bool fragmentShaderBarycentricEnabled = false;
|
||||
std::optional<ShaderFloatMode> floatMode;
|
||||
ShaderStageInputInfo inputInfo;
|
||||
const EmbeddedFetchPlan* embeddedFetch = nullptr;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public:
|
|||
void TranslateEmbeddedFetch(const RdnaInstruction& instruction, std::uint32_t attribute, std::uint32_t components);
|
||||
void TranslateInstruction(const RdnaInstruction& instruction);
|
||||
void SetPixelInput(const ShaderPixelInputInfo* info, bool barycentricEnabled) { pixelInput = info; fragmentShaderBarycentricEnabled = barycentricEnabled; }
|
||||
void SetFloatMode(const std::optional<ShaderFloatMode>& mode) { floatMode = mode; ieeeMode = mode.has_value() && mode->ieeeMode; }
|
||||
void AddBranchCondition(const BasicBlock& source, BlockInfo& info);
|
||||
void TranslateCodeTableLoad(const RdnaInstruction& instruction, const ControlFlowGraph::CodeTableLoad& table);
|
||||
|
||||
|
|
@ -168,6 +169,7 @@ private:
|
|||
bool floatUnary(const RdnaInstruction& inst, IrOpcode opcode);
|
||||
bool floatBinary(const RdnaInstruction& inst, IrOpcode opcode, bool reverse);
|
||||
bool floatTernary(const RdnaInstruction& inst, IrOpcode opcode, bool accumulator, bool mix);
|
||||
bool ieeeMinMaxF32(const RdnaInstruction& inst, IrOpcode opcode);
|
||||
bool vDivScaleF32(const RdnaInstruction& inst);
|
||||
bool vDivFmasF32(const RdnaInstruction& inst);
|
||||
bool vDivFixupF32(const RdnaInstruction& inst);
|
||||
|
|
@ -305,6 +307,8 @@ private:
|
|||
IrProgram& program;
|
||||
const ShaderPixelInputInfo* pixelInput = nullptr;
|
||||
bool fragmentShaderBarycentricEnabled = false;
|
||||
std::optional<ShaderFloatMode> floatMode;
|
||||
bool ieeeMode = false;
|
||||
IrBuilder ir;
|
||||
IrBlock& block;
|
||||
IrU1 instructionBranchCondition;
|
||||
|
|
|
|||
|
|
@ -490,6 +490,38 @@ bool TranslationContext::floatTernary(const RdnaInstruction& inst, IrOpcode opco
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TranslationContext::ieeeMinMaxF32(const RdnaInstruction& inst, IrOpcode opcode) {
|
||||
if (inst.destination.omod != 0u) throw std::runtime_error("IEEE-mode f32 min/max/med3 with an output modifier is not implemented");
|
||||
const bool ternary = opcode == IrOpcode::FPMinTri32 || opcode == IrOpcode::FPMaxTri32 || opcode == IrOpcode::FPMedTri32;
|
||||
std::array<IrValue*, 3> args{};
|
||||
for (std::uint32_t index = 0u; index < (ternary ? 3u : 2u); ++index) args[index] = readOperand(sourceAt(inst, index), IrType::F32);
|
||||
const auto signaling = [&](IrValue* value) {
|
||||
IrValue& bits = ir.BitCastU32(*value);
|
||||
return &ir.LogicalAnd(ir.IEqual(ir.BitwiseAnd(bits, ir.Constant(0x7fc00000u)), ir.Constant(0x7f800000u)), ir.INotEqual(ir.BitwiseAnd(bits, ir.Constant(0x003fffffu)), ir.Constant(0u)));
|
||||
};
|
||||
const auto quiet = [&](IrValue* value) { return &ir.BitCastF32(ir.BitwiseOr(ir.BitCastU32(*value), ir.Constant(0x00400000u))); };
|
||||
const auto pair = [&](IrOpcode pairOpcode, IrValue* lhs, IrValue* rhs) {
|
||||
IrValue& plain = ir.Emit(pairOpcode, IrType::F32, {lhs, rhs});
|
||||
IrValue& rhsChecked = ir.Emit(IrOpcode::SelectF32, IrType::F32, {signaling(rhs), quiet(rhs), &plain});
|
||||
return &ir.Emit(IrOpcode::SelectF32, IrType::F32, {signaling(lhs), quiet(lhs), &rhsChecked});
|
||||
};
|
||||
IrValue* result = nullptr;
|
||||
if (opcode == IrOpcode::FPMin32 || opcode == IrOpcode::FPMax32) {
|
||||
result = pair(opcode, args[0], args[1]);
|
||||
} else if (opcode == IrOpcode::FPMinTri32 || opcode == IrOpcode::FPMaxTri32) {
|
||||
const auto pairOpcode = opcode == IrOpcode::FPMinTri32 ? IrOpcode::FPMin32 : IrOpcode::FPMax32;
|
||||
result = pair(pairOpcode, pair(pairOpcode, args[0], args[1]), args[2]);
|
||||
} else {
|
||||
const auto isNan = [&](IrValue* value) { return &ir.Emit(IrOpcode::FPIsNan32, IrType::U1, {value}); };
|
||||
IrValue& anyNan = ir.LogicalOr(ir.LogicalOr(*isNan(args[0]), *isNan(args[1])), *isNan(args[2]));
|
||||
IrValue* minimum = pair(IrOpcode::FPMin32, pair(IrOpcode::FPMin32, args[0], args[1]), args[2]);
|
||||
IrValue& median = ir.Emit(IrOpcode::FPMedTri32, IrType::F32, {args[0], args[1], args[2]});
|
||||
result = &ir.Emit(IrOpcode::SelectF32, IrType::F32, {&anyNan, minimum, &median});
|
||||
}
|
||||
writeOperand(inst.destination, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TranslationContext::vFmaLegacyF32(const RdnaInstruction& inst) {
|
||||
IrValue* lhs = readOperand(sourceAt(inst, 0u), IrType::F32);
|
||||
IrValue* rhs = readOperand(sourceAt(inst, 1u), IrType::F32);
|
||||
|
|
|
|||
|
|
@ -433,6 +433,7 @@ IrProgram InstructionTranslator::Translate(const RdnaProgram& decoded, const Con
|
|||
const auto typedIndex = blockIndices.at(cfgBlock.id);
|
||||
TranslationContext context(program, *blocks[typedIndex], vectorLimit);
|
||||
context.SetPixelInput(options.inputInfo.pixel, options.fragmentShaderBarycentricEnabled);
|
||||
context.SetFloatMode(options.floatMode);
|
||||
for (std::uint32_t index = cfgBlock.instructionBegin; index < cfgBlock.instructionEnd; index++) {
|
||||
const auto& instruction = decoded.instructions[index];
|
||||
if (isCodeTableLoad(cfg, instruction.programCounter)) {
|
||||
|
|
|
|||
|
|
@ -933,9 +933,9 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
|
|||
case RdnaOpcode::VMulF32:
|
||||
return floatBinary(inst, IrOpcode::FPMul32, false);
|
||||
case RdnaOpcode::VMinF32:
|
||||
return floatBinary(inst, IrOpcode::FPMin32, false);
|
||||
return ieeeMode ? ieeeMinMaxF32(inst, IrOpcode::FPMin32) : floatBinary(inst, IrOpcode::FPMin32, false);
|
||||
case RdnaOpcode::VMaxF32:
|
||||
return floatBinary(inst, IrOpcode::FPMax32, false);
|
||||
return ieeeMode ? ieeeMinMaxF32(inst, IrOpcode::FPMax32) : floatBinary(inst, IrOpcode::FPMax32, false);
|
||||
case RdnaOpcode::VDivScaleF32:
|
||||
return vDivScaleF32(inst);
|
||||
case RdnaOpcode::VDivFmasF32:
|
||||
|
|
@ -960,11 +960,11 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
|
|||
case RdnaOpcode::VMadLegacyF32:
|
||||
return vFmaLegacyF32(inst);
|
||||
case RdnaOpcode::VMin3F32:
|
||||
return floatTernary(inst, IrOpcode::FPMinTri32, false, false);
|
||||
return ieeeMode ? ieeeMinMaxF32(inst, IrOpcode::FPMinTri32) : floatTernary(inst, IrOpcode::FPMinTri32, false, false);
|
||||
case RdnaOpcode::VMax3F32:
|
||||
return floatTernary(inst, IrOpcode::FPMaxTri32, false, false);
|
||||
return ieeeMode ? ieeeMinMaxF32(inst, IrOpcode::FPMaxTri32) : floatTernary(inst, IrOpcode::FPMaxTri32, false, false);
|
||||
case RdnaOpcode::VMed3F32:
|
||||
return floatTernary(inst, IrOpcode::FPMedTri32, false, false);
|
||||
return ieeeMode ? ieeeMinMaxF32(inst, IrOpcode::FPMedTri32) : floatTernary(inst, IrOpcode::FPMedTri32, false, false);
|
||||
case RdnaOpcode::VDot2cF32F16:
|
||||
return vDot2cF32F16(inst);
|
||||
case RdnaOpcode::VDot2F32F16:
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- A [COND_EXEC range](../../core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/Submission.cpp) must hold whole packets and end inside its command buffer. A chained INDIRECT_BUFFER or a REWIND inside a range throws, as what the CP does with the skipped dwords then is unknown.
|
||||
- A [COND_INDIRECT_BUFFER](../../core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/Submission.cpp) (`sceAgcCbBranch`) runs only with the always-pass compare function; a comparison or a predicated packet throws. Modes 1 and 2 run the first buffer, assumed to be the if-then and if-then-else modes of AMD's PM4 packet. [sceAgcCbBranch](../../core/libs/prx/libSceAgc/Cb/src/Branch.cpp) does not check the compare address of an always-pass branch or the address of an empty buffer, as PPSA14632 passes an uninitialised compare address and a null else buffer of 0 dwords.
|
||||
- [SET_*_REG_INDIRECT](../../core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/Submission.cpp) (libSceAgcDriver) reads its register list when the command buffer is submitted, with the packets. The console's graphics PFP reads it when it reaches the packet, so a list written after the submission (by the CPU, or by GPU work ahead of the packet behind PFP_SYNC_ME) is read here before that write.
|
||||
- The [shader float mode](../../core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp) (`FLOAT_MODE`, `DX10_CLAMP`, `IEEE_MODE` and `FP16_OVFL` of `COMPUTE_PGM_RSRC1` and `SPI_SHADER_PGM_RSRC1_PS/GS/HS`, bit positions from Mesa's `gfx10.json` and `gfx103.json`) is decoded into `GuestContext::floatMode` and is part of the shader cache keys and the serialized request, but no translation reads it yet (#981). Every float semantic still follows the single mode it was measured or written in, as the entries below record. The mode comes from the registered shader header's `sh_registers`, the same source at registration and at draw/dispatch so the prepared artifact keys match. A title that rewrites RSRC1 at run time, or a raw compute program with no header, compiles with that mode or none.
|
||||
- The [shader float mode](../../core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp) (`FLOAT_MODE`, `DX10_CLAMP`, `IEEE_MODE` and `FP16_OVFL` of `COMPUTE_PGM_RSRC1` and `SPI_SHADER_PGM_RSRC1_PS/GS/HS`, bit positions from Mesa's `gfx10.json` and `gfx103.json`) is decoded into `GuestContext::floatMode` and is part of the shader cache keys and the serialized request (#981). Only `IEEE_MODE` is read so far, by `v_min_f32`, `v_max_f32`, `v_min3_f32`, `v_max3_f32` and `v_med3_f32`. With IEEE=1 a signaling NaN operand returns that NaN quieted (the first operand checked first, min3/max3 as two nested pairs, med3 as min3 when any operand is NaN), measured on RDNA2 (gfx1035) over every combination of ±0, ±1, ±inf, denormals, quiet and signaling NaNs with f32 denormals kept and flushed. IEEE=0 and unknown modes keep the previous lowering, which matches IEEE=0. IEEE=1 with an output modifier throws. The f16 and f64 min/max/med3, NaN quieting in arithmetic, `DX10_CLAMP`, `FP16_OVFL` and `FLOAT_MODE` (f32 denormals flushed before the min/max compare in Astro's Playroom's 0xc0) still follow a single mode, as the entries below record. The mode comes from the registered shader header's `sh_registers`, the same source at registration and at draw/dispatch so the prepared artifact keys match. A title that rewrites RSRC1 at run time, or a raw compute program with no header, compiles with that mode or none.
|
||||
- [v_mullit_f32](../../core/shader/recompiler/Translation/src/FloatInstructions.cpp) follows the hardware measured with the MODE register at IEEE=1 and denormals kept (a signaling NaN src0 is quieted, a positive denormal src2 counts as positive): the recompiler does not read MODE, so other IEEE/denormal settings are not modelled.
|
||||
- [v_fma_legacy_f32](../../core/shader/recompiler/Translation/src/FloatInstructions.cpp) (VOP3 0x140) is assumed to be fused, which has not been measured on hardware. LLVM decodes this encoding as `v_mad_legacy_f32` for gfx1013, and `v_mac_legacy_f32` (VOP2 0x06) was measured to round its product before the add, so 0x140 may do the same.
|
||||
- The executable file that [relinker](../../core/relinker/elfpatcher/src/windows/WindowsPeWriter.cpp) generates opens the console when launched, which is inconvenient for playability.
|
||||
|
|
|
|||
Loading…
Reference in New Issue