summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs_nir.cpp25
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;
}
}