vl: ...
[mesa.git] / src / gallium / drivers / llvmpipe / lp_bld_interp.c
index 818c0e943e3dacbf4722111f3ccd40662b4ca4b9..838691e14b0fe6105b56186be2c3f2a8193b633d 100644 (file)
 #include "util/u_memory.h"
 #include "util/u_math.h"
 #include "tgsi/tgsi_parse.h"
-#include "lp_bld_debug.h"
-#include "lp_bld_const.h"
-#include "lp_bld_arit.h"
-#include "lp_bld_swizzle.h"
+#include "gallivm/lp_bld_debug.h"
+#include "gallivm/lp_bld_const.h"
+#include "gallivm/lp_bld_arit.h"
+#include "gallivm/lp_bld_swizzle.h"
 #include "lp_bld_interp.h"
 
 
+/*
+ * The shader JIT function operates on blocks of quads.
+ * Each block has 2x2 quads and each quad has 2x2 pixels.
+ *
+ * We iterate over the quads in order 0, 1, 2, 3:
+ *
+ * #################
+ * #   |   #   |   #
+ * #---0---#---1---#
+ * #   |   #   |   #
+ * #################
+ * #   |   #   |   #
+ * #---2---#---3---#
+ * #   |   #   |   #
+ * #################
+ *
+ * Within each quad, we have four pixels which are represented in SOA
+ * order:
+ *
+ * #########
+ * # 0 | 1 #
+ * #---+---#
+ * # 2 | 3 #
+ * #########
+ *
+ * So the green channel (for example) of the four pixels is stored in
+ * a single vector register: {g0, g1, g2, g3}.
+ */
+
+
 static void
 attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix)
 {
@@ -55,6 +85,10 @@ attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix
 }
 
 
