mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 16:51:20 +00:00
shader: support high products of 24-bit integers
This commit is contained in:
1 parent
22610cb93e
commit
54b937c85f
7 files changed
+128
-4
No files matched your search
@@ -700,6 +700,8 @@ if(BUILD_TESTING)
|
|||||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --integer16-ternary-only)
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --integer16-ternary-only)
|
||||||
add_test(NAME shader_recompiler_mad_u16
|
add_test(NAME shader_recompiler_mad_u16
|
||||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --mad-u16-only)
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --mad-u16-only)
|
||||||
|
add_test(NAME shader_recompiler_mul_hi24
|
||||||
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --mul-hi24-only)
|
||||||
add_test(NAME shader_recompiler_alignbyte
|
add_test(NAME shader_recompiler_alignbyte
|
||||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --alignbyte-only)
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --alignbyte-only)
|
||||||
add_test(NAME graphics_pipeline_rasterization
|
add_test(NAME graphics_pipeline_rasterization
|
||||||
|
|||||||
@@ -249,7 +249,9 @@ enum class Opcode {
|
|||||||
V_MIN_I32,
|
V_MIN_I32,
|
||||||
V_MAX_I32,
|
V_MAX_I32,
|
||||||
V_MUL_I32_I24,
|
V_MUL_I32_I24,
|
||||||
|
V_MUL_HI_I32_I24,
|
||||||
V_MUL_U32_U24,
|
V_MUL_U32_U24,
|
||||||
|
V_MUL_HI_U32_U24,
|
||||||
V_MUL_LO_U32,
|
V_MUL_LO_U32,
|
||||||
V_MUL_HI_U32,
|
V_MUL_HI_U32,
|
||||||
V_MUL_LO_I32,
|
V_MUL_LO_I32,
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ constexpr Vop2OpcodeInfo VOP2_OPCODE_LIST[] = {
|
|||||||
{0x05u, Opcode::V_SUBREV_F32},
|
{0x05u, Opcode::V_SUBREV_F32},
|
||||||
{0x08u, Opcode::V_MUL_F32, Vop2SdwaProfile::Float32},
|
{0x08u, Opcode::V_MUL_F32, Vop2SdwaProfile::Float32},
|
||||||
{0x09u, Opcode::V_MUL_I32_I24, Vop2SdwaProfile::IntegerPartialDestination},
|
{0x09u, Opcode::V_MUL_I32_I24, Vop2SdwaProfile::IntegerPartialDestination},
|
||||||
|
{0x0au, Opcode::V_MUL_HI_I32_I24, Vop2SdwaProfile::IntegerPartialDestination},
|
||||||
{0x0bu, Opcode::V_MUL_U32_U24, Vop2SdwaProfile::IntegerPartialDestination},
|
{0x0bu, Opcode::V_MUL_U32_U24, Vop2SdwaProfile::IntegerPartialDestination},
|
||||||
|
{0x0cu, Opcode::V_MUL_HI_U32_U24, Vop2SdwaProfile::IntegerPartialDestination},
|
||||||
{0x0fu, Opcode::V_MIN_F32},
|
{0x0fu, Opcode::V_MIN_F32},
|
||||||
{0x10u, Opcode::V_MAX_F32},
|
{0x10u, Opcode::V_MAX_F32},
|
||||||
{0x11u, Opcode::V_MIN_I32, Vop2SdwaProfile::IntegerFullDestination},
|
{0x11u, Opcode::V_MIN_I32, Vop2SdwaProfile::IntegerFullDestination},
|
||||||
@@ -1539,7 +1541,8 @@ bool SupportsNativeVop3Clamp(Opcode opcode) {
|
|||||||
return SupportsNativeVop3ResultModifiers(opcode) || UsesInexactClampControl(opcode) ||
|
return SupportsNativeVop3ResultModifiers(opcode) || UsesInexactClampControl(opcode) ||
|
||||||
opcode == Opcode::V_MAD_I16 || opcode == Opcode::V_MAD_U16 ||
|
opcode == Opcode::V_MAD_I16 || opcode == Opcode::V_MAD_U16 ||
|
||||||
opcode == Opcode::V_MIN3_I16 || opcode == Opcode::V_MAX3_I16 ||
|
opcode == Opcode::V_MIN3_I16 || opcode == Opcode::V_MAX3_I16 ||
|
||||||
opcode == Opcode::V_MAX3_U16 || opcode == Opcode::V_MED3_U16;
|
opcode == Opcode::V_MAX3_U16 || opcode == Opcode::V_MED3_U16 ||
|
||||||
|
opcode == Opcode::V_MUL_HI_I32_I24 || opcode == Opcode::V_MUL_HI_U32_U24;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mix,
|
bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mix,
|
||||||
@@ -1570,6 +1573,10 @@ bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mi
|
|||||||
return clamp != 0u || omod != 0u || neg != 0u;
|
return clamp != 0u || omod != 0u || neg != 0u;
|
||||||
}
|
}
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
case Opcode::V_MUL_HI_I32_I24:
|
||||||
|
case Opcode::V_MUL_HI_U32_U24:
|
||||||
|
// The high product fits in 32 bits, so clamp has no effect.
|
||||||
|
return abs != 0u || op_sel != 0u || omod != 0u || neg != 0u;
|
||||||
case Opcode::V_LDEXP_F32: return (abs & ~1u) != 0u || op_sel != 0u || (neg & ~1u) != 0u;
|
case Opcode::V_LDEXP_F32: return (abs & ~1u) != 0u || op_sel != 0u || (neg & ~1u) != 0u;
|
||||||
case Opcode::V_CVT_F32_UBYTE0:
|
case Opcode::V_CVT_F32_UBYTE0:
|
||||||
case Opcode::V_CVT_F32_UBYTE1:
|
case Opcode::V_CVT_F32_UBYTE1:
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ void Translator::V_FFBH_32(const Decoder::Instruction& inst, bool sign) {
|
|||||||
WriteOperand(DestinationOperand(inst), result);
|
WriteOperand(DestinationOperand(inst), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::Integer24(const Decoder::Instruction& inst, bool sign, bool addend) {
|
void Translator::Integer24(const Decoder::Instruction& inst, bool sign, bool addend, bool high) {
|
||||||
const auto extract24 = [&](IR::U32 value) {
|
const auto extract24 = [&](IR::U32 value) {
|
||||||
return IR::U32(
|
return IR::U32(
|
||||||
ir.Emit(sign ? IR::ValueOpcode::BitFieldSExtract : IR::ValueOpcode::BitFieldUExtract,
|
ir.Emit(sign ? IR::ValueOpcode::BitFieldSExtract : IR::ValueOpcode::BitFieldUExtract,
|
||||||
@@ -277,7 +277,9 @@ void Translator::Integer24(const Decoder::Instruction& inst, bool sign, bool add
|
|||||||
};
|
};
|
||||||
const auto lhs = extract24(ReadU32(inst.src0));
|
const auto lhs = extract24(ReadU32(inst.src0));
|
||||||
const auto rhs = extract24(ReadU32(inst.src1));
|
const auto rhs = extract24(ReadU32(inst.src1));
|
||||||
auto result = ir.IMul(lhs, rhs);
|
const auto multiply = high ? (sign ? IR::ValueOpcode::SMulHi : IR::ValueOpcode::UMulHi)
|
||||||
|
: IR::ValueOpcode::IMul32;
|
||||||
|
auto result = IR::U32(ir.Emit(multiply, {lhs, rhs}));
|
||||||
if (addend) {
|
if (addend) {
|
||||||
result = ir.IAdd(result, ReadU32(inst.src2));
|
result = ir.IAdd(result, ReadU32(inst.src2));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ private:
|
|||||||
void V_XOR3_B32(const Decoder::Instruction& inst);
|
void V_XOR3_B32(const Decoder::Instruction& inst);
|
||||||
void S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero, bool from_msb, bool sign);
|
void S_FF_I32_B64(const Decoder::Instruction& inst, bool find_zero, bool from_msb, bool sign);
|
||||||
void V_FFBH_32(const Decoder::Instruction& inst, bool sign);
|
void V_FFBH_32(const Decoder::Instruction& inst, bool sign);
|
||||||
void Integer24(const Decoder::Instruction& inst, bool sign, bool addend);
|
void Integer24(const Decoder::Instruction& inst, bool sign, bool addend, bool high = false);
|
||||||
void V_MAD_U64_U32(const Decoder::Instruction& inst);
|
void V_MAD_U64_U32(const Decoder::Instruction& inst);
|
||||||
void V_SAD_U32(const Decoder::Instruction& inst);
|
void V_SAD_U32(const Decoder::Instruction& inst);
|
||||||
void V_ADD3_U32(const Decoder::Instruction& inst);
|
void V_ADD3_U32(const Decoder::Instruction& inst);
|
||||||
|
|||||||
@@ -586,6 +586,8 @@ void Translator::EmitVector(const Decoder::Instruction& inst) {
|
|||||||
case O::V_MAD_U32_U24: return Integer24(inst, false, true);
|
case O::V_MAD_U32_U24: return Integer24(inst, false, true);
|
||||||
case O::V_MUL_I32_I24: return Integer24(inst, true, false);
|
case O::V_MUL_I32_I24: return Integer24(inst, true, false);
|
||||||
case O::V_MUL_U32_U24: return Integer24(inst, false, false);
|
case O::V_MUL_U32_U24: return Integer24(inst, false, false);
|
||||||
|
case O::V_MUL_HI_I32_I24: return Integer24(inst, true, false, true);
|
||||||
|
case O::V_MUL_HI_U32_U24: return Integer24(inst, false, false, true);
|
||||||
case O::V_MAD_U64_U32: return V_MAD_U64_U32(inst);
|
case O::V_MAD_U64_U32: return V_MAD_U64_U32(inst);
|
||||||
case O::V_SAD_U32: return V_SAD_U32(inst);
|
case O::V_SAD_U32: return V_SAD_U32(inst);
|
||||||
case O::V_ADD3_U32: return V_ADD3_U32(inst);
|
case O::V_ADD3_U32: return V_ADD3_U32(inst);
|
||||||
|
|||||||
@@ -26425,6 +26425,102 @@ TestCase Vop2SdwaMinI32CapturedByte0(u32 wave_size) {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase VectorMulHi24(u32 wave_size) {
|
||||||
|
using O = ShaderOpcode;
|
||||||
|
namespace D = ShaderRecompiler::Decoder;
|
||||||
|
constexpr std::array<u32, 8> lhs{0x7f7fffffu, 0xa5800000u, 0x12ffffffu, 0xab000000u,
|
||||||
|
0x00010000u, 0xffabcdefu, 0x80000001u, 0x7fffffffu};
|
||||||
|
constexpr std::array<u32, 8> rhs{0x00800000u, 0xcd800000u, 0x55000001u, 0x99ffffffu,
|
||||||
|
0xab010000u, 0x00ffffffu, 0xfffffffeu, 0xffffffffu};
|
||||||
|
TestCase test;
|
||||||
|
test.name = wave_size == 32 ? "VectorMulHi24Wave32" : "VectorMulHi24Wave64";
|
||||||
|
for (u32 lane = 0; lane < wave_size; ++lane) test.initial.push_back(lhs[lane % lhs.size()]);
|
||||||
|
for (u32 lane = 0; lane < wave_size; ++lane) test.initial.push_back(rhs[lane % rhs.size()]);
|
||||||
|
test.expected = test.initial;
|
||||||
|
auto &code = test.code;
|
||||||
|
code.push_back(EncodeVop2(0x1a, 30, InlineU32(2), 0));
|
||||||
|
AppendBufferLoadDword(&code, 2, 30);
|
||||||
|
AppendVMovU32(&code, 20, wave_size * sizeof(u32));
|
||||||
|
code.push_back(EncodeVop2(0x25, 30, Vgpr(20), 30));
|
||||||
|
AppendBufferLoadDword(&code, 3, 30);
|
||||||
|
for (bool sign : {true, false}) {
|
||||||
|
const u32 opcode = sign ? 0x0a : 0x0c;
|
||||||
|
for (u32 modifier = 0; modifier < 13; ++modifier) {
|
||||||
|
const u32 words[] = {
|
||||||
|
EncodeVop3Word0(0x100 + opcode, 7, modifier < 3 ? 1u << modifier : 0,
|
||||||
|
modifier >= 9 ? 1u << (modifier - 9) : 0),
|
||||||
|
EncodeVop3Word1(Vgpr(5), Vgpr(6), 0,
|
||||||
|
modifier >= 6 && modifier < 9 ? modifier - 5 : 0,
|
||||||
|
modifier >= 3 && modifier < 6 ? 1u << (modifier - 3) : 0)};
|
||||||
|
D::Instruction decoded;
|
||||||
|
D::DecodeInstruction(words, 0, decoded);
|
||||||
|
Require(test.name, "integer modifiers", decoded.opcode == O::UNSUPPORTED,
|
||||||
|
"24-bit high multiply accepted unsupported modifiers");
|
||||||
|
}
|
||||||
|
for (u32 variant = 0; variant < 10; ++variant) {
|
||||||
|
code.push_back(EncodeVop1(0x01, 5, Vgpr(2)));
|
||||||
|
code.push_back(EncodeVop1(0x01, 6, Vgpr(3)));
|
||||||
|
AppendVMovLiteral(&code, 7, 0xa5a5beefu);
|
||||||
|
u32 dst = 7;
|
||||||
|
switch (variant) {
|
||||||
|
case 0: dst = 5; code.push_back(EncodeVop2(opcode, dst, Vgpr(5), 6)); break;
|
||||||
|
case 1: dst = 6; AppendVop3(&code, 0x100 + opcode, dst, Vgpr(5), Vgpr(6)); break;
|
||||||
|
case 2: AppendVop3(&code, 0x100 + opcode, dst, Vgpr(5), Vgpr(6), 0, 0, 0, true); break;
|
||||||
|
case 3:
|
||||||
|
code.push_back(EncodeVop2(opcode, dst, 255, 6));
|
||||||
|
code.push_back(0x00ffffffu);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
AppendVop3(&code, 0x100 + opcode, dst, Vgpr(5), 255);
|
||||||
|
code.push_back(0x00800000u);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
AppendSMovLiteral(&code, 20, 0xffff0001u);
|
||||||
|
AppendVop3(&code, 0x100 + opcode, dst, Vgpr(5), 20);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
code.push_back(EncodeVop2(opcode, dst, 249, 6));
|
||||||
|
code.push_back(EncodeVop2Sdwa(5, variant == 7 ? 5 : 6, variant == 7 ? 2 : 0,
|
||||||
|
variant == 8 ? 4 : 6, 6, variant == 8));
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
code.push_back(EncodeVop2(opcode, dst, 250, 6));
|
||||||
|
code.push_back(EncodeVop2Dpp(5, 0x01b)); // Reverse each quad's source lanes.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
AppendStoreVgprAtLaneDwordOffset(&code, dst, 0, static_cast<u32>(test.expected.size()));
|
||||||
|
for (u32 lane = 0; lane < wave_size; ++lane) {
|
||||||
|
const u32 source_lane = variant == 9 ? lane ^ 3u : lane;
|
||||||
|
u32 a = lhs[source_lane % lhs.size()], b = rhs[lane % rhs.size()];
|
||||||
|
if (variant == 3) a = 0x00ffffffu;
|
||||||
|
if (variant == 4) b = 0x00800000u;
|
||||||
|
if (variant == 5) b = 0xffff0001u;
|
||||||
|
if (variant == 8) a = (a & 0x8000u) ? a | 0xffff0000u : a & 0xffffu;
|
||||||
|
const auto extend24 = [sign](u32 value) -> int64_t {
|
||||||
|
const int64_t low = value & 0x00ffffffu;
|
||||||
|
return sign && (value & 0x00800000u) ? low - 0x01000000 : low;
|
||||||
|
};
|
||||||
|
const uint64_t product = static_cast<uint64_t>(extend24(a) * extend24(b));
|
||||||
|
const u32 high = static_cast<u32>(product >> 32);
|
||||||
|
test.expected.push_back(variant == 7 ? 0xbeefu | (high << 16) : high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AppendEnd(&code);
|
||||||
|
test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::V_LSHLREV_B32, O::V_ADD_NC_U32,
|
||||||
|
O::BUFFER_LOAD_DWORD, O::V_MUL_HI_I32_I24, O::V_MUL_HI_U32_U24,
|
||||||
|
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||||
|
test.compute_info.wave_size = wave_size;
|
||||||
|
test.compute_info.threads_num[0] = wave_size;
|
||||||
|
test.compute_info.threads_num[1] = 1;
|
||||||
|
test.compute_info.threads_num[2] = 1;
|
||||||
|
test.compute_info.thread_ids_num = 1;
|
||||||
|
test.has_compute_info = true;
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
TestCase Vop2SdwaMulI24Destinations(u32 wave_size) {
|
TestCase Vop2SdwaMulI24Destinations(u32 wave_size) {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
constexpr std::array<u32, 5> sources{
|
constexpr std::array<u32, 5> sources{
|
||||||
@@ -46282,6 +46378,8 @@ std::vector<TestCase> MakeCases() {
|
|||||||
cases.push_back(Vop2SdwaMaxI32CapturedHighWord(64));
|
cases.push_back(Vop2SdwaMaxI32CapturedHighWord(64));
|
||||||
cases.push_back(Vop2SdwaMinI32CapturedByte0(32));
|
cases.push_back(Vop2SdwaMinI32CapturedByte0(32));
|
||||||
cases.push_back(Vop2SdwaMinI32CapturedByte0(64));
|
cases.push_back(Vop2SdwaMinI32CapturedByte0(64));
|
||||||
|
cases.push_back(VectorMulHi24(32));
|
||||||
|
cases.push_back(VectorMulHi24(64));
|
||||||
cases.push_back(Vop2SdwaMulI24Destinations(32));
|
cases.push_back(Vop2SdwaMulI24Destinations(32));
|
||||||
cases.push_back(Vop2SdwaMulI24Destinations(64));
|
cases.push_back(Vop2SdwaMulI24Destinations(64));
|
||||||
cases.push_back(Vop2SdwaMulU24Destinations(32));
|
cases.push_back(Vop2SdwaMulU24Destinations(32));
|
||||||
@@ -52727,6 +52825,17 @@ int main(int argc, char **argv) {
|
|||||||
std::setvbuf(stdout, nullptr, _IONBF, 0);
|
std::setvbuf(stdout, nullptr, _IONBF, 0);
|
||||||
EnsureConfigInitialized();
|
EnsureConfigInitialized();
|
||||||
CheckLeastRecentlyUsedCacheOrdering();
|
CheckLeastRecentlyUsedCacheOrdering();
|
||||||
|
if (argc == 2 && std::strcmp(argv[1], "--mul-hi24-only") == 0) {
|
||||||
|
VulkanHarness vulkan;
|
||||||
|
RunCase(&vulkan, VectorMulHi24(32));
|
||||||
|
RunCase(&vulkan, VectorMulHi24(64));
|
||||||
|
RunCase(&vulkan, Vop2SdwaMulI24Destinations(32));
|
||||||
|
RunCase(&vulkan, Vop2SdwaMulI24Destinations(64));
|
||||||
|
RunCase(&vulkan, Vop2SdwaMulU24Destinations(32));
|
||||||
|
RunCase(&vulkan, Vop2SdwaMulU24Destinations(64));
|
||||||
|
RunCase(&vulkan, VectorVop3IntegerOps());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--mad-u16-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--mad-u16-only") == 0) {
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
RunCase(&vulkan, Vop3MadU16(32));
|
RunCase(&vulkan, Vop3MadU16(32));
|
||||||
|
|||||||
Reference in new issue
Block a user