[Mesa-dev] [PATCH 7/7] anv: add nir pass to insert border color workaround

Lionel Landwerlin llandwerlin at gmail.com
Mon Nov 21 17:47:40 UTC 2016


This pass wraps sampler instructions with some logic to deal with border
colors with integer formats on Gen7.5.

Fixes most of :

  dEQP-VK.pipeline.sampler.view_type.*.format.*int.address_modes.all_mode_clamp_to_border_*

Remaining 11 failures :
  HSW:
       dEQP-VK.pipeline.sampler.view_type.*.format.b4g4r4a4_unorm_pack16.address_modes.all_mode_clamp_to_border_opaque_black
       dEQP-VK.pipeline.sampler.view_type.2d.format.r32_uint.address_modes.all_mode_clamp_to_border_*
       dEQP-VK.pipeline.sampler.view_type.2d.format.r32g32b32_uint.address_modes.all_mode_clamp_to_border_*

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
---
 src/intel/vulkan/Makefile.sources               |   1 +
 src/intel/vulkan/anv_nir.h                      |   3 +
 src/intel/vulkan/anv_nir_gen7_border_color_wa.c | 208 ++++++++++++++++++++++++
 src/intel/vulkan/anv_pipeline.c                 |   3 +
 4 files changed, 215 insertions(+)
 create mode 100644 src/intel/vulkan/anv_nir_gen7_border_color_wa.c

diff --git a/src/intel/vulkan/Makefile.sources b/src/intel/vulkan/Makefile.sources
index d81bc03..6361356 100644
--- a/src/intel/vulkan/Makefile.sources
+++ b/src/intel/vulkan/Makefile.sources
@@ -34,6 +34,7 @@ VULKAN_FILES := \
 	anv_nir.h \
 	anv_nir_apply_dynamic_offsets.c \
 	anv_nir_apply_pipeline_layout.c \
+	anv_nir_gen7_border_color_wa.c \
 	anv_nir_lower_push_constants.c \
 	anv_pass.c \
 	anv_pipeline.c \
diff --git a/src/intel/vulkan/anv_nir.h b/src/intel/vulkan/anv_nir.h
index 4fff7f4..649b5ed 100644
--- a/src/intel/vulkan/anv_nir.h
+++ b/src/intel/vulkan/anv_nir.h
@@ -40,6 +40,9 @@ void anv_nir_apply_pipeline_layout(struct anv_pipeline *pipeline,
                                    nir_shader *shader,
                                    struct brw_stage_prog_data *prog_data,
                                    struct anv_pipeline_bind_map *map);
+void anv_nir_apply_gen7_border_color(struct anv_pipeline *pipeline,
+                                     nir_shader *shader,
+                                     struct brw_stage_prog_data *prog_data);
 
 #ifdef __cplusplus
 }
