gallivm: checkpoint: texture LOD computation code gen
authorBrian Paul <brianp@vmware.com>
Fri, 5 Mar 2010 23:07:54 +0000 (16:07 -0700)
committerBrian Paul <brianp@vmware.com>
Fri, 5 Mar 2010 23:32:09 +0000 (16:32 -0700)
src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c

index 2b04bec..6b643fa 100644 (file)
@@ -1040,6 +1040,127 @@ lp_build_sample_compare(struct lp_build_sample_context *bld,
 }
 
 
+static int
+texture_dims(enum pipe_texture_target tex)
+{
+   switch (tex) {
+   case PIPE_TEXTURE_1D:
+      return 1;
+   case PIPE_TEXTURE_2D:
+   case PIPE_TEXTURE_CUBE:
+      return 2;
+   case PIPE_TEXTURE_3D:
+      return 3;
+   default:
+      assert(0 && "bad texture target in texture_dims()");
+      return 2;
+   }
+}
+
+
+/**
+ * Generate code to compute texture level of detail (lambda).
+ * \param s  vector of texcoord s values
+ * \param t  vector of texcoord t values
+ * \param r  vector of texcoord r values
+ * \param width  scalar int texture width
+ * \param height  scalar int texture height
+ * \param depth  scalar int texture depth
+ */
+static LLVMValueRef
+lp_build_lod_selector(struct lp_build_sample_context *bld,
+                      LLVMValueRef s,
+                      LLVMValueRef t,
+                      LLVMValueRef r,
+                      LLVMValueRef width,
+                      LLVMValueRef height,
+                      LLVMValueRef depth)
+
+{
+   const int dims = texture_dims(bld->static_state->target);
+   struct lp_build_context *coord_bld = &bld->coord_bld;
+
+   LLVMValueRef lod_bias = lp_build_const_scalar(bld->coord_bld.type,
+                                                 bld->static_state->lod_bias);
+   LLVMValueRef min_lod = lp_build_const_scalar(bld->coord_bld.type,
+                                                bld->static_state->min_lod);
+   LLVMValueRef max_lod = lp_build_const_scalar(bld->coord_bld.type,
+                                                bld->static_state->max_lod);
+
+   LLVMValueRef index0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
+   LLVMValueRef index1 = LLVMConstInt(LLVMInt32Type(), 1, 0);
+   LLVMValueRef index2 = LLVMConstInt(LLVMInt32Type(), 2, 0);
+
+   LLVMValueRef s0, s1, s2;
+   LLVMValueRef t0, t1, t2;
+   LLVMValueRef r0, r1, r2;
+   LLVMValueRef dsdx, dsdy, dtdx, dtdy, drdx, drdy;
+   LLVMValueRef rho, lod;
+
+   /*
+    * dsdx = abs(s[1] - s[0]);
+    * dsdy = abs(s[2] - s[0]);
+    * dtdx = abs(t[1] - t[0]);
+    * dtdy = abs(t[2] - t[0]);
+    * drdx = abs(r[1] - r[0]);
+    * drdy = abs(r[2] - r[0]);
+    * XXX we're assuming a four-element quad in 2x2 layout here.
+    */
+   s0 = LLVMBuildExtractElement(bld->builder, s, index0, "s0");
+   s1 = LLVMBuildExtractElement(bld->builder, s, index1, "s1");
+   s2 = LLVMBuildExtractElement(bld->builder, s, index2, "s2");
+   dsdx = lp_build_abs(coord_bld, lp_build_sub(coord_bld, s1, s0));
+   dsdy = lp_build_abs(coord_bld, lp_build_sub(coord_bld, s2, s0));
+   if (dims > 1) {
+      t0 = LLVMBuildExtractElement(bld->builder, t, index0, "t0");
+      t1 = LLVMBuildExtractElement(bld->builder, t, index1, "t1");
+      t2 = LLVMBuildExtractElement(bld->builder, t, index2, "t2");
+      dtdx = lp_build_abs(coord_bld, lp_build_sub(coord_bld, t1, t0));
+      dtdy = lp_build_abs(coord_bld, lp_build_sub(coord_bld, t2, t0));
+      if (dims > 2) {
+         r0 = LLVMBuildExtractElement(bld->builder, r, index0, "r0");
+         r1 = LLVMBuildExtractElement(bld->builder, r, index1, "r1");
+         r2 = LLVMBuildExtractElement(bld->builder, r, index2, "r2");
+         drdx = lp_build_abs(coord_bld, lp_build_sub(coord_bld, r1, r0));
+         drdy = lp_build_abs(coord_bld, lp_build_sub(coord_bld, r2, r0));
+      }
+   }
+
+   /* Compute rho = max of all partial derivatives scaled by texture size.
+    * XXX this can be vectorized somewhat
+    */
+   rho = lp_build_mul(coord_bld,
+                       lp_build_max(coord_bld, dsdx, dsdy),
+                       lp_build_int_to_float(coord_bld, width));
+   if (dims > 1) {
+      LLVMValueRef max;
+      max = lp_build_mul(coord_bld,
+                         lp_build_max(coord_bld, dtdx, dtdy),
+                         lp_build_int_to_float(coord_bld, height));
+      rho = lp_build_max(coord_bld, rho, max);
+      if (dims > 2) {
+         max = lp_build_mul(coord_bld,
+                            lp_build_max(coord_bld, drdx, drdy),
+                            lp_build_int_to_float(coord_bld, depth));
+         rho = lp_build_max(coord_bld, rho, max);
+      }
+   }
+
+   /* compute lod = log2(rho) */
+   lod = lp_build_log2(coord_bld, rho);
+
+   /* add lod bias */
+   lod = lp_build_add(coord_bld, lod, lod_bias);
+
+   /* clamp lod */
+   lod = lp_build_clamp(coord_bld, lod, min_lod, max_lod);
+
+   return lod;
+}
+
+
+
+
 /**
  * Build texture sampling code.
  * 'texel' will return a vector of four LLVMValueRefs corresponding to
@@ -1063,7 +1184,9 @@ lp_build_sample_soa(LLVMBuilderRef builder,
    LLVMValueRef data_ptr;
    LLVMValueRef s;
    LLVMValueRef t;
-   LLVMValueRef p;
+   LLVMValueRef r;
+
+   (void) lp_build_lod_selector;   /* temporary to silence warning */
 
    /* Setup our build context */
    memset(&bld, 0, sizeof bld);
@@ -1088,7 +1211,7 @@ lp_build_sample_soa(LLVMBuilderRef builder,
 
    s = coords[0];
    t = coords[1];
-   p = coords[2];
+   r = coords[2];
 
    width = lp_build_broadcast_scalar(&bld.uint_coord_bld, width);
    height = lp_build_broadcast_scalar(&bld.uint_coord_bld, height);
@@ -1119,5 +1242,5 @@ lp_build_sample_soa(LLVMBuilderRef builder,
    /* FIXME: respect static_state->min_mip_filter */;
    /* FIXME: respect static_state->mag_img_filter */;
 
-   lp_build_sample_compare(&bld, p, texel);
+   lp_build_sample_compare(&bld, r, texel);
 }