Browse Source

[vulkan] Subgroups gating correction

lsfg-android
CamilleLaVey 4 weeks ago
parent
commit
bb63996182
  1. 2
      src/shader_recompiler/backend/spirv/emit_spirv.cpp
  2. 42
      src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp
  3. 9
      src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
  4. 7
      src/shader_recompiler/profile.h
  5. 15
      src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
  6. 4
      src/video_core/vulkan_common/vulkan_device.h

2
src/shader_recompiler/backend/spirv/emit_spirv.cpp

@ -435,7 +435,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
}
if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id ||
info.uses_subgroup_shuffles) &&
profile.support_vote) {
profile.support_vote && profile.SupportsSubgroupStage(ctx.stage)) {
ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
if (!profile.warp_size_potentially_larger_than_guest) {

42
src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -10,7 +13,14 @@ Id SubgroupScope(EmitContext& ctx) {
return ctx.Const(static_cast<u32>(spv::Scope::Subgroup));
}
bool StageSupportsSubgroups(EmitContext& ctx) {
return ctx.profile.SupportsSubgroupStage(ctx.stage);
}
Id GetThreadId(EmitContext& ctx) {
if (!StageSupportsSubgroups(ctx)) {
return ctx.u32_zero_value;
}
return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id);
}
@ -68,6 +78,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask
}
Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) {
if (!StageSupportsSubgroups(ctx)) {
return value;
}
return ctx.OpSelect(
ctx.U32[1], in_range,
ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value);
@ -89,6 +102,9 @@ Id EmitLaneId(EmitContext& ctx) {
}
Id EmitVoteAll(EmitContext& ctx, Id pred) {
if (!StageSupportsSubgroups(ctx)) {
return pred;
}
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred);
}
@ -102,6 +118,9 @@ Id EmitVoteAll(EmitContext& ctx, Id pred) {
}
Id EmitVoteAny(EmitContext& ctx, Id pred) {
if (!StageSupportsSubgroups(ctx)) {
return pred;
}
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred);
}
@ -115,6 +134,9 @@ Id EmitVoteAny(EmitContext& ctx, Id pred) {
}
Id EmitVoteEqual(EmitContext& ctx, Id pred) {
if (!StageSupportsSubgroups(ctx)) {
return ctx.true_value;
}
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred);
}
@ -129,6 +151,9 @@ Id EmitVoteEqual(EmitContext& ctx, Id pred) {
}
Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
if (!StageSupportsSubgroups(ctx)) {
return ctx.OpSelect(ctx.U32[1], pred, ctx.Const(1u), ctx.u32_zero_value);
}
const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)};
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U);
@ -137,22 +162,37 @@ Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
}
Id EmitSubgroupEqMask(EmitContext& ctx) {
if (!StageSupportsSubgroups(ctx)) {
return ctx.Const(1u);
}
return LoadMask(ctx, ctx.subgroup_mask_eq);
}
Id EmitSubgroupLtMask(EmitContext& ctx) {
if (!StageSupportsSubgroups(ctx)) {
return ctx.u32_zero_value;
}
return LoadMask(ctx, ctx.subgroup_mask_lt);
}
Id EmitSubgroupLeMask(EmitContext& ctx) {
if (!StageSupportsSubgroups(ctx)) {
return ctx.Const(1u);
}
return LoadMask(ctx, ctx.subgroup_mask_le);
}
Id EmitSubgroupGtMask(EmitContext& ctx) {
if (!StageSupportsSubgroups(ctx)) {
return ctx.u32_zero_value;
}
return LoadMask(ctx, ctx.subgroup_mask_gt);
}
Id EmitSubgroupGeMask(EmitContext& ctx) {
if (!StageSupportsSubgroups(ctx)) {
return ctx.Const(1u);
}
return LoadMask(ctx, ctx.subgroup_mask_ge);
}
@ -222,7 +262,7 @@ Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id
Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle) {
const Id three{ctx.Const(3U)};
Id mask{ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id)};
Id mask{GetThreadId(ctx)};
mask = ctx.OpBitwiseAnd(ctx.U32[1], mask, three);
mask = ctx.OpShiftLeftLogical(ctx.U32[1], mask, ctx.Const(1U));
mask = ctx.OpShiftRightLogical(ctx.U32[1], swizzle, mask);

9
src/shader_recompiler/backend/spirv/spirv_emit_context.cpp

