i965/fs: Refactor the texture emission logic into a single function.
authorKenneth Graunke <kenneth@whitecape.org>
Fri, 10 Oct 2014 09:41:20 +0000 (11:41 +0200)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 16 Oct 2014 00:05:22 +0000 (17:05 -0700)
Before, we had 3 different emit functions for various different gen's,
as well as some ancilliary work that was the same across all gen's which
was either contained in functions or duplicated across the GLSL IR and
Mesa IR backends. Now, we have a single method, emit_texture(), that
takes all the information needed to make a texture instruction and
handles all the setup, and all we have to do to emit a texture
instruction while converting from GLSL IR, Mesa IR, or any new backend
is to extract the information emit_texture() needs and then call it.

v2: Significant rebasing (by Ken).

Signed-off-by: Connor Abbott <connor.abbott@intel.com>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Chris Forbes <chrisf@ijw.co.nz>
src/mesa/drivers/dri/i965/brw_fs.h
src/mesa/drivers/dri/i965/brw_fs_fp.cpp
src/mesa/drivers/dri/i965/brw_fs_visitor.cpp

index dc4e0c8c93306a4e7239ad4efe4153d21661f5d4..c62c1eb866f6bcb862b8abeb54277c3b4c14894e 100644 (file)
@@ -488,6 +488,20 @@ public:
                               fs_reg lod, fs_reg lod2, int grad_components,
                               fs_reg sample_index, fs_reg mcs, fs_reg sampler,
                               fs_reg offset_value);
+   void emit_texture(ir_texture_opcode op,
+                     const glsl_type *dest_type,
+                     fs_reg coordinate, const struct glsl_type *coord_type,
+                     fs_reg shadow_c,
+                     fs_reg lod, fs_reg dpdy, int grad_components,
+                     fs_reg sample_index,
+                     fs_reg offset, unsigned offset_components,
+                     fs_reg mcs,
+                     int gather_component,
+                     bool is_cube_array,
+                     bool is_rect,
+                     uint32_t sampler,
+                     fs_reg sampler_reg,
+                     int texunit);
    fs_reg emit_mcs_fetch(fs_reg coordinate, int components, fs_reg sampler);
    void emit_gen6_gather_wa(uint8_t wa, fs_reg dst);
    fs_reg fix_math_operand(fs_reg src);
index 825d793dc4a29e4034df728a44a07375a5c8c70b..1ba24a9170e3aab55093db5a4b42d967a2d49b1a 100644 (file)
@@ -476,28 +476,18 @@ fs_visitor::emit_fragment_program_code()
             unreachable("not reached");
          }
 
-         int coord_components = coordinate_type->vector_elements;
-
          if (fpi->TexShadow)
             shadow_c = offset(coordinate, 2);
 
-         coordinate = rescale_texcoord(coordinate, coordinate_type,
-                                       fpi->TexSrcTarget == TEXTURE_RECT_INDEX,
-                                       fpi->TexSrcUnit, fpi->TexSrcUnit);
-
-         fs_inst *inst;
-         if (brw->gen >= 7) {
-            inst = emit_texture_gen7(ir->op, dst, coordinate, coord_components, shadow_c, lod, dpdy, 0, sample_index, fs_reg(0u), fs_reg(fpi->TexSrcUnit), texel_offset);
-         } else if (brw->gen >= 5) {
-            inst = emit_texture_gen5(ir->op, dst, coordinate, coord_components, shadow_c, lod, dpdy, 0, sample_index, fpi->TexSrcUnit, false);
-         } else {
-            inst = emit_texture_gen4(ir->op, dst, coordinate, coord_components, shadow_c, lod, dpdy, 0, fpi->TexSrcUnit);
-         }
-
-         inst->shadow_compare = fpi->TexShadow;
-
-         /* Reuse the GLSL swizzle_result() handler. */
-         swizzle_result(ir->op, 4, dst, fpi->TexSrcUnit);
+         emit_texture(ir->op, glsl_type::vec4_type, coordinate, coordinate_type,
+                      shadow_c, lod, dpdy, 0, sample_index,
+                      reg_undef, 0, /* offset, components */
+                      reg_undef, /* mcs */
+                      0, /* gather component */
+                      false, /* is cube array */
+                      fpi->TexSrcTarget == TEXTURE_RECT_INDEX,
+                      fpi->TexSrcUnit, fs_reg(fpi->TexSrcUnit),
+                      fpi->TexSrcUnit);
          dst = this->result;
 
          break;
