pan/mdg: Use smaller LD_UNIFORM instructions

If we only read 8 bytes from a UBO, we need to use LD_UNIFORM.64 as
opposed to LD_UNIFORM.128. In addition to probably being faster, this
fixes a buffer overrun manifesting as MMU faults with source ID
0x500/0x600/0x700, visible in WebGL Aquarium.

This is essentially the same patch as 616394cf31 ("pan/mdg: Use
appropriate sizes for global loads/stores"), only this is for UBOs where
that was for SSBOs.

Before enabling PACKED_UNIFORMS, this bug was not visible since we could
guarantee the UBO size was a multiple of 16. We no longer have that
invariant, and in rare cases the last 8 bytes of the last 16-byte slot
of a mapped uniform buffer would overrun the BO and trigger a fault,
even if the result is unused.

Fixes: 24d7c413fe ("panfrost: Enable packed uniforms.")
Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10772>
This commit is contained in:
Alyssa Rosenzweig 2021-05-12 13:22:24 -04:00 committed by Marge Bot
parent df3edfc729
commit 01ef56a7e4

View file

@ -133,6 +133,8 @@ schedule_barrier(compiler_context *ctx)
M_LOAD(ld_attr_32, nir_type_uint32);
M_LOAD(ld_vary_32, nir_type_uint32);
M_LOAD(ld_ubo_32, nir_type_uint32);
M_LOAD(ld_ubo_64, nir_type_uint32);
M_LOAD(ld_ubo_128, nir_type_uint32);
M_LOAD(ld_32, nir_type_uint32);
M_LOAD(ld_64, nir_type_uint32);
@ -1161,11 +1163,26 @@ emit_ubo_read(
unsigned offset,
nir_src *indirect_offset,
unsigned indirect_shift,
unsigned index)
unsigned index,
unsigned nr_comps)
{
/* TODO: half-floats */
midgard_instruction ins;
unsigned dest_size = (instr->type == nir_instr_type_intrinsic) ?
nir_dest_bit_size(nir_instr_as_intrinsic(instr)->dest) : 32;
unsigned bitsize = dest_size * nr_comps;
/* Pick the smallest intrinsic to avoid out-of-bounds reads */
if (bitsize <= 32)
ins = m_ld_ubo_32(dest, 0);
else if (bitsize <= 64)
ins = m_ld_ubo_64(dest, 0);
else if (bitsize <= 128)
ins = m_ld_ubo_128(dest, 0);
else
unreachable("Invalid UBO read size");
midgard_instruction ins = m_ld_ubo_128(dest, 0);
ins.constants.u32[0] = offset;
if (instr->type == nir_instr_type_intrinsic)
@ -1498,7 +1515,7 @@ emit_sysval_read(compiler_context *ctx, nir_instr *instr,
/* Emit the read itself -- this is never indirect */
midgard_instruction *ins =
emit_ubo_read(ctx, instr, dest, (uniform * 16) + offset, NULL, 0,
sysval_ubo);
sysval_ubo, nr_components);
ins->mask = mask_of(nr_components);
}
@ -1752,7 +1769,7 @@ emit_intrinsic(compiler_context *ctx, nir_intrinsic_instr *instr)
reg = nir_dest_index(&instr->dest);
if (is_kernel) {
emit_ubo_read(ctx, &instr->instr, reg, offset, indirect_offset, 0, 0);
emit_ubo_read(ctx, &instr->instr, reg, offset, indirect_offset, 0, 0, nr_comp);
} else if (is_ubo) {
nir_src index = instr->src[0];
@ -1760,7 +1777,7 @@ emit_intrinsic(compiler_context *ctx, nir_intrinsic_instr *instr)
assert(nir_src_is_const(index));
uint32_t uindex = nir_src_as_uint(index);
emit_ubo_read(ctx, &instr->instr, reg, offset, indirect_offset, 0, uindex);
emit_ubo_read(ctx, &instr->instr, reg, offset, indirect_offset, 0, uindex, nr_comp);
} else if (is_global || is_shared || is_scratch) {
unsigned seg = is_global ? LDST_GLOBAL : (is_shared ? LDST_SHARED : LDST_SCRATCH);
emit_global(ctx, &instr->instr, true, reg, src_offset, seg);