state->min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
}
- if (state->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) {
+ if (state->min_mip_filter != PIPE_TEX_MIPFILTER_NONE ||
+ state->min_img_filter != state->mag_img_filter) {
if (sampler->lod_bias != 0.0f) {
state->lod_bias_non_zero = 1;
}
* \param derivs partial derivatives of (s, t, r, q) with respect to X and Y
* \param lod_bias optional float vector with the shader lod bias
* \param explicit_lod optional float vector with the explicit lod
- * \param width scalar int texture width
- * \param height scalar int texture height
- * \param depth scalar int texture depth
+ * \param cube_rho rho calculated by cube coord mapping (optional)
+ * \param out_lod_ipart integer part of lod
+ * \param out_lod_fpart float part of lod (never larger than 1 but may be negative)
+ * \param out_lod_positive (mask) if lod is positive (i.e. texture is minified)
*
* The resulting lod is scalar per quad, so only the first value per quad
* passed in from lod_bias, explicit_lod is used.
LLVMValueRef explicit_lod, /* optional */
unsigned mip_filter,
LLVMValueRef *out_lod_ipart,
- LLVMValueRef *out_lod_fpart)
+ LLVMValueRef *out_lod_fpart,
+ LLVMValueRef *out_lod_positive)
{
LLVMBuilderRef builder = bld->gallivm->builder;
LLVMValueRef lod;
*out_lod_ipart = bld->leveli_bld.zero;
+ *out_lod_positive = bld->leveli_bld.zero;
*out_lod_fpart = levelf_bld->zero;
+ /*
+ * For determining min/mag, we follow GL 4.1 spec, 3.9.12 Texture Magnification:
+ * "Implementations may either unconditionally assume c = 0 for the minification
+ * vs. magnification switch-over point, or may choose to make c depend on the
+ * combination of minification and magnification modes as follows: if the
+ * magnification filter is given by LINEAR and the minification filter is given
+ * by NEAREST_MIPMAP_NEAREST or NEAREST_MIPMAP_LINEAR, then c = 0.5. This is
+ * done to ensure that a minified texture does not appear "sharper" than a
+ * magnified texture. Otherwise c = 0."
+ * And 3.9.11 Texture Minification:
+ * "If lod is less than or equal to the constant c (see section 3.9.12) the
+ * texture is said to be magnified; if it is greater, the texture is minified."
+ * So, using 0 as switchover point always, and using magnification for lod == 0.
+ * Note that the always c = 0 behavior is new (first appearing in GL 3.1 spec),
+ * old GL versions required 0.5 for the modes listed above.
+ * I have no clue about the (undocumented) wishes of d3d9/d3d10 here!
+ */
+
if (bld->static_sampler_state->min_max_lod_equal) {
/* User is forcing sampling from a particular mipmap level.
* This is hit during mipmap generation.
if (mip_filter == PIPE_TEX_MIPFILTER_NONE ||
mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
/*
- * FIXME: this is not entirely correct, as out_lod_ipart is used
- * both for mip level determination as well as mag/min switchover
- * point (if different min/mag filters are used). In particular,
- * lod values between [-0.5,0] (rho between [sqrt(2), 1.0]) will
- * incorrectly use min filter instead of mag (the non-optimized
- * calculation further down has exactly the same problem).
+ * Don't actually need both all the time, ipart is needed
+ * for nearest mipfilter, pos_or_zero if min != mag.
*/
*out_lod_ipart = lp_build_ilog2(levelf_bld, rho);
- *out_lod_fpart = levelf_bld->zero;
+ *out_lod_positive = lp_build_cmp(levelf_bld, PIPE_FUNC_GREATER,
+ rho, levelf_bld->one);
return;
}
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR &&
!(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR)) {
lp_build_brilinear_rho(levelf_bld, rho, BRILINEAR_FACTOR,
out_lod_ipart, out_lod_fpart);
+ *out_lod_positive = lp_build_cmp(levelf_bld, PIPE_FUNC_GREATER,
+ rho, levelf_bld->one);
return;
}
}
}
}
+ *out_lod_positive = lp_build_cmp(levelf_bld, PIPE_FUNC_GREATER,
+ lod, levelf_bld->zero);
+
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
if (!(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR)) {
lp_build_brilinear_lod(levelf_bld, lod, BRILINEAR_FACTOR,
LLVMValueRef t,
LLVMValueRef r,
const LLVMValueRef *offsets,
- LLVMValueRef lod_ipart,
+ LLVMValueRef lod_positive,
LLVMValueRef lod_fpart,
LLVMValueRef ilevel0,
LLVMValueRef ilevel1,
LLVMValueRef texel_out[4])
{
- struct lp_build_context *int_bld = &bld->int_bld;
LLVMBuilderRef builder = bld->gallivm->builder;
const unsigned mip_filter = bld->static_sampler_state->min_mip_filter;
const unsigned min_filter = bld->static_sampler_state->min_img_filter;
* depending on the lod being > 0 or <= 0, respectively.
*/
struct lp_build_if_state if_ctx;
- LLVMValueRef minify;
/*
- * XXX this should take all lods into account, if some are min
- * some max probably could hack up the coords/weights in the linear
+ * FIXME this should take all lods into account, if some are min
+ * some max probably could hack up the weights in the linear
* path with selects to work for nearest.
- * If that's just two quads sitting next to each other it seems
- * quite ok to do the same filtering method on both though, at
- * least unless we have explicit lod (and who uses different
- * min/mag filter with that?)
*/
- if (bld->num_lods > 1)
- lod_ipart = LLVMBuildExtractElement(builder, lod_ipart,
- lp_build_const_int32(bld->gallivm, 0), "");
+ if (bld->leveli_bld.type.length > 1)
+ lod_positive = LLVMBuildExtractElement(builder, lod_positive,
+ lp_build_const_int32(bld->gallivm, 0), "");
- /* minify = lod >= 0.0 */
- minify = LLVMBuildICmp(builder, LLVMIntSGE,
- lod_ipart, int_bld->zero, "");
+ lod_positive = LLVMBuildTrunc(builder, lod_positive,
+ LLVMInt1TypeInContext(bld->gallivm->context), "");
- lp_build_if(&if_ctx, bld->gallivm, minify);
+ lp_build_if(&if_ctx, bld->gallivm, lod_positive);
{
/* Use the minification filter */
lp_build_sample_mipmap(bld,
const struct lp_derivatives *derivs, /* optional */
LLVMValueRef lod_bias, /* optional */
LLVMValueRef explicit_lod, /* optional */
- LLVMValueRef *lod_ipart,
+ LLVMValueRef *lod_pos_or_zero,
LLVMValueRef *lod_fpart,
LLVMValueRef *ilevel0,
LLVMValueRef *ilevel1)
const unsigned mag_filter = bld->static_sampler_state->mag_img_filter;
const unsigned target = bld->static_texture_state->target;
LLVMValueRef first_level, cube_rho = NULL;
+ LLVMValueRef lod_ipart = NULL;
/*
printf("%s mip %d min %d mag %d\n", __FUNCTION__,
coords[0], coords[1], coords[2], cube_rho,
derivs, lod_bias, explicit_lod,
mip_filter,
- lod_ipart, lod_fpart);
+ &lod_ipart, lod_fpart, lod_pos_or_zero);
} else {
- *lod_ipart = bld->leveli_bld.zero;
+ lod_ipart = bld->leveli_bld.zero;
+ *lod_pos_or_zero = bld->leveli_bld.zero;
}
/*
* We should be able to set ilevel0 = const(0) but that causes
* bad x86 code to be emitted.
*/
- assert(*lod_ipart);
- lp_build_nearest_mip_level(bld, texture_index, *lod_ipart, ilevel0, NULL);
+ assert(lod_ipart);
+ lp_build_nearest_mip_level(bld, texture_index, lod_ipart, ilevel0, NULL);
}
else {
first_level = bld->dynamic_state->first_level(bld->dynamic_state,
}
break;
case PIPE_TEX_MIPFILTER_NEAREST:
- assert(*lod_ipart);
- lp_build_nearest_mip_level(bld, texture_index, *lod_ipart, ilevel0, NULL);
+ assert(lod_ipart);
+ lp_build_nearest_mip_level(bld, texture_index, lod_ipart, ilevel0, NULL);
break;
case PIPE_TEX_MIPFILTER_LINEAR:
- assert(*lod_ipart);
+ assert(lod_ipart);
assert(*lod_fpart);
lp_build_linear_mip_levels(bld, texture_index,
- *lod_ipart, lod_fpart,
+ lod_ipart, lod_fpart,
ilevel0, ilevel1);
break;
}
unsigned sampler_unit,
LLVMValueRef *coords,
const LLVMValueRef *offsets,
- LLVMValueRef lod_ipart,
+ LLVMValueRef lod_positive,
LLVMValueRef lod_fpart,
LLVMValueRef ilevel0,
LLVMValueRef ilevel1,
LLVMValueRef *colors_out)
{
- struct lp_build_context *int_bld = &bld->int_bld;
LLVMBuilderRef builder = bld->gallivm->builder;
const struct lp_static_sampler_state *sampler_state = bld->static_sampler_state;
const unsigned mip_filter = sampler_state->min_mip_filter;
* depending on the lod being > 0 or <= 0, respectively.
*/
struct lp_build_if_state if_ctx;
- LLVMValueRef minify;
/*
- * XXX this should take all lods into account, if some are min
- * some max probably could hack up the coords/weights in the linear
+ * FIXME this should take all lods into account, if some are min
+ * some max probably could hack up the weights in the linear
* path with selects to work for nearest.
- * If that's just two quads sitting next to each other it seems
- * quite ok to do the same filtering method on both though, at
- * least unless we have explicit lod (and who uses different
- * min/mag filter with that?)
*/
- if (bld->num_lods > 1)
- lod_ipart = LLVMBuildExtractElement(builder, lod_ipart,
- lp_build_const_int32(bld->gallivm, 0), "");
+ if (bld->leveli_bld.type.length > 1)
+ lod_positive = LLVMBuildExtractElement(builder, lod_positive,
+ lp_build_const_int32(bld->gallivm, 0), "");
- /* minify = lod >= 0.0 */
- minify = LLVMBuildICmp(builder, LLVMIntSGE,
- lod_ipart, int_bld->zero, "");
+ lod_positive = LLVMBuildTrunc(builder, lod_positive,
+ LLVMInt1TypeInContext(bld->gallivm->context), "");
- lp_build_if(&if_ctx, bld->gallivm, minify);
+ lp_build_if(&if_ctx, bld->gallivm, lod_positive);
{
/* Use the minification filter */
lp_build_sample_mipmap(bld, sampler_unit,
/*
* There are other situations where at least the multiple int lods could be
* avoided like min and max lod being equal.
+ * XXX if num_lods == 1 (for multiple quads) the level bld contexts will still
+ * have length 4. Because lod_selector is always using per quad calcs in this
+ * case, but minification etc. don't need to bother. This is very brittle though
+ * e.g. num_lods might be 1 but still have multiple positive_lod values!
*/
if (lod_property == LP_SAMPLER_LOD_PER_ELEMENT &&
(explicit_lod || lod_bias ||
}
else {
- LLVMValueRef lod_ipart = NULL, lod_fpart = NULL;
+ LLVMValueRef lod_fpart = NULL, lod_positive = NULL;
LLVMValueRef ilevel0 = NULL, ilevel1 = NULL;
boolean use_aos = util_format_fits_8unorm(bld.format_desc) &&
/* not sure this is strictly needed or simply impossible */
lp_build_sample_common(&bld, texture_index, sampler_index,
newcoords,
derivs, lod_bias, explicit_lod,
- &lod_ipart, &lod_fpart,
+ &lod_positive, &lod_fpart,
&ilevel0, &ilevel1);
/*
if (mip_filter == PIPE_TEX_MIPFILTER_NONE) {
LLVMValueRef index0 = lp_build_const_int32(gallivm, 0);
/*
- * These parameters are the same for all quads,
- * could probably simplify.
+ * This parameter is the same for all quads could probably simplify.
*/
- lod_ipart = LLVMBuildExtractElement(builder, lod_ipart, index0, "");
ilevel0 = LLVMBuildExtractElement(builder, ilevel0, index0, "");
}
}
lp_build_sample_aos(&bld, sampler_index,
newcoords[0], newcoords[1],
newcoords[2],
- offsets, lod_ipart, lod_fpart,
+ offsets, lod_positive, lod_fpart,
ilevel0, ilevel1,
texel_out);
}
else {
lp_build_sample_general(&bld, sampler_index,
newcoords, offsets,
- lod_ipart, lod_fpart,
+ lod_positive, lod_fpart,
ilevel0, ilevel1,
texel_out);
}
for (i = 0; i < num_quads; i++) {
LLVMValueRef s4, t4, r4;
- LLVMValueRef lod_ipart4, lod_fpart4 = NULL;
+ LLVMValueRef lod_positive4, lod_fpart4 = NULL;
LLVMValueRef ilevel04, ilevel14 = NULL;
LLVMValueRef offsets4[4] = { NULL };
unsigned num_lods = bld4.num_lods;
}
}
}
- lod_ipart4 = lp_build_extract_range(gallivm, lod_ipart, num_lods * i, num_lods);
+ lod_positive4 = lp_build_extract_range(gallivm, lod_positive, num_lods * i, num_lods);
ilevel04 = lp_build_extract_range(gallivm, ilevel0, num_lods * i, num_lods);
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
ilevel14 = lp_build_extract_range(gallivm, ilevel1, num_lods * i, num_lods);
/* do sampling/filtering with fixed pt arithmetic */
lp_build_sample_aos(&bld4, sampler_index,
s4, t4, r4, offsets4,
- lod_ipart4, lod_fpart4,
+ lod_positive4, lod_fpart4,
ilevel04, ilevel14,
texelout4);
}
lp_build_sample_general(&bld4, sampler_index,
newcoords4, offsets4,
- lod_ipart4, lod_fpart4,
+ lod_positive4, lod_fpart4,
ilevel04, ilevel14,
texelout4);
}