From bbfad79c89f9b7886005d39b51129bcfd94830b8 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Tue, 2 Aug 2022 17:41:41 +0100 Subject: Vulkan: Add a workaround for input_position on Adreno drivers Adreno drivers will crash compiling geometry shaders if the input position is not wrapped in a gl_in struct. --- .../backend/spirv/emit_spirv_context_get_set.cpp | 7 ++-- .../backend/spirv/spirv_emit_context.cpp | 42 +++++++++++++++++----- .../backend/spirv/spirv_emit_context.h | 1 + 3 files changed, 39 insertions(+), 11 deletions(-) (limited to 'src/shader_recompiler/backend') 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..1590debc4 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,11 @@ 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/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index ecb2db494..eb1e3e0b6 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -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,24 @@ 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(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 input_generics{}; -- cgit v1.2.3 From 3f0985c7b01bbc5e7172bffb137f23385088aca6 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sat, 19 Nov 2022 15:53:19 +0000 Subject: shader_recompiler: SPIRV: Only enable int64 feature when supported --- src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/shader_recompiler/backend') diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index eb1e3e0b6..f874622b8 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"); } -- cgit v1.2.3 From 68ed60cee41ce93a637fd8463657b137d95fdae4 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Fri, 30 Dec 2022 13:45:00 +0000 Subject: shader_recompiler: Fix shuffle partitioning for >64 invoc-per-subgroup GPUs The existing implementation only supports 64 invoc-per-subgroup GPUs, and misbehaves on adreno when invocations need to be split into 4 emulated subgroups. --- .../backend/spirv/emit_spirv_warp.cpp | 58 +++++++++++----------- 1 file changed, 28 insertions(+), 30 deletions(-) (limited to 'src/shader_recompiler/backend') 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); } -- cgit v1.2.3 From 58fec43768c837c63453e87df8f337a2d139324a Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 5 Jan 2023 22:10:21 +0000 Subject: Run clang-format --- .../backend/spirv/emit_spirv_context_get_set.cpp | 11 ++++++----- src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/shader_recompiler/backend') 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 1590debc4..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,11 +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], 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))); + 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/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index f874622b8..a0c155fdb 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -729,7 +729,7 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { else return OpAccessChain(input_f32, input_position, u32_zero_value, masked_index); - } else { + } else { if (is_array) return OpAccessChain(input_f32, input_position, vertex, masked_index); else @@ -1390,7 +1390,8 @@ void EmitContext::DefineInputs(const IR::Program& program) { static_cast(spv::BuiltIn::Position)); Decorate(input_position_struct, spv::Decoration::Block); } else { - const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::FragCoord : spv::BuiltIn::Position}; + 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) { -- cgit v1.2.3