graphics: cleanup

This commit is contained in:
nmzik
2026-07-23 23:21:26 +02:00
parent 7638c25d76
commit a720b28b7f
25 changed files with 422 additions and 342 deletions
+64 -35
View File
@@ -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;
}
+32 -52
View File
@@ -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) {