[Mesa-dev] [PATCH] [RFC] st/mesa: handle indirect samplers in arrays/structs properly

Dave Airlie airlied at gmail.com
Thu Feb 4 07:07:29 UTC 2016


From: Dave Airlie <airlied at redhat.com>

The state tracker never handled this properly, and it finally
annoyed me for the second time so I decided to fix it properly.

This is inspired by the NIR sampler lowering code and I only realised
NIR seems to do its deref ordering different to GLSL at the last
minute, once I got that things got much easier.

it fixes a bunch of tests in
tests/spec/arb_gpu_shader5/execution/sampler_array_indexing/

It's rfc because I need to piglit it, and because I really am
not sure if all of the code is required.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 154 ++++++++++++++++++++++++++---
 1 file changed, 138 insertions(+), 16 deletions(-)

diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index b8182de..ddd0664 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -257,6 +257,7 @@ public:
    GLboolean cond_update;
    bool saturate;
    st_src_reg sampler; /**< sampler register */
+   int sampler_base;
    int sampler_array_size; /**< 1-based size of sampler array, 1 if not array */
    int tex_target; /**< One of TEXTURE_*_INDEX */
    glsl_base_type tex_type;
@@ -502,6 +503,18 @@ public:
 
    void emit_arl(ir_instruction *ir, st_dst_reg dst, st_src_reg src0);
 
+   void get_sampler_nonconst_offsets(ir_texture *ir,
+                                     unsigned *sampler_array_size,
+                                     unsigned *sampler_base,
+                                     unsigned *sampler_index,
+                                     st_src_reg *sampler_reg);
+   void calc_sampler_offsets(ir_texture *ir,
+                             ir_dereference *tail,
+                             unsigned *array_elements,
+                             unsigned *sampler_index,
+                             st_src_reg *indirect,
+                             unsigned *location);
+
    bool try_emit_mad(ir_expression *ir,
               int mul_operand);
    bool try_emit_mad_for_and_not(ir_expression *ir,
@@ -3436,18 +3449,130 @@ glsl_to_tgsi_visitor::visit(ir_call *ir)
    this->result = entry->return_reg;
 }
 
