[Mesa-dev] [PATCH 3/3] gallivm: kill old per-quad face selection code
Brian Paul
brianp at vmware.com
Thu Oct 3 12:40:44 PDT 2013
On 10/03/2013 09:42 AM, sroland at vmware.com wrote:
> From: Roland Scheidegger <sroland at vmware.com>
>
> Not used since ages, and it wouldn't work at all with explicit derivatives now
> (not that it did before as it ignored them but now the code would just use
> the derivs pre-projected which would be quite random numbers).
> ---
> src/gallium/auxiliary/gallivm/lp_bld_sample.c | 751 +++++++++++--------------
> 1 file changed, 313 insertions(+), 438 deletions(-)
>
> diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.c b/src/gallium/auxiliary/gallivm/lp_bld_sample.c
> index ce05522..3fac981 100644
> --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.c
> +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.c
> @@ -1493,323 +1493,135 @@ lp_build_cube_lookup(struct lp_build_sample_context *bld,
> struct lp_derivatives *derivs_out, /* optional */
> boolean need_derivs)
> {
> + /*
> + * Do per-pixel face selection. We cannot however (as we used to do)
> + * simply calculate the derivs afterwards (which is very bogus for
> + * explicit derivs btw) because the values would be "random" when
> + * not all pixels lie on the same face. So what we do here is just
> + * calculate the derivatives after scaling the coords by the absolute
> + * value of the inverse major axis, and essentially do rho calculation
> + * steps as if it were a 3d texture. This is perfect if all pixels hit
> + * the same face, but not so great at edges, I believe the max error
> + * should be sqrt(2) with no_rho_approx or 2 otherwise (essentially measuring
> + * the 3d distance between 2 points on the cube instead of measuring up/down
> + * the edge). Still this is possibly a win over just selecting the same face
> + * for all pixels. Unfortunately, something like that doesn't work for
> + * explicit derivatives.
> + */
> struct lp_build_context *coord_bld = &bld->coord_bld;
> LLVMBuilderRef builder = bld->gallivm->builder;
> struct gallivm_state *gallivm = bld->gallivm;
> LLVMValueRef si, ti, ri;
> + struct lp_build_context *cint_bld = &bld->int_coord_bld;
> + struct lp_type intctype = cint_bld->type;
> + LLVMValueRef signs, signt, signr, signma;
> + LLVMValueRef as, at, ar, face, face_s, face_t;
> + LLVMValueRef as_ge_at, maxasat, ar_ge_as_at;
> + LLVMValueRef snewx, tnewx, snewy, tnewy, snewz, tnewz;
> + LLVMValueRef tnegi, rnegi;
> + LLVMValueRef ma, mai, imahalfpos;
> + LLVMValueRef posHalf = lp_build_const_vec(gallivm, coord_bld->type, 0.5);
> + LLVMValueRef signmask = lp_build_const_int_vec(gallivm, intctype,
> + 1 << (intctype.width - 1));
> + LLVMValueRef signshift = lp_build_const_int_vec(gallivm, intctype,
> + intctype.width -1);
> + LLVMValueRef facex = lp_build_const_int_vec(gallivm, intctype, PIPE_TEX_FACE_POS_X);
> + LLVMValueRef facey = lp_build_const_int_vec(gallivm, intctype, PIPE_TEX_FACE_POS_Y);
> + LLVMValueRef facez = lp_build_const_int_vec(gallivm, intctype, PIPE_TEX_FACE_POS_Z);
> + LLVMValueRef s = coords[0];
> + LLVMValueRef t = coords[1];
> + LLVMValueRef r = coords[2];
> +
> + assert(PIPE_TEX_FACE_NEG_X == PIPE_TEX_FACE_POS_X + 1);
> + assert(PIPE_TEX_FACE_NEG_Y == PIPE_TEX_FACE_POS_Y + 1);
> + assert(PIPE_TEX_FACE_NEG_Z == PIPE_TEX_FACE_POS_Z + 1);
>
> - if (1 || coord_bld->type.length > 4) {
> - /*
> - * Do per-pixel face selection. We cannot however (as we used to do)
> - * simply calculate the derivs afterwards (which is very bogus for
> - * explicit derivs btw) because the values would be "random" when
> - * not all pixels lie on the same face. So what we do here is just
> - * calculate the derivatives after scaling the coords by the absolute
> - * value of the inverse major axis, and essentially do rho calculation
> - * steps as if it were a 3d texture. This is perfect if all pixels hit
> - * the same face, but not so great at edges, I believe the max error
> - * should be sqrt(2) with no_rho_approx or 2 otherwise (essentially measuring
> - * the 3d distance between 2 points on the cube instead of measuring up/down
> - * the edge). Still this is possibly a win over just selecting the same face
> - * for all pixels. Unfortunately, something like that doesn't work for
> - * explicit derivatives.
> - */
> - struct lp_build_context *cint_bld = &bld->int_coord_bld;
> - struct lp_type intctype = cint_bld->type;
> - LLVMValueRef signs, signt, signr, signma;
> - LLVMValueRef as, at, ar, face, face_s, face_t;
> - LLVMValueRef as_ge_at, maxasat, ar_ge_as_at;
> - LLVMValueRef snewx, tnewx, snewy, tnewy, snewz, tnewz;
> - LLVMValueRef tnegi, rnegi;
> - LLVMValueRef ma, mai, imahalfpos;
> - LLVMValueRef posHalf = lp_build_const_vec(gallivm, coord_bld->type, 0.5);
> - LLVMValueRef signmask = lp_build_const_int_vec(gallivm, intctype,
> - 1 << (intctype.width - 1));
> - LLVMValueRef signshift = lp_build_const_int_vec(gallivm, intctype,
> - intctype.width -1);
> - LLVMValueRef facex = lp_build_const_int_vec(gallivm, intctype, PIPE_TEX_FACE_POS_X);
> - LLVMValueRef facey = lp_build_const_int_vec(gallivm, intctype, PIPE_TEX_FACE_POS_Y);
> - LLVMValueRef facez = lp_build_const_int_vec(gallivm, intctype, PIPE_TEX_FACE_POS_Z);
> - LLVMValueRef s = coords[0];
> - LLVMValueRef t = coords[1];
> - LLVMValueRef r = coords[2];
> -
> - assert(PIPE_TEX_FACE_NEG_X == PIPE_TEX_FACE_POS_X + 1);
> - assert(PIPE_TEX_FACE_NEG_Y == PIPE_TEX_FACE_POS_Y + 1);
> - assert(PIPE_TEX_FACE_NEG_Z == PIPE_TEX_FACE_POS_Z + 1);
> + /*
> + * get absolute value (for x/y/z face selection) and sign bit
> + * (for mirroring minor coords and pos/neg face selection)
> + * of the original coords.
> + */
> + as = lp_build_abs(&bld->coord_bld, s);
> + at = lp_build_abs(&bld->coord_bld, t);
> + ar = lp_build_abs(&bld->coord_bld, r);
> +
> + /*
> + * major face determination: select x if x > y else select y
> + * select z if z >= max(x,y) else select previous result
> + * if some axis are the same we chose z over y, y over x - the
> + * dx10 spec seems to ask for it while OpenGL doesn't care (if we
> + * wouldn't care could save a select or two if using different
> + * compares and doing at_g_as_ar last since tnewx and tnewz are the
> + * same).
> + */
> + as_ge_at = lp_build_cmp(coord_bld, PIPE_FUNC_GREATER, as, at);
> + maxasat = lp_build_max(coord_bld, as, at);
> + ar_ge_as_at = lp_build_cmp(coord_bld, PIPE_FUNC_GEQUAL, ar, maxasat);
>
> + if (need_derivs && (derivs_in ||
> + ((gallivm_debug & GALLIVM_DEBUG_NO_QUAD_LOD) &&
> + (gallivm_debug & GALLIVM_DEBUG_NO_RHO_APPROX)))) {
> /*
> - * get absolute value (for x/y/z face selection) and sign bit
> - * (for mirroring minor coords and pos/neg face selection)
> - * of the original coords.
> + * XXX: This is really really complex.
> + * It is a bit overkill to use this for implicit derivatives as well,
> + * no way this is worth the cost in practice, but seems to be the
> + * only way for getting accurate and per-pixel lod values.
> */
> - as = lp_build_abs(&bld->coord_bld, s);
> - at = lp_build_abs(&bld->coord_bld, t);
> - ar = lp_build_abs(&bld->coord_bld, r);
> -
> + LLVMValueRef imapos, tmp, ddx[3], ddy[3];
> + LLVMValueRef madx, mady, madxdivma, madydivma;
> + LLVMValueRef sdxi, tdxi, rdxi, signsdx, signtdx, signrdx;
> + LLVMValueRef sdyi, tdyi, rdyi, signsdy, signtdy, signrdy;
> + LLVMValueRef tdxnegi, rdxnegi, tdynegi, rdynegi;
> + LLVMValueRef sdxnewx, sdxnewy, sdxnewz, tdxnewx, tdxnewy, tdxnewz;
> + LLVMValueRef sdynewx, sdynewy, sdynewz, tdynewx, tdynewy, tdynewz;
> + LLVMValueRef face_sdx, face_tdx, face_sdy, face_tdy;
> + LLVMValueRef posHalf = lp_build_const_vec(coord_bld->gallivm,
> + coord_bld->type, 0.5);
It looks like we already declared posHalf at the top of the function.
[...]
This is pretty complicated stuff but the code looks good otherwise, AFAICT.
For 1-3, Reviewed-by: Brian Paul <brianp at vmware.com>
More information about the mesa-dev
mailing list