mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-11-30 20:34:24 +01:00
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.
This commit is contained in:
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");
|
throw NotImplementedException("Indirect constant buffer loading");
|
||||||
}
|
}
|
||||||
const Register ret{ctx.reg_alloc.Define(inst)};
|
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);
|
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,
|
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()) {
|
if (!binding.IsImmediate()) {
|
||||||
throw NotImplementedException("Constant buffer indexing");
|
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)};
|
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)};
|
||||||
return ctx.OpLoad(result_type, access_chain);
|
return ctx.OpLoad(result_type, access_chain);
|
||||||
}
|
}
|
||||||
if (check_alignment && offset.U32() % element_size != 0) {
|
// Hardware been proved to read the aligned offset (e.g. LDC.U32 at 6 will read offset 4)
|
||||||
throw NotImplementedException("Unaligned immediate constant buffer load");
|
|
||||||
}
|
|
||||||
const Id imm_offset{ctx.Const(offset.U32() / element_size)};
|
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)};
|
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)};
|
||||||
return ctx.OpLoad(result_type, access_chain);
|
return ctx.OpLoad(result_type, access_chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
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,
|
return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset);
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 index_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) {
|
static std::pair<IR::U32, IR::U32> CbufAddr(u64 insn) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<20, 14, s64> offset;
|
BitField<20, 14, u64> offset;
|
||||||
BitField<34, 5, u64> binding;
|
BitField<34, 5, u64> binding;
|
||||||
} const cbuf{insn};
|
} const cbuf{insn};
|
||||||
|
|
||||||
if (cbuf.binding >= 18) {
|
if (cbuf.binding >= 18) {
|
||||||
throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding);
|
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);
|
throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset);
|
||||||
}
|
}
|
||||||
const IR::Value binding{static_cast<u32>(cbuf.binding)};
|
const IR::Value binding{static_cast<u32>(cbuf.binding)};
|
||||||
|
Loading…
Reference in New Issue
Block a user