mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
shader: disable DPP16 writes from EXEC-disabled sources without BOUND_CTRL
This commit is contained in:
@@ -147,9 +147,24 @@ uint32_t EmitDppWriteCondition(ValueEmitContext& ctx, const IR::DppMoveFlags& fl
|
|||||||
// Only row shifts (0x101-0x10f, 0x111-0x11f) can vacate a lane; other controls always read one.
|
// Only row shifts (0x101-0x10f, 0x111-0x11f) can vacate a lane; other controls always read one.
|
||||||
const bool row_shift = flags.control > 0x100u && flags.control < 0x120u &&
|
const bool row_shift = flags.control > 0x100u && flags.control < 0x120u &&
|
||||||
flags.control != 0x110u;
|
flags.control != 0x110u;
|
||||||
if (!flags.bound_control && row_shift) {
|
if (flags.bound_control || (flags.fetch_inactive && !row_shift)) {
|
||||||
|
return writable;
|
||||||
|
}
|
||||||
|
// Without BOUND_CTRL, a vacated source or, without FI, an EXEC-disabled one disables the write.
|
||||||
|
const auto target = EmitDppTargetLane(state, flags);
|
||||||
|
if (row_shift) {
|
||||||
|
writable = Binary(state, spv::OpLogicalAnd, TypeBool(state), writable, target.valid);
|
||||||
|
}
|
||||||
|
if (!flags.fetch_inactive) {
|
||||||
|
// Vacated lanes target outside their row; wrapping keeps the ballot index in range.
|
||||||
|
auto source = target.lane;
|
||||||
|
if (row_shift) {
|
||||||
|
lane = lane != 0 ? lane : EmitSubgroupLocalInvocationId(state);
|
||||||
|
source = EmitNative<spv::OpBitFieldInsert, IR::Type::U32>(
|
||||||
|
state, lane, source, ConstantU32(state, 0), ConstantU32(state, 4));
|
||||||
|
}
|
||||||
writable = Binary(state, spv::OpLogicalAnd, TypeBool(state), writable,
|
writable = Binary(state, spv::OpLogicalAnd, TypeBool(state), writable,
|
||||||
EmitDppTargetLane(state, flags).valid);
|
EmitSourceLaneActive(ctx, exec, source));
|
||||||
}
|
}
|
||||||
return writable;
|
return writable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28298,25 +28298,56 @@ TestCase VectorDppBankMaskPreservesDestination() {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase VectorDppBoundsControlZeroPreservesDestination() {
|
TestCase VectorDppInactiveSource(bool row_shift, bool bound_ctrl, u32 wave_size) {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
constexpr u32 sentinel = 0xaaaaaaaau;
|
||||||
|
// Each half mixes active, EXEC-disabled and (for row_shr:1) vacated sources.
|
||||||
|
const u32 masks[] = {0x5f5ff5f5u, 0xf5f55f5fu};
|
||||||
std::vector<u32> code;
|
std::vector<u32> code;
|
||||||
AppendVMovLiteral(&code, 2, 0xaaaaaaaau);
|
|
||||||
AppendVMovU32(&code, 1, 100);
|
AppendVMovU32(&code, 1, 100);
|
||||||
code.push_back(EncodeVop2(0x25, 2, 250, 1));
|
code.push_back(EncodeVop2(0x25, 1, Vgpr(0), 1));
|
||||||
code.push_back(EncodeVop2Dpp(0, 0x111));
|
AppendVMovU32(&code, 7, 1000);
|
||||||
code.push_back(EncodeVop2(0x1a, 3, InlineU32(2), 0));
|
code.push_back(EncodeVop2(0x25, 7, Vgpr(0), 7));
|
||||||
AppendBufferStoreDword(&code, 2, 3);
|
AppendVMovLiteral(&code, 2, sentinel);
|
||||||
|
AppendSMovLiteral(&code, 126, masks[0]);
|
||||||
|
if (wave_size == 64) AppendSMovLiteral(&code, 127, masks[1]);
|
||||||
|
// v_add_nc_u32_dpp v2, v1, v7 with row_shr:1 or quad_perm:[3,2,1,0]; bit 19 is BOUND_CTRL.
|
||||||
|
code.push_back(EncodeVop2(0x25, 2, 250, 7));
|
||||||
|
code.push_back(EncodeVop2Dpp(1, row_shift ? 0x111u : 0x01bu) |
|
||||||
|
(bound_ctrl ? 1u << 19 : 0u));
|
||||||
|
AppendSMovLiteral(&code, 126, 0xffffffffu);
|
||||||
|
if (wave_size == 64) AppendSMovLiteral(&code, 127, 0xffffffffu);
|
||||||
|
AppendStoreVgprAtLaneDwordOffset(&code, 2, 0, 0);
|
||||||
AppendEnd(&code);
|
AppendEnd(&code);
|
||||||
|
|
||||||
TestCase test;
|
TestCase test;
|
||||||
test.name = "VectorDppBoundsControlZeroPreservesDestination";
|
const char *names[2][2][2] = {
|
||||||
test.code = code;
|
{{"VectorDppQuadPermInactiveSourceKeepsWave32",
|
||||||
test.expected = {0xaaaaaaaau, 100, 101, 102, 103, 104, 105, 106};
|
"VectorDppQuadPermInactiveSourceKeepsWave64"},
|
||||||
test.opcodes = {O::V_MOV_B32, O::V_ADD_NC_U32, O::V_LSHLREV_B32,
|
{"VectorDppQuadPermInactiveSourceZeroWave32",
|
||||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
"VectorDppQuadPermInactiveSourceZeroWave64"}},
|
||||||
test.compute_info.threads_num[0] = 8;
|
{{"VectorDppRowShrInactiveSourceKeepsWave32",
|
||||||
|
"VectorDppRowShrInactiveSourceKeepsWave64"},
|
||||||
|
{"VectorDppRowShrInactiveSourceZeroWave32",
|
||||||
|
"VectorDppRowShrInactiveSourceZeroWave64"}}};
|
||||||
|
test.name = names[row_shift][bound_ctrl][wave_size == 64];
|
||||||
|
test.code = std::move(code);
|
||||||
|
test.expected.resize(wave_size, sentinel);
|
||||||
|
for (u32 lane = 0; lane < wave_size; ++lane) {
|
||||||
|
const auto mask = masks[lane / 32u];
|
||||||
|
if ((mask & (1u << (lane % 32u))) == 0) continue;
|
||||||
|
const bool vacated = row_shift && lane % 16u == 0;
|
||||||
|
const u32 source = row_shift ? lane - 1u : (lane & ~3u) | (3u - (lane & 3u));
|
||||||
|
if (!vacated && (mask & (1u << (source % 32u))) != 0) {
|
||||||
|
test.expected[lane] = 1100u + source + lane;
|
||||||
|
} else if (bound_ctrl) {
|
||||||
|
test.expected[lane] = 1000u + lane;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test.opcodes = {O::V_MOV_B32, O::V_ADD_NC_U32, O::S_MOV_B32,
|
||||||
|
O::V_LSHLREV_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||||
|
test.compute_info.wave_size = wave_size;
|
||||||
|
test.compute_info.threads_num[0] = wave_size;
|
||||||
test.compute_info.threads_num[1] = 1;
|
test.compute_info.threads_num[1] = 1;
|
||||||
test.compute_info.threads_num[2] = 1;
|
test.compute_info.threads_num[2] = 1;
|
||||||
test.compute_info.thread_ids_num = 1;
|
test.compute_info.thread_ids_num = 1;
|
||||||
@@ -44177,7 +44208,10 @@ std::vector<TestCase> MakeCases() {
|
|||||||
cases.push_back(ComputeWave64Minimum(false));
|
cases.push_back(ComputeWave64Minimum(false));
|
||||||
cases.push_back(ComputeWave64Minimum(true));
|
cases.push_back(ComputeWave64Minimum(true));
|
||||||
AddCase(VectorDppBankMaskPreservesDestination);
|
AddCase(VectorDppBankMaskPreservesDestination);
|
||||||
AddCase(VectorDppBoundsControlZeroPreservesDestination);
|
for (const bool row_shift : {false, true})
|
||||||
|
for (const bool bound_ctrl : {false, true})
|
||||||
|
for (const u32 wave_size : {32u, 64u})
|
||||||
|
cases.push_back(VectorDppInactiveSource(row_shift, bound_ctrl, wave_size));
|
||||||
AddCase(Vop3FmacF32NegatedSourceAccumulates);
|
AddCase(Vop3FmacF32NegatedSourceAccumulates);
|
||||||
AddCase(VectorMadF32RoundsProduct);
|
AddCase(VectorMadF32RoundsProduct);
|
||||||
AddCase(VectorMadF32FlushesDenorms);
|
AddCase(VectorMadF32FlushesDenorms);
|
||||||
@@ -50614,7 +50648,10 @@ int main(int argc, char **argv) {
|
|||||||
RunCase(&vulkan, VectorReadFirstLaneExecMasks(32));
|
RunCase(&vulkan, VectorReadFirstLaneExecMasks(32));
|
||||||
RunCase(&vulkan, VectorReadFirstLaneExecMasks(64));
|
RunCase(&vulkan, VectorReadFirstLaneExecMasks(64));
|
||||||
RunCase(&vulkan, VectorDppBankMaskPreservesDestination());
|
RunCase(&vulkan, VectorDppBankMaskPreservesDestination());
|
||||||
RunCase(&vulkan, VectorDppBoundsControlZeroPreservesDestination());
|
for (const bool row_shift : {false, true})
|
||||||
|
for (const bool bound_ctrl : {false, true})
|
||||||
|
for (const u32 wave_size : {32u, 64u})
|
||||||
|
RunCase(&vulkan, VectorDppInactiveSource(row_shift, bound_ctrl, wave_size));
|
||||||
for (const u32 op_sel : {0u, 1u, 2u})
|
for (const u32 op_sel : {0u, 1u, 2u})
|
||||||
for (const u32 wave_size : {32u, 64u})
|
for (const u32 wave_size : {32u, 64u})
|
||||||
RunCase(&vulkan, VectorPermlane16InactiveSource(op_sel, wave_size));
|
RunCase(&vulkan, VectorPermlane16InactiveSource(op_sel, wave_size));
|
||||||
|
|||||||
Reference in New Issue
Block a user