+/**
+ * Initialize the bld->a0, dadx, dady fields.  This involves fetching
+ * those values from the arrays which are passed into the JIT function.
+ */
 static void
 coeffs_init(struct lp_build_interp_soa_context *bld,
             LLVMValueRef a0_ptr,
@@ -66,8 +100,8 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
    unsigned chan;
 
    for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
-      unsigned mask = bld->mask[attrib];
-      unsigned mode = bld->mode[attrib];
+      const unsigned mask = bld->mask[attrib];
+      const unsigned interp = bld->interp[attrib];
       for(chan = 0; chan < NUM_CHANNELS; ++chan) {
          if(mask & (1 << chan)) {
             LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), attrib*NUM_CHANNELS + chan, 0);
@@ -75,7 +109,7 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
             LLVMValueRef dadx = NULL;
             LLVMValueRef dady = NULL;
 
-            switch( mode ) {
+            switch( interp ) {
             case TGSI_INTERPOLATE_PERSPECTIVE:
                /* fall-through */
 
@@ -91,7 +125,7 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
             case TGSI_INTERPOLATE_CONSTANT:
                a0 = LLVMBuildLoad(builder, LLVMBuildGEP(builder, a0_ptr, &index, 1, ""), "");
                a0 = lp_build_broadcast_scalar(&bld->base, a0);
-               attrib_name(a0, attrib, chan, ".dady");
+               attrib_name(a0, attrib, chan, ".a0");
                break;
 
             default:
@@ -109,29 +143,12 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
 
 
 /**
- * Multiply the dadx and dady with the xstep and ystep respectively.
+ * Emit LLVM code to compute the fragment shader input attribute values.
+ * For example, for a color input, we'll compute red, green, blue and alpha
+ * values for the four pixels in a quad.
+ * Recall that we're operating on 4-element vectors so each arithmetic
+ * operation is operating on the four pixels in a quad.
  */
-static void
-coeffs_update(struct lp_build_interp_soa_context *bld)
-{
-   unsigned attrib;
-   unsigned chan;
-
-   for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
-      unsigned mask = bld->mask[attrib];
-      unsigned mode = bld->mode[attrib];
-      if (mode != TGSI_INTERPOLATE_CONSTANT) {
-         for(chan = 0; chan < NUM_CHANNELS; ++chan) {
-            if(mask & (1 << chan)) {
-               bld->dadx[attrib][chan] = lp_build_mul_imm(&bld->base, bld->dadx[attrib][chan], bld->xstep);
-               bld->dady[attrib][chan] = lp_build_mul_imm(&bld->base, bld->dady[attrib][chan], bld->ystep);
-            }
-         }
-      }
-   }
-}
-
-
 static void
 attribs_init(struct lp_build_interp_soa_context *bld)
 {
@@ -142,8 +159,8 @@ attribs_init(struct lp_build_interp_soa_context *bld)
    unsigned chan;
 
    for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
-      unsigned mask = bld->mask[attrib];
-      unsigned mode = bld->mode[attrib];
+      const unsigned mask = bld->mask[attrib];
+      const unsigned interp = bld->interp[attrib];
       for(chan = 0; chan < NUM_CHANNELS; ++chan) {
          if(mask & (1 << chan)) {
             LLVMValueRef a0   = bld->a0  [attrib][chan];
@@ -153,15 +170,19 @@ attribs_init(struct lp_build_interp_soa_context *bld)
 
             res = a0;
 
-            if (mode != TGSI_INTERPOLATE_CONSTANT) {
+            if (interp != TGSI_INTERPOLATE_CONSTANT) {
+               /* res = res + x * dadx */
                res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, x, dadx));
+               /* res = res + y * dady */
                res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, y, dady));
             }
 
-            /* Keep the value of the attribue before perspective divide for faster updates */
+            /* Keep the value of the attribute before perspective divide
+             * for faster updates.
+             */
             bld->attribs_pre[attrib][chan] = res;
 
-            if (mode == TGSI_INTERPOLATE_PERSPECTIVE) {
+            if (interp == TGSI_INTERPOLATE_PERSPECTIVE) {
                LLVMValueRef w = bld->pos[3];
                assert(attrib != 0);
                if(!oow)
@@ -178,18 +199,24 @@ attribs_init(struct lp_build_interp_soa_context *bld)
 }
 
 
+/**
+ * Increment the shader input attribute values.
+ * This is called when we move from one quad to the next.
+ */
 static void
-attribs_update(struct lp_build_interp_soa_context *bld)
+attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
 {
    LLVMValueRef oow = NULL;
    unsigned attrib;
    unsigned chan;
 
+   assert(quad_index < 4);
+
    for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
-      unsigned mask = bld->mask[attrib];
-      unsigned mode = bld->mode[attrib];
+      const unsigned mask = bld->mask[attrib];
+      const unsigned interp = bld->interp[attrib];
 
-      if (mode != TGSI_INTERPOLATE_CONSTANT) {
+      if (interp != TGSI_INTERPOLATE_CONSTANT) {
          for(chan = 0; chan < NUM_CHANNELS; ++chan) {
             if(mask & (1 << chan)) {
                LLVMValueRef dadx = bld->dadx[attrib][chan];
@@ -198,15 +225,21 @@ attribs_update(struct lp_build_interp_soa_context *bld)
 
                res = bld->attribs_pre[attrib][chan];
 
-               if(bld->xstep)
+               if (quad_index == 1 || quad_index == 3) {
+                  /* top-right or bottom-right quad */
+                  /* build res = res + dadx + dadx */
                   res = lp_build_add(&bld->base, res, dadx);
+                  res = lp_build_add(&bld->base, res, dadx);
+               }
 
-               if(bld->ystep)
+               if (quad_index == 2 || quad_index == 3) {
+                  /* bottom-left or bottom-right quad */
+                  /* build res = res + dady + dady */
                   res = lp_build_add(&bld->base, res, dady);
+                  res = lp_build_add(&bld->base, res, dady);
+               }
 
-               bld->attribs_pre[attrib][chan] = res;
-
-               if (mode == TGSI_INTERPOLATE_PERSPECTIVE) {
+               if (interp == TGSI_INTERPOLATE_PERSPECTIVE) {
                   LLVMValueRef w = bld->pos[3];
                   assert(attrib != 0);
                   if(!oow)
@@ -242,17 +275,32 @@ pos_init(struct lp_build_interp_soa_context *bld,
 }
 
 
+/**
+ * Update quad position values when moving to the next quad.
+ */
 static void
-pos_update(struct lp_build_interp_soa_context *bld)
+pos_update(struct lp_build_interp_soa_context *bld, int quad_index)
 {
    LLVMValueRef x = bld->attribs[0][0];
    LLVMValueRef y = bld->attribs[0][1];
+   const int xstep = 2, ystep = 2;
 
-   if(bld->xstep)
-      x = lp_build_add(&bld->base, x, lp_build_const_scalar(bld->base.type, bld->xstep));
+   if (quad_index == 1 || quad_index == 3) {
+      /* top-right or bottom-right quad in block */
+      /* build x += xstep */
+      x = lp_build_add(&bld->base, x,
+                       lp_build_const_vec(bld->base.type, xstep));
+   }
 
-   if(bld->ystep)
-      y = lp_build_add(&bld->base, y, lp_build_const_scalar(bld->base.type, bld->ystep));
+   if (quad_index == 2) {
+      /* bottom-left quad in block */
+      /* build y += ystep */
+      y = lp_build_add(&bld->base, y,
+                       lp_build_const_vec(bld->base.type, ystep));
+      /* build x -= xstep */
+      x = lp_build_sub(&bld->base, x,
+                       lp_build_const_vec(bld->base.type, xstep));
+   }
 
    lp_build_name(x, "pos.x");
    lp_build_name(y, "pos.y");
@@ -262,18 +310,20 @@ pos_update(struct lp_build_interp_soa_context *bld)
 }
 
 
+/**
+ * Initialize fragment shader input attribute info.
+ */
 void
 lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
                          const struct tgsi_token *tokens,
+                         boolean flatshade,
                          LLVMBuilderRef builder,
                          struct lp_type type,
                          LLVMValueRef a0_ptr,
                          LLVMValueRef dadx_ptr,
                          LLVMValueRef dady_ptr,
                          LLVMValueRef x0,
-                         LLVMValueRef y0,
-                         int xstep,
-                         int ystep)
+                         LLVMValueRef y0)
 {
    struct tgsi_parse_context parse;
    struct tgsi_full_declaration *decl;
@@ -289,7 +339,7 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
    /* Position */
    bld->num_attribs = 1;
    bld->mask[0] = TGSI_WRITEMASK_ZW;
-   bld->mode[0] = TGSI_INTERPOLATE_LINEAR;
+   bld->interp[0] = TGSI_INTERPOLATE_LINEAR;
 
    /* Inputs */
    tgsi_parse_init( &parse, tokens );
@@ -303,13 +353,21 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
             unsigned first, last, mask;
             unsigned attrib;
 
-            first = decl->DeclarationRange.First;
-            last = decl->DeclarationRange.Last;
+            first = decl->Range.First;
+            last = decl->Range.Last;
             mask = decl->Declaration.UsageMask;
 
             for( attrib = first; attrib <= last; ++attrib ) {
                bld->mask[1 + attrib] = mask;
-               bld->mode[1 + attrib] = decl->Declaration.Interpolate;
+
+               /* XXX: have mesa set INTERP_CONSTANT in the fragment
+                * shader.
+                */
+               if (decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&
+                   flatshade)
+                  bld->interp[1 + attrib] = TGSI_INTERPOLATE_CONSTANT;
+               else
+                  bld->interp[1 + attrib] = decl->Declaration.Interpolate;
             }
 
             bld->num_attribs = MAX2(bld->num_attribs, 1 + last + 1);
@@ -318,6 +376,7 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
 
       case TGSI_TOKEN_TYPE_INSTRUCTION:
       case TGSI_TOKEN_TYPE_IMMEDIATE:
+      case TGSI_TOKEN_TYPE_PROPERTY:
          break;
 
       default:
@@ -331,21 +390,19 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
    pos_init(bld, x0, y0);
 
    attribs_init(bld);
-
-   bld->xstep = xstep;
-   bld->ystep = ystep;
-
-   coeffs_update(bld);
 }
 
 
 /**
- * Advance the position and inputs with the xstep and ystep.
+ * Advance the position and inputs to the given quad within the block.
  */
 void
-lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld)
+lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
+                           int quad_index)
 {
-   pos_update(bld);
+   assert(quad_index < 4);
+
+   pos_update(bld, quad_index);
 
-   attribs_update(bld);
+   attribs_update(bld, quad_index);
 }