#include "Translation/TranslationContext.hpp" #include "RdnaDecoder/RdnaImageOpDecoder.hpp" #include #include #include using namespace ShaderRecompiler; static void Require(bool value) { if (!value) throw std::runtime_error("image msaa load regression"); } static std::uint32_t Word0(std::uint32_t dmask, std::uint32_t dimension) { return (0x3cu << 26u) | (dmask << 8u) | (dimension << 3u) | 1u; } static RdnaInstruction Decode(std::uint32_t word0, std::uint32_t word1) { const std::array code{word0, word1}; return DecodeRdnaMimg(0u, code, 0u); } static bool Rejects(std::uint32_t word0, std::uint32_t word1) { try { (void)Decode(word0, word1); } catch (const std::runtime_error&) { return true; } return false; } static void Check(std::uint32_t dimension, bool a16, std::uint32_t components, std::uint32_t fragmentDword, std::uint32_t fragmentShift) { const RdnaInstruction instruction = Decode(Word0(0x4u, dimension), (a16 ? 0x40000000u : 0u) | (8u << 8u)); Require(instruction.op == RdnaOpcode::ImageMsaaLoad); Require(instruction.family == RdnaInstructionFamily::MIMG); Require(IsImageOpcode(instruction.op)); Require(instruction.imageOpcodeId == 0x80u); Require(instruction.imageAddressComponents == components); Require(instruction.dataComponents == 4u); Require(instruction.dataDwordCount == 4u); IrProgram program; auto& block = program.CreateBlock(); program.SetEntryBlock(block); TranslationContext context(program, block, 256); context.TranslateInstruction(instruction); std::vector reads; for (auto* value : block.Instructions()) { if (value->Opcode() == IrOpcode::ImageRead) { reads.push_back(value); } } Require(reads.size() == 4u); for (std::uint32_t fragment = 0u; fragment < 4u; ++fragment) { IrValue* address = reads[fragment]->Argument(1)->Resolve(); Require(address->Opcode() == IrOpcode::MakeImageAddress); IrValue* word = address->Argument(fragmentDword)->Resolve(); if (fragment == 0u) { Require(word->Opcode() != IrOpcode::IAdd32); continue; } Require(word->Opcode() == IrOpcode::IAdd32); IrValue* offset = word->Argument(1)->Resolve(); Require(offset->HasImmediate() && offset->ImmediateU32() == fragment << fragmentShift); const auto& memory = program.Resources().memoryInfo[reads[fragment]->Flags().index]; Require(memory.dmask == 0x4u && memory.dataDwords == 1u); } } int main() { Check(6u, false, 3u, 2u, 0u); Check(7u, false, 4u, 3u, 0u); Check(6u, true, 3u, 1u, 0u); Check(7u, true, 4u, 1u, 16u); Require(Rejects(Word0(0x1u, 1u), 0u)); Require(Rejects(Word0(0x3u, 6u), 0u)); Require(Rejects(Word0(0x1u, 6u), 0x80000000u)); Require(Rejects(Word0(0x1u, 6u) | 0x00010000u, 0u)); }