mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 16:51:20 +00:00
shader: support five VOP3 float conversion forms
This commit is contained in:
1 parent
128c938514
commit
41de2fd64e
4 files changed
+140
No files matched your search
@@ -692,6 +692,8 @@ if(BUILD_TESTING)
|
|||||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --tessellation-only)
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --tessellation-only)
|
||||||
add_test(NAME shader_recompiler_float_min_max
|
add_test(NAME shader_recompiler_float_min_max
|
||||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --float-min-max-only)
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --float-min-max-only)
|
||||||
|
add_test(NAME shader_recompiler_vop3_conversions
|
||||||
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --vop3-conversions-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
|
||||||
|
|||||||
@@ -157,6 +157,10 @@ constexpr OpcodeMap VOP3_ENCODED_VOP1_OPCODE_LIST[] = {
|
|||||||
{0x04u, Opcode::V_CVT_F64_I32},
|
{0x04u, Opcode::V_CVT_F64_I32},
|
||||||
{0x0fu, Opcode::V_CVT_F32_F64},
|
{0x0fu, Opcode::V_CVT_F32_F64},
|
||||||
{0x10u, Opcode::V_CVT_F64_F32},
|
{0x10u, Opcode::V_CVT_F64_F32},
|
||||||
|
{0x11u, Opcode::V_CVT_F32_UBYTE0},
|
||||||
|
{0x12u, Opcode::V_CVT_F32_UBYTE1},
|
||||||
|
{0x13u, Opcode::V_CVT_F32_UBYTE2},
|
||||||
|
{0x14u, Opcode::V_CVT_F32_UBYTE3},
|
||||||
{0x16u, Opcode::V_CVT_F64_U32},
|
{0x16u, Opcode::V_CVT_F64_U32},
|
||||||
{0x17u, Opcode::V_TRUNC_F64},
|
{0x17u, Opcode::V_TRUNC_F64},
|
||||||
{0x18u, Opcode::V_CEIL_F64},
|
{0x18u, Opcode::V_CEIL_F64},
|
||||||
@@ -167,6 +171,7 @@ constexpr OpcodeMap VOP3_ENCODED_VOP1_OPCODE_LIST[] = {
|
|||||||
{0x07u, Opcode::V_CVT_U32_F32},
|
{0x07u, Opcode::V_CVT_U32_F32},
|
||||||
{0x08u, Opcode::V_CVT_I32_F32},
|
{0x08u, Opcode::V_CVT_I32_F32},
|
||||||
{0x0au, Opcode::V_CVT_F16_F32},
|
{0x0au, Opcode::V_CVT_F16_F32},
|
||||||
|
{0x0bu, Opcode::V_CVT_F32_F16},
|
||||||
{0x0cu, Opcode::V_CVT_RPI_I32_F32},
|
{0x0cu, Opcode::V_CVT_RPI_I32_F32},
|
||||||
{0x0du, Opcode::V_CVT_FLR_I32_F32},
|
{0x0du, Opcode::V_CVT_FLR_I32_F32},
|
||||||
{0x0eu, Opcode::V_CVT_OFF_F32_I4},
|
{0x0eu, Opcode::V_CVT_OFF_F32_I4},
|
||||||
@@ -1557,6 +1562,12 @@ bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mi
|
|||||||
}
|
}
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
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_UBYTE1:
|
||||||
|
case Opcode::V_CVT_F32_UBYTE2:
|
||||||
|
case Opcode::V_CVT_F32_UBYTE3:
|
||||||
|
// Byte conversions ignore input modifiers and support all output modifiers.
|
||||||
|
return op_sel != 0u;
|
||||||
case Opcode::V_INTERP_P1LL_F16:
|
case Opcode::V_INTERP_P1LL_F16:
|
||||||
case Opcode::V_INTERP_P2_F16:
|
case Opcode::V_INTERP_P2_F16:
|
||||||
return abs != 0u || (op_sel & 0x7u) != 0u || clamp != 0u || omod != 0u || neg != 0u;
|
return abs != 0u || (op_sel & 0x7u) != 0u || clamp != 0u || omod != 0u || neg != 0u;
|
||||||
|
|||||||
@@ -29658,6 +29658,79 @@ TestCase VectorMed3F32NanUsesMin3Path(u32 wave) {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase Vop3FloatConversions(u32 wave_size) {
|
||||||
|
using O = ShaderOpcode;
|
||||||
|
struct ConversionCase {
|
||||||
|
u32 opcode, input, expected;
|
||||||
|
u32 abs = 0, neg = 0, omod = 0;
|
||||||
|
bool clamp = false;
|
||||||
|
u32 exec = 1;
|
||||||
|
};
|
||||||
|
const ConversionCase cases[] = {
|
||||||
|
{0x18b, 0xabcd3e00u, 0x3fc00000u}, // Only the low half: 1.5.
|
||||||
|
{0x18b, 0x7c00c100u, 0xc0200000u}, // -2.5, despite +inf in the high half.
|
||||||
|
{0x18b, 0x12340000u, 0x00000000u},
|
||||||
|
{0x18b, 0x12348000u, 0x80000000u},
|
||||||
|
{0x18b, 0x12347c00u, 0x7f800000u},
|
||||||
|
{0x18b, 0x1234fc00u, 0xff800000u},
|
||||||
|
{0x18b, 0x1234c100u, 0x40200000u, 1},
|
||||||
|
{0x18b, 0x12343e00u, 0xbfc00000u, 0, 1},
|
||||||
|
{0x18b, 0x1234c100u, 0xc0200000u, 1, 1},
|
||||||
|
{0x18b, 0x12343e00u, 0x40400000u, 0, 0, 1},
|
||||||
|
{0x18b, 0x12343e00u, 0x40c00000u, 0, 0, 2},
|
||||||
|
{0x18b, 0x12343e00u, 0x3f400000u, 0, 0, 3},
|
||||||
|
{0x18b, 0x12343e00u, 0x3f800000u, 0, 0, 0, true},
|
||||||
|
{0x18b, 0x12343e00u, 0x00000000u, 0, 1, 0, true},
|
||||||
|
{0x18b, 0x12347e00u, 0x00000000u, 0, 0, 0, true}, // NaN clamp.
|
||||||
|
{0x18b, 0x12343e00u, 0x12343e00u, 0, 0, 0, false, 0},
|
||||||
|
{0x191, 0xff807f00u, 0x00000000u},
|
||||||
|
{0x192, 0xff807f00u, 0x42fe0000u},
|
||||||
|
{0x193, 0xff807f00u, 0x43000000u},
|
||||||
|
{0x194, 0xff807f00u, 0x437f0000u},
|
||||||
|
{0x191, 0xff807f00u, 0x00000000u, 1, 1, 1},
|
||||||
|
{0x192, 0xff807f00u, 0x43fe0000u, 1, 1, 2}, // 127 * 4; input modifiers ignored.
|
||||||
|
{0x193, 0xff807f00u, 0x42800000u, 1, 1, 3}, // 128 / 2.
|
||||||
|
{0x194, 0xff807f00u, 0x3f800000u, 1, 1, 0, true},
|
||||||
|
{0x194, 0xff807f00u, 0xff807f00u, 0, 0, 0, false, 0},
|
||||||
|
};
|
||||||
|
TestCase test;
|
||||||
|
test.name = wave_size == 32 ? "Vop3FloatConversionsWave32" : "Vop3FloatConversionsWave64";
|
||||||
|
test.compute_info.wave_size = wave_size;
|
||||||
|
test.has_compute_info = true;
|
||||||
|
for (const auto &entry : cases) test.initial.push_back(entry.input);
|
||||||
|
test.expected = test.initial;
|
||||||
|
auto &code = test.code;
|
||||||
|
for (u32 i = 0; i < std::size(cases); ++i) {
|
||||||
|
const auto &entry = cases[i];
|
||||||
|
AppendVMovU32(&code, 30, i * 4u);
|
||||||
|
AppendBufferLoadDword(&code, 2, 30); // Runtime source aliases the destination.
|
||||||
|
code.push_back(EncodeSMovB32(126, InlineU32(entry.exec)));
|
||||||
|
AppendVop3(&code, entry.opcode, 2, Vgpr(2), 0, 0, entry.abs, 0,
|
||||||
|
entry.clamp, entry.omod, entry.neg);
|
||||||
|
code.push_back(EncodeSMovB32(126, InlineU32(1)));
|
||||||
|
AppendStoreVgpr(&code, 2, static_cast<u32>(test.expected.size()));
|
||||||
|
test.expected.push_back(entry.expected);
|
||||||
|
}
|
||||||
|
// Exercise scalar, literal, and inline sources for every new encoding too.
|
||||||
|
AppendSMovLiteral(&code, 12, 0x44333e00u);
|
||||||
|
const u32 scalar_results[] = {0x3fc00000u, 0, 0x42780000u, 0x424c0000u, 0x42880000u};
|
||||||
|
const u32 opcodes[] = {0x18b, 0x191, 0x192, 0x193, 0x194};
|
||||||
|
for (u32 i = 0; i < std::size(opcodes); ++i) {
|
||||||
|
for (const u32 source : {12u, 255u, InlineU32(0)}) {
|
||||||
|
AppendVop3(&code, opcodes[i], 2, source, 0);
|
||||||
|
if (source == 255u) code.push_back(0x44333e00u);
|
||||||
|
AppendStoreVgpr(&code, 2, static_cast<u32>(test.expected.size()));
|
||||||
|
test.expected.push_back(source == InlineU32(0) ? 0u : scalar_results[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AppendEnd(&code);
|
||||||
|
test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::BUFFER_LOAD_DWORD,
|
||||||
|
O::V_CVT_F32_F16, O::V_CVT_F32_UBYTE0, O::V_CVT_F32_UBYTE1,
|
||||||
|
O::V_CVT_F32_UBYTE2, O::V_CVT_F32_UBYTE3,
|
||||||
|
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
TestCase VectorFloatConversionOps() {
|
TestCase VectorFloatConversionOps() {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
@@ -46118,6 +46191,8 @@ std::vector<TestCase> MakeCases() {
|
|||||||
cases.push_back(VectorMed3F32NanUsesMin3Path(64));
|
cases.push_back(VectorMed3F32NanUsesMin3Path(64));
|
||||||
cases.push_back(VectorMinMaxF32RuntimeEdges(32));
|
cases.push_back(VectorMinMaxF32RuntimeEdges(32));
|
||||||
cases.push_back(VectorMinMaxF32RuntimeEdges(64));
|
cases.push_back(VectorMinMaxF32RuntimeEdges(64));
|
||||||
|
cases.push_back(Vop3FloatConversions(32));
|
||||||
|
cases.push_back(Vop3FloatConversions(64));
|
||||||
AddCase(VectorFloatConversionOps);
|
AddCase(VectorFloatConversionOps);
|
||||||
AddCase(VectorFrexpF32Edges);
|
AddCase(VectorFrexpF32Edges);
|
||||||
AddCase(CvtF32ToIntSaturatesNaNAndOutOfRange);
|
AddCase(CvtF32ToIntSaturatesNaNAndOutOfRange);
|
||||||
@@ -52446,6 +52521,13 @@ 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], "--vop3-conversions-only") == 0) {
|
||||||
|
VulkanHarness vulkan;
|
||||||
|
RunCase(&vulkan, Vop3FloatConversions(32));
|
||||||
|
RunCase(&vulkan, Vop3FloatConversions(64));
|
||||||
|
RunCase(&vulkan, VectorFloatConversionOps());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--cvt-pkrtz-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--cvt-pkrtz-only") == 0) {
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
RunCase(&vulkan, CvtPkrtzF16F32SubnormalRoundsTowardZero());
|
RunCase(&vulkan, CvtPkrtzF16F32SubnormalRoundsTowardZero());
|
||||||
|
|||||||
@@ -2397,6 +2397,50 @@ void TestNewShaderRecompilerVop3LaneReadDestinationEncoding() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestVop3FloatConversionDecode() {
|
||||||
|
namespace Decoder = ShaderRecompiler::Decoder;
|
||||||
|
const std::pair<uint32_t, Decoder::Opcode> conversions[] = {
|
||||||
|
{0x18b, Decoder::Opcode::V_CVT_F32_F16},
|
||||||
|
{0x191, Decoder::Opcode::V_CVT_F32_UBYTE0},
|
||||||
|
{0x192, Decoder::Opcode::V_CVT_F32_UBYTE1},
|
||||||
|
{0x193, Decoder::Opcode::V_CVT_F32_UBYTE2},
|
||||||
|
{0x194, Decoder::Opcode::V_CVT_F32_UBYTE3},
|
||||||
|
};
|
||||||
|
for (const auto &[encoding, opcode] : conversions) {
|
||||||
|
for (const uint32_t source : {261u, 12u, 128u, 255u}) {
|
||||||
|
const uint32_t code[] = {
|
||||||
|
EncodeVop3Word0(encoding, 20, 0, 1, true),
|
||||||
|
EncodeVop3Word1(source, 0, 0) | (2u << 27u) | (1u << 29u),
|
||||||
|
0xa5a53e00u,
|
||||||
|
};
|
||||||
|
Decoder::Instruction inst;
|
||||||
|
Decoder::DecodeInstruction(code, 0, inst);
|
||||||
|
Check(inst.opcode == opcode && inst.family == Decoder::Family::VOP3 &&
|
||||||
|
inst.src_count == 1 && inst.word_count == (source == 255u ? 3u : 2u),
|
||||||
|
"VOP3 conversion lost its opcode, unary source, or literal length");
|
||||||
|
Check(inst.dst.kind == Decoder::OperandKind::Vgpr && inst.dst.reg == 20 &&
|
||||||
|
inst.dst.sdwa_sel == 6 && inst.dst.clamp && inst.dst.omod == 2,
|
||||||
|
"VOP3 conversion lost its full-width destination or output modifiers");
|
||||||
|
const bool half = opcode == Decoder::Opcode::V_CVT_F32_F16;
|
||||||
|
Check(inst.src0.absolute == half && inst.src0.negate == half,
|
||||||
|
"VOP3 conversion must apply half-float modifiers and ignore byte modifiers");
|
||||||
|
Decoder::Operand expected_source;
|
||||||
|
Decoder::DecodeScalarSource(source, 0, expected_source);
|
||||||
|
Check(inst.src0.kind == expected_source.kind && inst.src0.reg == expected_source.reg &&
|
||||||
|
(source != 255u || inst.src0.value == code[2]),
|
||||||
|
"VOP3 conversion changed its source register or literal value");
|
||||||
|
}
|
||||||
|
for (const uint32_t op_sel : {1u, 2u, 4u, 8u}) {
|
||||||
|
const uint32_t code[] = {EncodeVop3Word0(encoding, 20, op_sel),
|
||||||
|
EncodeVop3Word1(261, 0, 0)};
|
||||||
|
Decoder::Instruction inst;
|
||||||
|
Decoder::DecodeInstruction(code, 0, inst);
|
||||||
|
Check(inst.opcode == Decoder::Opcode::UNSUPPORTED,
|
||||||
|
"VOP3 conversion accepted unsupported OP_SEL bits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TestNewShaderRecompilerMoreAluFamilies() {
|
void TestNewShaderRecompilerMoreAluFamilies() {
|
||||||
const uint32_t shader[] = {
|
const uint32_t shader[] = {
|
||||||
EncodeSopk(0x00, 9, 7), // s_movk_i32 s9, 7
|
EncodeSopk(0x00, 9, 7), // s_movk_i32 s9, 7
|
||||||
@@ -17158,6 +17202,7 @@ int main() {
|
|||||||
using namespace Libs::Graphics;
|
using namespace Libs::Graphics;
|
||||||
|
|
||||||
EnsureConfigInitialized();
|
EnsureConfigInitialized();
|
||||||
|
TestVop3FloatConversionDecode();
|
||||||
TestRayTracingInstructions();
|
TestRayTracingInstructions();
|
||||||
TestResourceDescriptorClassification();
|
TestResourceDescriptorClassification();
|
||||||
TestShaderBufferResourceSize();
|
TestShaderBufferResourceSize();
|
||||||
|
|||||||
Reference in new issue
Block a user