diff --git a/src/graphics/shader/recompiler/frontend/translate/Convert.cpp b/src/graphics/shader/recompiler/frontend/translate/Convert.cpp index 8a50db91f..79f36f1c5 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Convert.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Convert.cpp @@ -135,6 +135,8 @@ void Translator::V_PACK_B32_F16(const Decoder::Instruction& inst) { } IR::U32 Translator::PackU16Lanes(IR::U32 low, IR::U32 high) { + // A zero high lane zero-extends; descriptor tracking bounds a mask, not a bitfield insert. + if (high == IR::Value(0u)) return ir.BitwiseAnd(low, IR::U32(IR::Value(0xffffu))); return IR::U32( ir.Emit(IR::ValueOpcode::BitFieldInsert, {low, high, IR::Value(16u), IR::Value(16u)})); } diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 510d94c23..75844609f 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -9553,6 +9553,28 @@ void TestNativeConstantSamplerSelection() { CheckSpirvBinaryValidates(result.spirv); } +void TestPackedZeroHighSamplerTableKey() { + // s_pack_ll_b32_b16 with a zero high lane zero-extends a GPU-selected table key, so the + // sampler table stays bounded to 64Ki records. + const uint32_t shader[] = { + EncodeMubuf0(0x0c, 0, true), EncodeMubuf1(1, 3, 0), EncodeSopp(0x0c, 0), + EncodeVop1(0x02, 28, 257), EncodeSop2(0x32, 29, 28, 128), + EncodeSop2(0x1e, 30, 29, 132), + EncodeSmem0(0x0a, 24, 4), 30u << 25u, EncodeSopp(0x0c, 0), + EncodeMimg0(0x20, 0x1), EncodeMimg1(0, 4, 6, 2), + EncodeExp0(0x00, 0x1), EncodeExp1(0, 0, 0, 0), + EncodeSopp(0x01), + }; + auto options = MakeCompileOptions(ShaderType::Pixel); + options.user_data = ImageTestUserData(); + const auto translated = ShaderRecompiler::TranslateProgram(shader, options); + const auto plan = ShaderRecompiler::IR::ExtractResourcePlan(translated.program); + const auto& indirect = + plan.descriptor_sources[plan.info.samplers.at(0).source].indirect_descriptor; + Check(indirect && indirect->table_stride == 16u && indirect->table_maximum == 0xffffu, + "a zero-extended sampler table key lost its 16-bit bound"); +} + void TestBoundedMaterialBufferStores(bool scalar_key) { // Captured batch search and descriptor waterfall, with deformation arithmetic removed. const uint32_t shader[] = { @@ -16815,6 +16837,7 @@ int main() { TestNativeGuardedSamplerSource(false); TestNativeGuardedSamplerSource(true); TestNativeConstantSamplerSelection(); + TestPackedZeroHighSamplerTableKey(); for (const bool scalar_key : {false, true}) TestBoundedMaterialBufferStores(scalar_key); TestNativeDescriptorProvenanceKeepsGpuSelection(); TestCfgSiblingSharedExit();