shader: Implement VOTE
This commit is contained in:
		| @@ -259,6 +259,10 @@ void EmitContext::DefineInputs(const Info& info, Stage stage) { | ||||
|     if (info.uses_local_invocation_id) { | ||||
|         local_invocation_id = DefineInput(*this, U32[3], spv::BuiltIn::LocalInvocationId); | ||||
|     } | ||||
|     if (profile.warp_size_potentially_larger_than_guest && info.uses_subgroup_vote) { | ||||
|         subgroup_local_invocation_id = | ||||
|             DefineInput(*this, U32[1], spv::BuiltIn::SubgroupLocalInvocationId); | ||||
|     } | ||||
|     if (info.loads_position) { | ||||
|         const bool is_fragment{stage != Stage::Fragment}; | ||||
|         const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; | ||||
|   | ||||
| @@ -82,6 +82,7 @@ public: | ||||
|  | ||||
|     Id workgroup_id{}; | ||||
|     Id local_invocation_id{}; | ||||
|     Id subgroup_local_invocation_id{}; | ||||
|     Id instance_id{}; | ||||
|     Id instance_index{}; | ||||
|     Id base_instance{}; | ||||
| @@ -96,7 +97,7 @@ public: | ||||
|     std::array<Id, 32> output_generics{}; | ||||
|  | ||||
|     std::array<Id, 8> frag_color{}; | ||||
|     Id frag_depth {}; | ||||
|     Id frag_depth{}; | ||||
|  | ||||
|     std::vector<Id> interfaces; | ||||
|  | ||||
|   | ||||
| @@ -224,6 +224,15 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | ||||
|         ctx.AddExtension("SPV_KHR_shader_draw_parameters"); | ||||
|         ctx.AddCapability(spv::Capability::DrawParameters); | ||||
|     } | ||||
|     if (info.uses_subgroup_vote && profile.support_vote) { | ||||
|         ctx.AddExtension("SPV_KHR_shader_ballot"); | ||||
|         ctx.AddCapability(spv::Capability::SubgroupBallotKHR); | ||||
|         if (!profile.warp_size_potentially_larger_than_guest) { | ||||
|             // vote ops are only used when not taking the long path | ||||
|             ctx.AddExtension("SPV_KHR_subgroup_vote"); | ||||
|             ctx.AddCapability(spv::Capability::SubgroupVoteKHR); | ||||
|         } | ||||
|     } | ||||
|     // TODO: Track this usage | ||||
|     ctx.AddCapability(spv::Capability::ImageGatherExtended); | ||||
| } | ||||
|   | ||||
| @@ -346,5 +346,9 @@ Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va | ||||
|                                   Id coords, Id dref, Id bias_lc, Id offset); | ||||
| Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, | ||||
|                                   Id coords, Id dref, Id lod_lc, Id offset); | ||||
| Id EmitVoteAll(EmitContext& ctx, Id pred); | ||||
| Id EmitVoteAny(EmitContext& ctx, Id pred); | ||||
| Id EmitVoteEqual(EmitContext& ctx, Id pred); | ||||
| Id EmitSubgroupBallot(EmitContext& ctx, Id pred); | ||||
|  | ||||
| } // namespace Shader::Backend::SPIRV | ||||
|   | ||||
							
								
								
									
										58
									
								
								src/shader_recompiler/backend/spirv/emit_spirv_vote.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/shader_recompiler/backend/spirv/emit_spirv_vote.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| // Copyright 2021 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "shader_recompiler/backend/spirv/emit_spirv.h" | ||||
|  | ||||
| namespace Shader::Backend::SPIRV { | ||||
| namespace { | ||||
| Id LargeWarpBallot(EmitContext& ctx, Id ballot) { | ||||
|     const Id shift{ctx.Constant(ctx.U32[1], 5)}; | ||||
|     const Id local_index{ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id)}; | ||||
|     return ctx.OpVectorExtractDynamic(ctx.U32[1], ballot, local_index); | ||||
| } | ||||
| } // Anonymous namespace | ||||
|  | ||||
| Id EmitVoteAll(EmitContext& ctx, Id pred) { | ||||
|     if (!ctx.profile.warp_size_potentially_larger_than_guest) { | ||||
|         return ctx.OpSubgroupAllKHR(ctx.U1, pred); | ||||
|     } | ||||
|     const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; | ||||
|     const Id active_mask{LargeWarpBallot(ctx, mask_ballot)}; | ||||
|     const Id ballot{LargeWarpBallot(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; | ||||
|     const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; | ||||
|     return ctx.OpIEqual(ctx.U1, lhs, active_mask); | ||||
| } | ||||
|  | ||||
| Id EmitVoteAny(EmitContext& ctx, Id pred) { | ||||
|     if (!ctx.profile.warp_size_potentially_larger_than_guest) { | ||||
|         return ctx.OpSubgroupAnyKHR(ctx.U1, pred); | ||||
|     } | ||||
|     const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; | ||||
|     const Id active_mask{LargeWarpBallot(ctx, mask_ballot)}; | ||||
|     const Id ballot{LargeWarpBallot(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; | ||||
|     const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; | ||||
|     return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value); | ||||
| } | ||||
|  | ||||
| Id EmitVoteEqual(EmitContext& ctx, Id pred) { | ||||
|     if (!ctx.profile.warp_size_potentially_larger_than_guest) { | ||||
|         return ctx.OpSubgroupAllEqualKHR(ctx.U1, pred); | ||||
|     } | ||||
|     const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; | ||||
|     const Id active_mask{LargeWarpBallot(ctx, mask_ballot)}; | ||||
|     const Id ballot{LargeWarpBallot(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; | ||||
|     const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)}; | ||||
|     return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value), | ||||
|                            ctx.OpIEqual(ctx.U1, lhs, active_mask)); | ||||
| } | ||||
|  | ||||
| Id EmitSubgroupBallot(EmitContext& ctx, Id pred) { | ||||
|     const Id ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], pred)}; | ||||
|     if (!ctx.profile.warp_size_potentially_larger_than_guest) { | ||||
|         return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U); | ||||
|     } | ||||
|     return LargeWarpBallot(ctx, ballot); | ||||
| } | ||||
|  | ||||
| } // namespace Shader::Backend::SPIRV | ||||
		Reference in New Issue
	
	Block a user