index 9008e167df10264dd17119ce88d411ef4fe38b3e..8a11b04c0fa08e9c2e73f21292ce0f606bb6dc58 100644 (file)
@@ -1837,7 +1837,19 @@ fs_visitor::emit_mcs_fetch(fs_reg coordinate, int components, fs_reg sampler)
 }
 
 void
-fs_visitor::visit(ir_texture *ir)
+fs_visitor::emit_texture(ir_texture_opcode op,
+                         const glsl_type *dest_type,
+                         fs_reg coordinate, const struct glsl_type *coord_type,
+                         fs_reg shadow_c,
+                         fs_reg lod, fs_reg lod2, int grad_components,
+                         fs_reg sample_index,
+                         fs_reg offset_value, unsigned offset_components,
+                         fs_reg mcs,
+                         int gather_component,
+                         bool is_cube_array,
+                         bool is_rect,
+                         uint32_t sampler,
+                         fs_reg sampler_reg, int texunit)
 {
    const struct brw_sampler_prog_key_data *tex =
       (stage == MESA_SHADER_FRAGMENT) ?
@@ -1845,6 +1857,98 @@ fs_visitor::visit(ir_texture *ir)
    assert(tex);
    fs_inst *inst = NULL;
 
+   if (op == ir_tg4) {
+      /* When tg4 is used with the degenerate ZERO/ONE swizzles, don't bother
+       * emitting anything other than setting up the constant result.
+       */
+      int swiz = GET_SWZ(tex->swizzles[sampler], gather_component);
+      if (swiz == SWIZZLE_ZERO || swiz == SWIZZLE_ONE) {
+
+         fs_reg res = fs_reg(this, glsl_type::vec4_type);
+         this->result = res;
+
+         for (int i=0; i<4; i++) {
+            emit(MOV(res, fs_reg(swiz == SWIZZLE_ZERO ? 0.0f : 1.0f)));
+            res = offset(res, 1);
+         }
+         return;
+      }
+   }
+
+   if (coordinate.file != BAD_FILE) {
+      /* FINISHME: Texture coordinate rescaling doesn't work with non-constant
+       * samplers.  This should only be a problem with GL_CLAMP on Gen7.
+       */
+      coordinate = rescale_texcoord(coordinate, coord_type, is_rect,
+                                    sampler, texunit);
+   }
+
+   /* Writemasking doesn't eliminate channels on SIMD8 texture
+    * samples, so don't worry about them.
+    */
+   fs_reg dst(this, glsl_type::get_instance(dest_type->base_type, 4, 1));
+
+   int coord_components = coord_type ? coord_type->vector_elements : 0;
+
+   if (brw->gen >= 7) {
+      inst = emit_texture_gen7(op, dst, coordinate, coord_components,
+                               shadow_c, lod, lod2, grad_components,
+                               sample_index, mcs, sampler_reg,
+                               offset_value);
+   } else if (brw->gen >= 5) {
+      inst = emit_texture_gen5(op, dst, coordinate, coord_components,
+                               shadow_c, lod, lod2, grad_components,
+                               sample_index, sampler,
+                               offset_value.file != BAD_FILE);
+   } else {
+      inst = emit_texture_gen4(op, dst, coordinate, coord_components,
+                               shadow_c, lod, lod2, grad_components,
+                               sampler);
+   }
+
+   if (shadow_c.file != BAD_FILE)
+      inst->shadow_compare = true;
+
+   if (offset_value.file == IMM)
+      inst->texture_offset = offset_value.fixed_hw_reg.dw1.ud;
+
+   if (op == ir_tg4) {
+      inst->texture_offset |=
+         gather_channel(gather_component, sampler) << 16; /* M0.2:16-17 */
+
+      if (brw->gen == 6)
+         emit_gen6_gather_wa(tex->gen6_gather_wa[sampler], dst);
+   }
+
+   /* fixup #layers for cube map arrays */
+   if (op == ir_txs && is_cube_array) {
+      fs_reg depth = offset(dst, 2);
+      fs_reg fixed_depth = fs_reg(this, glsl_type::int_type);
+      emit_math(SHADER_OPCODE_INT_QUOTIENT, fixed_depth, depth, fs_reg(6));
+
+      fs_reg *fixed_payload = ralloc_array(mem_ctx, fs_reg, inst->regs_written);
+      int components = inst->regs_written / (dst.width / 8);
+      for (int i = 0; i < components; i++) {
+         if (i == 2) {
+            fixed_payload[i] = fixed_depth;
+         } else {
+            fixed_payload[i] = offset(dst, i);
+         }
+      }
+      emit(LOAD_PAYLOAD(dst, fixed_payload, components));
+   }
+
+   swizzle_result(op, dest_type->vector_elements, dst, sampler);
+}
+
+void
+fs_visitor::visit(ir_texture *ir)
+{
+   const struct brw_sampler_prog_key_data *tex =
+      (stage == MESA_SHADER_FRAGMENT) ?
+      &((brw_wm_prog_key*) this->key)->tex : NULL;
+   assert(tex);
+
    uint32_t sampler =
       _mesa_get_sampler_uniform_value(ir->sampler, shader_prog, prog);
 
@@ -1889,25 +1993,6 @@ fs_visitor::visit(ir_texture *ir)
     */
    int texunit = prog->SamplerUnits[sampler];
 
-   if (ir->op == ir_tg4) {
-      /* When tg4 is used with the degenerate ZERO/ONE swizzles, don't bother
-       * emitting anything other than setting up the constant result.
-       */
-      ir_constant *chan = ir->lod_info.component->as_constant();
-      int swiz = GET_SWZ(tex->swizzles[sampler], chan->value.i[0]);
-      if (swiz == SWIZZLE_ZERO || swiz == SWIZZLE_ONE) {
-
-         fs_reg res = fs_reg(this, glsl_type::vec4_type);
-         this->result = res;
-
-         for (int i=0; i<4; i++) {
-            emit(MOV(res, fs_reg(swiz == SWIZZLE_ZERO ? 0.0f : 1.0f)));
-            res = offset(res, 1);
-         }
-         return;
-      }
-   }
-
    /* Should be lowered by do_lower_texture_projection */
    assert(!ir->projector);
 
@@ -1919,19 +2004,13 @@ fs_visitor::visit(ir_texture *ir)
     * generating these values may involve SEND messages that need the MRFs.
     */
    fs_reg coordinate;
+   const glsl_type *coord_type = NULL;
    if (ir->coordinate) {
+      coord_type = ir->coordinate->type;
       ir->coordinate->accept(this);
-
-      coordinate = rescale_texcoord(this->result,
-                                    ir->coordinate->type,
-                                    ir->sampler->type->sampler_dimensionality ==
-                                    GLSL_SAMPLER_DIM_RECT,
-                                    sampler, texunit);
+      coordinate = this->result;
    }
 
-   int coord_components =
-      ir->coordinate ? ir->coordinate->type->vector_elements : 0;
-
    fs_reg shadow_comparitor;
    if (ir->shadow_comparitor) {
       ir->shadow_comparitor->accept(this);
@@ -1939,6 +2018,7 @@ fs_visitor::visit(ir_texture *ir)
    }
 
    fs_reg offset_value;
+   int offset_components = 0;
    if (ir->offset) {
       ir_constant *const_offset = ir->offset->as_constant();
       if (const_offset) {
@@ -1953,6 +2033,7 @@ fs_visitor::visit(ir_texture *ir)
          ir->offset->accept(this);
          offset_value = this->result;
       }
+      offset_components = ir->offset->type->vector_elements;
    }
 
    fs_reg lod, lod2, sample_index, mcs;
@@ -1996,66 +2077,21 @@ fs_visitor::visit(ir_texture *ir)
       unreachable("Unrecognized texture opcode");
    };
 
