summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/backend')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp8
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp58
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp45
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.h1
4 files changed, 70 insertions, 42 deletions
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 db9c94ce8..0cd87a48f 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
@@ -321,8 +321,12 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
case IR::Attribute::PositionY:
case IR::Attribute::PositionZ:
case IR::Attribute::PositionW:
- return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position,
- ctx.Const(element)));
+ return ctx.OpLoad(
+ ctx.F32[1],
+ ctx.need_input_position_indirect
+ ? AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position, ctx.u32_zero_value,
+ ctx.Const(element))
+ : AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position, ctx.Const(element)));
case IR::Attribute::InstanceId:
if (ctx.profile.support_vertex_instance_id) {
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_id));
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
index 2c90f2368..c5db19d09 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
@@ -58,11 +58,10 @@ Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) {
ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value);
}
-Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) {
- const Id thirty_two{ctx.Const(32u)};
- const Id is_upper_partition{ctx.OpSGreaterThanEqual(ctx.U1, invocation_id, thirty_two)};
- const Id upper_clamp{ctx.OpIAdd(ctx.U32[1], thirty_two, clamp)};
- return ctx.OpSelect(ctx.U32[1], is_upper_partition, upper_clamp, clamp);
+Id AddPartitionBase(EmitContext& ctx, Id thread_id) {
+ const Id partition_idx{ctx.OpShiftRightLogical(ctx.U32[1], GetThreadId(ctx), ctx.Const(5u))};
+ const Id partition_base{ctx.OpShiftLeftLogical(ctx.U32[1], partition_idx, ctx.Const(5u))};
+ return ctx.OpIAdd(ctx.U32[1], thread_id, partition_base);
}
} // Anonymous namespace
@@ -145,64 +144,63 @@ Id EmitSubgroupGeMask(EmitContext& ctx) {
Id EmitShuffleIndex(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
Id segmentation_mask) {
const Id not_seg_mask{ctx.OpNot(ctx.U32[1], segmentation_mask)};
- const Id thread_id{GetThreadId(ctx)};
- if (ctx.profile.warp_size_potentially_larger_than_guest) {
- const Id thirty_two{ctx.Const(32u)};
- const Id is_upper_partition{ctx.OpSGreaterThanEqual(ctx.U1, thread_id, thirty_two)};
- const Id upper_index{ctx.OpIAdd(ctx.U32[1], thirty_two, index)};
- const Id upper_clamp{ctx.OpIAdd(ctx.U32[1], thirty_two, clamp)};
- index = ctx.OpSelect(ctx.U32[1], is_upper_partition, upper_index, index);
- clamp = ctx.OpSelect(ctx.U32[1], is_upper_partition, upper_clamp, clamp);
- }
+ const Id thread_id{EmitLaneId(ctx)};
const Id min_thread_id{ComputeMinThreadId(ctx, thread_id, segmentation_mask)};
const Id max_thread_id{ComputeMaxThreadId(ctx, min_thread_id, clamp, not_seg_mask)};
const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], index, not_seg_mask)};
- const Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], lhs, min_thread_id)};
+ Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], lhs, min_thread_id)};
const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)};
+ if (ctx.profile.warp_size_potentially_larger_than_guest) {
+ src_thread_id = AddPartitionBase(ctx, src_thread_id);
+ }
+
SetInBoundsFlag(inst, in_range);
return SelectValue(ctx, in_range, value, src_thread_id);
}
Id EmitShuffleUp(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
Id segmentation_mask) {
- const Id thread_id{GetThreadId(ctx)};
- if (ctx.profile.warp_size_potentially_larger_than_guest) {
- clamp = GetUpperClamp(ctx, thread_id, clamp);
- }
+ const Id thread_id{EmitLaneId(ctx)};
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
- const Id src_thread_id{ctx.OpISub(ctx.U32[1], thread_id, index)};
+ Id src_thread_id{ctx.OpISub(ctx.U32[1], thread_id, index)};
const Id in_range{ctx.OpSGreaterThanEqual(ctx.U1, src_thread_id, max_thread_id)};
+ if (ctx.profile.warp_size_potentially_larger_than_guest) {
+ src_thread_id = AddPartitionBase(ctx, src_thread_id);
+ }
+
SetInBoundsFlag(inst, in_range);
return SelectValue(ctx, in_range, value, src_thread_id);
}
Id EmitShuffleDown(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
Id segmentation_mask) {
- const Id thread_id{GetThreadId(ctx)};
- if (ctx.profile.warp_size_potentially_larger_than_guest) {
- clamp = GetUpperClamp(ctx, thread_id, clamp);
- }
+ const Id thread_id{EmitLaneId(ctx)};
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
- const Id src_thread_id{ctx.OpIAdd(ctx.U32[1], thread_id, index)};
+ Id src_thread_id{ctx.OpIAdd(ctx.U32[1], thread_id, index)};
const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)};
+ if (ctx.profile.warp_size_potentially_larger_than_guest) {
+ src_thread_id = AddPartitionBase(ctx, src_thread_id);
+ }
+
SetInBoundsFlag(inst, in_range);
return SelectValue(ctx, in_range, value, src_thread_id);
}
Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
Id segmentation_mask) {
- const Id thread_id{GetThreadId(ctx)};
- if (ctx.profile.warp_size_potentially_larger_than_guest) {
- clamp = GetUpperClamp(ctx, thread_id, clamp);
- }
+ const Id thread_id{EmitLaneId(ctx)};
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
- const Id src_thread_id{ctx.OpBitwiseXor(ctx.U32[1], thread_id, index)};
+ Id src_thread_id{ctx.OpBitwiseXor(ctx.U32[1], thread_id, index)};
const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)};
+ if (ctx.profile.warp_size_potentially_larger_than_guest) {
+ src_thread_id = AddPartitionBase(ctx, src_thread_id);
+ }
+
SetInBoundsFlag(inst, in_range);
return SelectValue(ctx, in_range, value, src_thread_id);
}
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index ecb2db494..a0c155fdb 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -544,7 +544,7 @@ void EmitContext::DefineCommonTypes(const Info& info) {
U16 = Name(TypeInt(16, false), "u16");
S16 = Name(TypeInt(16, true), "s16");
}
- if (info.uses_int64) {
+ if (info.uses_int64 && profile.support_int64) {
AddCapability(spv::Capability::Int64);
U64 = Name(TypeInt(64, false), "u64");
}
@@ -721,9 +721,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
size_t label_index{0};
if (info.loads.AnyComponent(IR::Attribute::PositionX)) {
AddLabel(labels[label_index]);
- const Id pointer{is_array
- ? OpAccessChain(input_f32, input_position, vertex, masked_index)
- : OpAccessChain(input_f32, input_position, masked_index)};
+ const Id pointer{[&]() {
+ if (need_input_position_indirect) {
+ if (is_array)
+ return OpAccessChain(input_f32, input_position, vertex, u32_zero_value,
+ masked_index);
+ else
+ return OpAccessChain(input_f32, input_position, u32_zero_value,
+ masked_index);
+ } else {
+ if (is_array)
+ return OpAccessChain(input_f32, input_position, vertex, masked_index);
+ else
+ return OpAccessChain(input_f32, input_position, masked_index);
+ }
+ }()};
const Id result{OpLoad(F32[1], pointer)};
OpReturnValue(result);
++label_index;
@@ -1367,12 +1379,25 @@ void EmitContext::DefineInputs(const IR::Program& program) {
Decorate(layer, spv::Decoration::Flat);
}
if (loads.AnyComponent(IR::Attribute::PositionX)) {
- const bool is_fragment{stage != Stage::Fragment};
- const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord};
- input_position = DefineInput(*this, F32[4], true, built_in);
- if (profile.support_geometry_shader_passthrough) {
- if (info.passthrough.AnyComponent(IR::Attribute::PositionX)) {
- Decorate(input_position, spv::Decoration::PassthroughNV);
+ const bool is_fragment{stage == Stage::Fragment};
+ if (!is_fragment && profile.has_broken_spirv_position_input) {
+ need_input_position_indirect = true;
+
+ const Id input_position_struct = TypeStruct(F32[4]);
+ input_position = DefineInput(*this, input_position_struct, true);
+
+ MemberDecorate(input_position_struct, 0, spv::Decoration::BuiltIn,
+ static_cast<unsigned>(spv::BuiltIn::Position));
+ Decorate(input_position_struct, spv::Decoration::Block);
+ } else {
+ const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::FragCoord
+ : spv::BuiltIn::Position};
+ input_position = DefineInput(*this, F32[4], true, built_in);
+
+ if (profile.support_geometry_shader_passthrough) {
+ if (info.passthrough.AnyComponent(IR::Attribute::PositionX)) {
+ Decorate(input_position, spv::Decoration::PassthroughNV);
+ }
}
}
}
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
index 4414a5169..dbc5c55b9 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
@@ -280,6 +280,7 @@ public:
Id write_global_func_u32x2{};
Id write_global_func_u32x4{};
+ bool need_input_position_indirect{};
Id input_position{};
std::array<Id, 32> input_generics{};