mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 05:16:56 +01:00
shader: decode every PS5 image_gather4 encoding
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
This commit is contained in:
@@ -14,12 +14,6 @@ struct MimgSampleInfo {
|
||||
uint32_t flags = 0;
|
||||
};
|
||||
|
||||
struct MimgGatherInfo {
|
||||
uint32_t encoding = 0;
|
||||
Opcode decoded = Opcode::UNSUPPORTED;
|
||||
uint32_t flags = 0;
|
||||
};
|
||||
|
||||
struct MimgAtomicInfo {
|
||||
uint32_t encoding = 0;
|
||||
Opcode decoded = Opcode::UNSUPPORTED;
|
||||
@@ -181,23 +175,72 @@ constexpr MimgSampleInfo MIMG_SAMPLE_OPCODE_LIST[] = {
|
||||
ImageSampleFlagOffset | ImageSampleFlagAdjust},
|
||||
};
|
||||
|
||||
constexpr MimgGatherInfo MIMG_GATHER_OPCODE_LIST[] = {
|
||||
{0x44u, Opcode::IMAGE_GATHER4_L, ImageSampleFlagLod},
|
||||
{0x47u, Opcode::IMAGE_GATHER4_LZ, ImageSampleFlagLevelZero},
|
||||
{0x48u, Opcode::IMAGE_GATHER4_C, ImageSampleFlagCompare},
|
||||
{0x4cu, Opcode::IMAGE_GATHER4_C_L, ImageSampleFlagCompare | ImageSampleFlagLod},
|
||||
{0x4fu, Opcode::IMAGE_GATHER4_C_LZ,
|
||||
ImageSampleFlagCompare | ImageSampleFlagLevelZero},
|
||||
{0x57u, Opcode::IMAGE_GATHER4_LZ_O,
|
||||
ImageSampleFlagLevelZero | ImageSampleFlagOffset},
|
||||
{0x58u, Opcode::IMAGE_GATHER4_C_O,
|
||||
ImageSampleFlagCompare | ImageSampleFlagOffset},
|
||||
{0x5fu, Opcode::IMAGE_GATHER4_C_LZ_O,
|
||||
constexpr MimgSampleInfo MIMG_GATHER_OPCODE_LIST[] = {
|
||||
{0x40u, "image_gather4", 0},
|
||||
{0x41u, "image_gather4_cl", ImageSampleFlagLodClamp},
|
||||
{0x44u, "image_gather4_l", ImageSampleFlagLod},
|
||||
{0x45u, "image_gather4_b", ImageSampleFlagBias},
|
||||
{0x46u, "image_gather4_b_cl", ImageSampleFlagBias | ImageSampleFlagLodClamp},
|
||||
{0x47u, "image_gather4_lz", ImageSampleFlagLevelZero},
|
||||
{0x48u, "image_gather4_c", ImageSampleFlagCompare},
|
||||
{0x49u, "image_gather4_c_cl", ImageSampleFlagCompare | ImageSampleFlagLodClamp},
|
||||
{0x4cu, "image_gather4_c_l", ImageSampleFlagCompare | ImageSampleFlagLod},
|
||||
{0x4du, "image_gather4_c_b", ImageSampleFlagCompare | ImageSampleFlagBias},
|
||||
{0x4eu, "image_gather4_c_b_cl",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagLodClamp},
|
||||
{0x4fu, "image_gather4_c_lz", ImageSampleFlagCompare | ImageSampleFlagLevelZero},
|
||||
{0x50u, "image_gather4_o", ImageSampleFlagOffset},
|
||||
{0x51u, "image_gather4_cl_o", ImageSampleFlagLodClamp | ImageSampleFlagOffset},
|
||||
{0x54u, "image_gather4_l_o", ImageSampleFlagLod | ImageSampleFlagOffset},
|
||||
{0x55u, "image_gather4_b_o", ImageSampleFlagBias | ImageSampleFlagOffset},
|
||||
{0x56u, "image_gather4_b_cl_o",
|
||||
ImageSampleFlagBias | ImageSampleFlagLodClamp | ImageSampleFlagOffset},
|
||||
{0x57u, "image_gather4_lz_o", ImageSampleFlagLevelZero | ImageSampleFlagOffset},
|
||||
{0x58u, "image_gather4_c_o", ImageSampleFlagCompare | ImageSampleFlagOffset},
|
||||
{0x59u, "image_gather4_c_cl_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLodClamp | ImageSampleFlagOffset},
|
||||
{0x5cu, "image_gather4_c_l_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLod | ImageSampleFlagOffset},
|
||||
{0x5du, "image_gather4_c_b_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagOffset},
|
||||
{0x5eu, "image_gather4_c_b_cl_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagLodClamp |
|
||||
ImageSampleFlagOffset},
|
||||
{0x5fu, "image_gather4_c_lz_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLevelZero | ImageSampleFlagOffset},
|
||||
{0x61u, Opcode::IMAGE_GATHER4H, ImageSampleFlagGatherHorizontal},
|
||||
{0xc8u, Opcode::IMAGE_GATHER4_C, ImageSampleFlagCompare | ImageSampleFlagAdjust},
|
||||
{0xd8u, Opcode::IMAGE_GATHER4_C_O,
|
||||
{0x61u, "image_gather4h", ImageSampleFlagGatherHorizontal},
|
||||
{0xc0u, "image_gather4_a", ImageSampleFlagAdjust},
|
||||
{0xc1u, "image_gather4_cl_a", ImageSampleFlagLodClamp | ImageSampleFlagAdjust},
|
||||
{0xc5u, "image_gather4_b_a", ImageSampleFlagBias | ImageSampleFlagAdjust},
|
||||
{0xc6u, "image_gather4_b_cl_a",
|
||||
ImageSampleFlagBias | ImageSampleFlagLodClamp | ImageSampleFlagAdjust},
|
||||
{0xc8u, "image_gather4_c_a", ImageSampleFlagCompare | ImageSampleFlagAdjust},
|
||||
{0xc9u, "image_gather4_c_cl_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLodClamp | ImageSampleFlagAdjust},
|
||||
{0xcdu, "image_gather4_c_b_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagAdjust},
|
||||
{0xceu, "image_gather4_c_b_cl_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagLodClamp |
|
||||
ImageSampleFlagAdjust},
|
||||
{0xd0u, "image_gather4_o_a", ImageSampleFlagOffset | ImageSampleFlagAdjust},
|
||||
{0xd1u, "image_gather4_cl_o_a",
|
||||
ImageSampleFlagLodClamp | ImageSampleFlagOffset | ImageSampleFlagAdjust},
|
||||
{0xd5u, "image_gather4_b_o_a",
|
||||
ImageSampleFlagBias | ImageSampleFlagOffset | ImageSampleFlagAdjust},
|
||||
{0xd6u, "image_gather4_b_cl_o_a",
|
||||
ImageSampleFlagBias | ImageSampleFlagLodClamp | ImageSampleFlagOffset |
|
||||
ImageSampleFlagAdjust},
|
||||
{0xd8u, "image_gather4_c_o_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagOffset | ImageSampleFlagAdjust},
|
||||
{0xd9u, "image_gather4_c_cl_o_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLodClamp | ImageSampleFlagOffset |
|
||||
ImageSampleFlagAdjust},
|
||||
{0xddu, "image_gather4_c_b_o_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagOffset |
|
||||
ImageSampleFlagAdjust},
|
||||
{0xdeu, "image_gather4_c_b_cl_o_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagLodClamp |
|
||||
ImageSampleFlagOffset | ImageSampleFlagAdjust},
|
||||
};
|
||||
|
||||
constexpr MimgAtomicInfo MIMG_ATOMIC_OPCODE_LIST[] = {
|
||||
@@ -219,13 +262,13 @@ constexpr auto MIMG_SAMPLE_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_SAMPLE_OPCO
|
||||
constexpr auto MIMG_GATHER_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_GATHER_OPCODE_LIST);
|
||||
constexpr auto MIMG_ATOMIC_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_ATOMIC_OPCODE_LIST);
|
||||
|
||||
Opcode DecodeMimgOpcode(uint32_t opcode, const MimgSampleInfo* sample, const MimgGatherInfo* gather,
|
||||
Opcode DecodeMimgOpcode(uint32_t opcode, const MimgSampleInfo* sample, const MimgSampleInfo* gather,
|
||||
const MimgAtomicInfo* atomic) {
|
||||
if (sample != nullptr) {
|
||||
return Opcode::IMAGE_SAMPLE;
|
||||
}
|
||||
if (gather != nullptr) {
|
||||
return gather->decoded;
|
||||
return Opcode::IMAGE_GATHER4;
|
||||
}
|
||||
if (atomic != nullptr) {
|
||||
return atomic->decoded;
|
||||
@@ -244,24 +287,10 @@ Opcode DecodeMimgOpcode(uint32_t opcode, const MimgSampleInfo* sample, const Mim
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DecodeMimgSampleFlags(const MimgSampleInfo* sample, const MimgGatherInfo* gather) {
|
||||
if (sample != nullptr) {
|
||||
return sample->flags;
|
||||
}
|
||||
if (gather != nullptr) {
|
||||
return gather->flags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t DecodeMimgAddressComponents(uint32_t opcode, ImageDimension dimension,
|
||||
const MimgSampleInfo* sample, const MimgGatherInfo* gather,
|
||||
const MimgAtomicInfo* atomic) {
|
||||
if (sample != nullptr) {
|
||||
return ImageSampleAddressComponents(sample->flags, dimension);
|
||||
}
|
||||
if (gather != nullptr) {
|
||||
return ImageSampleAddressComponents(gather->flags, dimension);
|
||||
const MimgSampleInfo* sampled, const MimgAtomicInfo* atomic) {
|
||||
if (sampled != nullptr) {
|
||||
return ImageSampleAddressComponents(sampled->flags, dimension);
|
||||
}
|
||||
if (atomic != nullptr) {
|
||||
return ImageCoordComponents(dimension);
|
||||
@@ -329,16 +358,17 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
const auto dimension = DecodeImageDimension((word0 >> 3u) & 0x7u);
|
||||
const uint32_t word_count = 2u + nsa_dwords;
|
||||
|
||||
const uint32_t vdata = (word1 >> 8u) & 0xffu;
|
||||
const uint32_t vaddr = word1 & 0xffu;
|
||||
const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
|
||||
const uint32_t ssamp = (word1 >> 21u) & 0x1fu;
|
||||
const bool r128 = ((word0 >> 15u) & 0x1u) != 0u;
|
||||
const bool a16 = ((word1 >> 30u) & 0x1u) != 0u;
|
||||
const bool d16 = ((word1 >> 31u) & 0x1u) != 0u;
|
||||
const auto* sample = Detail::FindOpcode(MIMG_SAMPLE_OPS, opcode);
|
||||
const auto* gather = Detail::FindOpcode(MIMG_GATHER_OPS, opcode);
|
||||
const auto* atomic = Detail::FindOpcode(MIMG_ATOMIC_OPS, opcode);
|
||||
const uint32_t vdata = (word1 >> 8u) & 0xffu;
|
||||
const uint32_t vaddr = word1 & 0xffu;
|
||||
const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
|
||||
const uint32_t ssamp = (word1 >> 21u) & 0x1fu;
|
||||
const bool r128 = ((word0 >> 15u) & 0x1u) != 0u;
|
||||
const bool a16 = ((word1 >> 30u) & 0x1u) != 0u;
|
||||
const bool d16 = ((word1 >> 31u) & 0x1u) != 0u;
|
||||
const auto* sample = Detail::FindOpcode(MIMG_SAMPLE_OPS, opcode);
|
||||
const auto* gather = Detail::FindOpcode(MIMG_GATHER_OPS, opcode);
|
||||
const auto* atomic = Detail::FindOpcode(MIMG_ATOMIC_OPS, opcode);
|
||||
const auto* sampled = sample != nullptr ? sample : gather;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word_count = word_count;
|
||||
@@ -351,11 +381,11 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
inst.data_dwords = d16 ? (inst.data_components + 1u) / 2u : inst.data_components;
|
||||
inst.glc = ((word0 >> 13u) & 1u) != 0;
|
||||
inst.slc = ((word0 >> 25u) & 1u) != 0;
|
||||
inst.image_sample_flags = DecodeMimgSampleFlags(sample, gather);
|
||||
inst.image_sample_flags = sampled != nullptr ? sampled->flags : 0u;
|
||||
if (a16) {
|
||||
inst.image_sample_flags |= ImageSampleFlagA16;
|
||||
}
|
||||
if ((sample != nullptr || gather != nullptr) && (word0 & (1u << 12u)) != 0u) {
|
||||
if (sampled != nullptr && (word0 & (1u << 12u)) != 0u) {
|
||||
inst.image_sample_flags |= ImageSampleFlagUnnormalized;
|
||||
}
|
||||
inst.image_dimension = dimension;
|
||||
@@ -364,8 +394,7 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
for (uint32_t i = 0; i < nsa_dwords * 4u; i++) {
|
||||
inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu;
|
||||
}
|
||||
inst.image_address_components =
|
||||
DecodeMimgAddressComponents(opcode, dimension, sample, gather, atomic);
|
||||
inst.image_address_components = DecodeMimgAddressComponents(opcode, dimension, sampled, atomic);
|
||||
SetRawWords(inst, code, word_index, word_count);
|
||||
|
||||
if (inst.opcode == Opcode::UNSUPPORTED) {
|
||||
@@ -389,8 +418,8 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
}
|
||||
}
|
||||
}
|
||||
const bool supports_d16 = sample != nullptr || gather != nullptr || opcode == 0x00u ||
|
||||
opcode == 0x01u || opcode == 0x08u || opcode == 0x09u;
|
||||
const bool supports_d16 = sampled != nullptr || opcode == 0x00u || opcode == 0x01u ||
|
||||
opcode == 0x08u || opcode == 0x09u;
|
||||
if (d16 && !supports_d16) {
|
||||
SetUnsupported(inst, Family::MIMG, opcode, "MIMG opcode does not support D16 data");
|
||||
}
|
||||
@@ -407,9 +436,10 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
inst.src_count = 3;
|
||||
}
|
||||
|
||||
const char* MimgSampleOpcodeName(uint32_t opcode) {
|
||||
const auto* sample = Detail::FindOpcode(MIMG_SAMPLE_OPS, opcode);
|
||||
return sample != nullptr ? sample->name : nullptr;
|
||||
const char* MimgSampledOpcodeName(uint32_t opcode) {
|
||||
const auto* sample = Detail::FindOpcode(MIMG_SAMPLE_OPS, opcode);
|
||||
const auto* sampled = sample != nullptr ? sample : Detail::FindOpcode(MIMG_GATHER_OPS, opcode);
|
||||
return sampled != nullptr ? sampled->name : nullptr;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst);
|
||||
|
||||
const char* MimgSampleOpcodeName(uint32_t opcode);
|
||||
const char* MimgSampledOpcodeName(uint32_t opcode);
|
||||
|
||||
struct ImageAddressComponent {
|
||||
uint32_t bit_offset;
|
||||
|
||||
@@ -123,10 +123,9 @@ std::string ImageSampleFlagsToString(uint32_t flags) {
|
||||
}
|
||||
|
||||
std::string FormatMimg(const Instruction& inst) {
|
||||
const char* sample_name =
|
||||
inst.opcode == Opcode::IMAGE_SAMPLE ? MimgSampleOpcodeName(inst.opcode_id) : nullptr;
|
||||
const char* sampled_name = MimgSampledOpcodeName(inst.opcode_id);
|
||||
const std::string_view name =
|
||||
sample_name != nullptr ? sample_name : magic_enum::enum_name(inst.opcode);
|
||||
sampled_name != nullptr ? sampled_name : magic_enum::enum_name(inst.opcode);
|
||||
std::string text =
|
||||
fmt::format("0x{:08x}: {} {}, {}, {}, {} ; dmask=0x{:x} image_dim={}", inst.pc, name,
|
||||
OperandToString(inst.dst).c_str(), OperandToString(inst.src0).c_str(),
|
||||
@@ -138,22 +137,10 @@ std::string FormatMimg(const Instruction& inst) {
|
||||
if (inst.image_r128) {
|
||||
text += " r128=1";
|
||||
}
|
||||
switch (inst.opcode) {
|
||||
case Opcode::IMAGE_SAMPLE:
|
||||
case Opcode::IMAGE_GATHER4_L:
|
||||
case Opcode::IMAGE_GATHER4_LZ:
|
||||
case Opcode::IMAGE_GATHER4_C:
|
||||
case Opcode::IMAGE_GATHER4_C_L:
|
||||
case Opcode::IMAGE_GATHER4_C_LZ:
|
||||
case Opcode::IMAGE_GATHER4_LZ_O:
|
||||
case Opcode::IMAGE_GATHER4_C_O:
|
||||
case Opcode::IMAGE_GATHER4_C_LZ_O:
|
||||
case Opcode::IMAGE_GATHER4H:
|
||||
text += fmt::format(" sample_flags={} addr_components={}",
|
||||
ImageSampleFlagsToString(inst.image_sample_flags).c_str(),
|
||||
inst.image_address_components);
|
||||
break;
|
||||
default: break;
|
||||
if (sampled_name != nullptr) {
|
||||
text += fmt::format(" sample_flags={} addr_components={}",
|
||||
ImageSampleFlagsToString(inst.image_sample_flags).c_str(),
|
||||
inst.image_address_components);
|
||||
}
|
||||
if (inst.image_nsa_dwords != 0) {
|
||||
text += fmt::format(" nsa_dwords={} nsa_addr=", inst.image_nsa_dwords);
|
||||
@@ -616,15 +603,7 @@ std::string InstructionToString(const Instruction& inst) {
|
||||
case Opcode::IMAGE_LOAD_MIP:
|
||||
case Opcode::IMAGE_GET_RESINFO:
|
||||
case Opcode::IMAGE_GET_LOD:
|
||||
case Opcode::IMAGE_GATHER4_L:
|
||||
case Opcode::IMAGE_GATHER4_LZ:
|
||||
case Opcode::IMAGE_GATHER4_C:
|
||||
case Opcode::IMAGE_GATHER4_C_L:
|
||||
case Opcode::IMAGE_GATHER4_C_LZ:
|
||||
case Opcode::IMAGE_GATHER4_LZ_O:
|
||||
case Opcode::IMAGE_GATHER4_C_O:
|
||||
case Opcode::IMAGE_GATHER4_C_LZ_O:
|
||||
case Opcode::IMAGE_GATHER4H: return WithUnsupportedReason(inst, FormatMimg(inst));
|
||||
case Opcode::IMAGE_GATHER4: return WithUnsupportedReason(inst, FormatMimg(inst));
|
||||
case Opcode::S_LOAD_DWORD:
|
||||
case Opcode::S_LOAD_DWORDX2:
|
||||
case Opcode::S_LOAD_DWORDX4:
|
||||
|
||||
@@ -708,15 +708,7 @@ enum class Opcode {
|
||||
IMAGE_ATOMIC_FMIN,
|
||||
IMAGE_ATOMIC_FMAX,
|
||||
IMAGE_SAMPLE,
|
||||
IMAGE_GATHER4_L,
|
||||
IMAGE_GATHER4_LZ,
|
||||
IMAGE_GATHER4_C,
|
||||
IMAGE_GATHER4_C_L,
|
||||
IMAGE_GATHER4_C_LZ,
|
||||
IMAGE_GATHER4_LZ_O,
|
||||
IMAGE_GATHER4_C_O,
|
||||
IMAGE_GATHER4_C_LZ_O,
|
||||
IMAGE_GATHER4H,
|
||||
IMAGE_GATHER4,
|
||||
V_INTERP_P1_F32,
|
||||
V_INTERP_P2_F32,
|
||||
V_INTERP_MOV_F32,
|
||||
|
||||
@@ -1166,15 +1166,7 @@ void Translator::EmitMemory(const Decoder::Instruction& inst) {
|
||||
case Decoder::Opcode::IMAGE_STORE:
|
||||
case Decoder::Opcode::IMAGE_STORE_MIP: return IMAGE_STORE(inst);
|
||||
case Decoder::Opcode::IMAGE_SAMPLE: return IMAGE_SAMPLE(inst);
|
||||
case Decoder::Opcode::IMAGE_GATHER4_L:
|
||||
case Decoder::Opcode::IMAGE_GATHER4_LZ:
|
||||
case Decoder::Opcode::IMAGE_GATHER4_C:
|
||||
case Decoder::Opcode::IMAGE_GATHER4_C_L:
|
||||
case Decoder::Opcode::IMAGE_GATHER4_C_LZ:
|
||||
case Decoder::Opcode::IMAGE_GATHER4_LZ_O:
|
||||
case Decoder::Opcode::IMAGE_GATHER4_C_O:
|
||||
case Decoder::Opcode::IMAGE_GATHER4_C_LZ_O:
|
||||
case Decoder::Opcode::IMAGE_GATHER4H: return IMAGE_GATHER(inst);
|
||||
case Decoder::Opcode::IMAGE_GATHER4: return IMAGE_GATHER(inst);
|
||||
|
||||
case Decoder::Opcode::DS_MIN_F32:
|
||||
return DS_ATOMIC(inst, IR::ValueOpcode::SharedAtomicFMin32, false);
|
||||
|
||||
@@ -1723,7 +1723,7 @@ CompiledShader CompileCase(const TestCase &test, u32 host_subgroup_size = 64) {
|
||||
const auto uses_image =
|
||||
std::any_of(test.opcodes.begin(), test.opcodes.end(), [](auto op) {
|
||||
return op >= ShaderOpcode::IMAGE_GET_RESINFO &&
|
||||
op <= ShaderOpcode::IMAGE_GATHER4H;
|
||||
op <= ShaderOpcode::IMAGE_GATHER4;
|
||||
});
|
||||
if (uses_image && ((user_data[3] >> 28u) & 0xfu) == 0) {
|
||||
user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u;
|
||||
@@ -14132,7 +14132,7 @@ public:
|
||||
test.initial.assign(test.expected.size(), 0xdeadbeefu);
|
||||
test.expected_mip_descriptors = 2u;
|
||||
test.required_spirv = {"OpImageDrefGather", "OpSwitch"};
|
||||
test.decoded_counts = {{"IMAGE_GATHER4_C_L", 6u}};
|
||||
test.decoded_counts = {{"image_gather4_c_l", 6u}};
|
||||
const auto compiled = CompileCase(test, SubgroupSize());
|
||||
Require(test.name, "comparison mip resource", compiled.program.info.images.size() == 1u &&
|
||||
compiled.program.info.images[0].depth_compare,
|
||||
@@ -22771,13 +22771,7 @@ CoverageClass ClassifyOpcode(ShaderOpcode opcode,
|
||||
case Opcode::IMAGE_ATOMIC_FMIN:
|
||||
case Opcode::IMAGE_ATOMIC_FMAX:
|
||||
case Opcode::IMAGE_SAMPLE:
|
||||
case Opcode::IMAGE_GATHER4_LZ:
|
||||
case Opcode::IMAGE_GATHER4_C:
|
||||
case Opcode::IMAGE_GATHER4_C_L:
|
||||
case Opcode::IMAGE_GATHER4_C_LZ:
|
||||
case Opcode::IMAGE_GATHER4_LZ_O:
|
||||
case Opcode::IMAGE_GATHER4_C_O:
|
||||
case Opcode::IMAGE_GATHER4_C_LZ_O:
|
||||
case Opcode::IMAGE_GATHER4:
|
||||
return CoverageClass::NeedsImageCase;
|
||||
|
||||
case Opcode::V_INTERP_P1_F32:
|
||||
@@ -39002,7 +38996,7 @@ TestCase ImageSamplePackedUintConvertsSampleAndGather() {
|
||||
test.code = std::move(code);
|
||||
test.expected = {0x2abu, 0x456u, 0x321u, 0x321u,
|
||||
0x456u, 0x456u, 0x456u, 0x456u};
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_SAMPLE, O::IMAGE_GATHER4_LZ,
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_SAMPLE, O::IMAGE_GATHER4,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.sampled_image_rgba = std::vector<u32>(16, 0xaae2b321u);
|
||||
test.sampled_image_format = vk::Format::eR32Uint;
|
||||
@@ -39144,7 +39138,7 @@ template <bool rg, bool snorm = false> TestCase ImageSamplePacked8() {
|
||||
for (float value : expected) {
|
||||
test.expected.push_back(std::bit_cast<u32>(value));
|
||||
}
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_SAMPLE, O::IMAGE_GATHER4_LZ,
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_SAMPLE, O::IMAGE_GATHER4,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
return test;
|
||||
}
|
||||
@@ -39262,7 +39256,7 @@ TestCase ImageGather2DInstructionWith1DDescriptor() {
|
||||
test.name = "ImageGather2DInstructionWith1DDescriptor";
|
||||
test.code = code;
|
||||
test.expected = {0x40000000u, 0x40400000u, 0x40400000u, 0x40000000u};
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4_LZ, O::BUFFER_STORE_DWORD,
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.image_width = 4;
|
||||
test.image_height = 1;
|
||||
@@ -39531,9 +39525,8 @@ TestCase ImageSampleAndGather() {
|
||||
0x3f800000u,
|
||||
0};
|
||||
test.opcodes = {
|
||||
O::V_MOV_B32, O::IMAGE_SAMPLE, O::IMAGE_GET_LOD,
|
||||
O::IMAGE_GATHER4_LZ, O::IMAGE_GATHER4_LZ_O, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
O::V_MOV_B32, O::IMAGE_SAMPLE, O::IMAGE_GET_LOD, O::IMAGE_GATHER4,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.sampled_image_rgba = image;
|
||||
return test;
|
||||
}
|
||||
@@ -39601,7 +39594,7 @@ TestCase ImageGatherExplicitLod() {
|
||||
TestCase test;
|
||||
test.name = "ImageGatherExplicitLod";
|
||||
test.code = std::move(code);
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4_L, O::IMAGE_SAMPLE,
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4, O::IMAGE_SAMPLE,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
// A gather's single-mip descriptors must not replace the ordinary sample's
|
||||
// full mip chain when both instructions use the same guest descriptor.
|
||||
@@ -39726,7 +39719,7 @@ template <u32 mode> TestCase ImageGatherLodPerLane() {
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.opcodes = {O::V_MOV_B32, O::V_LSHLREV_B32, O::BUFFER_LOAD_DWORD,
|
||||
O::IMAGE_GATHER4_L, O::V_ADD_NC_U32, O::BUFFER_STORE_DWORD,
|
||||
O::IMAGE_GATHER4, O::V_ADD_NC_U32, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32_32_32_32Float);
|
||||
test.user_data[1] |= (3u << 30u) | (mode == 3 ? 768u << 8u : 0u);
|
||||
@@ -39778,7 +39771,7 @@ TestCase ImageD16GatherPacksHalfPairs() {
|
||||
test.name = "ImageD16GatherPacksHalfPairs";
|
||||
test.code = code;
|
||||
test.expected = {0x38003800u, 0x38003800u};
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4_LZ, O::BUFFER_STORE_DWORD,
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.sampled_image_rgba = image;
|
||||
test.decoded_counts = {{"d16=1", 1}};
|
||||
@@ -40022,6 +40015,63 @@ TestCase ImageSampleA16CompareBiasRdna2AddressOrder() {
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase ImageGatherAddressVariants() {
|
||||
using O = ShaderOpcode;
|
||||
struct Gather {
|
||||
u32 opcode;
|
||||
bool offset;
|
||||
bool bias;
|
||||
bool lod_or_clamp;
|
||||
};
|
||||
// Plain, LOD clamp, bias, LOD and offset gathers, with and without gradient adjust.
|
||||
constexpr Gather gathers[] = {
|
||||
{0x40, false, false, false}, {0x41, false, false, true},
|
||||
{0x45, false, true, false}, {0x46, false, true, true},
|
||||
{0x50, true, false, false}, {0x51, true, false, true},
|
||||
{0x54, true, false, true}, {0x55, true, true, false},
|
||||
{0x56, true, true, true}, {0xc0, false, false, false},
|
||||
{0xc1, false, false, true}, {0xc5, false, true, false},
|
||||
{0xc6, false, true, true}, {0xd0, true, false, false},
|
||||
{0xd1, true, false, true}, {0xd5, true, true, false},
|
||||
{0xd6, true, true, true},
|
||||
};
|
||||
const auto texel = [](u32 x, u32 y) { return std::bit_cast<u32>(float(1u + x + y * 4u)); };
|
||||
auto image = MakeRgbaImage(4, 4);
|
||||
for (u32 y = 0; y < 4u; y++) {
|
||||
for (u32 x = 0; x < 4u; x++) {
|
||||
SetRgbaPixel(&image, 4, x, y, texel(x, y), 0, 0, 0);
|
||||
}
|
||||
}
|
||||
TestCase test;
|
||||
test.name = "ImageGatherAddressVariants";
|
||||
for (u32 index = 0; index < std::size(gathers); index++) {
|
||||
const auto &gather = gathers[index];
|
||||
// Zero bias, clamp and LOD keep the base level; a misplaced offset or bias moves the footprint.
|
||||
u32 vaddr = 20;
|
||||
if (gather.offset) AppendVMovU32(&test.code, vaddr++, 0x3fu); // x offset -1
|
||||
if (gather.bias) AppendVMovU32(&test.code, vaddr++, 0);
|
||||
AppendVMovLiteral(&test.code, vaddr++, std::bit_cast<u32>(0.6875f));
|
||||
AppendVMovLiteral(&test.code, vaddr++, std::bit_cast<u32>(0.4375f));
|
||||
if (gather.lod_or_clamp) AppendVMovU32(&test.code, vaddr++, 0);
|
||||
test.code.push_back(EncodeMimg0(gather.opcode, 0x1));
|
||||
test.code.push_back(EncodeMimg1(0, 20));
|
||||
for (u32 component = 0; component < 4u; component++) {
|
||||
AppendStoreVgpr(&test.code, component, index * 4u + component);
|
||||
}
|
||||
// Footprint x 2..3, y 1..2, or x 1..2 with the offset, in (x0, y1), (x1, y1), (x1, y0),
|
||||
// (x0, y0) order.
|
||||
const u32 x0 = gather.offset ? 1u : 2u;
|
||||
for (const auto [x, y] : {std::pair{x0, 2u}, {x0 + 1u, 2u}, {x0 + 1u, 1u}, {x0, 1u}}) {
|
||||
test.expected.push_back(texel(x, y));
|
||||
}
|
||||
}
|
||||
AppendEnd(&test.code);
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.sampled_image_rgba = image;
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase ImageGatherCompareOpcodes() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -40052,15 +40102,21 @@ TestCase ImageGatherCompareOpcodes() {
|
||||
AppendStoreVgpr(&code, 8, 1);
|
||||
AppendStoreVgpr(&code, 0, 2);
|
||||
AppendStoreVgpr(&code, 12, 3);
|
||||
// The other compare gathers.
|
||||
constexpr u32 variants[] = {0x49, 0x4c, 0x4d, 0x4e, 0x59, 0x5c, 0x5d, 0x5e,
|
||||
0xc8, 0xc9, 0xcd, 0xce, 0xd8, 0xd9, 0xdd, 0xde};
|
||||
for (u32 index = 0; index < std::size(variants); index++) {
|
||||
code.push_back(EncodeMimg0(variants[index], 0x1));
|
||||
code.push_back(EncodeMimg1(40, 20));
|
||||
AppendStoreVgpr(&code, 40, 4u + index);
|
||||
}
|
||||
AppendEnd(&code);
|
||||
|
||||
TestCase test;
|
||||
test.name = "ImageGatherCompareOpcodes";
|
||||
test.code = code;
|
||||
test.opcodes = {
|
||||
O::V_MOV_B32, O::IMAGE_GATHER4_C, O::IMAGE_GATHER4_C_LZ,
|
||||
O::IMAGE_GATHER4_C_O, O::IMAGE_GATHER4_C_LZ_O, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.required_spirv = {"OpImageDrefGather", "ConstOffset"};
|
||||
test.forbidden_spirv = {"OpBitFieldSExtract"};
|
||||
test.compile_only = true;
|
||||
@@ -45822,6 +45878,7 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(ImageGetResinfoDmaskWidthHeight);
|
||||
AddCase(ImageGetResinfoDmaskMipLevels);
|
||||
AddCase(ImageSampleAndGather);
|
||||
AddCase(ImageGatherAddressVariants);
|
||||
AddCase(ImageCubeGradientsPreserveDerivatives);
|
||||
AddCase(ImageGatherExplicitLod);
|
||||
AddCase(ImageSampleLodClamp);
|
||||
@@ -52321,6 +52378,7 @@ int main(int argc, char **argv) {
|
||||
RunCase(&vulkan, ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu<32>());
|
||||
RunCase(&vulkan, ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu<64>());
|
||||
RunCase(&vulkan, ImageSampleAndGather());
|
||||
RunCase(&vulkan, ImageGatherAddressVariants());
|
||||
RunCase(nullptr, ImageGatherCompareOpcodes());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4715,6 +4715,73 @@ void TestImageAtomicWidthDecoder() {
|
||||
}
|
||||
}
|
||||
|
||||
void TestImageGatherDecoder() {
|
||||
using namespace ShaderRecompiler::Decoder;
|
||||
struct Gather {
|
||||
uint32_t opcode;
|
||||
const char *name;
|
||||
uint32_t address_vgprs;
|
||||
};
|
||||
// Every PS5 image_gather4 encoding, with the vaddr VGPR count of its 2D full-float form.
|
||||
constexpr Gather gathers[] = {
|
||||
{0x40, "image_gather4", 2}, {0x41, "image_gather4_cl", 3},
|
||||
{0x44, "image_gather4_l", 3}, {0x45, "image_gather4_b", 3},
|
||||
{0x46, "image_gather4_b_cl", 4}, {0x47, "image_gather4_lz", 2},
|
||||
{0x48, "image_gather4_c", 3}, {0x49, "image_gather4_c_cl", 4},
|
||||
{0x4c, "image_gather4_c_l", 4}, {0x4d, "image_gather4_c_b", 4},
|
||||
{0x4e, "image_gather4_c_b_cl", 5}, {0x4f, "image_gather4_c_lz", 3},
|
||||
{0x50, "image_gather4_o", 3}, {0x51, "image_gather4_cl_o", 4},
|
||||
{0x54, "image_gather4_l_o", 4}, {0x55, "image_gather4_b_o", 4},
|
||||
{0x56, "image_gather4_b_cl_o", 5}, {0x57, "image_gather4_lz_o", 3},
|
||||
{0x58, "image_gather4_c_o", 4}, {0x59, "image_gather4_c_cl_o", 5},
|
||||
{0x5c, "image_gather4_c_l_o", 5}, {0x5d, "image_gather4_c_b_o", 5},
|
||||
{0x5e, "image_gather4_c_b_cl_o", 6}, {0x5f, "image_gather4_c_lz_o", 4},
|
||||
{0x61, "image_gather4h", 2}, {0xc0, "image_gather4_a", 2},
|
||||
{0xc1, "image_gather4_cl_a", 3}, {0xc5, "image_gather4_b_a", 3},
|
||||
{0xc6, "image_gather4_b_cl_a", 4}, {0xc8, "image_gather4_c_a", 3},
|
||||
{0xc9, "image_gather4_c_cl_a", 4}, {0xcd, "image_gather4_c_b_a", 4},
|
||||
{0xce, "image_gather4_c_b_cl_a", 5}, {0xd0, "image_gather4_o_a", 3},
|
||||
{0xd1, "image_gather4_cl_o_a", 4}, {0xd5, "image_gather4_b_o_a", 4},
|
||||
{0xd6, "image_gather4_b_cl_o_a", 5}, {0xd8, "image_gather4_c_o_a", 4},
|
||||
{0xd9, "image_gather4_c_cl_o_a", 5}, {0xdd, "image_gather4_c_b_o_a", 5},
|
||||
{0xde, "image_gather4_c_b_cl_o_a", 6},
|
||||
};
|
||||
const auto expected_flags = [](std::string_view name) {
|
||||
if (name == "image_gather4h") return uint32_t{ImageSampleFlagGatherHorizontal};
|
||||
uint32_t flags = 0;
|
||||
for (size_t at = name.find('_', 6); at != std::string_view::npos;) {
|
||||
const auto end = name.find('_', at + 1);
|
||||
const auto modifier = name.substr(at + 1, end - at - 1);
|
||||
if (modifier == "c") flags |= ImageSampleFlagCompare;
|
||||
if (modifier == "b") flags |= ImageSampleFlagBias;
|
||||
if (modifier == "cl") flags |= ImageSampleFlagLodClamp;
|
||||
if (modifier == "l") flags |= ImageSampleFlagLod;
|
||||
if (modifier == "lz") flags |= ImageSampleFlagLevelZero;
|
||||
if (modifier == "o") flags |= ImageSampleFlagOffset;
|
||||
if (modifier == "a") flags |= ImageSampleFlagAdjust;
|
||||
at = end;
|
||||
}
|
||||
return flags;
|
||||
};
|
||||
for (uint32_t opcode = 0; opcode < 0x100u; ++opcode) {
|
||||
const auto *gather = std::ranges::find(gathers, opcode, &Gather::opcode);
|
||||
const uint32_t words[] = {EncodeMimg0(opcode, 0x1), EncodeMimg1(8, 0, 1, 0)};
|
||||
Instruction decoded;
|
||||
DecodeInstruction(words, 0, decoded);
|
||||
if (gather == std::end(gathers)) {
|
||||
Check(decoded.opcode != Opcode::IMAGE_GATHER4,
|
||||
"a non-gather MIMG encoding decoded as image_gather4");
|
||||
continue;
|
||||
}
|
||||
Check(decoded.opcode == Opcode::IMAGE_GATHER4 && decoded.data_components == 4u &&
|
||||
decoded.image_sample_flags == expected_flags(gather->name) &&
|
||||
decoded.image_address_components == gather->address_vgprs &&
|
||||
InstructionToString(decoded).find(std::string(gather->name) + " ") !=
|
||||
std::string::npos,
|
||||
"a PS5 gather encoding lost its opcode, name, modifiers or address count");
|
||||
}
|
||||
}
|
||||
|
||||
void TestNewShaderDecoderArchitecture() {
|
||||
using namespace ShaderRecompiler::Decoder;
|
||||
|
||||
@@ -5657,7 +5724,7 @@ void TestImageAddressOperands() {
|
||||
const uint32_t captured[] = {0xf130010au, 0x00a30013u, 0x00161a19u};
|
||||
Decoder::Instruction gather;
|
||||
Decoder::DecodeInstruction(captured, 0, gather);
|
||||
Check(gather.opcode == Decoder::Opcode::IMAGE_GATHER4_C_L &&
|
||||
Check(gather.opcode == Decoder::Opcode::IMAGE_GATHER4 &&
|
||||
gather.opcode_id == 0x4cu && gather.word_count == 3u &&
|
||||
gather.image_dimension == Decoder::ImageDimension::Dim2D &&
|
||||
gather.dmask == 1u && gather.data_components == 4u &&
|
||||
@@ -5671,7 +5738,7 @@ void TestImageAddressOperands() {
|
||||
gather.image_nsa_addr[2] == 22u && !gather.glc && !gather.slc &&
|
||||
!gather.image_r128,
|
||||
"captured IMAGE_GATHER4_C_L lost compare/LOD, NSA, or result metadata");
|
||||
Check(Decoder::InstructionToString(gather).find("IMAGE_GATHER4_C_L") != std::string::npos,
|
||||
Check(Decoder::InstructionToString(gather).find("image_gather4_c_l") != std::string::npos,
|
||||
"captured IMAGE_GATHER4_C_L is missing from the decoded dump");
|
||||
struct Case {
|
||||
uint32_t opcode;
|
||||
@@ -17022,6 +17089,7 @@ int main() {
|
||||
// here.
|
||||
TestScalarAshrI64Decoder();
|
||||
TestImageAtomicWidthDecoder();
|
||||
TestImageGatherDecoder();
|
||||
TestDsReturningAtomic64Decoder();
|
||||
TestDsCompareStore32Decoder();
|
||||
TestDsFloatMinMaxDecoder();
|
||||
|
||||
Reference in New Issue
Block a user