diff options
3 files changed, 13 insertions, 8 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index 787612def..9ad668b86 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp | |||
| @@ -18,6 +18,14 @@ void GetCbuf(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU | |||
| 18 | throw NotImplementedException("Indirect constant buffer loading"); | 18 | throw NotImplementedException("Indirect constant buffer loading"); |
| 19 | } | 19 | } |
| 20 | const Register ret{ctx.reg_alloc.Define(inst)}; | 20 | const Register ret{ctx.reg_alloc.Define(inst)}; |
| 21 | if (offset.type == Type::U32) { | ||
| 22 | // Avoid reading arrays out of bounds, matching hardware's behavior | ||
| 23 | const u32 imm_offset{offset.imm_u32}; | ||
| 24 | if (offset.imm_u32 >= 0x10'000) { | ||
| 25 | ctx.Add("MOV.S {},0;", ret); | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | } | ||
| 21 | ctx.Add("LDC.{} {},c{}[{}];", size, ret, binding.U32(), offset); | 29 | ctx.Add("LDC.{} {},c{}[{}];", size, ret, binding.U32(), offset); |
| 22 | } | 30 | } |
| 23 | 31 | ||
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index c1b69c234..442a958a5 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | |||
| @@ -122,7 +122,7 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | |||
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, | 124 | Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, |
| 125 | const IR::Value& binding, const IR::Value& offset, bool check_alignment = true) { | 125 | const IR::Value& binding, const IR::Value& offset) { |
| 126 | if (!binding.IsImmediate()) { | 126 | if (!binding.IsImmediate()) { |
| 127 | throw NotImplementedException("Constant buffer indexing"); | 127 | throw NotImplementedException("Constant buffer indexing"); |
| 128 | } | 128 | } |
| @@ -138,17 +138,14 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, | |||
| 138 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)}; | 138 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, index)}; |
| 139 | return ctx.OpLoad(result_type, access_chain); | 139 | return ctx.OpLoad(result_type, access_chain); |
| 140 | } | 140 | } |
| 141 | if (check_alignment && offset.U32() % element_size != 0) { | 141 | // Hardware been proved to read the aligned offset (e.g. LDC.U32 at 6 will read offset 4) |
| 142 | throw NotImplementedException("Unaligned immediate constant buffer load"); | ||
| 143 | } | ||
| 144 | const Id imm_offset{ctx.Const(offset.U32() / element_size)}; | 142 | const Id imm_offset{ctx.Const(offset.U32() / element_size)}; |
| 145 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)}; | 143 | const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, imm_offset)}; |
| 146 | return ctx.OpLoad(result_type, access_chain); | 144 | return ctx.OpLoad(result_type, access_chain); |
| 147 | } | 145 | } |
| 148 | 146 | ||
| 149 | Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 147 | Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 150 | return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset, | 148 | return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset); |
| 151 | false); | ||
| 152 | } | 149 | } |
| 153 | 150 | ||
| 154 | Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 index_offset) { | 151 | Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 index_offset) { |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp index 88bbac0a5..b446aae0e 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp | |||
| @@ -122,14 +122,14 @@ IR::F64 TranslatorVisitor::GetDoubleReg39(u64 insn) { | |||
| 122 | static std::pair<IR::U32, IR::U32> CbufAddr(u64 insn) { | 122 | static std::pair<IR::U32, IR::U32> CbufAddr(u64 insn) { |
| 123 | union { | 123 | union { |
| 124 | u64 raw; | 124 | u64 raw; |
| 125 | BitField<20, 14, s64> offset; | 125 | BitField<20, 14, u64> offset; |
| 126 | BitField<34, 5, u64> binding; | 126 | BitField<34, 5, u64> binding; |
| 127 | } const cbuf{insn}; | 127 | } const cbuf{insn}; |
| 128 | 128 | ||
| 129 | if (cbuf.binding >= 18) { | 129 | if (cbuf.binding >= 18) { |
| 130 | throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding); | 130 | throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding); |
| 131 | } | 131 | } |
| 132 | if (cbuf.offset >= 0x10'000 || cbuf.offset < 0) { | 132 | if (cbuf.offset >= 0x10'000) { |
| 133 | throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset); | 133 | throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset); |
| 134 | } | 134 | } |
| 135 | const IR::Value binding{static_cast<u32>(cbuf.binding)}; | 135 | const IR::Value binding{static_cast<u32>(cbuf.binding)}; |