-   /* Writemasking doesn't eliminate channels on SIMD8 texture
-    * samples, so don't worry about them.
-    */
-   fs_reg dst = fs_reg(this, glsl_type::get_instance(ir->type->base_type, 4, 1));
-
-   if (brw->gen >= 7) {
-      inst = emit_texture_gen7(ir->op, dst, coordinate, coord_components,
-                               shadow_comparitor,
-                               lod, lod2, grad_components,
-                               sample_index, mcs, sampler_reg,
-                               offset_value);
-   } else if (brw->gen >= 5) {
-      inst = emit_texture_gen5(ir->op, dst, coordinate, coord_components,
-                               shadow_comparitor,
-                               lod, lod2, grad_components,
-                               sample_index, sampler,
-                               ir->offset != NULL);
-   } else {
-      inst = emit_texture_gen4(ir->op, dst, coordinate, coord_components,
-                               shadow_comparitor,
-                               lod, lod2, grad_components,
-                               sampler);
-   }
-
-   if (offset_value.file == IMM)
-      inst->texture_offset = offset_value.fixed_hw_reg.dw1.ud;
-
+   int gather_component = 0;
    if (ir->op == ir_tg4)
-      inst->texture_offset |= gather_channel(ir->lod_info.component->as_constant()->value.i[0], sampler) << 16; // M0.2:16-17
+      gather_component = ir->lod_info.component->as_constant()->value.i[0];
 
