+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;
+}
+
+
+
+