mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
graphics: cleanup
This commit is contained in:
@@ -212,6 +212,62 @@ const MimgAtomicInfo* LookupAtomic(uint32_t opcode) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Opcode DecodeMimgOpcode(uint32_t opcode, const MimgSampleInfo* sample, const MimgGatherInfo* gather,
|
||||
const MimgAtomicInfo* atomic) {
|
||||
if (sample != nullptr) {
|
||||
return Opcode::ImageSample;
|
||||
}
|
||||
if (gather != nullptr) {
|
||||
return gather->decoded;
|
||||
}
|
||||
if (atomic != nullptr) {
|
||||
return atomic->decoded;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case 0x00u: return Opcode::ImageLoad;
|
||||
case 0x01u: return Opcode::ImageLoadMip;
|
||||
case 0x08u: return Opcode::ImageStore;
|
||||
case 0x09u: return Opcode::ImageStoreMip;
|
||||
case 0x0eu: return Opcode::ImageGetResinfo;
|
||||
case 0x60u: return Opcode::ImageGetLod;
|
||||
default: return Opcode::Unsupported;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (atomic != nullptr) {
|
||||
return 3u;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case 0x01u:
|
||||
case 0x09u: return ImageCoordComponents(dimension) + 1u;
|
||||
case 0x00u:
|
||||
case 0x08u:
|
||||
case 0x60u: return ImageCoordComponents(dimension);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t CountDmaskComponents(uint32_t dmask) {
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < 4u; i++) {
|
||||
@@ -262,39 +318,22 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
inst.word_count = word_count;
|
||||
inst.family = Family::MIMG;
|
||||
inst.opcode_id = opcode;
|
||||
inst.opcode = (sample != nullptr ? Opcode::ImageSample
|
||||
: gather != nullptr ? gather->decoded
|
||||
: atomic != nullptr ? atomic->decoded
|
||||
: opcode == 0x00u ? Opcode::ImageLoad
|
||||
: opcode == 0x01u ? Opcode::ImageLoadMip
|
||||
: opcode == 0x08u ? Opcode::ImageStore
|
||||
: opcode == 0x09u ? Opcode::ImageStoreMip
|
||||
: opcode == 0x0eu ? Opcode::ImageGetResinfo
|
||||
: opcode == 0x60u ? Opcode::ImageGetLod
|
||||
: Opcode::Unsupported);
|
||||
inst.opcode = DecodeMimgOpcode(opcode, sample, gather, atomic);
|
||||
inst.dmask = (word0 >> 8u) & 0xfu;
|
||||
inst.data_dwords = gather != nullptr ? 4u : CountDmaskComponents(inst.dmask);
|
||||
inst.glc = ((word0 >> 13u) & 1u) != 0;
|
||||
inst.slc = ((word0 >> 25u) & 1u) != 0;
|
||||
inst.image_sample_flags = (sample != nullptr ? sample->flags
|
||||
: gather != nullptr ? gather->flags
|
||||
: 0u) |
|
||||
(a16 ? ImageSampleFlagA16 : 0u);
|
||||
inst.image_dimension = dimension;
|
||||
inst.image_nsa_dwords = nsa_dwords;
|
||||
inst.image_sample_flags = DecodeMimgSampleFlags(sample, gather);
|
||||
if (a16) {
|
||||
inst.image_sample_flags |= ImageSampleFlagA16;
|
||||
}
|
||||
inst.image_dimension = dimension;
|
||||
inst.image_nsa_dwords = nsa_dwords;
|
||||
for (uint32_t i = 0; i < nsa_dwords * 4u && i < MaxImageNsaAddressComponents; i++) {
|
||||
inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu;
|
||||
}
|
||||
inst.image_address_components =
|
||||
sample != nullptr ? ImageSampleAddressComponents(sample->flags, dimension)
|
||||
: gather != nullptr ? ImageSampleAddressComponents(gather->flags, dimension)
|
||||
: atomic != nullptr ? 3u
|
||||
: opcode == 0x60u ? ImageCoordComponents(dimension)
|
||||
: opcode == 0x01u ? ImageCoordComponents(dimension) + 1u
|
||||
: opcode == 0x00u ? ImageCoordComponents(dimension)
|
||||
: (opcode == 0x09u ? ImageCoordComponents(dimension) + 1u
|
||||
: opcode == 0x08u ? ImageCoordComponents(dimension)
|
||||
: 0u);
|
||||
DecodeMimgAddressComponents(opcode, dimension, sample, gather, atomic);
|
||||
SetRawWords(inst, code, word_index, word_count);
|
||||
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
@@ -318,14 +357,4 @@ const char* MimgSampleOpcodeName(uint32_t opcode) {
|
||||
return sample != nullptr ? sample->name : nullptr;
|
||||
}
|
||||
|
||||
uint32_t MimgSampleOpcodeFlags(uint32_t opcode) {
|
||||
const auto* sample = LookupSample(opcode);
|
||||
return sample != nullptr ? sample->flags : 0u;
|
||||
}
|
||||
|
||||
uint32_t MimgSampleAddressComponents(uint32_t opcode) {
|
||||
const auto* sample = LookupSample(opcode);
|
||||
return sample != nullptr ? sample->address_components : 0u;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
@@ -9,8 +9,6 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
std::string* error);
|
||||
|
||||
const char* MimgSampleOpcodeName(uint32_t opcode);
|
||||
uint32_t MimgSampleOpcodeFlags(uint32_t opcode);
|
||||
uint32_t MimgSampleAddressComponents(uint32_t opcode);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
|
||||
}
|
||||
|
||||
bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
|
||||
ResourceSnapshot& snapshot, std::string* error) {
|
||||
ResourceSnapshot& snapshot, std::string* error) {
|
||||
if (!program.resource_tracking_complete) {
|
||||
if (error != nullptr) {
|
||||
*error = "shader resources were not tracked";
|
||||
@@ -256,10 +256,12 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
|
||||
base &= ~uint64_t {3};
|
||||
}
|
||||
const auto before = static_cast<uint64_t>(-static_cast<int64_t>(address.min_offset));
|
||||
const auto binding_base = address.kind == ResourceKind::Flat
|
||||
? base & ~(FlatAddressWindowSize - 1u)
|
||||
: base >= before ? base - before
|
||||
: 0;
|
||||
uint64_t binding_base = 0;
|
||||
if (address.kind == ResourceKind::Flat) {
|
||||
binding_base = base & ~(FlatAddressWindowSize - 1u);
|
||||
} else if (base >= before) {
|
||||
binding_base = base - before;
|
||||
}
|
||||
next.addresses.push_back({base, binding_base});
|
||||
} else {
|
||||
if (!runtime.flat_memory_base.has_value()) {
|
||||
@@ -289,7 +291,7 @@ bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std
|
||||
program.binding_layout_complete) {
|
||||
if (error != nullptr) {
|
||||
*error = !program.resource_tracking_complete ? "shader resources were not tracked"
|
||||
: "resource specialization is too late";
|
||||
: "resource specialization is too late";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -347,8 +349,8 @@ bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std
|
||||
}
|
||||
struct ImagePatch {
|
||||
std::reference_wrapper<Instruction> inst;
|
||||
ResourceKind kind;
|
||||
Decoder::ImageDimension dimension;
|
||||
ResourceKind kind;
|
||||
Decoder::ImageDimension dimension;
|
||||
};
|
||||
std::vector<ImagePatch> patches;
|
||||
for (auto& block: program.blocks) {
|
||||
|
||||
@@ -392,7 +392,7 @@ private:
|
||||
|
||||
void ClearVectorLanes(uint32_t reg, ScalarState& state) {
|
||||
const auto first = state.vector_lanes.lower_bound(VectorLaneKey(reg, 0));
|
||||
const auto last = state.vector_lanes.lower_bound((static_cast<uint64_t>(reg) + 1u) << 32u);
|
||||
const auto last = state.vector_lanes.lower_bound((static_cast<uint64_t>(reg) + 1u) << 32u);
|
||||
state.vector_lanes.erase(first, last);
|
||||
}
|
||||
|
||||
@@ -416,8 +416,8 @@ private:
|
||||
for (uint32_t i = 0; i < inst.src_count; i++) {
|
||||
uint32_t src_reg = 0;
|
||||
if (ScalarRegister(inst.src[i], src_reg) &&
|
||||
state.regs[src_reg] > ScalarProvenance::Unknown) {
|
||||
address_base = state.regs[src_reg];
|
||||
state.regs[src_reg] > ScalarProvenance::Unknown) {
|
||||
address_base = state.regs[src_reg];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -529,16 +529,18 @@ private:
|
||||
if (inst.dst.kind == OperandKind::Register && inst.dst.reg.file == RegisterFile::Scc) {
|
||||
state.scc = inst.op == Opcode::MoveU32 && inst.src_count != 0
|
||||
? OperandValue(inst.src[0], state)
|
||||
: ScalarProvenance::Unknown;
|
||||
: ScalarProvenance::Unknown;
|
||||
return;
|
||||
}
|
||||
if (inst.dst.kind == OperandKind::Register && inst.dst.reg.file == RegisterFile::M0) {
|
||||
const auto before = state;
|
||||
const auto op = Operation(inst.op);
|
||||
state.m0 = inst.op == Opcode::MoveU32 && inst.src_count != 0
|
||||
? OperandValue(inst.src[0], before)
|
||||
: op != ScalarValueOp::Unknown ? Define(inst, op, before)
|
||||
: ScalarProvenance::Unknown;
|
||||
state.m0 = ScalarProvenance::Unknown;
|
||||
if (inst.op == Opcode::MoveU32 && inst.src_count != 0) {
|
||||
state.m0 = OperandValue(inst.src[0], before);
|
||||
} else if (op != ScalarValueOp::Unknown) {
|
||||
state.m0 = Define(inst, op, before);
|
||||
}
|
||||
UpdateScc(inst, before, state);
|
||||
return;
|
||||
}
|
||||
@@ -558,10 +560,14 @@ private:
|
||||
switch (inst.op) {
|
||||
case Opcode::MoveU32:
|
||||
case Opcode::MoveF32Bits:
|
||||
value = inst.src_count == 0 ? ScalarProvenance::Unknown
|
||||
: inst.src[0].kind == OperandKind::PcRelativeU32
|
||||
? InternValue({ScalarValueOp::PcRelativeLow, inst.pc, inst.src[0].imm})
|
||||
: OperandValue(inst.src[0], before);
|
||||
if (inst.src_count != 0) {
|
||||
if (inst.src[0].kind == OperandKind::PcRelativeU32) {
|
||||
value =
|
||||
InternValue({ScalarValueOp::PcRelativeLow, inst.pc, inst.src[0].imm});
|
||||
} else {
|
||||
value = OperandValue(inst.src[0], before);
|
||||
}
|
||||
}
|
||||
if (inst.op == Opcode::MoveU32 && inst.src_count != 0 &&
|
||||
inst.src[0].kind == OperandKind::ImmediateU32 && inst.src[0].imm == 0 &&
|
||||
dst != 0) {
|
||||
@@ -578,10 +584,10 @@ private:
|
||||
uint32_t src = 0;
|
||||
if (inst.src_count != 0 && dst + 1 < ScalarRegisters) {
|
||||
if (ScalarRegister(inst.src[0], src) && src + 1 < ScalarRegisters) {
|
||||
value = before.regs[src];
|
||||
value = before.regs[src];
|
||||
state.regs[dst + 1] = before.regs[src + 1];
|
||||
} else {
|
||||
value = OperandValue(inst.src[0], before);
|
||||
value = OperandValue(inst.src[0], before);
|
||||
state.regs[dst + 1] = Constant(
|
||||
inst.src[0].kind == OperandKind::ImmediateU32 && inst.src[0].sext_64
|
||||
? UINT32_MAX
|
||||
@@ -687,7 +693,7 @@ private:
|
||||
if (inst.memory.kind == ResourceKind::Buffer ||
|
||||
(inst.memory.kind == ResourceKind::ScalarBuffer &&
|
||||
inst.op == Opcode::SBufferLoadDword)) {
|
||||
const auto base = inst.memory.resource * 4u;
|
||||
const auto base = inst.memory.resource * 4u;
|
||||
inst.memory.resource_source = AddDescriptor(state, base, 4);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,9 +180,11 @@ bool IsDecodedSgpr(const Decoder::Operand& op) {
|
||||
}
|
||||
|
||||
uint32_t DecodedSgprReg(const Decoder::Operand& op) {
|
||||
return op.kind == Decoder::OperandKind::VccLo
|
||||
? 106u
|
||||
: (op.kind == Decoder::OperandKind::VccHi ? 107u : op.reg);
|
||||
switch (op.kind) {
|
||||
case Decoder::OperandKind::VccLo: return 106u;
|
||||
case Decoder::OperandKind::VccHi: return 107u;
|
||||
default: return op.reg;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDecodedVgpr(const Decoder::Operand& op) {
|
||||
@@ -340,14 +342,13 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
||||
const bool vertex_index_accumulator =
|
||||
IsDecodedVgpr(inst.dst) &&
|
||||
(inst.dst.reg == 0 || (user_data_base == 8 && inst.dst.reg == 5));
|
||||
uint32_t sad_zero = 0;
|
||||
uint32_t sad_zero = 0;
|
||||
const bool vertex_offset_add =
|
||||
vertex_index_accumulator && IsDecodedSgpr(inst.src0) &&
|
||||
((inst.opcode == Decoder::Opcode::VAddI32 && IsDecodedVgpr(inst.src1) &&
|
||||
inst.src1.reg == inst.dst.reg) ||
|
||||
(user_data_base == 8 && inst.dst.reg == 5 &&
|
||||
inst.opcode == Decoder::Opcode::VSadU32 && IsDecodedVgpr(inst.src2) &&
|
||||
inst.src2.reg == inst.dst.reg &&
|
||||
(user_data_base == 8 && inst.dst.reg == 5 && inst.opcode == Decoder::Opcode::VSadU32 &&
|
||||
IsDecodedVgpr(inst.src2) && inst.src2.reg == inst.dst.reg &&
|
||||
TryDecodedOperandConstant(sgprs, inst.src1, sad_zero) && sad_zero == 0));
|
||||
if (data.loads.empty() && vertex_offset_add) {
|
||||
const auto reg = DecodedSgprReg(inst.src0);
|
||||
@@ -636,7 +637,7 @@ uint32_t RewriteEmbeddedVertexFetches(IR::Program& ir, const ShaderVertexInputIn
|
||||
} // namespace
|
||||
|
||||
bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
|
||||
CompileResult& result, std::string* error) {
|
||||
CompileResult& result, std::string* error) {
|
||||
if (code.empty()) {
|
||||
if (error != nullptr) {
|
||||
*error = "invalid shader recompiler input";
|
||||
@@ -804,10 +805,11 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
|
||||
runtime.user_data = std::span<const uint32_t>(user_data, options.user_data_count);
|
||||
runtime.shader_base = options.shader_base != 0 ? options.shader_base
|
||||
: reinterpret_cast<uint64_t>(code.data());
|
||||
runtime.read_memory = options.read_memory != nullptr ? options.read_memory
|
||||
: options.user_data == nullptr ? ReadZeroMemory
|
||||
: nullptr;
|
||||
runtime.userdata = options.read_memory_data;
|
||||
runtime.read_memory = options.read_memory;
|
||||
if (runtime.read_memory == nullptr && options.user_data == nullptr) {
|
||||
runtime.read_memory = ReadZeroMemory;
|
||||
}
|
||||
runtime.userdata = options.read_memory_data;
|
||||
runtime.flat_memory_base = options.flat_memory_base;
|
||||
if (!IR::MaterializeResources(ir, runtime, resources, error)) {
|
||||
return false;
|
||||
|
||||
@@ -12,9 +12,13 @@ bool PatchSrtReads(Program& program, std::string* error) {
|
||||
if (!program.srt_plan_complete || program.srt_patching_complete ||
|
||||
program.resource_tracking_complete) {
|
||||
if (error != nullptr) {
|
||||
*error = !program.srt_plan_complete ? "SRT plan is not ready"
|
||||
: program.srt_patching_complete ? "SRT reads already patched"
|
||||
: "resources already tracked";
|
||||
if (!program.srt_plan_complete) {
|
||||
*error = "SRT plan is not ready";
|
||||
} else if (program.srt_patching_complete) {
|
||||
*error = "SRT reads already patched";
|
||||
} else {
|
||||
*error = "resources already tracked";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -553,6 +553,17 @@ bool DecodeVop1Sdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_i
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
}
|
||||
|
||||
void ApplyDppModifier(Operand& operand, uint32_t modifier) {
|
||||
operand.negate = ((modifier >> 20u) & 0x1u) != 0u;
|
||||
operand.absolute = ((modifier >> 21u) & 0x1u) != 0u;
|
||||
operand.dpp = true;
|
||||
operand.dpp_ctrl = (modifier >> 8u) & 0x1ffu;
|
||||
operand.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u;
|
||||
operand.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u;
|
||||
operand.dpp_bank_mask = (modifier >> 24u) & 0xfu;
|
||||
operand.dpp_row_mask = (modifier >> 28u) & 0xfu;
|
||||
}
|
||||
|
||||
bool DecodeVop1Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t opcode, uint32_t vdst, Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
@@ -572,15 +583,8 @@ bool DecodeVop1Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
|
||||
!DecodeScalarSource(src0 + 256u, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
inst.src0.negate = ((modifier >> 20u) & 0x1u) != 0u;
|
||||
inst.src0.absolute = ((modifier >> 21u) & 0x1u) != 0u;
|
||||
inst.src0.dpp = true;
|
||||
inst.src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu;
|
||||
inst.src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u;
|
||||
inst.src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u;
|
||||
inst.src0.dpp_bank_mask = (modifier >> 24u) & 0xfu;
|
||||
inst.src0.dpp_row_mask = (modifier >> 28u) & 0xfu;
|
||||
inst.src_count = 1;
|
||||
ApplyDppModifier(inst.src0, modifier);
|
||||
inst.src_count = 1;
|
||||
|
||||
if (!IsVop1FloatSourceOpcode(inst.opcode) && (inst.src0.negate || inst.src0.absolute)) {
|
||||
SetUnsupported(inst, Family::VOP1, opcode,
|
||||
@@ -988,16 +992,9 @@ bool DecodeVop2Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
|
||||
return false;
|
||||
}
|
||||
ApplyDefaultVop2F16Destination(inst);
|
||||
inst.src0.negate = ((modifier >> 20u) & 0x1u) != 0u;
|
||||
inst.src0.absolute = ((modifier >> 21u) & 0x1u) != 0u;
|
||||
inst.src0.dpp = true;
|
||||
inst.src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu;
|
||||
inst.src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u;
|
||||
inst.src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u;
|
||||
inst.src0.dpp_bank_mask = (modifier >> 24u) & 0xfu;
|
||||
inst.src0.dpp_row_mask = (modifier >> 28u) & 0xfu;
|
||||
inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u;
|
||||
inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u;
|
||||
ApplyDppModifier(inst.src0, modifier);
|
||||
inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u;
|
||||
inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u;
|
||||
|
||||
if (!IsVop2FloatSourceOpcode(inst.opcode) &&
|
||||
(inst.src0.negate || inst.src0.absolute || inst.src1.negate || inst.src1.absolute)) {
|
||||
@@ -1142,18 +1139,11 @@ bool DecodeVopcDpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
|
||||
!DecodeVectorGpr(vsrc1, inst.src1, error)) {
|
||||
return false;
|
||||
}
|
||||
inst.dst.kind = IsVopcCompareExec(inst.opcode) ? OperandKind::ExecLo : OperandKind::VccLo;
|
||||
inst.src0.negate = ((modifier >> 20u) & 0x1u) != 0u;
|
||||
inst.src0.absolute = ((modifier >> 21u) & 0x1u) != 0u;
|
||||
inst.src0.dpp = true;
|
||||
inst.src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu;
|
||||
inst.src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u;
|
||||
inst.src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u;
|
||||
inst.src0.dpp_bank_mask = (modifier >> 24u) & 0xfu;
|
||||
inst.src0.dpp_row_mask = (modifier >> 28u) & 0xfu;
|
||||
inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u;
|
||||
inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u;
|
||||
inst.src_count = 2;
|
||||
inst.dst.kind = IsVopcCompareExec(inst.opcode) ? OperandKind::ExecLo : OperandKind::VccLo;
|
||||
ApplyDppModifier(inst.src0, modifier);
|
||||
inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u;
|
||||
inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u;
|
||||
inst.src_count = 2;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
}
|
||||
|
||||
@@ -1249,20 +1239,8 @@ void ApplyVop3pMixAbsModifiers(Instruction& inst) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyNativeVop3MadMixModifiers(Instruction& inst, uint32_t op_sel, uint32_t abs,
|
||||
uint32_t neg) {
|
||||
Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2};
|
||||
for (uint32_t i = 0; i < 3u; i++) {
|
||||
sources[i]->op_sel = ((op_sel >> i) & 1u) != 0;
|
||||
sources[i]->op_sel_hi = true;
|
||||
sources[i]->negate = ((neg >> i) & 1u) != 0;
|
||||
sources[i]->absolute = ((abs >> i) & 1u) != 0;
|
||||
}
|
||||
inst.dst.sdwa_sel = ((op_sel & 0x8u) != 0) ? 5u : 4u;
|
||||
}
|
||||
|
||||
void ApplyNativeVop3F16TernaryModifiers(Instruction& inst, uint32_t op_sel, uint32_t abs,
|
||||
uint32_t neg) {
|
||||
void ApplyNativeVop3TernaryModifiers(Instruction& inst, uint32_t op_sel, uint32_t abs,
|
||||
uint32_t neg) {
|
||||
Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2};
|
||||
for (uint32_t i = 0; i < 3u; i++) {
|
||||
sources[i]->op_sel = ((op_sel >> i) & 1u) != 0;
|
||||
@@ -1601,11 +1579,13 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
HasUnsupportedNativeVop3Modifiers(inst.opcode, permlane, mad_mix, vop3b_uses_sdst,
|
||||
scalar_modifier_limits, abs, op_sel, clamp, omod, neg);
|
||||
if (modifiers) {
|
||||
SetUnsupported(inst, Family::VOP3, opcode,
|
||||
permlane && (op_sel & ~0x3u) != 0
|
||||
? "VOP3 perm-lane op_sel bits are not implemented"
|
||||
: mad_mix ? "VOP3 mad-mix clamp/omod is not implemented"
|
||||
: "VOP3 source modifiers are not implemented");
|
||||
const char* reason = "VOP3 source modifiers are not implemented";
|
||||
if (permlane && (op_sel & ~0x3u) != 0) {
|
||||
reason = "VOP3 perm-lane op_sel bits are not implemented";
|
||||
} else if (mad_mix) {
|
||||
reason = "VOP3 mad-mix clamp/omod is not implemented";
|
||||
}
|
||||
SetUnsupported(inst, Family::VOP3, opcode, reason);
|
||||
return true;
|
||||
}
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
@@ -1703,9 +1683,9 @@ bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
||||
return false;
|
||||
}
|
||||
if (mad_mix) {
|
||||
ApplyNativeVop3MadMixModifiers(inst, op_sel, abs, neg);
|
||||
ApplyNativeVop3TernaryModifiers(inst, op_sel, abs, neg);
|
||||
} else if (f16_ternary) {
|
||||
ApplyNativeVop3F16TernaryModifiers(inst, op_sel, abs, neg);
|
||||
ApplyNativeVop3TernaryModifiers(inst, op_sel, abs, neg);
|
||||
} else if (b16_binary) {
|
||||
ApplyNativeVop3B16BinaryModifiers(inst, op_sel);
|
||||
} else if (pack_b32_f16) {
|
||||
|
||||
@@ -10,6 +10,71 @@
|
||||
namespace Libs::Graphics::ShaderRecompiler::IR {
|
||||
namespace {
|
||||
|
||||
Opcode BufferLoadOpcode(const Decoder::Instruction& decoded) {
|
||||
switch (decoded.data_bits) {
|
||||
case 8u: return decoded.data_signed ? Opcode::BufferLoadSbyte : Opcode::BufferLoadUbyte;
|
||||
case 16u: return decoded.data_signed ? Opcode::BufferLoadSshort : Opcode::BufferLoadUshort;
|
||||
default: return Opcode::BufferLoadDword;
|
||||
}
|
||||
}
|
||||
|
||||
Opcode BufferStoreOpcode(uint32_t data_bits) {
|
||||
switch (data_bits) {
|
||||
case 8u: return Opcode::BufferStoreByte;
|
||||
case 16u: return Opcode::BufferStoreShort;
|
||||
default: return Opcode::BufferStoreDword;
|
||||
}
|
||||
}
|
||||
|
||||
Opcode DsReadOpcode(const Decoder::Instruction& decoded) {
|
||||
switch (decoded.data_bits) {
|
||||
case 8u: return decoded.data_signed ? Opcode::DsReadSbyte : Opcode::DsReadUbyte;
|
||||
case 16u: return decoded.data_signed ? Opcode::DsReadSshort : Opcode::DsReadUshort;
|
||||
default: return Opcode::DsReadB32;
|
||||
}
|
||||
}
|
||||
|
||||
Opcode FlatLoadOpcode(const Decoder::Instruction& decoded) {
|
||||
switch (decoded.data_bits) {
|
||||
case 8u: return decoded.data_signed ? Opcode::FlatLoadSbyte : Opcode::FlatLoadUbyte;
|
||||
case 16u: return decoded.data_signed ? Opcode::FlatLoadSshort : Opcode::FlatLoadUshort;
|
||||
default: return Opcode::FlatLoadDword;
|
||||
}
|
||||
}
|
||||
|
||||
Opcode FlatStoreOpcode(uint32_t data_bits) {
|
||||
switch (data_bits) {
|
||||
case 8u: return Opcode::FlatStoreByte;
|
||||
case 16u: return Opcode::FlatStoreShort;
|
||||
default: return Opcode::FlatStoreDword;
|
||||
}
|
||||
}
|
||||
|
||||
Opcode DsWriteOpcode(uint32_t data_bits) {
|
||||
switch (data_bits) {
|
||||
case 8u: return Opcode::DsWriteByte;
|
||||
case 16u: return Opcode::DsWriteShort;
|
||||
default: return Opcode::DsWriteB32;
|
||||
}
|
||||
}
|
||||
|
||||
Opcode LoweredImageOpcode(Decoder::Opcode opcode) {
|
||||
switch (opcode) {
|
||||
case Decoder::Opcode::ImageGetResinfo: return Opcode::ImageGetResinfo;
|
||||
case Decoder::Opcode::ImageGetLod: return Opcode::ImageGetLod;
|
||||
case Decoder::Opcode::ImageLoad:
|
||||
case Decoder::Opcode::ImageLoadMip: return Opcode::ImageLoad;
|
||||
case Decoder::Opcode::ImageGather4Lz:
|
||||
case Decoder::Opcode::ImageGather4C:
|
||||
case Decoder::Opcode::ImageGather4CLz:
|
||||
case Decoder::Opcode::ImageGather4LzO:
|
||||
case Decoder::Opcode::ImageGather4CO:
|
||||
case Decoder::Opcode::ImageGather4CLzO:
|
||||
case Decoder::Opcode::ImageGather4H: return Opcode::ImageGather4;
|
||||
default: return Opcode::ImageSample;
|
||||
}
|
||||
}
|
||||
|
||||
bool LowerScalarBufferLoadDword(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op,
|
||||
std::string* error) {
|
||||
for (uint32_t i = 0; i < decoded.data_dwords; i++) {
|
||||
@@ -54,12 +119,7 @@ bool LowerBufferAddressSources(const Decoder::Instruction& decoded, Instruction&
|
||||
}
|
||||
|
||||
bool LowerBufferLoad(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
||||
const auto ir_op =
|
||||
decoded.data_bits == 8u
|
||||
? (decoded.data_signed ? Opcode::BufferLoadSbyte : Opcode::BufferLoadUbyte)
|
||||
: decoded.data_bits == 16u
|
||||
? (decoded.data_signed ? Opcode::BufferLoadSshort : Opcode::BufferLoadUshort)
|
||||
: Opcode::BufferLoadDword;
|
||||
const auto ir_op = BufferLoadOpcode(decoded);
|
||||
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
||||
const auto typed_format_components = TypedBufferFormatComponentCount(decoded);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
@@ -85,9 +145,7 @@ bool LowerBufferLoad(const Decoder::Instruction& decoded, BasicBlock& block, std
|
||||
}
|
||||
|
||||
bool LowerBufferStore(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
||||
const auto ir_op = decoded.data_bits == 8u ? Opcode::BufferStoreByte
|
||||
: decoded.data_bits == 16u ? Opcode::BufferStoreShort
|
||||
: Opcode::BufferStoreDword;
|
||||
const auto ir_op = BufferStoreOpcode(decoded.data_bits);
|
||||
auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
||||
if (decoded.data_bits == 32u) {
|
||||
const auto typed_format_components = TypedBufferFormatComponentCount(decoded);
|
||||
@@ -131,11 +189,7 @@ ResourceKind DsMemoryKind(const Decoder::Instruction& decoded) {
|
||||
}
|
||||
|
||||
bool LowerDsRead(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
||||
const auto ir_op = decoded.data_bits == 8u
|
||||
? (decoded.data_signed ? Opcode::DsReadSbyte : Opcode::DsReadUbyte)
|
||||
: decoded.data_bits == 16u
|
||||
? (decoded.data_signed ? Opcode::DsReadSshort : Opcode::DsReadUshort)
|
||||
: Opcode::DsReadB32;
|
||||
const auto ir_op = DsReadOpcode(decoded);
|
||||
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
Instruction inst;
|
||||
@@ -164,8 +218,7 @@ bool LowerDsRead2(const Decoder::Instruction& decoded, BasicBlock& block, uint32
|
||||
inst.src_count = 1;
|
||||
inst.memory =
|
||||
ByteOffsetMemoryInfo(decoded, DsMemoryKind(decoded), offsets[read] + dword * 4u);
|
||||
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, index), inst.dst,
|
||||
error) ||
|
||||
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, index), inst.dst, error) ||
|
||||
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
|
||||
return false;
|
||||
}
|
||||
@@ -309,11 +362,7 @@ bool LowerImageAtomicU32(const Decoder::Instruction& decoded, BasicBlock& block,
|
||||
|
||||
bool LowerFlatLoad(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
||||
const auto kind = FlatSegmentResourceKind(decoded.memory_segment);
|
||||
const auto ir_op = decoded.data_bits == 8u
|
||||
? (decoded.data_signed ? Opcode::FlatLoadSbyte : Opcode::FlatLoadUbyte)
|
||||
: decoded.data_bits == 16u
|
||||
? (decoded.data_signed ? Opcode::FlatLoadSshort : Opcode::FlatLoadUshort)
|
||||
: Opcode::FlatLoadDword;
|
||||
const auto ir_op = FlatLoadOpcode(decoded);
|
||||
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
||||
if (decoded.data_bits == 32u && count > 1u) {
|
||||
Instruction inst;
|
||||
@@ -356,9 +405,7 @@ bool LowerFlatLoad(const Decoder::Instruction& decoded, BasicBlock& block, std::
|
||||
|
||||
bool LowerFlatStore(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
||||
const auto kind = FlatSegmentResourceKind(decoded.memory_segment);
|
||||
const auto ir_op = decoded.data_bits == 8u ? Opcode::FlatStoreByte
|
||||
: decoded.data_bits == 16u ? Opcode::FlatStoreShort
|
||||
: Opcode::FlatStoreDword;
|
||||
const auto ir_op = FlatStoreOpcode(decoded.data_bits);
|
||||
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
||||
for (uint32_t dword = 0; dword < count; dword++) {
|
||||
Instruction inst;
|
||||
@@ -382,9 +429,7 @@ bool LowerFlatStore(const Decoder::Instruction& decoded, BasicBlock& block, std:
|
||||
}
|
||||
|
||||
bool LowerDsWrite(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
||||
const auto ir_op = decoded.data_bits == 8u ? Opcode::DsWriteByte
|
||||
: decoded.data_bits == 16u ? Opcode::DsWriteShort
|
||||
: Opcode::DsWriteB32;
|
||||
const auto ir_op = DsWriteOpcode(decoded.data_bits);
|
||||
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
Instruction inst;
|
||||
@@ -445,20 +490,7 @@ bool LowerImageOperation(const Decoder::Instruction& decoded, BasicBlock& block,
|
||||
return true;
|
||||
}
|
||||
|
||||
inst.op = decoded.opcode == Decoder::Opcode::ImageGetResinfo ? Opcode::ImageGetResinfo
|
||||
: decoded.opcode == Decoder::Opcode::ImageGetLod ? Opcode::ImageGetLod
|
||||
: decoded.opcode == Decoder::Opcode::ImageLoad ||
|
||||
decoded.opcode == Decoder::Opcode::ImageLoadMip
|
||||
? Opcode::ImageLoad
|
||||
: decoded.opcode == Decoder::Opcode::ImageGather4Lz ||
|
||||
decoded.opcode == Decoder::Opcode::ImageGather4C ||
|
||||
decoded.opcode == Decoder::Opcode::ImageGather4CLz ||
|
||||
decoded.opcode == Decoder::Opcode::ImageGather4LzO ||
|
||||
decoded.opcode == Decoder::Opcode::ImageGather4CO ||
|
||||
decoded.opcode == Decoder::Opcode::ImageGather4CLzO ||
|
||||
decoded.opcode == Decoder::Opcode::ImageGather4H
|
||||
? Opcode::ImageGather4
|
||||
: Opcode::ImageSample;
|
||||
inst.op = LoweredImageOpcode(decoded.opcode);
|
||||
inst.src_count = 1;
|
||||
inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::Image);
|
||||
if (!LowerRegisterOperand(decoded.dst, inst.dst, error) ||
|
||||
|
||||
@@ -11,10 +11,13 @@ void EmitPerInvocationMask(EmitterState& state, const IR::Operand& dst, uint32_t
|
||||
}
|
||||
|
||||
uint32_t EmitLogicalBinary(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs) {
|
||||
const auto logical_opcode = opcode == OpBitwiseAnd ? OpLogicalAnd
|
||||
: opcode == OpBitwiseOr ? OpLogicalOr
|
||||
: OpLogicalNotEqual;
|
||||
const auto value = state.builder.AllocateId();
|
||||
uint32_t logical_opcode = OpLogicalNotEqual;
|
||||
switch (opcode) {
|
||||
case OpBitwiseAnd: logical_opcode = OpLogicalAnd; break;
|
||||
case OpBitwiseOr: logical_opcode = OpLogicalOr; break;
|
||||
default: break;
|
||||
}
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({logical_opcode, state.bool_type, value, lhs, rhs});
|
||||
return value;
|
||||
}
|
||||
@@ -469,10 +472,11 @@ uint32_t EmitSignExtendLow16U32(EmitterState& state, uint32_t value) {
|
||||
|
||||
uint32_t EmitU16LaneBits(EmitterState& state, const IR::Operand& operand, bool high_lane,
|
||||
bool sign_extend) {
|
||||
const auto raw = EmitValueLoad(state, operand);
|
||||
const auto lane = high_lane ? (operand.op_sel_hi ? 1u : 0u) : (operand.op_sel ? 1u : 0u);
|
||||
auto bits = lane != 0u ? EmitShiftRightConstant(state, raw, 16) : raw;
|
||||
bits = EmitAndConstant(state, bits, 0xffffu);
|
||||
const auto raw = EmitValueLoad(state, operand);
|
||||
const auto selected_lane = high_lane ? operand.op_sel_hi : operand.op_sel;
|
||||
const auto lane = selected_lane ? 1u : 0u;
|
||||
auto bits = lane != 0u ? EmitShiftRightConstant(state, raw, 16) : raw;
|
||||
bits = EmitAndConstant(state, bits, 0xffffu);
|
||||
if (high_lane ? operand.negate_hi : operand.negate) {
|
||||
bits = EmitAndConstant(state, EmitNegateU32(state, bits), 0xffffu);
|
||||
}
|
||||
@@ -502,8 +506,12 @@ void EmitMinMaxU16(EmitterState& state, const IR::Instruction& inst, bool signed
|
||||
const auto rhs = EmitU16LaneBits(state, inst.src[1], false, signed_value);
|
||||
const auto cond = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
const auto op = signed_value ? (max_value ? OpSGreaterThan : OpSLessThan)
|
||||
: (max_value ? OpUGreaterThan : OpULessThan);
|
||||
uint32_t op = 0;
|
||||
if (signed_value) {
|
||||
op = max_value ? OpSGreaterThan : OpSLessThan;
|
||||
} else {
|
||||
op = max_value ? OpUGreaterThan : OpULessThan;
|
||||
}
|
||||
state.builder.AddFunction({op, state.bool_type, cond, lhs, rhs});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, lhs, rhs});
|
||||
EmitStoreU32(state, inst.dst, EmitAndConstant(state, ret, 0xffffu));
|
||||
@@ -2039,10 +2047,11 @@ void EmitDot2AccF32F16(EmitterState& state, const IR::Instruction& inst) {
|
||||
}
|
||||
|
||||
uint32_t EmitPackedF16Lane(EmitterState& state, const IR::Operand& operand, bool high_lane) {
|
||||
const auto raw = EmitValueLoad(state, operand);
|
||||
const auto unpacked = state.builder.AllocateId();
|
||||
auto value = state.builder.AllocateId();
|
||||
const auto lane = high_lane ? (operand.op_sel_hi ? 1u : 0u) : (operand.op_sel ? 1u : 0u);
|
||||
const auto raw = EmitValueLoad(state, operand);
|
||||
const auto unpacked = state.builder.AllocateId();
|
||||
auto value = state.builder.AllocateId();
|
||||
const auto selected_lane = high_lane ? operand.op_sel_hi : operand.op_sel;
|
||||
const auto lane = selected_lane ? 1u : 0u;
|
||||
state.builder.AddFunction(
|
||||
{OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, raw});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.float_type, value, unpacked, lane});
|
||||
@@ -2069,10 +2078,11 @@ void EmitCompareF16(EmitterState& state, const IR::Instruction& inst, uint32_t o
|
||||
}
|
||||
|
||||
uint32_t EmitPackedF16LaneBits(EmitterState& state, const IR::Operand& operand, bool high_lane) {
|
||||
const auto raw = EmitValueLoad(state, operand);
|
||||
const auto lane = high_lane ? (operand.op_sel_hi ? 1u : 0u) : (operand.op_sel ? 1u : 0u);
|
||||
auto bits = lane != 0u ? EmitShiftRightConstant(state, raw, 16) : raw;
|
||||
bits = EmitAndConstant(state, bits, 0xffffu);
|
||||
const auto raw = EmitValueLoad(state, operand);
|
||||
const auto selected_lane = high_lane ? operand.op_sel_hi : operand.op_sel;
|
||||
const auto lane = selected_lane ? 1u : 0u;
|
||||
auto bits = lane != 0u ? EmitShiftRightConstant(state, raw, 16) : raw;
|
||||
bits = EmitAndConstant(state, bits, 0xffffu);
|
||||
if (operand.absolute) {
|
||||
bits = EmitAndConstant(state, bits, 0x7fffu);
|
||||
}
|
||||
@@ -2403,8 +2413,12 @@ uint32_t EmitPackedInteger16Select(EmitterState& state, uint32_t lhs, uint32_t r
|
||||
bool signed_compare, bool max_value) {
|
||||
const auto cond = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
const auto op = signed_compare ? (max_value ? OpSGreaterThanEqual : OpSLessThan)
|
||||
: (max_value ? OpUGreaterThanEqual : OpULessThan);
|
||||
uint32_t op = 0;
|
||||
if (signed_compare) {
|
||||
op = max_value ? OpSGreaterThanEqual : OpSLessThan;
|
||||
} else {
|
||||
op = max_value ? OpUGreaterThanEqual : OpULessThan;
|
||||
}
|
||||
state.builder.AddFunction({op, state.bool_type, cond, lhs, rhs});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, lhs, rhs});
|
||||
return ret;
|
||||
@@ -2419,9 +2433,12 @@ uint32_t EmitPackedInteger16Lane(EmitterState& state, const IR::Instruction& ins
|
||||
const auto arithmetic = opcode == IR::Opcode::PackedAshrrevI16;
|
||||
const auto value = EmitU16LaneBits(state, inst.src[1], high_lane, arithmetic);
|
||||
const auto ret = state.builder.AllocateId();
|
||||
const auto shift_op = opcode == IR::Opcode::PackedLshlrevB16 ? OpShiftLeftLogical
|
||||
: arithmetic ? OpShiftRightArithmetic
|
||||
: OpShiftRightLogical;
|
||||
uint32_t shift_op = OpShiftRightLogical;
|
||||
switch (opcode) {
|
||||
case IR::Opcode::PackedLshlrevB16: shift_op = OpShiftLeftLogical; break;
|
||||
case IR::Opcode::PackedAshrrevI16: shift_op = OpShiftRightArithmetic; break;
|
||||
default: break;
|
||||
}
|
||||
state.builder.AddFunction({shift_op, state.uint_type, ret, value, count});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,23 @@ uint32_t ConstantImageGatherHorizontalOffsets(EmitterState& state) {
|
||||
return value;
|
||||
}
|
||||
|
||||
IR::DescriptorBindingKind StorageImageBindingKind(ImageViewKind view, bool uint_image) {
|
||||
switch (view) {
|
||||
case ImageViewKind::Dim2D:
|
||||
return uint_image ? IR::DescriptorBindingKind::StorageUint2D
|
||||
: IR::DescriptorBindingKind::Storage2D;
|
||||
case ImageViewKind::Dim2DArray:
|
||||
return uint_image ? IR::DescriptorBindingKind::StorageUint2DArray
|
||||
: IR::DescriptorBindingKind::Storage2DArray;
|
||||
case ImageViewKind::Dim3D:
|
||||
return uint_image ? IR::DescriptorBindingKind::StorageUint3D
|
||||
: IR::DescriptorBindingKind::Storage3D;
|
||||
default:
|
||||
return uint_image ? IR::DescriptorBindingKind::StorageUint2D
|
||||
: IR::DescriptorBindingKind::Storage2D;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t LoadStorageImageDescriptorAtIndex(EmitterState& state, uint32_t resource,
|
||||
uint32_t array_index, bool uint_image,
|
||||
ImageViewKind view) {
|
||||
@@ -30,9 +47,8 @@ uint32_t LoadStorageImageDescriptorAtIndex(EmitterState& state, uint32_t resourc
|
||||
uint_image ? state.ptr_uniform_storage_image_uint : state.ptr_uniform_storage_image;
|
||||
uint32_t variable =
|
||||
uint_image ? state.storage_image_uint_variable : state.storage_image_variable;
|
||||
uint32_t image_type = uint_image ? state.storage_image_uint_type : state.storage_image_type;
|
||||
IR::DescriptorBindingKind kind = uint_image ? IR::DescriptorBindingKind::StorageUint2D
|
||||
: IR::DescriptorBindingKind::Storage2D;
|
||||
uint32_t image_type = uint_image ? state.storage_image_uint_type : state.storage_image_type;
|
||||
const auto kind = StorageImageBindingKind(view, uint_image);
|
||||
switch (view) {
|
||||
case ImageViewKind::Dim2D: break;
|
||||
case ImageViewKind::Dim2DArray:
|
||||
@@ -42,8 +58,6 @@ uint32_t LoadStorageImageDescriptorAtIndex(EmitterState& state, uint32_t resourc
|
||||
: state.storage_image_2d_array_variable;
|
||||
image_type = uint_image ? state.storage_image_uint_2d_array_type
|
||||
: state.storage_image_2d_array_type;
|
||||
kind = uint_image ? IR::DescriptorBindingKind::StorageUint2DArray
|
||||
: IR::DescriptorBindingKind::Storage2DArray;
|
||||
break;
|
||||
case ImageViewKind::Dim3D:
|
||||
pointer_type = uint_image ? state.ptr_uniform_storage_image_uint_3d
|
||||
@@ -52,8 +66,6 @@ uint32_t LoadStorageImageDescriptorAtIndex(EmitterState& state, uint32_t resourc
|
||||
uint_image ? state.storage_image_uint_3d_variable : state.storage_image_3d_variable;
|
||||
image_type =
|
||||
uint_image ? state.storage_image_uint_3d_type : state.storage_image_3d_type;
|
||||
kind = uint_image ? IR::DescriptorBindingKind::StorageUint3D
|
||||
: IR::DescriptorBindingKind::Storage3D;
|
||||
break;
|
||||
}
|
||||
const auto pointer =
|
||||
@@ -170,16 +182,8 @@ void EmitImageLoad(EmitterState& state, const IR::Instruction& inst) {
|
||||
void EmitImageStore(EmitterState& state, const IR::Instruction& inst) {
|
||||
const auto uint_image = inst.memory.kind == IR::ResourceKind::StorageImageUint;
|
||||
const auto view = StorageImageViewKind(state, inst.memory, uint_image, inst.pc);
|
||||
const auto binding = ResourceForDescriptor(
|
||||
state,
|
||||
uint_image
|
||||
? (view == ImageViewKind::Dim2DArray ? IR::DescriptorBindingKind::StorageUint2DArray
|
||||
: view == ImageViewKind::Dim3D ? IR::DescriptorBindingKind::StorageUint3D
|
||||
: IR::DescriptorBindingKind::StorageUint2D)
|
||||
: (view == ImageViewKind::Dim2DArray ? IR::DescriptorBindingKind::Storage2DArray
|
||||
: view == ImageViewKind::Dim3D ? IR::DescriptorBindingKind::Storage3D
|
||||
: IR::DescriptorBindingKind::Storage2D),
|
||||
inst.memory.resource);
|
||||
const auto binding = ResourceForDescriptor(state, StorageImageBindingKind(view, uint_image),
|
||||
inst.memory.resource);
|
||||
const auto image = LoadStorageImageDescriptorAtIndex(state, inst.memory.resource,
|
||||
binding.array_index, uint_image, view);
|
||||
|
||||
@@ -269,14 +273,17 @@ void EmitImageSample(EmitterState& state, const IR::Instruction& inst) {
|
||||
const auto view = SampledImageViewKind(state, inst.memory, inst.pc);
|
||||
const auto sampled_image = MakeSampledImage(state, inst.memory, inst.pc, view);
|
||||
|
||||
const auto layout = MakeImageSampleLayout(inst, view);
|
||||
const auto base_coord = EmitImageCoordF32(state, inst, layout, view);
|
||||
const auto sample = state.builder.AllocateId();
|
||||
const auto dref = HasImageSampleFlag(inst, Decoder::ImageSampleFlagCompare);
|
||||
const bool integer = inst.memory.kind == IR::ResourceKind::ImageUint;
|
||||
const auto result_type = dref ? state.float_type
|
||||
: integer ? state.vec4_uint_type
|
||||
: state.vec4_float_type;
|
||||
const auto layout = MakeImageSampleLayout(inst, view);
|
||||
const auto base_coord = EmitImageCoordF32(state, inst, layout, view);
|
||||
const auto sample = state.builder.AllocateId();
|
||||
const auto dref = HasImageSampleFlag(inst, Decoder::ImageSampleFlagCompare);
|
||||
const bool integer = inst.memory.kind == IR::ResourceKind::ImageUint;
|
||||
uint32_t result_type = state.vec4_float_type;
|
||||
if (dref) {
|
||||
result_type = state.float_type;
|
||||
} else if (integer) {
|
||||
result_type = state.vec4_uint_type;
|
||||
}
|
||||
const auto explicit_lod = ImageSampleNeedsExplicitLod(state, inst);
|
||||
const auto opcode = ImageSampleOpcode(state, inst);
|
||||
const auto coord =
|
||||
|
||||
@@ -38,14 +38,14 @@ uint32_t EmitSdwaExtractU32(EmitterState& state, const IR::Operand& operand, uin
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.int_type, signed_value, value});
|
||||
state.builder.AddFunction({OpBitFieldSExtract, state.int_type, extracted, signed_value,
|
||||
ConstantU32(state, offset), ConstantU32(state, width)});
|
||||
ConstantU32(state, offset), ConstantU32(state, width)});
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, extracted});
|
||||
return bits;
|
||||
}
|
||||
|
||||
const auto extracted = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitFieldUExtract, state.uint_type, extracted, value,
|
||||
ConstantU32(state, offset), ConstantU32(state, width)});
|
||||
ConstantU32(state, offset), ConstantU32(state, width)});
|
||||
return extracted;
|
||||
}
|
||||
|
||||
@@ -65,8 +65,7 @@ DppTargetLane EmitDppQuadPermTargetLane(EmitterState& state, uint32_t subid, uin
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, quad_base, subid, ConstantU32(state, 0xfffffffcu)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, shift, lane, ConstantU32(state, 1)});
|
||||
state.builder.AddFunction(
|
||||
@@ -86,8 +85,7 @@ DppTargetLane EmitDppRowShiftTargetLane(EmitterState& state, uint32_t subid, uin
|
||||
const auto valid = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)});
|
||||
if (left) {
|
||||
state.builder.AddFunction(
|
||||
{OpIAdd, state.uint_type, lane_shifted, lane, ConstantU32(state, amount)});
|
||||
@@ -114,8 +112,7 @@ DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState& state, uint32_t subi
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction(
|
||||
{OpUGreaterThanEqual, state.bool_type, in_high, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction({OpISub, state.uint_type, minus, lane, ConstantU32(state, amount)});
|
||||
@@ -174,7 +171,7 @@ uint32_t EmitDppValueU32(EmitterState& state, const IR::Operand& operand, uint32
|
||||
const auto target = EmitDppTargetLane(state, operand.dpp_ctrl);
|
||||
const auto shuffled = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, shuffled,
|
||||
ConstantU32(state, ScopeSubgroup), value, target.lane});
|
||||
ConstantU32(state, ScopeSubgroup), value, target.lane});
|
||||
if (operand.dpp_fetch_inactive) {
|
||||
return shuffled;
|
||||
}
|
||||
@@ -235,8 +232,7 @@ uint32_t EmitLaneMaskPartU32(EmitterState& state, uint32_t part) {
|
||||
const auto subid = EmitSubgroupLocalInvocationId(state);
|
||||
const auto lane = state.builder.AllocateId();
|
||||
const auto bit = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), lane});
|
||||
if (part == 0) {
|
||||
@@ -265,8 +261,7 @@ uint32_t EmitThreadMaskBelowPartU32(EmitterState& state, uint32_t part) {
|
||||
const auto lane = state.builder.AllocateId();
|
||||
const auto bit = state.builder.AllocateId();
|
||||
const auto below = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), lane});
|
||||
state.builder.AddFunction({OpISub, state.uint_type, below, bit, ConstantU32(state, 1)});
|
||||
@@ -462,7 +457,7 @@ uint32_t EmitVertexParameterComponentU32(EmitterState& state, const InputBinding
|
||||
const auto pointer_type = VertexParameterScalarPointerType(state, kind);
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, pointer_type, pointer, input.variable_id,
|
||||
ConstantU32(state, component)});
|
||||
ConstantU32(state, component)});
|
||||
state.builder.AddFunction({OpLoad, scalar_type, raw, pointer});
|
||||
}
|
||||
|
||||
@@ -527,10 +522,13 @@ uint32_t EmitFloatLoad(EmitterState& state, const IR::Operand& operand) {
|
||||
uint32_t ApplyResultModifiersF32(EmitterState& state, uint32_t value, const IR::Operand& dst) {
|
||||
uint32_t result = value;
|
||||
if (dst.omod != 0) {
|
||||
const uint32_t bits = dst.omod == 1u ? 0x40000000u
|
||||
: dst.omod == 2u ? 0x40800000u
|
||||
: 0x3f000000u;
|
||||
const auto scaled = state.builder.AllocateId();
|
||||
uint32_t bits = 0x3f000000u;
|
||||
switch (dst.omod) {
|
||||
case 1u: bits = 0x40000000u; break;
|
||||
case 2u: bits = 0x40800000u; break;
|
||||
default: break;
|
||||
}
|
||||
const auto scaled = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpFMul, state.float_type, scaled, result, ConstantF32(state, bits)});
|
||||
result = scaled;
|
||||
@@ -540,7 +538,7 @@ uint32_t ApplyResultModifiersF32(EmitterState& state, uint32_t value, const IR::
|
||||
}
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpExtInst, state.float_type, ret, state.glsl_std450, GlslFClamp,
|
||||
result, ConstantF32(state, 0), ConstantF32(state, 0x3f800000u)});
|
||||
result, ConstantF32(state, 0), ConstantF32(state, 0x3f800000u)});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -565,7 +563,7 @@ uint32_t EmitMixF32Load(EmitterState& state, const IR::Operand& operand) {
|
||||
const auto unpacked = state.builder.AllocateId();
|
||||
auto f32 = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450,
|
||||
GlslUnpackHalf2x16, bits});
|
||||
GlslUnpackHalf2x16, bits});
|
||||
state.builder.AddFunction(
|
||||
{OpCompositeExtract, state.float_type, f32, unpacked, operand.op_sel ? 1u : 0u});
|
||||
if (operand.absolute) {
|
||||
@@ -651,7 +649,7 @@ uint32_t EmitLaneIndexActiveBool(EmitterState& state, uint32_t lane) {
|
||||
if (state.per_invocation_masks) {
|
||||
const auto ballot = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot,
|
||||
ConstantU32(state, ScopeSubgroup), EmitExecActiveBool(state)});
|
||||
ConstantU32(state, ScopeSubgroup), EmitExecActiveBool(state)});
|
||||
return EmitBallotLaneActiveBool(state, ballot, lane);
|
||||
}
|
||||
const auto lane_low = state.builder.AllocateId();
|
||||
@@ -682,7 +680,7 @@ uint32_t EmitLaneIndexActiveBool(EmitterState& state, uint32_t lane) {
|
||||
uint32_t EmitSubgroupLaneActiveBool(EmitterState& state, uint32_t lane) {
|
||||
const auto active_ballot = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, active_ballot,
|
||||
ConstantU32(state, ScopeSubgroup), EmitTrueBool(state)});
|
||||
ConstantU32(state, ScopeSubgroup), EmitTrueBool(state)});
|
||||
return EmitBallotLaneActiveBool(state, active_ballot, lane);
|
||||
}
|
||||
uint32_t EmitBallotLaneActiveBool(EmitterState& state, uint32_t active_ballot, uint32_t lane) {
|
||||
|
||||
Reference in New Issue
Block a user