diff --git a/src/graphics/shader/recompiler/frontend/translate/Translate.cpp b/src/graphics/shader/recompiler/frontend/translate/Translate.cpp index abcaf1830..4efd3b23a 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Translate.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Translate.cpp @@ -841,9 +841,16 @@ bool TranslateProgram(const IR::Program& source, IR::ValueProgram& result, entry_ir.SetScalarReg(reg, entry_ir.GetUserData(reg)); } entry_ir.SetExec(IR::U1(IR::Value(true))); - entry_ir.SetExecLo(IR::U32(IR::Value(per_invocation_masks ? 1u : 0xffffffffu))); - entry_ir.SetExecHi( - IR::U32(IR::Value(!per_invocation_masks && source.wave_size > 32u ? 0xffffffffu : 0u))); + if (source.stage == ShaderType::Compute && !per_invocation_masks) { + const auto active = entry_ir.Emit(IR::ValueOpcode::Ballot, {IR::Value(true)}); + entry_ir.SetExecLo(entry_ir.CompositeExtract(active, 0)); + entry_ir.SetExecHi(source.wave_size > 32u ? entry_ir.CompositeExtract(active, 1) + : IR::U32(IR::Value(0u))); + } else { + entry_ir.SetExecLo(IR::U32(IR::Value(per_invocation_masks ? 1u : 0xffffffffu))); + entry_ir.SetExecHi(IR::U32( + IR::Value(!per_invocation_masks && source.wave_size > 32u ? 0xffffffffu : 0u))); + } if (source.stage == ShaderType::Compute) { const auto* cs = compute_input_info; const auto thread_ids = diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index bf1af39a5..4646e79d9 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -11734,7 +11734,7 @@ TestCase ScalarSaveExecOps() { return {"ScalarSaveExecOps", code, {}, - {0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, + {0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0x00000003u, 0xffffffffu, 0x00000003u, 0x00000002u, 0xffffffffu, 1}, {O::S_MOV_B32, O::S_AND_SAVEEXEC_B64, O::S_ORN2_SAVEEXEC_B64, @@ -17190,7 +17190,7 @@ TestCase DsAppendConsumeUsesEncodedLdsSelector() { return {"DsAppendConsumeLdsSelector", code, {}, - {10, 74, 0, 10}, + {10, 11, 0, 10}, {O::S_MOV_B32, O::V_MOV_B32, O::DS_WRITE_B32, O::DS_READ_B32, O::DS_APPEND, O::DS_CONSUME, O::BUFFER_STORE_DWORD, O::S_ENDPGM}}; } @@ -17224,7 +17224,7 @@ TestCase DsAppendUsesEncodedGdsSelector() { TestCase test{"DsAppendGdsSelector", code, {}, - {10, 74, 20, 84, 40, 104}, + {10, 11, 20, 21, 40, 41}, {O::S_MOV_B32, O::DS_APPEND, O::DS_CONSUME, O::BUFFER_STORE_DWORD, O::S_ENDPGM}}; test.gds_initial = {10, 20, 30, 40}; diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 80fc2f2af..463a4e232 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -8640,12 +8640,18 @@ void TestTypedEntryStateIsMinimal() { uint32_t set_exec = 0; uint32_t set_exec_lo = 0; uint32_t set_exec_hi = 0; + uint32_t ballots = 0; IR::Value exec; IR::Value exec_lo; IR::Value exec_hi; + const IR::Inst *ballot = nullptr; for (const auto *block : values.blocks) { for (const auto &inst : *block) { switch (inst.GetOpcode()) { + case IR::ValueOpcode::Ballot: + ballots++; + ballot = &inst; + break; case IR::ValueOpcode::SetExec: set_exec++; exec = inst.Arg(0).Resolve(); @@ -8677,14 +8683,29 @@ void TestTypedEntryStateIsMinimal() { exec.IsImmediate() && exec.U1(), "typed entry does not define EXEC exactly once"); if (lane_mode == ShaderLaneMaskMode::PerInvocation) { - Check(exec_lo.IsImmediate() && exec_lo.U32() == 1u && + Check(ballots == 0u && exec_lo.IsImmediate() && exec_lo.U32() == 1u && exec_hi.IsImmediate() && exec_hi.U32() == 0u, "per-invocation entry EXEC is not the local {1,0} mask"); } else { - Check(exec_lo.IsImmediate() && exec_lo.U32() == 0xffffffffu && - exec_hi.IsImmediate() && - exec_hi.U32() == (wave_size == 32u ? 0u : 0xffffffffu), - "native entry EXEC does not match the guest wave width"); + Check(ballots == 1u && !exec_lo.IsImmediate(), + "native compute entry EXEC does not use the active subgroup mask"); + const auto *lo = exec_lo.ResolveInstruction(); + Check(lo != nullptr && + lo->GetOpcode() == IR::ValueOpcode::CompositeExtractU32x4 && + lo->Arg(0).ResolveInstruction() == ballot && + lo->Arg(1).Resolve().U32() == 0u, + "native compute EXEC_LO does not use ballot word zero"); + if (wave_size == 32u) { + Check(exec_hi.IsImmediate() && exec_hi.U32() == 0u, + "native wave32 entry defined EXEC_HI"); + } else { + const auto *hi = exec_hi.ResolveInstruction(); + Check(hi != nullptr && + hi->GetOpcode() == IR::ValueOpcode::CompositeExtractU32x4 && + hi->Arg(0).ResolveInstruction() == ballot && + hi->Arg(1).Resolve().U32() == 1u, + "native wave64 EXEC_HI does not use ballot word one"); + } } IR::RewriteToSsa(values.blocks);