+static unsigned
+glsl_get_length(const struct glsl_type *type)
+{
+   return type->is_matrix() ? type->matrix_columns : type->length;
+}
+
+void
+glsl_to_tgsi_visitor::calc_sampler_offsets(ir_texture *ir,
+                                           ir_dereference *tail,
+                                           unsigned *array_elements,
+                                           unsigned *sampler_index,
+                                           st_src_reg *indirect,
+                                           unsigned *location)
+{
+   switch (tail->ir_type) {
+   case ir_type_dereference_record: {
+      ir_dereference_record *deref_record = tail->as_dereference_record();
+      const glsl_type *struct_type = deref_record->record->type;
+      int tmp = 0;
+      unsigned i;
+
+      calc_sampler_offsets(ir, deref_record->record->as_dereference(), array_elements, sampler_index, indirect, location);
+
+      for (i = 0; i < struct_type->length; i++) {
+         if (strcmp(struct_type->fields.structure[i].name, deref_record->field) == 0)
+            break;
+      }
+      if (i < struct_type->length)
+         tmp = struct_type->record_location_offset(i);
+
+      *location += tmp;
+      break;
+   }
+
+   case ir_type_dereference_array: {
+      ir_dereference_array *deref_arr = tail->as_dereference_array();
+      ir_constant *index = deref_arr->array_index->constant_expression_value();
+      bool next_is_record = (deref_arr->array->ir_type == ir_type_dereference_record);
+
+      if (deref_arr->array->ir_type == ir_type_dereference_variable && ir->sampler == tail) {
+         ir_dereference_variable *deref_var = deref_arr->array->as_dereference_variable();
+         *location += deref_var->var->data.location;
+      }
+
+      if (index && deref_arr->array->ir_type == ir_type_dereference_variable)
+         *sampler_index += index->value.u[0] * *array_elements;
+
+      if (!index || next_is_record) {
+         st_src_reg temp_reg;
+         st_dst_reg temp_dst;
+
+         temp_reg = get_temp(glsl_type::uint_type);
+         temp_dst = st_dst_reg(temp_reg);
+         temp_dst.writemask = 1;
+
+         if (!index) {
+            deref_arr->array_index->accept(this);
+            emit_asm(NULL, TGSI_OPCODE_MUL, temp_dst, this->result, st_src_reg_for_int(*array_elements));
+         } else {
+            emit_asm(NULL, TGSI_OPCODE_MOV, temp_dst, st_src_reg_for_int(index->value.u[0]));
+         }
+         if (indirect->file == PROGRAM_UNDEFINED)
+            *indirect = temp_reg;
+         else {
+            temp_dst = st_dst_reg(*indirect);
+            temp_dst.writemask = 1;
+            emit_asm(NULL, TGSI_OPCODE_ADD, temp_dst, *indirect, temp_reg);
+         }
+      }
+
+      *array_elements *= glsl_get_length(deref_arr->array->type);
+
+      calc_sampler_offsets(ir, deref_arr->array->as_dereference(), array_elements, sampler_index, indirect, location);
+      break;
+   }
+   case ir_type_dereference_variable: {
+      if (ir->sampler == tail) {
+         ir_dereference_variable *deref_var = tail->as_dereference_variable();
+         *location = deref_var->var->data.location;
+      }
+      break;
+   }
+   default:
+      break;
+   }
+}
+
+void
+glsl_to_tgsi_visitor::get_sampler_nonconst_offsets(ir_texture *ir,
+                                                   unsigned *sampler_array_size,
+                                                   unsigned *sampler_base,
+                                                   unsigned *sampler_index,
+                                                   st_src_reg *sampler_reg)
+{
+   unsigned location = 0;
+   GLuint shader = _mesa_program_enum_to_shader_stage(this->prog->Target);
+   st_src_reg indirect;
+   unsigned array_elements = 1;
+
+   memset(&indirect, 0, sizeof(indirect));
+   indirect.file = PROGRAM_UNDEFINED;
+
+   calc_sampler_offsets(ir, ir->sampler, &array_elements, sampler_index, &indirect, &location);
+
+   if (indirect.file != PROGRAM_UNDEFINED) {
+      sampler_reg->reladdr = ralloc(mem_ctx, st_src_reg);
+      *sampler_reg->reladdr = indirect;
+   }
+   *sampler_array_size = array_elements;
+   *sampler_base = this->shader_program->UniformStorage[location].opaque[shader].index;
+   *sampler_index += *sampler_base;
+}
+
 void
 glsl_to_tgsi_visitor::visit(ir_texture *ir)
 {
    st_src_reg result_src, coord, cube_sc, lod_info, projector, dx, dy;
    st_src_reg offset[MAX_GLSL_TEXTURE_OFFSET], sample_index, component;
-   st_src_reg levels_src;
+   st_src_reg levels_src, sampler_reg;
    st_dst_reg result_dst, coord_dst, cube_sc_dst;
    glsl_to_tgsi_instruction *inst = NULL;
    unsigned opcode = TGSI_OPCODE_NOP;
    const glsl_type *sampler_type = ir->sampler->type;
-   ir_rvalue *sampler_index =
-      _mesa_get_sampler_array_nonconst_index(ir->sampler);
+   unsigned sampler_array_size = 1, sampler_index = 0, sampler_base = 0;
    bool is_cube_array = false;
    unsigned i;
 
@@ -3669,10 +3794,10 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir)
       coord_dst.writemask = WRITEMASK_XYZW;
    }
 
-   if (sampler_index) {
-      sampler_index->accept(this);
-      emit_arl(ir, sampler_reladdr, this->result);
-   }
+   get_sampler_nonconst_offsets(ir, &sampler_array_size, &sampler_base,
+                                &sampler_index, &sampler_reg);
+   if (sampler_reg.reladdr)
+      emit_arl(ir, sampler_reladdr, *sampler_reg.reladdr);
 
    if (opcode == TGSI_OPCODE_TXD)
       inst = emit_asm(ir, opcode, result_dst, coord, dx, dy);
@@ -3705,16 +3830,13 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir)
    if (ir->shadow_comparitor)
       inst->tex_shadow = GL_TRUE;
 
-   inst->sampler.index = _mesa_get_sampler_uniform_value(ir->sampler,
-                                                         this->shader_program,
-                                                         this->prog);
-   if (sampler_index) {
+   inst->sampler.index = sampler_index;
+   inst->sampler_array_size = sampler_array_size;
+   inst->sampler_base = sampler_base;
+
+   if (sampler_reg.reladdr) {
       inst->sampler.reladdr = ralloc(mem_ctx, st_src_reg);
       memcpy(inst->sampler.reladdr, &sampler_reladdr, sizeof(sampler_reladdr));
-      inst->sampler_array_size =
-         ir->sampler->as_dereference_array()->array->type->array_size();
-   } else {
-      inst->sampler_array_size = 1;
    }
 
    if (ir->offset) {
@@ -3915,7 +4037,7 @@ count_resources(glsl_to_tgsi_visitor *v, gl_program *prog)
    foreach_in_list(glsl_to_tgsi_instruction, inst, &v->instructions) {
       if (inst->info->is_tex) {
          for (int i = 0; i < inst->sampler_array_size; i++) {
-            unsigned idx = inst->sampler.index + i;
+            unsigned idx = inst->sampler_base + i;
             v->samplers_used |= 1 << idx;
 
             debug_assert(idx < (int)ARRAY_SIZE(v->sampler_types));
-- 
2.5.0



More information about the mesa-dev mailing list