mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 08:41:20 +00:00
shader: support four 16-bit integer ternary operations
This commit is contained in:
1 parent
138d5b86c4
commit
0386f33bf3
5 files changed
+95
-2
No files matched your search
@@ -696,6 +696,8 @@ if(BUILD_TESTING)
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --vop3-conversions-only)
|
||||
add_test(NAME shader_recompiler_quadmask
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --quadmask-only)
|
||||
add_test(NAME shader_recompiler_integer16_ternary
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --integer16-ternary-only)
|
||||
add_test(NAME shader_recompiler_alignbyte
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --alignbyte-only)
|
||||
add_test(NAME graphics_pipeline_rasterization
|
||||
|
||||
@@ -278,16 +278,20 @@ enum class Opcode {
|
||||
V_MIN3_I32,
|
||||
V_MIN3_U32,
|
||||
V_MIN3_F16,
|
||||
V_MIN3_I16,
|
||||
V_MIN3_U16,
|
||||
V_MAX3_F32,
|
||||
V_MAX3_I32,
|
||||
V_MAX3_U32,
|
||||
V_MAX3_F16,
|
||||
V_MAX3_I16,
|
||||
V_MAX3_U16,
|
||||
V_MED3_F32,
|
||||
V_MED3_I32,
|
||||
V_MED3_U32,
|
||||
V_MED3_F16,
|
||||
V_MED3_I16,
|
||||
V_MED3_U16,
|
||||
V_SAD_U32,
|
||||
V_ADD3_U32,
|
||||
V_LSHL_ADD_U32,
|
||||
|
||||
@@ -339,16 +339,20 @@ constexpr OpcodeMap VOP3_OPCODE_LIST[] = {
|
||||
{0x152u, Opcode::V_MIN3_I32},
|
||||
{0x153u, Opcode::V_MIN3_U32},
|
||||
{0x351u, Opcode::V_MIN3_F16},
|
||||
{0x352u, Opcode::V_MIN3_I16},
|
||||
{0x353u, Opcode::V_MIN3_U16},
|
||||
{0x154u, Opcode::V_MAX3_F32},
|
||||
{0x155u, Opcode::V_MAX3_I32},
|
||||
{0x156u, Opcode::V_MAX3_U32},
|
||||
{0x354u, Opcode::V_MAX3_F16},
|
||||
{0x355u, Opcode::V_MAX3_I16},
|
||||
{0x356u, Opcode::V_MAX3_U16},
|
||||
{0x157u, Opcode::V_MED3_F32},
|
||||
{0x158u, Opcode::V_MED3_I32},
|
||||
{0x159u, Opcode::V_MED3_U32},
|
||||
{0x357u, Opcode::V_MED3_F16},
|
||||
{0x358u, Opcode::V_MED3_I16},
|
||||
{0x359u, Opcode::V_MED3_U16},
|
||||
{0x15du, Opcode::V_SAD_U32},
|
||||
{0x15eu, Opcode::V_CVT_PK_U8_F32},
|
||||
{0x178u, Opcode::V_XOR3_B32},
|
||||
@@ -494,7 +498,9 @@ bool IsNativeVop3F16TernaryOpcode(Opcode opcode) {
|
||||
}
|
||||
|
||||
bool IsNativeVop3B16TernaryOpcode(Opcode opcode) {
|
||||
return opcode == Opcode::V_MIN3_U16 || opcode == Opcode::V_MED3_I16 ||
|
||||
return opcode == Opcode::V_MIN3_I16 || opcode == Opcode::V_MIN3_U16 ||
|
||||
opcode == Opcode::V_MAX3_I16 || opcode == Opcode::V_MAX3_U16 ||
|
||||
opcode == Opcode::V_MED3_I16 || opcode == Opcode::V_MED3_U16 ||
|
||||
opcode == Opcode::V_MAD_I16;
|
||||
}
|
||||
|
||||
@@ -1530,7 +1536,9 @@ bool SupportsNativeVop3ResultModifiers(Opcode opcode) {
|
||||
|
||||
bool SupportsNativeVop3Clamp(Opcode opcode) {
|
||||
return SupportsNativeVop3ResultModifiers(opcode) || UsesInexactClampControl(opcode) ||
|
||||
opcode == Opcode::V_MAD_I16;
|
||||
opcode == Opcode::V_MAD_I16 || opcode == Opcode::V_MIN3_I16 ||
|
||||
opcode == Opcode::V_MAX3_I16 || opcode == Opcode::V_MAX3_U16 ||
|
||||
opcode == Opcode::V_MED3_U16;
|
||||
}
|
||||
|
||||
bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mix,
|
||||
|
||||
@@ -378,6 +378,10 @@ void Translator::EmitVector(const Decoder::Instruction& inst) {
|
||||
case O::V_MAD_I16: return V_MAD_I16(inst);
|
||||
case O::V_MED3_I16: return Integer16Ternary(inst, IR::ValueOpcode::SMedTri32, true);
|
||||
case O::V_MIN3_U16: return Integer16Ternary(inst, IR::ValueOpcode::UMinTri32, false);
|
||||
case O::V_MIN3_I16: return Integer16Ternary(inst, IR::ValueOpcode::SMinTri32, true);
|
||||
case O::V_MAX3_I16: return Integer16Ternary(inst, IR::ValueOpcode::SMaxTri32, true);
|
||||
case O::V_MAX3_U16: return Integer16Ternary(inst, IR::ValueOpcode::UMaxTri32, false);
|
||||
case O::V_MED3_U16: return Integer16Ternary(inst, IR::ValueOpcode::UMedTri32, false);
|
||||
case O::V_MIN_I16: return Integer16Binary(inst, IR::ValueOpcode::SMin32, true);
|
||||
case O::V_MAX_I16: return Integer16Binary(inst, IR::ValueOpcode::SMax32, true);
|
||||
case O::V_MIN_U16: return Integer16Binary(inst, IR::ValueOpcode::UMin32, false);
|
||||
|
||||
@@ -26810,6 +26810,71 @@ TestCase Vop3MadI16CapturedSelectorsAndSaturation() {
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase Vop3Integer16Ternary(u32 wave_size) {
|
||||
using O = ShaderOpcode;
|
||||
namespace D = ShaderRecompiler::Decoder;
|
||||
struct Operation { u32 encoding; O opcode; bool sign; u32 sorted_index; };
|
||||
constexpr std::array operations{
|
||||
Operation{0x352, O::V_MIN3_I16, true, 0},
|
||||
Operation{0x355, O::V_MAX3_I16, true, 2},
|
||||
Operation{0x356, O::V_MAX3_U16, false, 2},
|
||||
Operation{0x359, O::V_MED3_U16, false, 1}};
|
||||
constexpr std::array<std::array<u32, 3>, 4> inputs{{
|
||||
{0x80007fffu, 0xffff0000u, 0x0001ffffu},
|
||||
{0x00098000u, 0xffff0007u, 0x7fff0005u},
|
||||
{0xffff8000u, 0xffff8000u, 0x00008000u},
|
||||
{0x00000000u, 0x7fff7fffu, 0x7fff7fffu}}};
|
||||
TestCase test;
|
||||
test.name = wave_size == 32 ? "Vop3Integer16TernaryWave32" : "Vop3Integer16TernaryWave64";
|
||||
for (const auto &input : inputs) test.initial.insert(test.initial.end(), input.begin(), input.end());
|
||||
test.expected = test.initial;
|
||||
auto &code = test.code;
|
||||
for (const auto &operation : operations) {
|
||||
// Integer ternaries accept half selectors, but no floating-point modifiers.
|
||||
for (u32 modifier = 0; modifier < 9; ++modifier) {
|
||||
const u32 words[] = {
|
||||
EncodeVop3Word0(operation.encoding, 9, modifier < 3 ? 1u << modifier : 0),
|
||||
EncodeVop3Word1(Vgpr(2), Vgpr(3), Vgpr(4),
|
||||
modifier >= 6 ? 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,
|
||||
"16-bit integer ternary accepted a floating-point modifier");
|
||||
}
|
||||
for (u32 i = 0; i < inputs.size(); ++i) {
|
||||
for (u32 variant = 0; variant < 32; ++variant) {
|
||||
const u32 selectors = variant & 15u;
|
||||
std::array<int32_t, 3> selected{};
|
||||
for (u32 operand = 0; operand < 3; ++operand) {
|
||||
AppendVMovU32(&code, 30, (i * 3 + operand) * sizeof(u32));
|
||||
AppendBufferLoadDword(&code, 2 + operand, 30);
|
||||
const u32 half = (inputs[i][operand] >> (((selectors >> operand) & 1u) * 16)) & 0xffffu;
|
||||
selected[operand] = operation.sign && half >= 0x8000u
|
||||
? static_cast<int32_t>(half) - 0x10000 : static_cast<int32_t>(half);
|
||||
}
|
||||
code.push_back(EncodeVop1(0x02, 12, Vgpr(3))); // Broadcast source 1 from an SGPR.
|
||||
const u32 dst = selectors & 1u ? 2u : 9u; // Also cover source/destination aliasing.
|
||||
AppendVMovLiteral(&code, 9, 0xa5a5beefu);
|
||||
AppendVop3(&code, operation.encoding, dst, Vgpr(2), 12, Vgpr(4), 0, selectors, variant >= 16);
|
||||
AppendStoreVgpr(&code, dst, static_cast<u32>(test.expected.size()));
|
||||
std::sort(selected.begin(), selected.end());
|
||||
const u32 result = static_cast<u32>(selected[operation.sorted_index]) & 0xffffu;
|
||||
const u32 old = dst == 2 ? inputs[i][0] : 0xa5a5beefu;
|
||||
test.expected.push_back(selectors & 8u ? (old & 0xffffu) | (result << 16)
|
||||
: (old & 0xffff0000u) | result);
|
||||
}
|
||||
}
|
||||
test.opcodes.push_back(operation.opcode);
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.opcodes.insert(test.opcodes.end(), {O::V_MOV_B32, O::V_READFIRSTLANE_B32,
|
||||
O::BUFFER_LOAD_DWORD, O::BUFFER_STORE_DWORD, O::S_ENDPGM});
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.has_compute_info = true;
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase Vop3Min3U16CapturedAndSelectors() {
|
||||
using O = ShaderOpcode;
|
||||
struct MinCase {
|
||||
@@ -46174,6 +46239,8 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(Vop3MulLoU16CapturedAndSelectors);
|
||||
AddCase(Vop3MadI16CapturedSelectorsAndSaturation);
|
||||
AddCase(Vop3F32ClampFlushesNaN);
|
||||
cases.push_back(Vop3Integer16Ternary(32));
|
||||
cases.push_back(Vop3Integer16Ternary(64));
|
||||
AddCase(Vop3Min3U16CapturedAndSelectors);
|
||||
AddCase(Vop3Med3I16Captured);
|
||||
AddCase(Vop2SdwaMinU32PreservesWordDestination);
|
||||
@@ -52604,6 +52671,14 @@ int main(int argc, char **argv) {
|
||||
std::setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
EnsureConfigInitialized();
|
||||
CheckLeastRecentlyUsedCacheOrdering();
|
||||
if (argc == 2 && std::strcmp(argv[1], "--integer16-ternary-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, Vop3Integer16Ternary(32));
|
||||
RunCase(&vulkan, Vop3Integer16Ternary(64));
|
||||
RunCase(&vulkan, Vop3Min3U16CapturedAndSelectors());
|
||||
RunCase(&vulkan, Vop3Med3I16Captured());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--quadmask-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, ScalarQuadmaskB32(32));
|
||||
|
||||
Reference in new issue
Block a user