mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
shader: decode unsigned byte loads into preserved low halves
Co-authored-by: fxpw <fxpw@outlook.com>
This commit is contained in:
@@ -48,6 +48,7 @@ constexpr MemoryOpcodeInfo MUBUF_OPCODE_LIST[] = {
|
||||
{0x1du, Opcode::BUFFER_STORE_DWORDX2, 2, 32},
|
||||
{0x1eu, Opcode::BUFFER_STORE_DWORDX4, 4, 32},
|
||||
{0x1fu, Opcode::BUFFER_STORE_DWORDX3, 3, 32},
|
||||
{0x20u, Opcode::BUFFER_LOAD_UBYTE_D16, 1, 8},
|
||||
{0x24u, Opcode::BUFFER_LOAD_SHORT_D16, 1, 16},
|
||||
{0x25u, Opcode::BUFFER_LOAD_SHORT_D16_HI, 1, 16},
|
||||
{0x30u, Opcode::BUFFER_ATOMIC_SWAP, 1, 32},
|
||||
@@ -310,6 +311,7 @@ void DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
|
||||
inst.data_components = 4u;
|
||||
}
|
||||
if (inst.opcode == Opcode::BUFFER_LOAD_FORMAT_D16_X ||
|
||||
inst.opcode == Opcode::BUFFER_LOAD_UBYTE_D16 ||
|
||||
inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16 ||
|
||||
inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16_HI) {
|
||||
inst.dst.sdwa_sel = inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16_HI ? 5u : 4u;
|
||||
|
||||
@@ -638,6 +638,7 @@ std::string InstructionToString(const Instruction& inst) {
|
||||
case Opcode::BUFFER_STORE_FORMAT_XYZW:
|
||||
case Opcode::BUFFER_STORE_FORMAT_D16_X:
|
||||
case Opcode::BUFFER_LOAD_UBYTE:
|
||||
case Opcode::BUFFER_LOAD_UBYTE_D16:
|
||||
case Opcode::BUFFER_LOAD_USHORT:
|
||||
case Opcode::BUFFER_LOAD_SHORT_D16:
|
||||
case Opcode::BUFFER_LOAD_SHORT_D16_HI:
|
||||
|
||||
@@ -554,6 +554,7 @@ enum class Opcode {
|
||||
BUFFER_STORE_FORMAT_XYZW,
|
||||
BUFFER_STORE_FORMAT_D16_X,
|
||||
BUFFER_LOAD_UBYTE,
|
||||
BUFFER_LOAD_UBYTE_D16,
|
||||
BUFFER_LOAD_SBYTE,
|
||||
BUFFER_LOAD_USHORT,
|
||||
BUFFER_LOAD_SSHORT,
|
||||
|
||||
@@ -973,6 +973,7 @@ void Translator::EmitMemory(const Decoder::Instruction& inst) {
|
||||
}
|
||||
|
||||
case Decoder::Opcode::BUFFER_LOAD_UBYTE:
|
||||
case Decoder::Opcode::BUFFER_LOAD_UBYTE_D16:
|
||||
case Decoder::Opcode::BUFFER_LOAD_SBYTE:
|
||||
case Decoder::Opcode::BUFFER_LOAD_USHORT:
|
||||
case Decoder::Opcode::BUFFER_LOAD_SSHORT:
|
||||
|
||||
@@ -20209,6 +20209,7 @@ CoverageClass ClassifyOpcode(ShaderOpcode opcode,
|
||||
case Opcode::BUFFER_STORE_FORMAT_XYZ:
|
||||
case Opcode::BUFFER_STORE_FORMAT_XYZW:
|
||||
case Opcode::BUFFER_LOAD_UBYTE:
|
||||
case Opcode::BUFFER_LOAD_UBYTE_D16:
|
||||
case Opcode::BUFFER_LOAD_SBYTE:
|
||||
case Opcode::BUFFER_LOAD_USHORT:
|
||||
case Opcode::BUFFER_LOAD_SSHORT:
|
||||
@@ -30020,12 +30021,17 @@ TestCase BufferLoadVariants() {
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
TestCase BufferLoadShortD16Captured(bool high) {
|
||||
TestCase BufferLoadD16Captured(ShaderOpcode opcode, u32 wave_size = 32) {
|
||||
const bool high = opcode == ShaderOpcode::BUFFER_LOAD_SHORT_D16_HI;
|
||||
const bool byte = opcode == ShaderOpcode::BUFFER_LOAD_UBYTE_D16;
|
||||
TestCase test;
|
||||
test.name = high ? "BufferLoadShortD16HiCaptured" : "BufferLoadShortD16Captured";
|
||||
test.name = byte ? (wave_size == 64 ? "BufferLoadUbyteD16Captured64" : "BufferLoadUbyteD16Captured32")
|
||||
: high ? "BufferLoadShortD16HiCaptured" : "BufferLoadShortD16Captured";
|
||||
auto& code = test.code;
|
||||
const u32 data_reg = high ? 20u : 1u, index_reg = high ? 21u : 15u;
|
||||
const std::array<u32, 2> load = high ? std::array{0xe0942006u, 0x80021415u}
|
||||
const u32 data_reg = byte ? 0u : high ? 20u : 1u;
|
||||
const u32 index_reg = byte ? 3u : high ? 21u : 15u;
|
||||
const std::array<u32, 2> load = byte ? std::array{0xe080e000u, 0x80040003u}
|
||||
: high ? std::array{0xe0942006u, 0x80021415u}
|
||||
: std::array{0xe090200eu, 0x8000010fu};
|
||||
AppendVMovU32(&code, index_reg, 1);
|
||||
AppendVMovLiteral(&code, data_reg, 0xabcd1234u);
|
||||
@@ -30043,27 +30049,49 @@ TestCase BufferLoadShortD16Captured(bool high) {
|
||||
AppendVMovLiteral(&code, data_reg, 0xbeef5678u);
|
||||
code.insert(code.end(), load.begin(), load.end());
|
||||
AppendStoreVgpr(&code, data_reg, 2);
|
||||
if (byte) {
|
||||
AppendVMovU32(&code, index_reg, 1);
|
||||
for (u32 offset = 1; offset <= 3; ++offset) {
|
||||
AppendVMovLiteral(&code, data_reg, 0xa1b2ffffu);
|
||||
code.insert(code.end(), {load[0] | offset, load[1]});
|
||||
AppendStoreVgpr(&code, data_reg, 2 + offset);
|
||||
}
|
||||
code.insert(code.end(), {load[0], load[1] | (index_reg << 8u)});
|
||||
AppendStoreVgpr(&code, index_reg, 6);
|
||||
}
|
||||
AppendEnd(&code);
|
||||
const u32 stride = high ? 16u : 32u;
|
||||
test.initial.assign(high ? 12u : 20u, 0xa5a5a5a5u);
|
||||
test.initial[high ? 5u : 11u] = 0x8001cafeu;
|
||||
test.initial[byte ? 8u : high ? 5u : 11u] = byte ? 0xff007f80u : 0x8001cafeu;
|
||||
if (high) test.initial[7] = 0xcafefaceu;
|
||||
test.expected = test.initial;
|
||||
test.expected[0] = high ? 0x8001cafeu : 0xabcd8001u;
|
||||
test.expected[0] = byte ? 0xabcd0080u : high ? 0x8001cafeu : 0xabcd8001u;
|
||||
test.expected[1] = 0xdeaf4321u;
|
||||
test.expected[2] = high ? 0x00005678u : 0xbeef0000u;
|
||||
test.user_data = MakeStructuredStorageBufferData(stride, 2);
|
||||
if (high) std::copy_n(test.user_data.begin(), 4, test.user_data.begin() + 8);
|
||||
if (byte) {
|
||||
std::copy_n(test.user_data.begin(), 4, test.user_data.begin() + 16);
|
||||
test.expected[3] = 0xa1b2007fu;
|
||||
test.expected[4] = 0xa1b20000u;
|
||||
test.expected[5] = 0xa1b200ffu;
|
||||
test.expected[6] = 0x80u;
|
||||
test.compute_info.threads_num[0] = test.compute_info.threads_num[1] =
|
||||
test.compute_info.threads_num[2] = 1;
|
||||
test.compute_info.wave_size = static_cast<uint8_t>(wave_size);
|
||||
test.has_compute_info = true;
|
||||
test.required_spirv = {"Volatile"};
|
||||
}
|
||||
test.user_data[50] = static_cast<u32>(test.initial.size() * sizeof(u32));
|
||||
test.user_data[51] = 3u << 28u;
|
||||
test.has_user_data = true;
|
||||
test.storage_buffer_range_bytes = stride * 2u;
|
||||
test.opcodes = {ShaderOpcode::V_MOV_B32, ShaderOpcode::S_MOV_B64,
|
||||
ShaderOpcode::BUFFER_LOAD_SHORT_D16, ShaderOpcode::BUFFER_STORE_DWORD,
|
||||
ShaderOpcode::S_ENDPGM};
|
||||
if (high) test.opcodes.push_back(ShaderOpcode::BUFFER_LOAD_SHORT_D16_HI);
|
||||
test.decoded_counts = {{high ? "BUFFER_LOAD_SHORT_D16_HI v20.sdwa(sel=5,sext=0)"
|
||||
: "BUFFER_LOAD_SHORT_D16 v1.sdwa(sel=4,sext=0)", 3}};
|
||||
opcode, ShaderOpcode::BUFFER_STORE_DWORD, ShaderOpcode::S_ENDPGM};
|
||||
if (high) test.opcodes.push_back(ShaderOpcode::BUFFER_LOAD_SHORT_D16);
|
||||
test.decoded_counts = {{byte ? "BUFFER_LOAD_UBYTE_D16 v0.sdwa(sel=4,sext=0)"
|
||||
: high ? "BUFFER_LOAD_SHORT_D16_HI v20.sdwa(sel=5,sext=0)"
|
||||
: "BUFFER_LOAD_SHORT_D16 v1.sdwa(sel=4,sext=0)", byte ? 6u : 3u}};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -40364,7 +40392,10 @@ std::vector<TestCase> MakeCases() {
|
||||
cases.push_back(BufferOffsetsUsePackedWords(false));
|
||||
cases.push_back(BufferOffsetsUsePackedWords(true));
|
||||
AddCase(BufferLoadVariants);
|
||||
for (const bool high : {false, true}) cases.push_back(BufferLoadShortD16Captured(high));
|
||||
for (const auto opcode : {ShaderOpcode::BUFFER_LOAD_SHORT_D16, ShaderOpcode::BUFFER_LOAD_SHORT_D16_HI})
|
||||
cases.push_back(BufferLoadD16Captured(opcode));
|
||||
for (const u32 wave : {32u, 64u})
|
||||
cases.push_back(BufferLoadD16Captured(ShaderOpcode::BUFFER_LOAD_UBYTE_D16, wave));
|
||||
for (const u32 component : {4u, 2u, 0u}) {
|
||||
cases.push_back(BufferSubwordLoadsAtHostOffset(2, component, false));
|
||||
}
|
||||
@@ -46279,7 +46310,10 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--flat-d16-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
for (const bool high : {false, true}) RunCase(&vulkan, BufferLoadShortD16Captured(high));
|
||||
for (const auto opcode : {ShaderOpcode::BUFFER_LOAD_SHORT_D16, ShaderOpcode::BUFFER_LOAD_SHORT_D16_HI})
|
||||
RunCase(&vulkan, BufferLoadD16Captured(opcode));
|
||||
for (const u32 wave : {32u, 64u})
|
||||
RunCase(&vulkan, BufferLoadD16Captured(ShaderOpcode::BUFFER_LOAD_UBYTE_D16, wave));
|
||||
RunCase(&vulkan, FlatStoreSlcCaptured());
|
||||
RunCase(&vulkan, FlatLoadDlcCaptured(32));
|
||||
RunCase(&vulkan, FlatLoadDlcCaptured(64));
|
||||
|
||||
@@ -15357,6 +15357,24 @@ void TestGraphicsPushConstantPlacement() {
|
||||
CheckSpirvBinaryValidates(spill.spirv);
|
||||
}
|
||||
|
||||
void TestCapturedBufferLoadUbyteD16Decode() {
|
||||
namespace Decoder = ShaderRecompiler::Decoder;
|
||||
const uint32_t code[] = {0xe080e000u, 0x80040003u};
|
||||
Decoder::Instruction inst;
|
||||
Decoder::DecodeInstruction(code, 0, inst);
|
||||
Check(inst.opcode == Decoder::Opcode::BUFFER_LOAD_UBYTE_D16 &&
|
||||
inst.word_count == 2 && inst.data_dwords == 1 && inst.data_bits == 8 &&
|
||||
!inst.data_signed && !inst.formatted && !inst.typed,
|
||||
"captured BUFFER_LOAD_UBYTE_D16 lost its unsigned byte payload");
|
||||
Check(inst.dst.kind == Decoder::OperandKind::Vgpr && inst.dst.reg == 0 &&
|
||||
inst.dst.sdwa_sel == 4 && inst.dst.sdwa_dst_unused == 2 &&
|
||||
inst.src0.kind == Decoder::OperandKind::Vgpr && inst.src0.reg == 3 &&
|
||||
inst.src1.kind == Decoder::OperandKind::Sgpr && inst.src1.reg == 16 &&
|
||||
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_LOAD_UBYTE_D16 lost its preserved half, address, or coherence flags");
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerUnsupportedMemoryDecode() {
|
||||
const uint32_t mubuf_unknown[] = {EncodeMubuf0(0x7b), EncodeMubuf1(0, 0, 1),
|
||||
0xbf810000u};
|
||||
@@ -16040,6 +16058,7 @@ int main() {
|
||||
TestComputeLdsAllocationIdentity();
|
||||
TestPixelProgramCacheBindingIdentity();
|
||||
TestGraphicsPushConstantPlacement();
|
||||
TestCapturedBufferLoadUbyteD16Decode();
|
||||
TestNewShaderRecompilerUnsupportedMemoryDecode();
|
||||
|
||||
TestNewShaderRecompilerVop3LaneReadDestinationEncoding();
|
||||
|
||||
Reference in New Issue
Block a user