mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-03 11:13:54 +00:00
[vulkan] Implementation for VK_EXT_shader_quad_control (#4168)
An experimental approach to introduce an smarter way to use and access QUAD's capabilities on shaders, suggested by @gidoly some months ago, finally came into something usable; current implementation checks GLASM, GLSL and Vulkan on their own way, stablishes proper emitters and receivers for Quads inside our recompiler, which are the introductions for future changes; checks for support and actual feature bit, OpCodes and mask were added within this PR. Meanwhile the expected behavior was to reduce graphical issues (on games with Quad shaders reliant), we encountered a very slight performance increase depending on what game and shader are actually compiled. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4168 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: Samuel <lizzie@eden-emu.dev>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -665,6 +665,8 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU3
|
||||
const IR::Value& clamp, const IR::Value& segmentation_mask);
|
||||
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 index,
|
||||
const IR::Value& clamp, const IR::Value& segmentation_mask);
|
||||
void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 lane);
|
||||
void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 direction);
|
||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b,
|
||||
ScalarU32 swizzle);
|
||||
void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -97,6 +100,24 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, Sca
|
||||
Shuffle(ctx, inst, value, index, clamp, segmentation_mask, "XOR");
|
||||
}
|
||||
|
||||
void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 lane) {
|
||||
const Register ret{ctx.reg_alloc.Define(inst)};
|
||||
ctx.Add("AND.U RC.x,{}.threadid,~3;"
|
||||
"AND.U RC.y,{},3;"
|
||||
"OR.U RC.x,RC.x,RC.y;"
|
||||
"SHFIDX.U {},{},RC.x,0x1C03;"
|
||||
"MOV.U {}.x,{}.y;",
|
||||
ctx.stage_name, lane, ret, value, ret, ret);
|
||||
}
|
||||
|
||||
void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, ScalarU32 value, ScalarU32 direction) {
|
||||
const Register ret{ctx.reg_alloc.Define(inst)};
|
||||
ctx.Add("ADD.U RC.x,{},1;"
|
||||
"SHFXOR.U {},{},RC.x,0x1C03;"
|
||||
"MOV.U {}.x,{}.y;",
|
||||
direction, ret, value, ret, ret);
|
||||
}
|
||||
|
||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, ScalarF32 op_a, ScalarF32 op_b,
|
||||
ScalarU32 swizzle) {
|
||||
const auto ret{ctx.reg_alloc.Define(inst)};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -743,6 +743,10 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
std::string_view index, std::string_view clamp,
|
||||
std::string_view segmentation_mask);
|
||||
void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
std::string_view lane);
|
||||
void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
std::string_view direction);
|
||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,
|
||||
std::string_view swizzle);
|
||||
void EmitDPdxFine(EmitContext& ctx, IR::Inst& inst, std::string_view op_a);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -200,6 +203,18 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view val
|
||||
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
|
||||
}
|
||||
|
||||
void EmitQuadBroadcast(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
std::string_view lane) {
|
||||
const auto src_thread_id{fmt::format("(({}&~3)|({}& 3))", THREAD_ID, lane)};
|
||||
ctx.AddU32("{}=readInvocationARB({},{});", inst, value, src_thread_id);
|
||||
}
|
||||
|
||||
void EmitQuadSwap(EmitContext& ctx, IR::Inst& inst, std::string_view value,
|
||||
std::string_view direction) {
|
||||
const auto src_thread_id{fmt::format("({}^({}+1))", THREAD_ID, direction)};
|
||||
ctx.AddU32("{}=readInvocationARB({},{});", inst, value, src_thread_id);
|
||||
}
|
||||
|
||||
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,
|
||||
std::string_view swizzle) {
|
||||
const auto mask{fmt::format("({}>>((gl_SubGroupInvocationARB&3)<<1))&3", swizzle)};
|
||||
|
||||
@@ -322,6 +322,11 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
||||
if (ctx.runtime_info.force_early_z) {
|
||||
ctx.AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests);
|
||||
}
|
||||
if (ctx.profile.support_shader_quad_control && program.info.uses_quad_shuffles) {
|
||||
ctx.AddExtension("SPV_KHR_quad_control");
|
||||
ctx.AddCapability(spv::Capability::QuadControlKHR);
|
||||
ctx.AddExecutionMode(main, spv::ExecutionMode::RequireFullQuadsKHR);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException("Stage {}", program.stage);
|
||||
@@ -443,6 +448,12 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
||||
ctx.AddCapability(spv::Capability::GroupNonUniformVote);
|
||||
}
|
||||
}
|
||||
if (info.uses_quad_shuffles) {
|
||||
if (profile.support_quad_shuffles) {
|
||||
ctx.AddCapability(spv::Capability::GroupNonUniformQuad);
|
||||
}
|
||||
ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
|
||||
}
|
||||
if (info.uses_int64_bit_atomics && profile.support_int64_atomics) {
|
||||
ctx.AddCapability(spv::Capability::Int64Atomics);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -622,6 +622,8 @@ Id EmitShuffleDown(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clam
|
||||
Id segmentation_mask);
|
||||
Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
||||
Id segmentation_mask);
|
||||
Id EmitQuadBroadcast(EmitContext& ctx, Id value, Id lane);
|
||||
Id EmitQuadSwap(EmitContext& ctx, Id value, Id direction);
|
||||
Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle);
|
||||
Id EmitDPdxFine(EmitContext& ctx, Id op_a);
|
||||
Id EmitDPdyFine(EmitContext& ctx, Id op_a);
|
||||
|
||||
@@ -260,6 +260,21 @@ Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id
|
||||
return SelectValue(ctx, in_range, value, src_thread_id);
|
||||
}
|
||||
|
||||
Id EmitQuadBroadcast(EmitContext& ctx, Id value, Id lane) {
|
||||
if (ctx.profile.support_quad_shuffles) {
|
||||
return ctx.OpGroupNonUniformQuadBroadcast(ctx.U32[1], SubgroupScope(ctx), value, lane);
|
||||
}
|
||||
const Id base{ctx.OpBitwiseAnd(ctx.U32[1], GetThreadId(ctx), ctx.Const(~3u))};
|
||||
const Id local_lane{ctx.OpBitwiseAnd(ctx.U32[1], lane, ctx.Const(3u))};
|
||||
const Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], base, local_lane)};
|
||||
return ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id);
|
||||
}
|
||||
|
||||
Id EmitQuadSwap(EmitContext& ctx, Id value, Id direction) {
|
||||
const Id xor_mask{ctx.OpIAdd(ctx.U32[1], direction, ctx.Const(1u))};
|
||||
return ctx.OpGroupNonUniformShuffleXor(ctx.U32[1], SubgroupScope(ctx), value, xor_mask);
|
||||
}
|
||||
|
||||
Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle) {
|
||||
const Id three{ctx.Const(3U)};
|
||||
Id mask{GetThreadId(ctx)};
|
||||
|
||||
Reference in New Issue
Block a user