shader: Move loop safety tests to code emission

This commit is contained in:
ReinUsesLisp 2021-06-21 01:07:10 -03:00 committed by ameerj
parent 3877918e96
commit 808ef97a08
16 changed files with 54 additions and 108 deletions

View file

@ -71,6 +71,7 @@ public:
std::string_view stage_name = "invalid";
std::string_view attrib_name = "invalid";
u32 num_safety_loop_vars{};
bool uses_y_direction{};
};

View file

@ -6,6 +6,8 @@
#include <string>
#include <tuple>
#include "common/div_ceil.h"
#include "common/settings.h"
#include "shader_recompiler/backend/bindings.h"
#include "shader_recompiler/backend/glasm/emit_context.h"
#include "shader_recompiler/backend/glasm/emit_glasm.h"
@ -222,6 +224,14 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
ctx.Add("REP;");
break;
case IR::AbstractSyntaxNode::Type::Repeat:
if (!Settings::values.disable_shader_loop_safety_checks) {
const u32 loop_index{ctx.num_safety_loop_vars++};
const u32 vector_index{loop_index / 4};
const char component{"xyzw"[loop_index % 4]};
ctx.Add("SUB.S.CC loop{}.{},loop{}.{},1;"
"BRK(LT.{});",
vector_index, component, vector_index, component, component);
}
if (node.data.repeat.cond.IsImmediate()) {
if (node.data.repeat.cond.U1()) {
ctx.Add("ENDREP;");
@ -425,6 +435,10 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I
if (program.info.uses_fswzadd) {
header += "FSWZA[4],FSWZB[4],";
}
const u32 num_safety_loop_vectors{Common::DivCeil(ctx.num_safety_loop_vars, 4u)};
for (u32 index = 0; index < num_safety_loop_vectors; ++index) {
header += fmt::format("loop{},", index);
}
header += "RC;"
"LONG TEMP ";
for (size_t index = 0; index < ctx.reg_alloc.NumUsedLongRegisters(); ++index) {
@ -441,6 +455,9 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I
"MOV.F FSWZB[2],1;"
"MOV.F FSWZB[3],-1;";
}
for (u32 index = 0; index < num_safety_loop_vectors; ++index) {
header += fmt::format("MOV.S loop{},{{0x2000,0x2000,0x2000,0x2000}};", index);
}
if (ctx.uses_y_direction) {
header += "PARAM y_direction[1]={state.material.front.ambient};";
}

View file

@ -42,8 +42,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
void EmitGetGotoVariable(EmitContext& ctx);
void EmitSetIndirectBranchVariable(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 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);

View file

@ -153,14 +153,6 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
NotImplemented();
}
void EmitSetLoopSafetyVariable(EmitContext& ctx) {
NotImplemented();
}
void EmitGetLoopSafetyVariable(EmitContext& ctx) {
NotImplemented();
}
void EmitGetZFlag(EmitContext& ctx) {
NotImplemented();
}

View file

@ -153,6 +153,8 @@ public:
std::vector<TextureImageDefinition> images;
std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
u32 num_safety_loop_vars{};
bool uses_y_direction{};
bool uses_cc_carry{};

View file

@ -6,6 +6,7 @@
#include <string>
#include "common/alignment.h"
#include "common/settings.h"
#include "shader_recompiler/backend/glsl/emit_context.h"
#include "shader_recompiler/backend/glsl/emit_glsl.h"
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
@ -156,7 +157,12 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
ctx.Add("for(;;){{");
break;
case IR::AbstractSyntaxNode::Type::Repeat:
ctx.Add("if(!{}){{break;}}}}", ctx.var_alloc.Consume(node.data.repeat.cond));
if (Settings::values.disable_shader_loop_safety_checks) {
ctx.Add("if(!{}){{break;}}}}", ctx.var_alloc.Consume(node.data.repeat.cond));
} else {
ctx.Add("if(--loop{}<0 || !{}){{break;}}}}", ctx.num_safety_loop_vars++,
ctx.var_alloc.Consume(node.data.repeat.cond));
}
break;
default:
throw NotImplementedException("AbstractSyntaxNode Type {}", node.type);
@ -198,6 +204,9 @@ void DefineVariables(const EmitContext& ctx, std::string& header) {
ctx.var_alloc.Representation(index, type), type_name);
}
}
for (u32 i = 0; i < ctx.num_safety_loop_vars; ++i) {
header += fmt::format("int loop{}=0x2000;", i);
}
}
} // Anonymous namespace

View file

@ -44,8 +44,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
void EmitGetGotoVariable(EmitContext& ctx);
void EmitSetIndirectBranchVariable(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,
const IR::Value& offset);
void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,

View file

@ -46,14 +46,6 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
NotImplemented();
}
void EmitSetLoopSafetyVariable(EmitContext& ctx) {
NotImplemented();
}
void EmitGetLoopSafetyVariable(EmitContext& ctx) {
NotImplemented();
}
void EmitGetZFlag(EmitContext& ctx) {
NotImplemented();
}

View file

@ -8,6 +8,7 @@
#include <utility>
#include <vector>
#include "common/settings.h"
#include "shader_recompiler/backend/spirv/emit_spirv.h"
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
#include "shader_recompiler/frontend/ir/basic_block.h"
@ -151,9 +152,25 @@ void Traverse(EmitContext& ctx, IR::Program& program) {
}
break;
case IR::AbstractSyntaxNode::Type::Repeat: {
Id cond{ctx.Def(node.data.repeat.cond)};
if (!Settings::values.disable_shader_loop_safety_checks) {
const Id pointer_type{ctx.TypePointer(spv::StorageClass::Private, ctx.U32[1])};
const Id safety_counter{ctx.AddGlobalVariable(
pointer_type, spv::StorageClass::Private, ctx.Const(0x2000u))};
if (ctx.profile.supported_spirv >= 0x00010400) {
ctx.interfaces.push_back(safety_counter);
}
const Id old_counter{ctx.OpLoad(ctx.U32[1], safety_counter)};
const Id new_counter{ctx.OpISub(ctx.U32[1], old_counter, ctx.Const(1u))};
ctx.OpStore(safety_counter, new_counter);
const Id safety_cond{
ctx.OpSGreaterThanEqual(ctx.U1, new_counter, ctx.u32_zero_value)};
cond = ctx.OpLogicalAnd(ctx.U1, cond, safety_cond);
}
const Id loop_header_label{node.data.repeat.loop_header->Definition<Id>()};
const Id merge_label{node.data.repeat.merge->Definition<Id>()};
ctx.OpBranchConditional(ctx.Def(node.data.repeat.cond), loop_header_label, merge_label);
ctx.OpBranchConditional(cond, loop_header_label, merge_label);
break;
}
case IR::AbstractSyntaxNode::Type::Return:

View file

@ -198,14 +198,6 @@ void EmitGetIndirectBranchVariable(EmitContext&) {
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) {
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)};

View file

@ -43,8 +43,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
void EmitGetGotoVariable(EmitContext& ctx);
void EmitSetIndirectBranchVariable(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 EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);