summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/settings.h3
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_instructions.h2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp8
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp24
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h2
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp14
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h3
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc2
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp42
-rw-r--r--src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp66
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp4
-rw-r--r--src/yuzu/configuration/config.cpp4
-rw-r--r--src/yuzu/configuration/configure_debug.cpp8
-rw-r--r--src/yuzu/configuration/configure_debug.ui26
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/default_ini.h8
16 files changed, 183 insertions, 35 deletions
diff --git a/src/common/settings.h b/src/common/settings.h
index ce1bc647d..ac0590690 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -308,6 +308,9 @@ struct Values {
308 // Renderer 308 // Renderer
309 Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"}; 309 Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
310 BasicSetting<bool> renderer_debug{false, "debug"}; 310 BasicSetting<bool> renderer_debug{false, "debug"};
311 BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
312 BasicSetting<bool> disable_shader_loop_safety_checks{false,
313 "disable_shader_loop_safety_checks"};
311 Setting<int> vulkan_device{0, "vulkan_device"}; 314 Setting<int> vulkan_device{0, "vulkan_device"};
312 315
313 Setting<u16> resolution_factor{1, "resolution_factor"}; 316 Setting<u16> resolution_factor{1, "resolution_factor"};
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
index c9f4826ce..fef9ff9be 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -42,6 +42,8 @@ void EmitSetGotoVariable(EmitContext& ctx);
42void EmitGetGotoVariable(EmitContext& ctx); 42void EmitGetGotoVariable(EmitContext& ctx);
43void EmitSetIndirectBranchVariable(EmitContext& ctx); 43void EmitSetIndirectBranchVariable(EmitContext& ctx);
44void EmitGetIndirectBranchVariable(EmitContext& ctx); 44void EmitGetIndirectBranchVariable(EmitContext& ctx);
45void EmitSetLoopSafetyVariable(EmitContext& ctx);
46void EmitGetLoopSafetyVariable(EmitContext& ctx);
45void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); 47void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
46void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); 48void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
47void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); 49void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
index 95bcbd750..60735fe31 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
@@ -153,6 +153,14 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
153 NotImplemented(); 153 NotImplemented();
154} 154}
155 155
156void EmitSetLoopSafetyVariable(EmitContext& ctx) {
157 NotImplemented();
158}
159
160void EmitGetLoopSafetyVariable(EmitContext& ctx) {
161 NotImplemented();
162}
163
156void EmitGetZFlag(EmitContext& ctx) { 164void EmitGetZFlag(EmitContext& ctx) {
157 NotImplemented(); 165 NotImplemented();
158} 166}
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 442a958a5..42fff74e3 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
@@ -163,35 +163,43 @@ Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 inde
163} // Anonymous namespace 163} // Anonymous namespace
164 164
165void EmitGetRegister(EmitContext&) { 165void EmitGetRegister(EmitContext&) {
166 throw NotImplementedException("SPIR-V Instruction"); 166 throw LogicError("Unreachable instruction");
167} 167}
168 168
169void EmitSetRegister(EmitContext&) { 169void EmitSetRegister(EmitContext&) {
170 throw NotImplementedException("SPIR-V Instruction"); 170 throw LogicError("Unreachable instruction");
171} 171}
172 172
173void EmitGetPred(EmitContext&) { 173void EmitGetPred(EmitContext&) {
174 throw NotImplementedException("SPIR-V Instruction"); 174 throw LogicError("Unreachable instruction");
175} 175}
176 176
177void EmitSetPred(EmitContext&) { 177void EmitSetPred(EmitContext&) {
178 throw NotImplementedException("SPIR-V Instruction"); 178 throw LogicError("Unreachable instruction");
179} 179}
180 180
181void EmitSetGotoVariable(EmitContext&) { 181void EmitSetGotoVariable(EmitContext&) {
182 throw NotImplementedException("SPIR-V Instruction"); 182 throw LogicError("Unreachable instruction");
183} 183}
184 184
185void EmitGetGotoVariable(EmitContext&) { 185void EmitGetGotoVariable(EmitContext&) {
186 throw NotImplementedException("SPIR-V Instruction"); 186 throw LogicError("Unreachable instruction");
187} 187}
188 188
189void EmitSetIndirectBranchVariable(EmitContext&) { 189void EmitSetIndirectBranchVariable(EmitContext&) {
190 throw NotImplementedException("SPIR-V Instruction"); 190 throw LogicError("Unreachable instruction");
191} 191}
192 192
193void EmitGetIndirectBranchVariable(EmitContext&) { 193void EmitGetIndirectBranchVariable(EmitContext&) {
194 throw NotImplementedException("SPIR-V Instruction"); 194 throw LogicError("Unreachable instruction");
195}
196
197void EmitSetLoopSafetyVariable(EmitContext&) {
198 throw LogicError("Unreachable instruction");
199}
200
201void EmitGetLoopSafetyVariable(EmitContext&) {
202 throw LogicError("Unreachable instruction");
195} 203}
196 204
197Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 205Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index 1181e7b4f..e3e5b03fe 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -43,6 +43,8 @@ void EmitSetGotoVariable(EmitContext& ctx);
43void EmitGetGotoVariable(EmitContext& ctx); 43void EmitGetGotoVariable(EmitContext& ctx);
44void EmitSetIndirectBranchVariable(EmitContext& ctx); 44void EmitSetIndirectBranchVariable(EmitContext& ctx);
45void EmitGetIndirectBranchVariable(EmitContext& ctx); 45void EmitGetIndirectBranchVariable(EmitContext& ctx);
46void EmitSetLoopSafetyVariable(EmitContext& ctx);
47void EmitGetLoopSafetyVariable(EmitContext& ctx);
46Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 48Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
47Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 49Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
48Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 50Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index e9fd41237..6c37af5e7 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -125,6 +125,12 @@ U1 IREmitter::GetPred(IR::Pred pred, bool is_negated) {
125 } 125 }
126} 126}
127 127
128void IREmitter::SetPred(IR::Pred pred, const U1& value) {
129 if (pred != IR::Pred::PT) {
130 Inst(Opcode::SetPred, pred, value);
131 }
132}
133
128U1 IREmitter::GetGotoVariable(u32 id) { 134U1 IREmitter::GetGotoVariable(u32 id) {
129 return Inst<U1>(Opcode::GetGotoVariable, id); 135 return Inst<U1>(Opcode::GetGotoVariable, id);
130} 136}
@@ -141,8 +147,12 @@ void IREmitter::SetIndirectBranchVariable(const U32& value) {
141 Inst(Opcode::SetIndirectBranchVariable, value); 147 Inst(Opcode::SetIndirectBranchVariable, value);
142} 148}
143 149
144void IREmitter::SetPred(IR::Pred pred, const U1& value) { 150U32 IREmitter::GetLoopSafetyVariable(u32 id) {
145 Inst(Opcode::SetPred, pred, value); 151 return Inst<U32>(Opcode::GetLoopSafetyVariable, id);
152}
153
154void IREmitter::SetLoopSafetyVariable(u32 id, const U32& counter) {
155 Inst(Opcode::SetLoopSafetyVariable, id, counter);
146} 156}
147 157
148U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) { 158U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) {
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index bb3500c54..7caab1f61 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -55,6 +55,9 @@ public:
55 [[nodiscard]] U32 GetIndirectBranchVariable(); 55 [[nodiscard]] U32 GetIndirectBranchVariable();
56 void SetIndirectBranchVariable(const U32& value); 56 void SetIndirectBranchVariable(const U32& value);
57 57
58 [[nodiscard]] U32 GetLoopSafetyVariable(u32 id);
59 void SetLoopSafetyVariable(u32 id, const U32& counter);
60
58 [[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset); 61 [[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset);
59 [[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize, 62 [[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
60 bool is_signed); 63 bool is_signed);
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 8a8d0d759..e87aeddd5 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -32,6 +32,8 @@ OPCODE(GetGotoVariable, U1, U32,
32OPCODE(SetGotoVariable, Void, U32, U1, ) 32OPCODE(SetGotoVariable, Void, U32, U1, )
33OPCODE(GetIndirectBranchVariable, U32, ) 33OPCODE(GetIndirectBranchVariable, U32, )
34OPCODE(SetIndirectBranchVariable, Void, U32, ) 34OPCODE(SetIndirectBranchVariable, Void, U32, )
35OPCODE(GetLoopSafetyVariable, U32, U32, )
36OPCODE(SetLoopSafetyVariable, Void, U32, U32, )
35OPCODE(GetCbufU8, U32, U32, U32, ) 37OPCODE(GetCbufU8, U32, U32, U32, )
36OPCODE(GetCbufS8, U32, U32, U32, ) 38OPCODE(GetCbufS8, U32, U32, U32, )
37OPCODE(GetCbufU16, U32, U32, U32, ) 39OPCODE(GetCbufU16, U32, U32, U32, )
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index c1e0646e6..b2b8c492a 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -9,11 +9,13 @@
9#include <unordered_map> 9#include <unordered_map>
10#include <utility> 10#include <utility>
11#include <vector> 11#include <vector>
12#include <version>
12 13
13#include <fmt/format.h> 14#include <fmt/format.h>
14 15
15#include <boost/intrusive/list.hpp> 16#include <boost/intrusive/list.hpp>
16 17
18#include "common/settings.h"
17#include "shader_recompiler/environment.h" 19#include "shader_recompiler/environment.h"
18#include "shader_recompiler/frontend/ir/basic_block.h" 20#include "shader_recompiler/frontend/ir/basic_block.h"
19#include "shader_recompiler/frontend/ir/ir_emitter.h" 21#include "shader_recompiler/frontend/ir/ir_emitter.h"
@@ -739,8 +741,25 @@ private:
739 } 741 }
740 case StatementType::Loop: { 742 case StatementType::Loop: {
741 IR::Block* const loop_header_block{block_pool.Create(inst_pool)}; 743 IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
742 if (current_block) { 744 const u32 this_loop_id{loop_id++};
743 current_block->AddBranch(loop_header_block); 745
746 if (Settings::values.disable_shader_loop_safety_checks) {
747 if (current_block) {
748 current_block->AddBranch(loop_header_block);
749 }
750 } else {
751 IR::Block* const init_block{block_pool.Create(inst_pool)};
752 IR::IREmitter ir{*init_block};
753 ir.SetLoopSafetyVariable(this_loop_id, ir.Imm32(0x2000));
754
755 if (current_block) {
756 current_block->AddBranch(init_block);
757 }
758 init_block->AddBranch(loop_header_block);
759
760 auto& init_node{syntax_list.emplace_back()};
761 init_node.type = IR::AbstractSyntaxNode::Type::Block;
762 init_node.data.block = init_block;
744 } 763 }
745 auto& header_node{syntax_list.emplace_back()}; 764 auto& header_node{syntax_list.emplace_back()};
746 header_node.type = IR::AbstractSyntaxNode::Type::Block; 765 header_node.type = IR::AbstractSyntaxNode::Type::Block;
@@ -758,7 +777,16 @@ private:
758 777
759 // The continue block is located at the end of the loop 778 // The continue block is located at the end of the loop
760 IR::IREmitter ir{*continue_block}; 779 IR::IREmitter ir{*continue_block};
761 const IR::U1 cond{ir.ConditionRef(VisitExpr(ir, *stmt.cond))}; 780 IR::U1 cond{VisitExpr(ir, *stmt.cond)};
781 if (!Settings::values.disable_shader_loop_safety_checks) {
782 const IR::U32 old_counter{ir.GetLoopSafetyVariable(this_loop_id)};
783 const IR::U32 new_counter{ir.ISub(old_counter, ir.Imm32(1))};
784 ir.SetLoopSafetyVariable(this_loop_id, new_counter);
785
786 const IR::U1 safety_cond{ir.INotEqual(new_counter, ir.Imm32(0))};
787 cond = ir.LogicalAnd(cond, safety_cond);
788 }
789 cond = ir.ConditionRef(cond);
762 790
763 IR::Block* const body_block{syntax_list.at(body_block_index).data.block}; 791 IR::Block* const body_block{syntax_list.at(body_block_index).data.block};
764 loop_header_block->AddBranch(body_block); 792 loop_header_block->AddBranch(body_block);
@@ -863,8 +891,14 @@ private:
863 ObjectPool<IR::Block>& block_pool; 891 ObjectPool<IR::Block>& block_pool;
864 Environment& env; 892 Environment& env;
865 IR::AbstractSyntaxList& syntax_list; 893 IR::AbstractSyntaxList& syntax_list;
866 // TODO: Make this constexpr when std::vector is constexpr 894 u32 loop_id{};
895
896// TODO: C++20 Remove this when all compilers support constexpr std::vector
897#if __cpp_lib_constexpr_vector >= 201907
898 static constexpr Flow::Block dummy_flow_block;
899#else
867 const Flow::Block dummy_flow_block; 900 const Flow::Block dummy_flow_block;
901#endif
868}; 902};
869} // Anonymous namespace 903} // Anonymous namespace
870 904
diff --git a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
index e54499ba5..a4ba393ef 100644
--- a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
+++ b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
@@ -48,73 +48,91 @@ struct GotoVariable : FlagTag {
48 u32 index; 48 u32 index;
49}; 49};
50 50
51struct LoopSafetyVariable {
52 LoopSafetyVariable() = default;
53 explicit LoopSafetyVariable(u32 index_) : index{index_} {}
54
55 auto operator<=>(const LoopSafetyVariable&) const noexcept = default;
56
57 u32 index;
58};
59
51struct IndirectBranchVariable { 60struct IndirectBranchVariable {
52 auto operator<=>(const IndirectBranchVariable&) const noexcept = default; 61 auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
53}; 62};
54 63
55using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, 64using Variant =
56 OverflowFlagTag, GotoVariable, IndirectBranchVariable>; 65 std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, OverflowFlagTag,
57using ValueMap = boost::container::flat_map<IR::Block*, IR::Value, std::less<IR::Block*>>; 66 GotoVariable, LoopSafetyVariable, IndirectBranchVariable>;
67using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>;
58 68
59struct DefTable { 69struct DefTable {
60 const IR::Value& Def(IR::Block* block, IR::Reg variable) noexcept { 70 const IR::Value& Def(IR::Block* block, IR::Reg variable) {
61 return block->SsaRegValue(variable); 71 return block->SsaRegValue(variable);
62 } 72 }
63 void SetDef(IR::Block* block, IR::Reg variable, const IR::Value& value) noexcept { 73 void SetDef(IR::Block* block, IR::Reg variable, const IR::Value& value) {
64 block->SetSsaRegValue(variable, value); 74 block->SetSsaRegValue(variable, value);
65 } 75 }
66 76
67 const IR::Value& Def(IR::Block* block, IR::Pred variable) noexcept { 77 const IR::Value& Def(IR::Block* block, IR::Pred variable) {
68 return preds[IR::PredIndex(variable)][block]; 78 return preds[IR::PredIndex(variable)][block];
69 } 79 }
70 void SetDef(IR::Block* block, IR::Pred variable, const IR::Value& value) noexcept { 80 void SetDef(IR::Block* block, IR::Pred variable, const IR::Value& value) {
71 preds[IR::PredIndex(variable)].insert_or_assign(block, value); 81 preds[IR::PredIndex(variable)].insert_or_assign(block, value);
72 } 82 }
73 83
74 const IR::Value& Def(IR::Block* block, GotoVariable variable) noexcept { 84 const IR::Value& Def(IR::Block* block, GotoVariable variable) {
75 return goto_vars[variable.index][block]; 85 return goto_vars[variable.index][block];
76 } 86 }
77 void SetDef(IR::Block* block, GotoVariable variable, const IR::Value& value) noexcept { 87 void SetDef(IR::Block* block, GotoVariable variable, const IR::Value& value) {
78 goto_vars[variable.index].insert_or_assign(block, value); 88 goto_vars[variable.index].insert_or_assign(block, value);
79 } 89 }
80 90
81 const IR::Value& Def(IR::Block* block, IndirectBranchVariable) noexcept { 91 const IR::Value& Def(IR::Block* block, LoopSafetyVariable variable) {
92 return loop_safety_vars[variable.index][block];
93 }
94 void SetDef(IR::Block* block, LoopSafetyVariable variable, const IR::Value& value) {
95 loop_safety_vars[variable.index].insert_or_assign(block, value);
96 }
97
98 const IR::Value& Def(IR::Block* block, IndirectBranchVariable) {
82 return indirect_branch_var[block]; 99 return indirect_branch_var[block];
83 } 100 }
84 void SetDef(IR::Block* block, IndirectBranchVariable, const IR::Value& value) noexcept { 101 void SetDef(IR::Block* block, IndirectBranchVariable, const IR::Value& value) {
85 indirect_branch_var.insert_or_assign(block, value); 102 indirect_branch_var.insert_or_assign(block, value);
86 } 103 }
87 104
88 const IR::Value& Def(IR::Block* block, ZeroFlagTag) noexcept { 105 const IR::Value& Def(IR::Block* block, ZeroFlagTag) {
89 return zero_flag[block]; 106 return zero_flag[block];
90 } 107 }
91 void SetDef(IR::Block* block, ZeroFlagTag, const IR::Value& value) noexcept { 108 void SetDef(IR::Block* block, ZeroFlagTag, const IR::Value& value) {
92 zero_flag.insert_or_assign(block, value); 109 zero_flag.insert_or_assign(block, value);
93 } 110 }
94 111
95 const IR::Value& Def(IR::Block* block, SignFlagTag) noexcept { 112 const IR::Value& Def(IR::Block* block, SignFlagTag) {
96 return sign_flag[block]; 113 return sign_flag[block];
97 } 114 }
98 void SetDef(IR::Block* block, SignFlagTag, const IR::Value& value) noexcept { 115 void SetDef(IR::Block* block, SignFlagTag, const IR::Value& value) {
99 sign_flag.insert_or_assign(block, value); 116 sign_flag.insert_or_assign(block, value);
100 } 117 }
101 118
102 const IR::Value& Def(IR::Block* block, CarryFlagTag) noexcept { 119 const IR::Value& Def(IR::Block* block, CarryFlagTag) {
103 return carry_flag[block]; 120 return carry_flag[block];
104 } 121 }
105 void SetDef(IR::Block* block, CarryFlagTag, const IR::Value& value) noexcept { 122 void SetDef(IR::Block* block, CarryFlagTag, const IR::Value& value) {
106 carry_flag.insert_or_assign(block, value); 123 carry_flag.insert_or_assign(block, value);
107 } 124 }
108 125
109 const IR::Value& Def(IR::Block* block, OverflowFlagTag) noexcept { 126 const IR::Value& Def(IR::Block* block, OverflowFlagTag) {
110 return overflow_flag[block]; 127 return overflow_flag[block];
111 } 128 }
112 void SetDef(IR::Block* block, OverflowFlagTag, const IR::Value& value) noexcept { 129 void SetDef(IR::Block* block, OverflowFlagTag, const IR::Value& value) {
113 overflow_flag.insert_or_assign(block, value); 130 overflow_flag.insert_or_assign(block, value);
114 } 131 }
115 132
116 std::array<ValueMap, IR::NUM_USER_PREDS> preds; 133 std::array<ValueMap, IR::NUM_USER_PREDS> preds;
117 boost::container::flat_map<u32, ValueMap> goto_vars; 134 boost::container::flat_map<u32, ValueMap> goto_vars;
135 boost::container::flat_map<u32, ValueMap> loop_safety_vars;
118 ValueMap indirect_branch_var; 136 ValueMap indirect_branch_var;
119 ValueMap zero_flag; 137 ValueMap zero_flag;
120 ValueMap sign_flag; 138 ValueMap sign_flag;
@@ -134,6 +152,10 @@ IR::Opcode UndefOpcode(const FlagTag&) noexcept {
134 return IR::Opcode::UndefU1; 152 return IR::Opcode::UndefU1;
135} 153}
136 154
155IR::Opcode UndefOpcode(const LoopSafetyVariable&) noexcept {
156 return IR::Opcode::UndefU32;
157}
158
137IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept { 159IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept {
138 return IR::Opcode::UndefU32; 160 return IR::Opcode::UndefU32;
139} 161}
@@ -315,6 +337,9 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
315 case IR::Opcode::SetGotoVariable: 337 case IR::Opcode::SetGotoVariable:
316 pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1)); 338 pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
317 break; 339 break;
340 case IR::Opcode::SetLoopSafetyVariable:
341 pass.WriteVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block, inst.Arg(0));
342 break;
318 case IR::Opcode::SetIndirectBranchVariable: 343 case IR::Opcode::SetIndirectBranchVariable:
319 pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0)); 344 pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0));
320 break; 345 break;
@@ -343,6 +368,9 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
343 case IR::Opcode::GetGotoVariable: 368 case IR::Opcode::GetGotoVariable:
344 inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block)); 369 inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block));
345 break; 370 break;
371 case IR::Opcode::GetLoopSafetyVariable:
372 inst.ReplaceUsesWith(pass.ReadVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block));
373 break;
346 case IR::Opcode::GetIndirectBranchVariable: 374 case IR::Opcode::GetIndirectBranchVariable:
347 inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block)); 375 inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block));
348 break; 376 break;
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 8eb37a77a..bf063c047 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -467,7 +467,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
467 } 467 }
468 468
469 VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv; 469 VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv;
470 if (nv_device_diagnostics_config) { 470 if (Settings::values.enable_nsight_aftermath && nv_device_diagnostics_config) {
471 nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>(); 471 nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>();
472 472
473 diagnostics_nv = { 473 diagnostics_nv = {
@@ -781,7 +781,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
781 test(has_ext_shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, false); 781 test(has_ext_shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, false);
782 test(has_khr_workgroup_memory_explicit_layout, 782 test(has_khr_workgroup_memory_explicit_layout,
783 VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, false); 783 VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, false);
784 if (Settings::values.renderer_debug) { 784 if (Settings::values.enable_nsight_aftermath) {
785 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, 785 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
786 true); 786 true);
787 } 787 }
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index a5e032959..dc69574a9 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -824,6 +824,8 @@ void Config::ReadRendererValues() {
824 824
825 if (global) { 825 if (global) {
826 ReadBasicSetting(Settings::values.renderer_debug); 826 ReadBasicSetting(Settings::values.renderer_debug);
827 ReadBasicSetting(Settings::values.enable_nsight_aftermath);
828 ReadBasicSetting(Settings::values.disable_shader_loop_safety_checks);
827 } 829 }
828 830
829 qt_config->endGroup(); 831 qt_config->endGroup();
@@ -1353,6 +1355,8 @@ void Config::SaveRendererValues() {
1353 1355
1354 if (global) { 1356 if (global) {
1355 WriteBasicSetting(Settings::values.renderer_debug); 1357 WriteBasicSetting(Settings::values.renderer_debug);
1358 WriteBasicSetting(Settings::values.enable_nsight_aftermath);
1359 WriteBasicSetting(Settings::values.disable_shader_loop_safety_checks);
1356 } 1360 }
1357 1361
1358 qt_config->endGroup(); 1362 qt_config->endGroup();
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 8fceb3878..f7e29dbd7 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -45,8 +45,13 @@ void ConfigureDebug::SetConfiguration() {
45 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue()); 45 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
46 ui->enable_cpu_debugging->setEnabled(runtime_lock); 46 ui->enable_cpu_debugging->setEnabled(runtime_lock);
47 ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue()); 47 ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue());
48 ui->enable_nsight_aftermath->setEnabled(runtime_lock);
49 ui->enable_nsight_aftermath->setChecked(Settings::values.enable_nsight_aftermath.GetValue());
48 ui->disable_macro_jit->setEnabled(runtime_lock); 50 ui->disable_macro_jit->setEnabled(runtime_lock);
49 ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue()); 51 ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue());
52 ui->disable_loop_safety_checks->setEnabled(runtime_lock);
53 ui->disable_loop_safety_checks->setChecked(
54 Settings::values.disable_shader_loop_safety_checks.GetValue());
50 ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue()); 55 ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
51} 56}
52 57
@@ -61,6 +66,9 @@ void ConfigureDebug::ApplyConfiguration() {
61 Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); 66 Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
62 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); 67 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
63 Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); 68 Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked();
69 Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked();
70 Settings::values.disable_shader_loop_safety_checks =
71 ui->disable_loop_safety_checks->isChecked();
64 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); 72 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
65 Settings::values.extended_logging = ui->extended_logging->isChecked(); 73 Settings::values.extended_logging = ui->extended_logging->isChecked();
66 Debugger::ToggleConsole(); 74 Debugger::ToggleConsole();
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 1260ad6f0..c8baf2921 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -126,6 +126,16 @@
126 </widget> 126 </widget>
127 </item> 127 </item>
128 <item> 128 <item>
129 <widget class="QCheckBox" name="enable_nsight_aftermath">
130 <property name="toolTip">
131 <string>When checked, it enables Nsight Aftermath crash dumps</string>
132 </property>
133 <property name="text">
134 <string>Enable Nsight Aftermath</string>
135 </property>
136 </widget>
137 </item>
138 <item>
129 <widget class="QCheckBox" name="disable_macro_jit"> 139 <widget class="QCheckBox" name="disable_macro_jit">
130 <property name="enabled"> 140 <property name="enabled">
131 <bool>true</bool> 141 <bool>true</bool>
@@ -138,6 +148,16 @@
138 </property> 148 </property>
139 </widget> 149 </widget>
140 </item> 150 </item>
151 <item>
152 <widget class="QCheckBox" name="disable_loop_safety_checks">
153 <property name="toolTip">
154 <string>When checked, it executes shaders without loop logic changes</string>
155 </property>
156 <property name="text">
157 <string>Disable Loop safety checks</string>
158 </property>
159 </widget>
160 </item>
141 </layout> 161 </layout>
142 </widget> 162 </widget>
143 </item> 163 </item>
@@ -252,11 +272,17 @@
252 <tabstops> 272 <tabstops>
253 <tabstop>log_filter_edit</tabstop> 273 <tabstop>log_filter_edit</tabstop>
254 <tabstop>toggle_console</tabstop> 274 <tabstop>toggle_console</tabstop>
275 <tabstop>extended_logging</tabstop>
255 <tabstop>open_log_button</tabstop> 276 <tabstop>open_log_button</tabstop>
256 <tabstop>homebrew_args_edit</tabstop> 277 <tabstop>homebrew_args_edit</tabstop>
257 <tabstop>enable_graphics_debugging</tabstop> 278 <tabstop>enable_graphics_debugging</tabstop>
279 <tabstop>enable_nsight_aftermath</tabstop>
280 <tabstop>disable_macro_jit</tabstop>
281 <tabstop>disable_loop_safety_checks</tabstop>
258 <tabstop>reporting_services</tabstop> 282 <tabstop>reporting_services</tabstop>
259 <tabstop>quest_flag</tabstop> 283 <tabstop>quest_flag</tabstop>
284 <tabstop>use_debug_asserts</tabstop>
285 <tabstop>use_auto_stub</tabstop>
260 </tabstops> 286 </tabstops>
261 <resources/> 287 <resources/>
262 <connections/> 288 <connections/>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 3e22fee37..763df6dd6 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -444,6 +444,8 @@ void Config::ReadValues() {
444 // Renderer 444 // Renderer
445 ReadSetting("Renderer", Settings::values.renderer_backend); 445 ReadSetting("Renderer", Settings::values.renderer_backend);
446 ReadSetting("Renderer", Settings::values.renderer_debug); 446 ReadSetting("Renderer", Settings::values.renderer_debug);
447 ReadSetting("Renderer", Settings::values.enable_nsight_aftermath);
448 ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks);
447 ReadSetting("Renderer", Settings::values.vulkan_device); 449 ReadSetting("Renderer", Settings::values.vulkan_device);
448 450
449 ReadSetting("Renderer", Settings::values.fullscreen_mode); 451 ReadSetting("Renderer", Settings::values.fullscreen_mode);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 88d33ecab..a6ca7b6cd 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -221,6 +221,14 @@ backend =
221# 0 (default): Disabled, 1: Enabled 221# 0 (default): Disabled, 1: Enabled
222debug = 222debug =
223 223
224# Enable Nsight Aftermath crash dumps
225# 0 (default): Disabled, 1: Enabled
226nsight_aftermath =
227
228# Disable shader loop safety checks, executing the shader without loop logic changes
229# 0 (default): Disabled, 1: Enabled
230disable_shader_loop_safety_checks =
231
224# Which Vulkan physical device to use (defaults to 0) 232# Which Vulkan physical device to use (defaults to 0)
225vulkan_device = 233vulkan_device =
226 234