@ -1447,7 +1447,7 @@ void EmitContext::DefineInputs(const IR::Program& program) {
if (info.uses_is_helper_invocation) {
is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation);
}
if (info.uses_subgroup_mask) {
if (info.uses_subgroup_mask && profile.SupportsSubgroupStage(stage)) {
subgroup_mask_eq = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupEqMaskKHR);
subgroup_mask_lt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLtMaskKHR);
subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR);
@ -1461,9 +1461,10 @@ void EmitContext::DefineInputs(const IR::Program& program) {
Decorate(subgroup_mask_ge, spv::Decoration::Flat);
}
}
if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
(profile.warp_size_potentially_larger_than_guest &&
(info.uses_subgroup_vote || info.uses_subgroup_mask))) {
if ((info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
(profile.warp_size_potentially_larger_than_guest &&
(info.uses_subgroup_vote || info.uses_subgroup_mask))) &&
profile.SupportsSubgroupStage(stage)) {
AddCapability(spv::Capability::GroupNonUniform);
subgroup_local_invocation_id =
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);

7
src/shader_recompiler/profile.h

@ -10,6 +10,8 @@
namespace Shader {
enum class Stage : u32;
struct Profile {
u32 supported_spirv{0x00010000};
bool unified_descriptor_binding{};
@ -32,6 +34,7 @@ struct Profile {
bool support_fp64_signed_zero_nan_preserve{};
bool support_explicit_workgroup_layout{};
bool support_vote{};
u32 supported_subgroup_stages{0x7F};
bool support_viewport_index_layer_non_geometry{};
bool support_viewport_mask{};
bool support_typeless_image_loads{};
@ -95,6 +98,10 @@ struct Profile {
u64 min_ssbo_alignment{};
u32 max_user_clip_distances{};
bool SupportsSubgroupStage(Stage stage) const {
return (supported_subgroup_stages & (1u << static_cast<u32>(stage))) != 0;
}
};
} // namespace Shader

15
src/video_core/renderer_vulkan/vk_pipeline_cache.cpp

@ -353,6 +353,20 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
serialization_thread(1, "VkPipelineSerialization") {
const auto& float_control{device.FloatControlProperties()};
const VkDriverId driver_id{device.GetDriverID()};
const VkShaderStageFlags subgroup_stages{device.GetSubgroupSupportedStages()};
const auto subgroup_stage_bit{[subgroup_stages](VkShaderStageFlags flag, Shader::Stage stage) {
return (subgroup_stages & flag) != 0 ? (1u << static_cast<u32>(stage)) : 0u;
}};
const u32 supported_subgroup_stages{
subgroup_stage_bit(VK_SHADER_STAGE_VERTEX_BIT, Shader::Stage::VertexA) |
subgroup_stage_bit(VK_SHADER_STAGE_VERTEX_BIT, Shader::Stage::VertexB) |
subgroup_stage_bit(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
Shader::Stage::TessellationControl) |
subgroup_stage_bit(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
Shader::Stage::TessellationEval) |
subgroup_stage_bit(VK_SHADER_STAGE_GEOMETRY_BIT, Shader::Stage::Geometry) |
subgroup_stage_bit(VK_SHADER_STAGE_FRAGMENT_BIT, Shader::Stage::Fragment) |
subgroup_stage_bit(VK_SHADER_STAGE_COMPUTE_BIT, Shader::Stage::Compute)};
profile = Shader::Profile{
.supported_spirv = device.SupportedSpirvVersion(),
.unified_descriptor_binding = true,
@ -382,6 +396,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
.support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
.supported_subgroup_stages = supported_subgroup_stages,
.support_viewport_index_layer_non_geometry =
device.IsExtShaderViewportIndexLayerSupported(),
.support_viewport_mask = device.IsNvViewportArray2Supported(),

4
src/video_core/vulkan_common/vulkan_device.h

@ -430,6 +430,10 @@ FN_MAX_LIMIT_LIST
return properties.subgroup_properties.supportedOperations & feature;
}
VkShaderStageFlags GetSubgroupSupportedStages() const {
return properties.subgroup_properties.supportedStages;
}
/// Returns the maximum number of push descriptors.
u32 MaxPushDescriptors() const {
return properties.push_descriptor.maxPushDescriptors;

Loading…
Cancel
Save