shader: Add support for "negative" and unaligned offsets
"Negative" offsets don't exist. They are shown as such due to a bug in nvdisasm. Unaligned offsets have been proved to read the aligned offset. For example, when reading an U32, if the offset is 6, the offset read will be 4.pull/6585/head
parent
5d170de0b5
commit
05d41fa9b7
|
|
@ -18,6 +18,14 @@ void GetCbuf(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU
|
|||
throw NotImplementedException("Indirect constant buffer loading");
|
||||
}
|
||||
const Register ret{ctx.reg_alloc.Define(inst)};
|
||||
if (offset.type == Type::U32) {
|
||||
// Avoid reading arrays out of bounds, matching hardware's behavior
|
||||
const u32 imm_offset{offset.imm_u32};
|
||||
if (offset.imm_u32 >= 0x10'000) {
|
||||
ctx.Add("MOV.S {},0;", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ctx.Add("LDC.{} {},c{}[{}];", size, ret, binding.U32(), offset);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
|
|||
}
|
||||
|
||||
Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size,
|
||||
const IR::Value& binding, const IR::Value& offset, bool check_alignment = true) {
|
||||
const IR::Value& binding, const IR::Value& offset) {
|
||||
if (!binding.IsImmediate()) {
|
||||
throw NotImplementedException("Constant buffer indexing");
|
||||
}
|
||||
|
|
@ -138,17 +138,14 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
|
|||
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)};
|
||||
return ctx.OpLoad(result_type, access_chain);
|
||||
}
|
||||
if (check_alignment && offset.U32() % element_size != 0) {
|
||||
throw NotImplementedException("Unaligned immediate constant buffer load");
|
||||
}
|
||||
// Hardware been proved to read the aligned offset (e.g. LDC.U32 at 6 will read offset 4)
|
||||
const Id imm_offset{ctx.Const(offset.U32() / element_size)};
|
||||
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)};
|
||||
return ctx.OpLoad(result_type, access_chain);
|
||||
}
|
||||
|
||||
Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||
return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset,
|
||||
false);
|
||||
return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset);
|
||||
}
|
||||
|
||||
Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 index_offset) {
|
||||
|
|
|
|||
|
|
@ -122,14 +122,14 @@ IR::F64 TranslatorVisitor::GetDoubleReg39(u64 insn) {
|
|||
static std::pair<IR::U32, IR::U32> CbufAddr(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<20, 14, s64> offset;
|
||||
BitField<20, 14, u64> offset;
|
||||
BitField<34, 5, u64> binding;
|
||||
} const cbuf{insn};
|
||||
|
||||
if (cbuf.binding >= 18) {
|
||||
throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding);
|
||||
}
|
||||
if (cbuf.offset >= 0x10'000 || cbuf.offset < 0) {
|
||||
if (cbuf.offset >= 0x10'000) {
|
||||
throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset);
|
||||
}
|
||||
const IR::Value binding{static_cast<u32>(cbuf.binding)};
|
||||
|
|
|
|||
Loading…
Reference in New Issue