anv: Make sure robust UBO access does not fault

We can just conditionally replace the address with an address to a zero
initialized cacheline if the read is going to go out of bounds.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40149>
This commit is contained in:
Calder Young 2026-03-02 22:57:57 -08:00 committed by Marge Bot
parent 64b5823d33
commit 8ce98fedc4
5 changed files with 48 additions and 30 deletions

View file

@ -609,6 +609,8 @@ enum intel_shader_reloc_id {
BRW_SHADER_RELOC_PRINTF_BUFFER_ADDR_LOW,
BRW_SHADER_RELOC_PRINTF_BUFFER_ADDR_HIGH,
BRW_SHADER_RELOC_PRINTF_BUFFER_SIZE,
BRW_SHADER_RELOC_NULL_CACHELINE_ADDR_LOW,
BRW_SHADER_RELOC_NULL_CACHELINE_ADDR_HIGH,
/* Leave this entry last: */
BRW_SHADER_RELOC_EMBEDDED_SAMPLER_HANDLE,
BRW_SHADER_RELOC_LAST_EMBEDDED_SAMPLER_HANDLE =

View file

@ -961,6 +961,10 @@ VkResult anv_CreateDevice(
physical_device->rt_uuid,
sizeof(physical_device->rt_uuid));
/* A null cache line for bounded UBO loads. */
wa_addr = anv_address_add_aligned(wa_addr, 64, 64);
device->null_cacheline_addr = wa_addr;
/* Make sure the workaround address is the last one in the workaround BO,
* so that writes never overwrite other bits of data stored in the
* workaround BO.

View file

@ -24,6 +24,27 @@
#include "anv_nir.h"
#include "nir_builder.h"
static nir_def *
lower_ubo_load_addr(nir_builder *b, nir_def *base_addr,
nir_def *offset, nir_def *bound,
unsigned load_size)
{
nir_def *addr = nir_iadd(b, base_addr, nir_u2u64(b, offset));
if (bound) {
addr =
nir_bcsel(b,
nir_ult(b, nir_iadd_imm(b, offset, load_size - 1), bound),
addr,
nir_pack_64_2x32_split(
b,
nir_load_reloc_const_intel(b, BRW_SHADER_RELOC_NULL_CACHELINE_ADDR_LOW),
nir_load_reloc_const_intel(b, BRW_SHADER_RELOC_NULL_CACHELINE_ADDR_HIGH)));
}
return addr;
}
static bool
lower_ubo_load_instr(nir_builder *b, nir_intrinsic_instr *load,
UNUSED void *_data)
@ -58,7 +79,10 @@ lower_ubo_load_instr(nir_builder *b, nir_intrinsic_instr *load,
/* Load two just in case we go over a 64B boundary */
nir_def *data[2];
for (unsigned i = 0; i < 2; i++) {
nir_def *addr = nir_iadd_imm(b, base_addr, aligned_offset + i * 64);
nir_def *addr =
lower_ubo_load_addr(b, base_addr,
nir_imm_int(b, aligned_offset + i * 64),
bound, 1);
data[i] = nir_load_global_constant_uniform_block_intel(
b, 16, 32, addr,
@ -95,34 +119,14 @@ lower_ubo_load_instr(nir_builder *b, nir_intrinsic_instr *load,
load->num_components, bit_size);
} else {
nir_def *offset = load->src[1].ssa;
nir_def *addr = nir_iadd(b, base_addr, nir_u2u64(b, offset));
unsigned load_size = byte_size * load->num_components;
if (bound) {
nir_def *zero = nir_imm_zero(b, load->num_components, bit_size);
unsigned load_size = byte_size * load->num_components;
nir_def *in_bounds =
nir_ult(b, nir_iadd_imm(b, offset, load_size - 1), bound);
nir_push_if(b, in_bounds);
nir_def *load_val =
nir_load_global_constant(b, load->def.num_components,
load->def.bit_size, addr,
.access = nir_intrinsic_access(load),
.align_mul = nir_intrinsic_align_mul(load),
.align_offset = nir_intrinsic_align_offset(load));
nir_pop_if(b, NULL);
val = nir_if_phi(b, load_val, zero);
} else {
val = nir_load_global_constant(b, load->def.num_components,
load->def.bit_size, addr,
.access = nir_intrinsic_access(load),
.align_mul = nir_intrinsic_align_mul(load),
.align_offset = nir_intrinsic_align_offset(load));
}
nir_def *addr = lower_ubo_load_addr(b, base_addr, offset, bound, load_size);
val = nir_load_global_constant(b, load->def.num_components,
load->def.bit_size, addr,
.access = nir_intrinsic_access(load),
.align_mul = nir_intrinsic_align_mul(load),
.align_offset = nir_intrinsic_align_offset(load));
}
nir_def_replace(&load->def, val);
@ -134,6 +138,5 @@ bool
anv_nir_lower_ubo_loads(nir_shader *shader)
{
return nir_shader_intrinsics_pass(shader, lower_ubo_load_instr,
nir_metadata_none,
NULL);
nir_metadata_none, NULL);
}

View file

@ -2666,6 +2666,7 @@ struct anv_device {
*/
struct anv_bo * workaround_bo;
struct anv_address workaround_address;
struct anv_address null_cacheline_addr;
struct anv_bo * dummy_aux_bo;
struct anv_bo * mem_fence_bo;

View file

@ -587,6 +587,14 @@ anv_shader_set_relocs(struct anv_device *device,
.id = INTEL_SHADER_RELOC_SHADER_START_OFFSET,
.value = shader->kernel.offset,
};
reloc_values[rv_count++] = (struct intel_shader_reloc_value) {
.id = BRW_SHADER_RELOC_NULL_CACHELINE_ADDR_HIGH,
.value = anv_address_physical(device->null_cacheline_addr) >> 32,
};
reloc_values[rv_count++] = (struct intel_shader_reloc_value) {
.id = BRW_SHADER_RELOC_NULL_CACHELINE_ADDR_LOW,
.value = anv_address_physical(device->null_cacheline_addr) & 0xffffffff,
};
if (brw_shader_stage_is_bindless(shader->vk.stage)) {
const struct brw_bs_prog_data *bs_prog_data =
brw_bs_prog_data_const(shader->prog_data);