summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-05-30 23:08:17 -0300
committerGravatar ameerj2021-07-22 21:51:34 -0400
commit05d41fa9b70af6d469f2f6f1474436c9255e9bc3 (patch)
tree52bd8f8a6456c46fc9120aafa99b2d4a45b79746 /src
parentshader: Implement ISCADD32I (diff)
downloadyuzu-05d41fa9b70af6d469f2f6f1474436c9255e9bc3.tar.gz
yuzu-05d41fa9b70af6d469f2f6f1474436c9255e9bc3.tar.xz
yuzu-05d41fa9b70af6d469f2f6f1474436c9255e9bc3.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp8
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp9
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp4
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
124Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, 124Id 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
149Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 147Id 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
154Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 index_offset) { 151Id 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) {
122static std::pair<IR::U32, IR::U32> CbufAddr(u64 insn) { 122static 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)};