From ac11e00b15a9b046f69fc8cdfc8b4c130b078180 Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Tue, 5 Aug 2025 23:13:15 +0200 Subject: [PATCH] nir/serialize: make alu src deserialization consistent for unused swizzles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we have 3 paths for ALU serialization/deserialization in NIR: 1. If the ALU is qualified as packed_src_ssa_16bit (identity swizzle) - The write will store an object index only. - The read will only load the swizzles actually used, the rest are 0. 2. If the ALU is not qualified as packed_src_ssa_16bit, we have two cases: 2.1 Up to vec4: - The write stores all 4 swizzle components. - The read loads all 4 swizzle components. 2.2 vec8/16 - The write stores only swizzle components used, the rest are 0. - The read loads only swizzle components used, the rest are 0. This inconsistency in how these paths encode/decode unsused swizzle components can cause issues in some scenarios where a backend compiler may receive functionally equivalent NIR shaders from Mesa that won't produce the same sha1, leading to unnecessary cache misses. This patch makes path 2.1 always encode and decode unused swizzle components as 0, making it consistent with the other paths. This fixes issues where sometimes backends need to compile a shader twice before it is effectively retrieved from the disk cache. This has been observed at least with V3d and Panfrost. The problem occurs when an ALU src with unused swizzle components is serialized in the Mesa frontend using path 1, but when it later hits the backend it is serialized using path 2.1. The backend uses the sha1 of the serialized NIR for the cache key. On the second execution the Mesa frontend has a cache hit and when it deserializes the alu src, it sets its unused components to 0 but that will cause the backend to have a cache miss since that NIR doesn't match the one it cached on the first execution. By always making unused swizzle components decode and encode consistently to 0 in all paths we ensure the issue never happens and that NIR variants that only differ in swizzle components that are not used lead to cache hits. Reviewed-by: Alejandro Piñeiro Reviewed-by: Marek Olšák Reviewed-by: Eric R. Smith Part-of: --- src/compiler/nir/nir_serialize.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/compiler/nir/nir_serialize.c b/src/compiler/nir/nir_serialize.c index 3f15a4c445b..98c020201d9 100644 --- a/src/compiler/nir/nir_serialize.c +++ b/src/compiler/nir/nir_serialize.c @@ -751,9 +751,12 @@ write_alu(write_ctx *ctx, const nir_alu_instr *alu) if (packed) { src.alu.swizzle_x = alu->src[i].swizzle[0]; - src.alu.swizzle_y = alu->src[i].swizzle[1]; - src.alu.swizzle_z = alu->src[i].swizzle[2]; - src.alu.swizzle_w = alu->src[i].swizzle[3]; + if (src_channels >= 2) + src.alu.swizzle_y = alu->src[i].swizzle[1]; + if (src_channels >= 3) + src.alu.swizzle_z = alu->src[i].swizzle[2]; + if (src_channels >= 4) + src.alu.swizzle_w = alu->src[i].swizzle[3]; } write_src_full(ctx, &alu->src[i].src, src); @@ -810,9 +813,12 @@ read_alu(read_ctx *ctx, union packed_instr header) if (packed) { alu->src[i].swizzle[0] = src.alu.swizzle_x; - alu->src[i].swizzle[1] = src.alu.swizzle_y; - alu->src[i].swizzle[2] = src.alu.swizzle_z; - alu->src[i].swizzle[3] = src.alu.swizzle_w; + if (src_channels >= 2) + alu->src[i].swizzle[1] = src.alu.swizzle_y; + if (src_channels >= 3) + alu->src[i].swizzle[2] = src.alu.swizzle_z; + if (src_channels >= 4) + alu->src[i].swizzle[3] = src.alu.swizzle_w; } else { /* Load swizzles for vec8 and vec16. */ for (unsigned o = 0; o < src_channels; o += 8) {