diff --git a/src/intel/vulkan/anv_nir_gen7_border_color_wa.c b/src/intel/vulkan/anv_nir_gen7_border_color_wa.c
new file mode 100644
index 0000000..d65f70f
--- /dev/null
+++ b/src/intel/vulkan/anv_nir_gen7_border_color_wa.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * Implements a pass replaces integer sampler accesses with some logic to work
+ * around broken border colors with integer formats on Ivybridge and Haswell.
+ */
+
+#include "anv_nir.h"
+#include "nir/nir_builder.h"
+#include "nir/nir_opcodes.h"
+
+static void
+wrap_tex_instr(nir_builder *b,
+               nir_tex_instr *tex_instr,
+               nir_variable *sampler,
+               const struct anv_descriptor_set_layout *set_layout)
+{
+   nir_ssa_def *zeroi = nir_imm_int(b, 0);
+   nir_intrinsic_instr *vk_instr =
+      nir_intrinsic_instr_create(b->shader,
+                                 nir_intrinsic_vulkan_resource_index);
+   vk_instr->num_components = 1;
+   vk_instr->src[0] = nir_src_for_ssa(zeroi); /* array index */
+   nir_intrinsic_set_desc_set(vk_instr, 0);
+   nir_intrinsic_set_binding(vk_instr, set_layout->border_color_index);
+   nir_ssa_dest_init(&vk_instr->instr, &vk_instr->dest, 1, 32, NULL);
+   nir_builder_instr_insert(b, &vk_instr->instr);
+
+   nir_intrinsic_instr *load_wrapping_instr =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_ubo);
+   load_wrapping_instr->num_components = 1;
+   load_wrapping_instr->src[0] = nir_src_for_ssa(&vk_instr->dest.ssa);
+   load_wrapping_instr->src[1] = /* ubo offset */
+      nir_src_for_ssa(nir_imm_int(b, offsetof(struct gen7_border_color,
+                                              wrapping)));
+   nir_ssa_dest_init(&load_wrapping_instr->instr, &load_wrapping_instr->dest,
+                     load_wrapping_instr->num_components, 32, NULL);
+   nir_builder_instr_insert(b, &load_wrapping_instr->instr);
+
+
+
+   nir_ssa_def *tex_coords =
+      tex_instr->src[nir_tex_instr_src_index(tex_instr,
+                                             nir_tex_src_coord)].src.ssa,
+      *cond = NULL,
+      *zerof = nir_imm_float(b, 0.0f),
+      *onef = nir_imm_float(b, 1.0f);
+   uint32_t coord_components = tex_instr->coord_components;
+   if (glsl_sampler_type_is_array(sampler->type))
+      coord_components -= 1;
+   for (unsigned i = 0; i < coord_components; ++i) {
+      nir_ssa_def *component = nir_channel(b, tex_coords, i),
+         *lt_def = nir_flt(b, component, zerof),
+         *gt_def = nir_flt(b, onef, component),
+         *bounds_cond = nir_ior(b, lt_def, gt_def),
+         *border_cond =
+            nir_inot(b, nir_ieq(b, nir_iand(b, &load_wrapping_instr->dest.ssa,
+                                            nir_imm_int(b, 1 << i)),
+                                zeroi)),
+         *inner_cond = nir_iand(b, border_cond, bounds_cond);
+
+      if (cond == NULL)
+         cond = inner_cond;
+      else
+         cond = nir_ior(b, cond, inner_cond);
+   }
+   nir_if *if_stmt = nir_if_create(b->shader);
+   if_stmt->condition = nir_src_for_ssa(nir_inot(b, cond));
+   nir_builder_cf_insert(b, &if_stmt->cf_node);
+
+   /* Fill out the new then-block */
+   nir_instr_remove(&tex_instr->instr);
+   nir_instr_insert_after_cf_list(&if_stmt->then_list, &tex_instr->instr);
+
+   /* Fill out the new else-block */
+   b->cursor = nir_after_cf_list(&if_stmt->else_list);
+   const struct anv_descriptor_set_binding_layout *binding_layout =
+      &set_layout->binding[tex_instr->sampler->var->data.binding];
+   uint32_t binding_offset = sizeof(struct gen7_border_color) *
+      binding_layout->border_color_array_index;
+
+   /* Load border color. */
+   nir_intrinsic_instr *load_color_instr =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_ubo);
+   load_color_instr->num_components = 4;
+   load_color_instr->src[0] = nir_src_for_ssa(&vk_instr->dest.ssa);
+   load_color_instr->src[1] = /* ubo offset */
+      nir_src_for_ssa(nir_imm_int(b, binding_offset));
+   nir_ssa_dest_init(&load_color_instr->instr, &load_color_instr->dest,
+                     load_color_instr->num_components, 32, NULL);
+   nir_builder_instr_insert(b, &load_color_instr->instr);
+
+   /* Load border color mask. */
+   nir_intrinsic_instr *load_mask_instr =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_ubo);
+   load_mask_instr->num_components = 4;
+   load_mask_instr->src[0] = nir_src_for_ssa(&vk_instr->dest.ssa);
+   load_mask_instr->src[1] = /* ubo offset */
+      nir_src_for_ssa(nir_imm_int(b, binding_offset +
+                                  offsetof(struct gen7_border_color,
+                                           color_mask)));
+   nir_ssa_dest_init(&load_mask_instr->instr, &load_mask_instr->dest,
+                     load_mask_instr->num_components, 32, NULL);
+   nir_builder_instr_insert(b, &load_mask_instr->instr);
+
+   /* Load the alpha overwrite. */
+   nir_intrinsic_instr *load_alpha_instr =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_ubo);
+   load_alpha_instr->num_components = 1;
+   load_alpha_instr->src[0] = nir_src_for_ssa(&vk_instr->dest.ssa);
+   load_alpha_instr->src[1] = /* ubo offset */
+      nir_src_for_ssa(nir_imm_int(b, binding_offset +
+                                  offsetof(struct gen7_border_color,
+                                           alpha_overwrite)));
+   nir_ssa_dest_init(&load_alpha_instr->instr, &load_alpha_instr->dest,
+                     load_alpha_instr->num_components, 32, NULL);
+   nir_builder_instr_insert(b, &load_alpha_instr->instr);
+
+   nir_ssa_def *masked_color =
+      nir_iand(b, &load_color_instr->dest.ssa, &load_mask_instr->dest.ssa);
+   nir_ssa_def *color_components[4] = {
+      nir_channel(b, masked_color, 0),
+      nir_channel(b, masked_color, 1),
+      nir_channel(b, masked_color, 2),
+      nir_ior(b, nir_channel(b, masked_color, 3), &load_alpha_instr->dest.ssa)
+   };
+   nir_ssa_def *color = nir_vec(b, color_components, 4);
+
+   /* We need a phi node to gather either values. */
+   nir_phi_instr *phi = nir_phi_instr_create(b->shader);
+   nir_ssa_dest_init(&phi->instr, &phi->dest,
+                     tex_instr->dest.ssa.num_components,
+                     tex_instr->dest.ssa.bit_size, NULL);
+
+   nir_phi_src *src1 = ralloc(phi, nir_phi_src);
+   struct exec_node *tnode = exec_list_get_tail(&if_stmt->then_list);
+   src1->pred = exec_node_data(nir_block, tnode, cf_node.node);
+   src1->src = nir_src_for_ssa(&tex_instr->dest.ssa);
+   exec_list_push_tail(&phi->srcs, &src1->node);
+
+   nir_phi_src *src2 = ralloc(phi, nir_phi_src);
+   struct exec_node *enode = exec_list_get_tail(&if_stmt->else_list);
+   src2->pred = exec_node_data(nir_block, enode, cf_node.node);
+   src2->src = nir_src_for_ssa(color);
+   exec_list_push_tail(&phi->srcs, &src2->node);
+
+   nir_ssa_def_rewrite_uses(&tex_instr->dest.ssa,
+                            nir_src_for_ssa(&phi->dest.ssa));
+   nir_instr_insert_after_cf(&if_stmt->cf_node, &phi->instr);
+}
+
+void
+anv_nir_apply_gen7_border_color(struct anv_pipeline *pipeline,
+                                nir_shader *shader,
+                                struct brw_stage_prog_data *prog_data)
+{
+   const struct anv_pipeline_layout *layout = pipeline->layout;
+   const struct anv_descriptor_set_layout *set_layout = layout->set[0].layout;
+
+   nir_foreach_function(function, shader) {
+      if (!function->impl)
+         continue;
+
+      nir_builder builder;
+      nir_builder_init(&builder, function->impl);
+
+      nir_foreach_block(block, function->impl) {
+         nir_foreach_instr_safe(instr, block) {
+            if (instr->type != nir_instr_type_tex)
+               continue;
+
+            nir_tex_instr *tex_instr = nir_instr_as_tex(instr);
+            if (!tex_instr->sampler ||
+                nir_tex_instr_src_index(tex_instr, nir_tex_src_coord) == -1)
+               continue;
+
+            nir_variable *sampler = tex_instr->sampler->var;
+            if (glsl_get_sampler_result_type(sampler->type) == GLSL_TYPE_FLOAT) {
+               continue;
+            }
+
+            builder.cursor = nir_before_instr(instr);
+            wrap_tex_instr(&builder, tex_instr, sampler, set_layout);
+         }
+      }
+   }
+}
diff --git a/src/intel/vulkan/anv_pipeline.c b/src/intel/vulkan/anv_pipeline.c
index 2fdc9cc..0d5f801 100644
--- a/src/intel/vulkan/anv_pipeline.c
+++ b/src/intel/vulkan/anv_pipeline.c
@@ -316,6 +316,9 @@ anv_pipeline_compile(struct anv_pipeline *pipeline,
    if (nir == NULL)
       return NULL;
 
+   if (pipeline->device->info.is_haswell)
+      anv_nir_apply_gen7_border_color(pipeline, nir, prog_data);
+
    anv_nir_lower_push_constants(nir);
 
    /* Figure out the number of parameters */
-- 
2.10.2



More information about the mesa-dev mailing list