-   if (ir->shadow_comparitor)
-      inst->shadow_compare = true;
-
-   /* fixup #layers for cube map arrays */
-   if (ir->op == ir_txs) {
-      glsl_type const *type = ir->sampler->type;
-      if (type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE &&
-          type->sampler_array) {
-         fs_reg depth = offset(dst, 2);
-         fs_reg fixed_depth = fs_reg(this, glsl_type::int_type);
-         emit_math(SHADER_OPCODE_INT_QUOTIENT, fixed_depth, depth, fs_reg(6));
-
-         fs_reg *fixed_payload = ralloc_array(mem_ctx, fs_reg, inst->regs_written);
-         int components = inst->regs_written / (dst.width / 8);
-         for (int i = 0; i < components; i++) {
-            if (i == 2) {
-               fixed_payload[i] = fixed_depth;
-            } else {
-               fixed_payload[i] = offset(dst, i);
-            }
-         }
-         emit(LOAD_PAYLOAD(dst, fixed_payload, components));
-      }
-   }
+   bool is_rect =
+      ir->sampler->type->sampler_dimensionality == GLSL_SAMPLER_DIM_RECT;
 
-   if (brw->gen == 6 && ir->op == ir_tg4) {
-      emit_gen6_gather_wa(tex->gen6_gather_wa[sampler], dst);
-   }
+   bool is_cube_array =
+      ir->sampler->type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE &&
+      ir->sampler->type->sampler_array;
 
-   swizzle_result(ir->op, ir->type->vector_elements, dst, sampler);
+   emit_texture(ir->op, ir->type, coordinate, coord_type, shadow_comparitor,
+                lod, lod2, grad_components, sample_index, offset_value,
+                offset_components, mcs, gather_component,
+                is_cube_array, is_rect, sampler, sampler_reg, texunit);
 }
 
 /**