diff options
author | Francisco Jerez <[email protected]> | 2015-07-27 14:33:06 +0300 |
---|---|---|
committer | Francisco Jerez <[email protected]> | 2015-08-11 15:07:40 +0300 |
commit | 13a04abc277089275217dce119e18acf4d4ce52d (patch) | |
tree | c23d449ee6176c7bae470fe3cb3e64b8490386f7 /src | |
parent | a47ae8de2cf30fbe45318a18a2ea032f30ab7d10 (diff) |
i965/fs: Clamp image array indices to the array bounds on IVB.
This fixes the spec@arb_shader_image_load_store@invalid index bounds
piglit tests on IVB, which were causing a GPU hang and then a crash
due to the invalid binding table index result of the array index
calculation. Other generations seem to behave sensibly when an
invalid surface is provided so it doesn't look like we need to care.
Reviewed-by: Jordan Justen <[email protected]>
Reviewed-by: Chris Forbes <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/mesa/drivers/dri/i965/brw_fs_nir.cpp | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp index 9d691f7eb9f..ce4153df70e 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_nir.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_nir.cpp @@ -1170,14 +1170,31 @@ fs_visitor::get_nir_image_deref(const nir_deref_var *deref) nir_deref_as_array(deref->deref.child); assert(deref->deref.child->deref_type == nir_deref_type_array && deref_array->deref.child == NULL); + const unsigned size = glsl_get_length(deref->var->type); + const unsigned base = MIN2(deref_array->base_offset, size - 1); - image = offset(image, bld, - deref_array->base_offset * BRW_IMAGE_PARAM_SIZE); + image = offset(image, bld, base * BRW_IMAGE_PARAM_SIZE); if (deref_array->deref_array_type == nir_deref_array_type_indirect) { fs_reg *tmp = new(mem_ctx) fs_reg(vgrf(glsl_type::int_type)); - bld.MUL(*tmp, get_nir_src(deref_array->indirect), - fs_reg(BRW_IMAGE_PARAM_SIZE)); + + if (devinfo->gen == 7 && !devinfo->is_haswell) { + /* IVB hangs when trying to access an invalid surface index with + * the dataport. According to the spec "if the index used to + * select an individual element is negative or greater than or + * equal to the size of the array, the results of the operation + * are undefined but may not lead to termination" -- which is one + * of the possible outcomes of the hang. Clamp the index to + * prevent access outside of the array bounds. + */ + bld.emit_minmax(*tmp, retype(get_nir_src(deref_array->indirect), + BRW_REGISTER_TYPE_UD), + fs_reg(size - base - 1), BRW_CONDITIONAL_L); + } else { + bld.MOV(*tmp, get_nir_src(deref_array->indirect)); + } + + bld.MUL(*tmp, *tmp, fs_reg(BRW_IMAGE_PARAM_SIZE)); image.reladdr = tmp; } } |