shader: Add shader loop safety check settings
Also add a setting for enable Nsight Aftermath.
This commit is contained in:
parent
487057b8d2
commit
373f75d944
|
@ -308,6 +308,9 @@ struct Values {
|
||||||
// Renderer
|
// Renderer
|
||||||
Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
|
Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
|
||||||
BasicSetting<bool> renderer_debug{false, "debug"};
|
BasicSetting<bool> renderer_debug{false, "debug"};
|
||||||
|
BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
|
||||||
|
BasicSetting<bool> disable_shader_loop_safety_checks{false,
|
||||||
|
"disable_shader_loop_safety_checks"};
|
||||||
Setting<int> vulkan_device{0, "vulkan_device"};
|
Setting<int> vulkan_device{0, "vulkan_device"};
|
||||||
|
|
||||||
Setting<u16> resolution_factor{1, "resolution_factor"};
|
Setting<u16> resolution_factor{1, "resolution_factor"};
|
||||||
|
|
|
@ -42,6 +42,8 @@ void EmitSetGotoVariable(EmitContext& ctx);
|
||||||
void EmitGetGotoVariable(EmitContext& ctx);
|
void EmitGetGotoVariable(EmitContext& ctx);
|
||||||
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
||||||
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
||||||
|
void EmitSetLoopSafetyVariable(EmitContext& ctx);
|
||||||
|
void EmitGetLoopSafetyVariable(EmitContext& ctx);
|
||||||
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
||||||
void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
||||||
void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
||||||
|
|
|
@ -153,6 +153,14 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitSetLoopSafetyVariable(EmitContext& ctx) {
|
||||||
|
NotImplemented();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitGetLoopSafetyVariable(EmitContext& ctx) {
|
||||||
|
NotImplemented();
|
||||||
|
}
|
||||||
|
|
||||||
void EmitGetZFlag(EmitContext& ctx) {
|
void EmitGetZFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,35 +163,43 @@ Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 inde
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void EmitGetRegister(EmitContext&) {
|
void EmitGetRegister(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetRegister(EmitContext&) {
|
void EmitSetRegister(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetPred(EmitContext&) {
|
void EmitGetPred(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetPred(EmitContext&) {
|
void EmitSetPred(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetGotoVariable(EmitContext&) {
|
void EmitSetGotoVariable(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetGotoVariable(EmitContext&) {
|
void EmitGetGotoVariable(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetIndirectBranchVariable(EmitContext&) {
|
void EmitSetIndirectBranchVariable(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetIndirectBranchVariable(EmitContext&) {
|
void EmitGetIndirectBranchVariable(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitSetLoopSafetyVariable(EmitContext&) {
|
||||||
|
throw LogicError("Unreachable instruction");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitGetLoopSafetyVariable(EmitContext&) {
|
||||||
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||||
|
|
|
@ -43,6 +43,8 @@ void EmitSetGotoVariable(EmitContext& ctx);
|
||||||
void EmitGetGotoVariable(EmitContext& ctx);
|
void EmitGetGotoVariable(EmitContext& ctx);
|
||||||
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
||||||
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
||||||
|
void EmitSetLoopSafetyVariable(EmitContext& ctx);
|
||||||
|
void EmitGetLoopSafetyVariable(EmitContext& ctx);
|
||||||
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
||||||
Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
||||||
Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
||||||
|
|
|
@ -125,6 +125,12 @@ U1 IREmitter::GetPred(IR::Pred pred, bool is_negated) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IREmitter::SetPred(IR::Pred pred, const U1& value) {
|
||||||
|
if (pred != IR::Pred::PT) {
|
||||||
|
Inst(Opcode::SetPred, pred, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
U1 IREmitter::GetGotoVariable(u32 id) {
|
U1 IREmitter::GetGotoVariable(u32 id) {
|
||||||
return Inst<U1>(Opcode::GetGotoVariable, id);
|
return Inst<U1>(Opcode::GetGotoVariable, id);
|
||||||
}
|
}
|
||||||
|
@ -141,8 +147,12 @@ void IREmitter::SetIndirectBranchVariable(const U32& value) {
|
||||||
Inst(Opcode::SetIndirectBranchVariable, value);
|
Inst(Opcode::SetIndirectBranchVariable, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetPred(IR::Pred pred, const U1& value) {
|
U32 IREmitter::GetLoopSafetyVariable(u32 id) {
|
||||||
Inst(Opcode::SetPred, pred, value);
|
return Inst<U32>(Opcode::GetLoopSafetyVariable, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::SetLoopSafetyVariable(u32 id, const U32& counter) {
|
||||||
|
Inst(Opcode::SetLoopSafetyVariable, id, counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) {
|
U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) {
|
||||||
|
|
|
@ -55,6 +55,9 @@ public:
|
||||||
[[nodiscard]] U32 GetIndirectBranchVariable();
|
[[nodiscard]] U32 GetIndirectBranchVariable();
|
||||||
void SetIndirectBranchVariable(const U32& value);
|
void SetIndirectBranchVariable(const U32& value);
|
||||||
|
|
||||||
|
[[nodiscard]] U32 GetLoopSafetyVariable(u32 id);
|
||||||
|
void SetLoopSafetyVariable(u32 id, const U32& counter);
|
||||||
|
|
||||||
[[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset);
|
[[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset);
|
||||||
[[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
|
[[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
|
||||||
bool is_signed);
|
bool is_signed);
|
||||||
|
|
|
@ -32,6 +32,8 @@ OPCODE(GetGotoVariable, U1, U32,
|
||||||
OPCODE(SetGotoVariable, Void, U32, U1, )
|
OPCODE(SetGotoVariable, Void, U32, U1, )
|
||||||
OPCODE(GetIndirectBranchVariable, U32, )
|
OPCODE(GetIndirectBranchVariable, U32, )
|
||||||
OPCODE(SetIndirectBranchVariable, Void, U32, )
|
OPCODE(SetIndirectBranchVariable, Void, U32, )
|
||||||
|
OPCODE(GetLoopSafetyVariable, U32, U32, )
|
||||||
|
OPCODE(SetLoopSafetyVariable, Void, U32, U32, )
|
||||||
OPCODE(GetCbufU8, U32, U32, U32, )
|
OPCODE(GetCbufU8, U32, U32, U32, )
|
||||||
OPCODE(GetCbufS8, U32, U32, U32, )
|
OPCODE(GetCbufS8, U32, U32, U32, )
|
||||||
OPCODE(GetCbufU16, U32, U32, U32, )
|
OPCODE(GetCbufU16, U32, U32, U32, )
|
||||||
|
|
|
@ -9,11 +9,13 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <version>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <boost/intrusive/list.hpp>
|
#include <boost/intrusive/list.hpp>
|
||||||
|
|
||||||
|
#include "common/settings.h"
|
||||||
#include "shader_recompiler/environment.h"
|
#include "shader_recompiler/environment.h"
|
||||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||||
#include "shader_recompiler/frontend/ir/ir_emitter.h"
|
#include "shader_recompiler/frontend/ir/ir_emitter.h"
|
||||||
|
@ -739,8 +741,25 @@ private:
|
||||||
}
|
}
|
||||||
case StatementType::Loop: {
|
case StatementType::Loop: {
|
||||||
IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
|
IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
|
||||||
if (current_block) {
|
const u32 this_loop_id{loop_id++};
|
||||||
current_block->AddBranch(loop_header_block);
|
|
||||||
|
if (Settings::values.disable_shader_loop_safety_checks) {
|
||||||
|
if (current_block) {
|
||||||
|
current_block->AddBranch(loop_header_block);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
IR::Block* const init_block{block_pool.Create(inst_pool)};
|
||||||
|
IR::IREmitter ir{*init_block};
|
||||||
|
ir.SetLoopSafetyVariable(this_loop_id, ir.Imm32(0x2000));
|
||||||
|
|
||||||
|
if (current_block) {
|
||||||
|
current_block->AddBranch(init_block);
|
||||||
|
}
|
||||||
|
init_block->AddBranch(loop_header_block);
|
||||||
|
|
||||||
|
auto& init_node{syntax_list.emplace_back()};
|
||||||
|
init_node.type = IR::AbstractSyntaxNode::Type::Block;
|
||||||
|
init_node.data.block = init_block;
|
||||||
}
|
}
|
||||||
auto& header_node{syntax_list.emplace_back()};
|
auto& header_node{syntax_list.emplace_back()};
|
||||||
header_node.type = IR::AbstractSyntaxNode::Type::Block;
|
header_node.type = IR::AbstractSyntaxNode::Type::Block;
|
||||||
|
@ -758,7 +777,16 @@ private:
|
||||||
|
|
||||||
// The continue block is located at the end of the loop
|
// The continue block is located at the end of the loop
|
||||||
IR::IREmitter ir{*continue_block};
|
IR::IREmitter ir{*continue_block};
|
||||||
const IR::U1 cond{ir.ConditionRef(VisitExpr(ir, *stmt.cond))};
|
IR::U1 cond{VisitExpr(ir, *stmt.cond)};
|
||||||
|
if (!Settings::values.disable_shader_loop_safety_checks) {
|
||||||
|
const IR::U32 old_counter{ir.GetLoopSafetyVariable(this_loop_id)};
|
||||||
|
const IR::U32 new_counter{ir.ISub(old_counter, ir.Imm32(1))};
|
||||||
|
ir.SetLoopSafetyVariable(this_loop_id, new_counter);
|
||||||
|
|
||||||
|
const IR::U1 safety_cond{ir.INotEqual(new_counter, ir.Imm32(0))};
|
||||||
|
cond = ir.LogicalAnd(cond, safety_cond);
|
||||||
|
}
|
||||||
|
cond = ir.ConditionRef(cond);
|
||||||
|
|
||||||
IR::Block* const body_block{syntax_list.at(body_block_index).data.block};
|
IR::Block* const body_block{syntax_list.at(body_block_index).data.block};
|
||||||
loop_header_block->AddBranch(body_block);
|
loop_header_block->AddBranch(body_block);
|
||||||
|
@ -863,8 +891,14 @@ private:
|
||||||
ObjectPool<IR::Block>& block_pool;
|
ObjectPool<IR::Block>& block_pool;
|
||||||
Environment& env;
|
Environment& env;
|
||||||
IR::AbstractSyntaxList& syntax_list;
|
IR::AbstractSyntaxList& syntax_list;
|
||||||
// TODO: Make this constexpr when std::vector is constexpr
|
u32 loop_id{};
|
||||||
|
|
||||||
|
// TODO: C++20 Remove this when all compilers support constexpr std::vector
|
||||||
|
#if __cpp_lib_constexpr_vector >= 201907
|
||||||
|
static constexpr Flow::Block dummy_flow_block;
|
||||||
|
#else
|
||||||
const Flow::Block dummy_flow_block;
|
const Flow::Block dummy_flow_block;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
|
|
@ -48,73 +48,91 @@ struct GotoVariable : FlagTag {
|
||||||
u32 index;
|
u32 index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LoopSafetyVariable {
|
||||||
|
LoopSafetyVariable() = default;
|
||||||
|
explicit LoopSafetyVariable(u32 index_) : index{index_} {}
|
||||||
|
|
||||||
|
auto operator<=>(const LoopSafetyVariable&) const noexcept = default;
|
||||||
|
|
||||||
|
u32 index;
|
||||||
|
};
|
||||||
|
|
||||||
struct IndirectBranchVariable {
|
struct IndirectBranchVariable {
|
||||||
auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
|
auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag,
|
using Variant =
|
||||||
OverflowFlagTag, GotoVariable, IndirectBranchVariable>;
|
std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, OverflowFlagTag,
|
||||||
using ValueMap = boost::container::flat_map<IR::Block*, IR::Value, std::less<IR::Block*>>;
|
GotoVariable, LoopSafetyVariable, IndirectBranchVariable>;
|
||||||
|
using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>;
|
||||||
|
|
||||||
struct DefTable {
|
struct DefTable {
|
||||||
const IR::Value& Def(IR::Block* block, IR::Reg variable) noexcept {
|
const IR::Value& Def(IR::Block* block, IR::Reg variable) {
|
||||||
return block->SsaRegValue(variable);
|
return block->SsaRegValue(variable);
|
||||||
}
|
}
|
||||||
void SetDef(IR::Block* block, IR::Reg variable, const IR::Value& value) noexcept {
|
void SetDef(IR::Block* block, IR::Reg variable, const IR::Value& value) {
|
||||||
block->SetSsaRegValue(variable, value);
|
block->SetSsaRegValue(variable, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, IR::Pred variable) noexcept {
|
const IR::Value& Def(IR::Block* block, IR::Pred variable) {
|
||||||
return preds[IR::PredIndex(variable)][block];
|
return preds[IR::PredIndex(variable)][block];
|
||||||
}
|
}
|
||||||
void SetDef(IR::Block* block, IR::Pred variable, const IR::Value& value) noexcept {
|
void SetDef(IR::Block* block, IR::Pred variable, const IR::Value& value) {
|
||||||
preds[IR::PredIndex(variable)].insert_or_assign(block, value);
|
preds[IR::PredIndex(variable)].insert_or_assign(block, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, GotoVariable variable) noexcept {
|
const IR::Value& Def(IR::Block* block, GotoVariable variable) {
|
||||||
return goto_vars[variable.index][block];
|
return goto_vars[variable.index][block];
|
||||||
}
|
}
|
||||||
void SetDef(IR::Block* block, GotoVariable variable, const IR::Value& value) noexcept {
|
void SetDef(IR::Block* block, GotoVariable variable, const IR::Value& value) {
|
||||||
goto_vars[variable.index].insert_or_assign(block, value);
|
goto_vars[variable.index].insert_or_assign(block, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, IndirectBranchVariable) noexcept {
|
const IR::Value& Def(IR::Block* block, LoopSafetyVariable variable) {
|
||||||
|
return loop_safety_vars[variable.index][block];
|
||||||
|
}
|
||||||
|
void SetDef(IR::Block* block, LoopSafetyVariable variable, const IR::Value& value) {
|
||||||
|
loop_safety_vars[variable.index].insert_or_assign(block, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const IR::Value& Def(IR::Block* block, IndirectBranchVariable) {
|
||||||
return indirect_branch_var[block];
|
return indirect_branch_var[block];
|
||||||
}
|
}
|
||||||
void SetDef(IR::Block* block, IndirectBranchVariable, const IR::Value& value) noexcept {
|
void SetDef(IR::Block* block, IndirectBranchVariable, const IR::Value& value) {
|
||||||
indirect_branch_var.insert_or_assign(block, value);
|
indirect_branch_var.insert_or_assign(block, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, ZeroFlagTag) noexcept {
|
const IR::Value& Def(IR::Block* block, ZeroFlagTag) {
|
||||||
return zero_flag[block];
|
return zero_flag[block];
|
||||||
}
|
}
|
||||||
void SetDef(IR::Block* block, ZeroFlagTag, const IR::Value& value) noexcept {
|
void SetDef(IR::Block* block, ZeroFlagTag, const IR::Value& value) {
|
||||||
zero_flag.insert_or_assign(block, value);
|
zero_flag.insert_or_assign(block, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, SignFlagTag) noexcept {
|
const IR::Value& Def(IR::Block* block, SignFlagTag) {
|
||||||
return sign_flag[block];
|
return sign_flag[block];
|
||||||
}
|
}
|
||||||
void SetDef(IR::Block* block, SignFlagTag, const IR::Value& value) noexcept {
|
void SetDef(IR::Block* block, SignFlagTag, const IR::Value& value) {
|
||||||
sign_flag.insert_or_assign(block, value);
|
sign_flag.insert_or_assign(block, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, CarryFlagTag) noexcept {
|
const IR::Value& Def(IR::Block* block, CarryFlagTag) {
|
||||||
return carry_flag[block];
|
return carry_flag[block];
|
||||||
}
|
}
|
||||||
void SetDef(IR::Block* block, CarryFlagTag, const IR::Value& value) noexcept {
|
void SetDef(IR::Block* block, CarryFlagTag, const IR::Value& value) {
|
||||||
carry_flag.insert_or_assign(block, value);
|
carry_flag.insert_or_assign(block, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, OverflowFlagTag) noexcept {
|
const IR::Value& Def(IR::Block* block, OverflowFlagTag) {
|
||||||
return overflow_flag[block];
|
return overflow_flag[block];
|
||||||
}
|
}
|
||||||
void SetDef(IR::Block* block, OverflowFlagTag, const IR::Value& value) noexcept {
|
void SetDef(IR::Block* block, OverflowFlagTag, const IR::Value& value) {
|
||||||
overflow_flag.insert_or_assign(block, value);
|
overflow_flag.insert_or_assign(block, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<ValueMap, IR::NUM_USER_PREDS> preds;
|
std::array<ValueMap, IR::NUM_USER_PREDS> preds;
|
||||||
boost::container::flat_map<u32, ValueMap> goto_vars;
|
boost::container::flat_map<u32, ValueMap> goto_vars;
|
||||||
|
boost::container::flat_map<u32, ValueMap> loop_safety_vars;
|
||||||
ValueMap indirect_branch_var;
|
ValueMap indirect_branch_var;
|
||||||
ValueMap zero_flag;
|
ValueMap zero_flag;
|
||||||
ValueMap sign_flag;
|
ValueMap sign_flag;
|
||||||
|
@ -134,6 +152,10 @@ IR::Opcode UndefOpcode(const FlagTag&) noexcept {
|
||||||
return IR::Opcode::UndefU1;
|
return IR::Opcode::UndefU1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::Opcode UndefOpcode(const LoopSafetyVariable&) noexcept {
|
||||||
|
return IR::Opcode::UndefU32;
|
||||||
|
}
|
||||||
|
|
||||||
IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept {
|
IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept {
|
||||||
return IR::Opcode::UndefU32;
|
return IR::Opcode::UndefU32;
|
||||||
}
|
}
|
||||||
|
@ -315,6 +337,9 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
|
||||||
case IR::Opcode::SetGotoVariable:
|
case IR::Opcode::SetGotoVariable:
|
||||||
pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
|
pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
|
||||||
break;
|
break;
|
||||||
|
case IR::Opcode::SetLoopSafetyVariable:
|
||||||
|
pass.WriteVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block, inst.Arg(0));
|
||||||
|
break;
|
||||||
case IR::Opcode::SetIndirectBranchVariable:
|
case IR::Opcode::SetIndirectBranchVariable:
|
||||||
pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0));
|
pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0));
|
||||||
break;
|
break;
|
||||||
|
@ -343,6 +368,9 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
|
||||||
case IR::Opcode::GetGotoVariable:
|
case IR::Opcode::GetGotoVariable:
|
||||||
inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block));
|
inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block));
|
||||||
break;
|
break;
|
||||||
|
case IR::Opcode::GetLoopSafetyVariable:
|
||||||
|
inst.ReplaceUsesWith(pass.ReadVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block));
|
||||||
|
break;
|
||||||
case IR::Opcode::GetIndirectBranchVariable:
|
case IR::Opcode::GetIndirectBranchVariable:
|
||||||
inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block));
|
inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -467,7 +467,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv;
|
VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv;
|
||||||
if (nv_device_diagnostics_config) {
|
if (Settings::values.enable_nsight_aftermath && nv_device_diagnostics_config) {
|
||||||
nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>();
|
nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>();
|
||||||
|
|
||||||
diagnostics_nv = {
|
diagnostics_nv = {
|
||||||
|
@ -781,7 +781,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||||
test(has_ext_shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, false);
|
test(has_ext_shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, false);
|
||||||
test(has_khr_workgroup_memory_explicit_layout,
|
test(has_khr_workgroup_memory_explicit_layout,
|
||||||
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, false);
|
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, false);
|
||||||
if (Settings::values.renderer_debug) {
|
if (Settings::values.enable_nsight_aftermath) {
|
||||||
test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
|
test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -824,6 +824,8 @@ void Config::ReadRendererValues() {
|
||||||
|
|
||||||
if (global) {
|
if (global) {
|
||||||
ReadBasicSetting(Settings::values.renderer_debug);
|
ReadBasicSetting(Settings::values.renderer_debug);
|
||||||
|
ReadBasicSetting(Settings::values.enable_nsight_aftermath);
|
||||||
|
ReadBasicSetting(Settings::values.disable_shader_loop_safety_checks);
|
||||||
}
|
}
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
@ -1353,6 +1355,8 @@ void Config::SaveRendererValues() {
|
||||||
|
|
||||||
if (global) {
|
if (global) {
|
||||||
WriteBasicSetting(Settings::values.renderer_debug);
|
WriteBasicSetting(Settings::values.renderer_debug);
|
||||||
|
WriteBasicSetting(Settings::values.enable_nsight_aftermath);
|
||||||
|
WriteBasicSetting(Settings::values.disable_shader_loop_safety_checks);
|
||||||
}
|
}
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
|
@ -45,8 +45,13 @@ void ConfigureDebug::SetConfiguration() {
|
||||||
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
|
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
|
||||||
ui->enable_cpu_debugging->setEnabled(runtime_lock);
|
ui->enable_cpu_debugging->setEnabled(runtime_lock);
|
||||||
ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue());
|
ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue());
|
||||||
|
ui->enable_nsight_aftermath->setEnabled(runtime_lock);
|
||||||
|
ui->enable_nsight_aftermath->setChecked(Settings::values.enable_nsight_aftermath.GetValue());
|
||||||
ui->disable_macro_jit->setEnabled(runtime_lock);
|
ui->disable_macro_jit->setEnabled(runtime_lock);
|
||||||
ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue());
|
ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue());
|
||||||
|
ui->disable_loop_safety_checks->setEnabled(runtime_lock);
|
||||||
|
ui->disable_loop_safety_checks->setChecked(
|
||||||
|
Settings::values.disable_shader_loop_safety_checks.GetValue());
|
||||||
ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
|
ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +66,9 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||||
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
|
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
|
||||||
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
|
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
|
||||||
Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked();
|
Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked();
|
||||||
|
Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked();
|
||||||
|
Settings::values.disable_shader_loop_safety_checks =
|
||||||
|
ui->disable_loop_safety_checks->isChecked();
|
||||||
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
|
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
|
||||||
Settings::values.extended_logging = ui->extended_logging->isChecked();
|
Settings::values.extended_logging = ui->extended_logging->isChecked();
|
||||||
Debugger::ToggleConsole();
|
Debugger::ToggleConsole();
|
||||||
|
|
|
@ -125,6 +125,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="enable_nsight_aftermath">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>When checked, it enables Nsight Aftermath crash dumps</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Nsight Aftermath</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="disable_macro_jit">
|
<widget class="QCheckBox" name="disable_macro_jit">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
|
@ -138,6 +148,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="disable_loop_safety_checks">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>When checked, it executes shaders without loop logic changes</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Disable Loop safety checks</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -252,11 +272,17 @@
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>log_filter_edit</tabstop>
|
<tabstop>log_filter_edit</tabstop>
|
||||||
<tabstop>toggle_console</tabstop>
|
<tabstop>toggle_console</tabstop>
|
||||||
|
<tabstop>extended_logging</tabstop>
|
||||||
<tabstop>open_log_button</tabstop>
|
<tabstop>open_log_button</tabstop>
|
||||||
<tabstop>homebrew_args_edit</tabstop>
|
<tabstop>homebrew_args_edit</tabstop>
|
||||||
<tabstop>enable_graphics_debugging</tabstop>
|
<tabstop>enable_graphics_debugging</tabstop>
|
||||||
|
<tabstop>enable_nsight_aftermath</tabstop>
|
||||||
|
<tabstop>disable_macro_jit</tabstop>
|
||||||
|
<tabstop>disable_loop_safety_checks</tabstop>
|
||||||
<tabstop>reporting_services</tabstop>
|
<tabstop>reporting_services</tabstop>
|
||||||
<tabstop>quest_flag</tabstop>
|
<tabstop>quest_flag</tabstop>
|
||||||
|
<tabstop>use_debug_asserts</tabstop>
|
||||||
|
<tabstop>use_auto_stub</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|
|
@ -444,6 +444,8 @@ void Config::ReadValues() {
|
||||||
// Renderer
|
// Renderer
|
||||||
ReadSetting("Renderer", Settings::values.renderer_backend);
|
ReadSetting("Renderer", Settings::values.renderer_backend);
|
||||||
ReadSetting("Renderer", Settings::values.renderer_debug);
|
ReadSetting("Renderer", Settings::values.renderer_debug);
|
||||||
|
ReadSetting("Renderer", Settings::values.enable_nsight_aftermath);
|
||||||
|
ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks);
|
||||||
ReadSetting("Renderer", Settings::values.vulkan_device);
|
ReadSetting("Renderer", Settings::values.vulkan_device);
|
||||||
|
|
||||||
ReadSetting("Renderer", Settings::values.fullscreen_mode);
|
ReadSetting("Renderer", Settings::values.fullscreen_mode);
|
||||||
|
|
|
@ -221,6 +221,14 @@ backend =
|
||||||
# 0 (default): Disabled, 1: Enabled
|
# 0 (default): Disabled, 1: Enabled
|
||||||
debug =
|
debug =
|
||||||
|
|
||||||
|
# Enable Nsight Aftermath crash dumps
|
||||||
|
# 0 (default): Disabled, 1: Enabled
|
||||||
|
nsight_aftermath =
|
||||||
|
|
||||||
|
# Disable shader loop safety checks, executing the shader without loop logic changes
|
||||||
|
# 0 (default): Disabled, 1: Enabled
|
||||||
|
disable_shader_loop_safety_checks =
|
||||||
|
|
||||||
# Which Vulkan physical device to use (defaults to 0)
|
# Which Vulkan physical device to use (defaults to 0)
|
||||||
vulkan_device =
|
vulkan_device =
|
||||||
|
|
||||||
|
|
Reference in New Issue