mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
shader: support RDNA2 high-half short buffer stores
Co-authored-by: fxpw <fxpw@outlook.com>
This commit is contained in:
@@ -44,6 +44,7 @@ constexpr MemoryOpcodeInfo MUBUF_OPCODE_LIST[] = {
|
||||
{0x18u, Opcode::BUFFER_STORE_BYTE, 1, 8},
|
||||
{0x19u, Opcode::BUFFER_STORE_BYTE_D16_HI, 1, 8},
|
||||
{0x1au, Opcode::BUFFER_STORE_SHORT, 1, 16},
|
||||
{0x1bu, Opcode::BUFFER_STORE_SHORT_D16_HI, 1, 16},
|
||||
{0x1cu, Opcode::BUFFER_STORE_DWORD, 1, 32},
|
||||
{0x1du, Opcode::BUFFER_STORE_DWORDX2, 2, 32},
|
||||
{0x1eu, Opcode::BUFFER_STORE_DWORDX4, 4, 32},
|
||||
@@ -319,6 +320,8 @@ void DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
|
||||
inst.dst.sdwa_sel = inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16_HI ? 5u : 4u;
|
||||
} else if (inst.opcode == Opcode::BUFFER_STORE_BYTE_D16_HI) {
|
||||
inst.dst.sdwa_sel = 2u;
|
||||
} else if (inst.opcode == Opcode::BUFFER_STORE_SHORT_D16_HI) {
|
||||
inst.dst.sdwa_sel = 5u;
|
||||
}
|
||||
DecodeVectorGpr(vaddr, inst.src0);
|
||||
DecodeScalarSource(srsrc * 4u, pc, inst.src1);
|
||||
|
||||
@@ -650,6 +650,7 @@ std::string InstructionToString(const Instruction& inst) {
|
||||
case Opcode::BUFFER_STORE_BYTE:
|
||||
case Opcode::BUFFER_STORE_BYTE_D16_HI:
|
||||
case Opcode::BUFFER_STORE_SHORT:
|
||||
case Opcode::BUFFER_STORE_SHORT_D16_HI:
|
||||
case Opcode::BUFFER_STORE_DWORD:
|
||||
case Opcode::BUFFER_STORE_DWORDX2:
|
||||
case Opcode::BUFFER_STORE_DWORDX3:
|
||||
|
||||
@@ -568,6 +568,7 @@ enum class Opcode {
|
||||
BUFFER_STORE_BYTE,
|
||||
BUFFER_STORE_BYTE_D16_HI,
|
||||
BUFFER_STORE_SHORT,
|
||||
BUFFER_STORE_SHORT_D16_HI,
|
||||
BUFFER_STORE_DWORD,
|
||||
BUFFER_STORE_DWORDX2,
|
||||
BUFFER_STORE_DWORDX3,
|
||||
|
||||
@@ -1001,6 +1001,7 @@ void Translator::EmitMemory(const Decoder::Instruction& inst) {
|
||||
case Decoder::Opcode::BUFFER_STORE_BYTE:
|
||||
case Decoder::Opcode::BUFFER_STORE_BYTE_D16_HI:
|
||||
case Decoder::Opcode::BUFFER_STORE_SHORT:
|
||||
case Decoder::Opcode::BUFFER_STORE_SHORT_D16_HI:
|
||||
case Decoder::Opcode::BUFFER_STORE_FORMAT_X:
|
||||
case Decoder::Opcode::BUFFER_STORE_FORMAT_XY:
|
||||
case Decoder::Opcode::BUFFER_STORE_FORMAT_XYZ:
|
||||
|
||||
@@ -30939,38 +30939,49 @@ TestCase BufferStoreVariants() {
|
||||
O::BUFFER_STORE_DWORDX4, O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
TestCase BufferStoreByteD16Hi(bool masked) {
|
||||
TestCase BufferStoreD16Hi(bool halfword, bool masked, u32 wave_size) {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = masked ? "BufferStoreByteD16HiMasked" : "BufferStoreByteD16HiAdjacentLanes";
|
||||
if (halfword) {
|
||||
test.name = wave_size == 32u
|
||||
? (masked ? "BufferStoreShortD16HiMasked32" : "BufferStoreShortD16HiAdjacentLanes32")
|
||||
: (masked ? "BufferStoreShortD16HiMasked64" : "BufferStoreShortD16HiAdjacentLanes64");
|
||||
} else {
|
||||
test.name = masked ? "BufferStoreByteD16HiMasked" : "BufferStoreByteD16HiAdjacentLanes";
|
||||
}
|
||||
const u32 element_bytes = halfword ? 2u : 1u;
|
||||
AppendVMovLiteral(&test.code, 4, 0xa5c39b72u);
|
||||
test.code.push_back(EncodeVop2(0x25, 25, InlineU32(4), 0));
|
||||
if (masked) {
|
||||
AppendSMovLiteral(&test.code, 126, 0x55555555u);
|
||||
AppendSMovLiteral(&test.code, 127, 0xaaaaaaaau);
|
||||
AppendSMovLiteral(&test.code, 127, wave_size == 64 ? 0xaaaaaaaau : 0u);
|
||||
}
|
||||
// Captured b21e373811f28e31 pc 0x1b8c: e0646000 80020419.
|
||||
test.code.push_back(EncodeMubuf0(0x19u, 0, true, false, true));
|
||||
// Short variant uses 3e8244db54b38b0c pc 0x211c with the same test registers.
|
||||
test.code.push_back(EncodeMubuf0(halfword ? 0x1bu : 0x19u, 0, true, false, true));
|
||||
test.code.push_back(EncodeMubuf1(4, 2, 25));
|
||||
AppendEnd(&test.code);
|
||||
test.initial = std::vector<u32>(20, 0x11223344u);
|
||||
test.initial = std::vector<u32>((wave_size * element_bytes + 16u) / 4u, 0x11223344u);
|
||||
test.expected = test.initial;
|
||||
for (u32 lane = 0; lane < 60; lane++) {
|
||||
for (u32 lane = 0; lane < wave_size - 4u; lane++) {
|
||||
const u32 mask = !masked ? 0xffffffffu : lane < 32 ? 0x55555555u : 0xaaaaaaaau;
|
||||
if (((mask >> (lane % 32)) & 1u) == 0) continue;
|
||||
const u32 byte = lane + 4, shift = (byte % 4) * 8;
|
||||
test.expected[byte / 4] = (test.expected[byte / 4] & ~(0xffu << shift)) | (0xc3u << shift);
|
||||
const u32 byte = (lane + 4u) * element_bytes, shift = (byte % 4u) * 8u;
|
||||
const u32 bits = halfword ? 0xffffu : 0xffu, value = halfword ? 0xa5c3u : 0xc3u;
|
||||
test.expected[byte / 4u] = (test.expected[byte / 4u] & ~(bits << shift)) | (value << shift);
|
||||
}
|
||||
const auto descriptor = MakeStructuredStorageBufferData(1, 64);
|
||||
const auto descriptor = MakeStructuredStorageBufferData(element_bytes, wave_size);
|
||||
std::copy_n(descriptor.begin(), 4, test.user_data.begin() + 8);
|
||||
test.has_user_data = true;
|
||||
test.storage_buffer_range_bytes = 64;
|
||||
test.compute_info.threads_num[0] = 64;
|
||||
test.storage_buffer_range_bytes = wave_size * element_bytes;
|
||||
test.compute_info.threads_num[0] = wave_size;
|
||||
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1;
|
||||
test.compute_info.thread_ids_num = 1;
|
||||
test.compute_info.wave_size = 64;
|
||||
test.compute_info.wave_size = static_cast<uint8_t>(wave_size);
|
||||
test.has_compute_info = true;
|
||||
test.opcodes = {O::V_MOV_B32, O::V_ADD_NC_U32, O::BUFFER_STORE_BYTE_D16_HI, O::S_ENDPGM};
|
||||
test.opcodes = {O::V_MOV_B32, O::V_ADD_NC_U32,
|
||||
halfword ? O::BUFFER_STORE_SHORT_D16_HI : O::BUFFER_STORE_BYTE_D16_HI, O::S_ENDPGM};
|
||||
test.required_spirv = {"Volatile"};
|
||||
test.forbidden_spirv = {"OpAtomicLoad", "OpAtomicCompareExchange"};
|
||||
return test;
|
||||
}
|
||||
@@ -40772,8 +40783,11 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(BufferLoadFormatXyRejectsPartialRecord);
|
||||
AddCase(BufferStoreFormatXyRejectsPartialRecord);
|
||||
AddCase(BufferStoreVariants);
|
||||
cases.push_back(BufferStoreByteD16Hi(false));
|
||||
cases.push_back(BufferStoreByteD16Hi(true));
|
||||
for (bool masked : {false, true}) {
|
||||
cases.push_back(BufferStoreD16Hi(false, masked, 64));
|
||||
for (u32 wave_size : {32u, 64u})
|
||||
cases.push_back(BufferStoreD16Hi(true, masked, wave_size));
|
||||
}
|
||||
AddCase(BufferFormatVariants);
|
||||
AddCase(BufferLoadFormatXyzwSnapshotsOverlappingAddress);
|
||||
AddCase(BufferLoadFormatXyzwResource32_32FloatAppliesXy01);
|
||||
@@ -46482,8 +46496,11 @@ int main(int argc, char **argv) {
|
||||
RunCase(&vulkan, BufferStoreFormatXyRejectsPartialRecord());
|
||||
RunCase(&vulkan, BufferFormatStoreVariants());
|
||||
RunCase(&vulkan, TBufferStoreFormatXSintWritesSubDword());
|
||||
RunCase(&vulkan, BufferStoreByteD16Hi(false));
|
||||
RunCase(&vulkan, BufferStoreByteD16Hi(true));
|
||||
for (bool masked : {false, true}) {
|
||||
RunCase(&vulkan, BufferStoreD16Hi(false, masked, 64));
|
||||
for (u32 wave_size : {32u, 64u})
|
||||
RunCase(&vulkan, BufferStoreD16Hi(true, masked, wave_size));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--buffer-float16-store-only") == 0) {
|
||||
|
||||
@@ -15387,6 +15387,24 @@ void TestCapturedBufferLoadUbyteD16Decode() {
|
||||
"captured BUFFER_LOAD_UBYTE_D16 lost its preserved half, address, or coherence flags");
|
||||
}
|
||||
|
||||
void TestCapturedBufferStoreShortD16HiDecode() {
|
||||
namespace Decoder = ShaderRecompiler::Decoder;
|
||||
const uint32_t code[] = {0xe06c6000u, 0x80010326u};
|
||||
Decoder::Instruction inst;
|
||||
Decoder::DecodeInstruction(code, 0, inst);
|
||||
Check(inst.opcode == Decoder::Opcode::BUFFER_STORE_SHORT_D16_HI &&
|
||||
inst.word_count == 2 && inst.data_dwords == 1 && inst.data_bits == 16 &&
|
||||
!inst.data_signed && !inst.formatted && !inst.typed,
|
||||
"captured BUFFER_STORE_SHORT_D16_HI lost its raw halfword payload");
|
||||
Check(inst.dst.kind == Decoder::OperandKind::Vgpr && inst.dst.reg == 3 &&
|
||||
inst.dst.sdwa_sel == 5 && !inst.dst.sdwa_sext &&
|
||||
inst.src0.kind == Decoder::OperandKind::Vgpr && inst.src0.reg == 38 &&
|
||||
inst.src1.kind == Decoder::OperandKind::Sgpr && inst.src1.reg == 4 &&
|
||||
inst.src2.kind == Decoder::OperandKind::IntegerInlineConstant && inst.src2.value == 0 &&
|
||||
inst.idxen && !inst.offen && inst.offset == 0 && inst.glc && !inst.dlc && !inst.slc,
|
||||
"captured BUFFER_STORE_SHORT_D16_HI lost its high half, address, or coherence flags");
|
||||
}
|
||||
|
||||
void TestCapturedBufferStoreD16XyzwDecode() {
|
||||
namespace Decoder = ShaderRecompiler::Decoder;
|
||||
const uint32_t code[] = {0xe21c6000u, 0x8002000eu};
|
||||
@@ -16089,6 +16107,7 @@ int main() {
|
||||
TestPixelProgramCacheBindingIdentity();
|
||||
TestGraphicsPushConstantPlacement();
|
||||
TestCapturedBufferLoadUbyteD16Decode();
|
||||
TestCapturedBufferStoreShortD16HiDecode();
|
||||
TestCapturedBufferStoreD16XyzwDecode();
|
||||
TestNewShaderRecompilerUnsupportedMemoryDecode();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user