/* * Helper for building packed ddx/ddy vector for one coord (scalar per quad * values). The vector will look like this (8-wide): * dr1dx _____ -dr1dy _____ dr2dx _____ -dr2dy _____ * This only requires one shuffle instead of two for more straightforward packing. */ LLVMValueRef lp_build_packed_ddx_ddy_onecoord(struct lp_build_context *bld, LLVMValueRef a) { struct gallivm_state *gallivm = bld->gallivm; LLVMBuilderRef builder = gallivm->builder; LLVMValueRef vec1, vec2; /* use aos swizzle helper */ static const unsigned char swizzle1[] = { /* no-op swizzle */ LP_BLD_QUAD_TOP_LEFT, LP_BLD_SWIZZLE_DONTCARE, LP_BLD_QUAD_BOTTOM_LEFT, LP_BLD_SWIZZLE_DONTCARE }; static const unsigned char swizzle2[] = { LP_BLD_QUAD_TOP_RIGHT, LP_BLD_SWIZZLE_DONTCARE, LP_BLD_QUAD_TOP_LEFT, LP_BLD_SWIZZLE_DONTCARE }; vec1 = lp_build_swizzle_aos(bld, a, swizzle1); vec2 = lp_build_swizzle_aos(bld, a, swizzle2); if (bld->type.floating) return LLVMBuildFSub(builder, vec2, vec1, "ddxddy"); else return LLVMBuildSub(builder, vec2, vec1, "ddxddy"); }
/* * To be able to handle multiple quads at once in texture sampling and * do lod calculations per quad, it is necessary to get the per-quad * derivatives into the lp_build_rho function. * For 8-wide vectors the packed derivative values for 3 coords would * look like this, this scales to a arbitrary (multiple of 4) vector size: * ds1dx ds1dy dt1dx dt1dy ds2dx ds2dy dt2dx dt2dy * dr1dx dr1dy _____ _____ dr2dx dr2dy _____ _____ * The second vector will be unused for 1d and 2d textures. */ LLVMValueRef lp_build_packed_ddx_ddy_onecoord(struct lp_build_context *bld, LLVMValueRef a) { struct gallivm_state *gallivm = bld->gallivm; LLVMBuilderRef builder = gallivm->builder; LLVMValueRef vec1, vec2; /* same packing as _twocoord, but can use aos swizzle helper */ /* * XXX could make swizzle1 a noop swizzle by using right top/bottom * pair for ddy */ static const unsigned char swizzle1[] = { LP_BLD_QUAD_TOP_LEFT, LP_BLD_QUAD_TOP_LEFT, LP_BLD_SWIZZLE_DONTCARE, LP_BLD_SWIZZLE_DONTCARE }; static const unsigned char swizzle2[] = { LP_BLD_QUAD_TOP_RIGHT, LP_BLD_QUAD_BOTTOM_LEFT, LP_BLD_SWIZZLE_DONTCARE, LP_BLD_SWIZZLE_DONTCARE }; vec1 = lp_build_swizzle_aos(bld, a, swizzle1); vec2 = lp_build_swizzle_aos(bld, a, swizzle2); if (bld->type.floating) return LLVMBuildFSub(builder, vec2, vec1, "ddxddy"); else return LLVMBuildSub(builder, vec2, vec1, "ddxddy"); }
LLVMValueRef lp_build_ddy(struct lp_build_context *bld, LLVMValueRef a) { LLVMValueRef a_top = lp_build_swizzle_aos(bld, a, swizzle_top); LLVMValueRef a_bottom = lp_build_swizzle_aos(bld, a, swizzle_bottom); return lp_build_sub(bld, a_bottom, a_top); }
LLVMValueRef lp_build_ddx(struct lp_build_context *bld, LLVMValueRef a) { LLVMValueRef a_left = lp_build_swizzle_aos(bld, a, swizzle_left); LLVMValueRef a_right = lp_build_swizzle_aos(bld, a, swizzle_right); return lp_build_sub(bld, a_right, a_left); }
/** * Basic swizzling. Rearrange the order of the unswizzled array elements * according to the format description. PIPE_SWIZZLE_ZERO/ONE are supported * too. * Ex: if unswizzled[4] = {B, G, R, x}, then swizzled_out[4] = {R, G, B, 1}. */ LLVMValueRef lp_build_format_swizzle_aos(const struct util_format_description *desc, struct lp_build_context *bld, LLVMValueRef unswizzled) { unsigned char swizzles[4]; unsigned chan; assert(bld->type.length % 4 == 0); for (chan = 0; chan < 4; ++chan) { enum util_format_swizzle swizzle; if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) { /* * For ZS formats do RGBA = ZZZ1 */ if (chan == 3) { swizzle = UTIL_FORMAT_SWIZZLE_1; } else if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) { swizzle = UTIL_FORMAT_SWIZZLE_0; } else { swizzle = desc->swizzle[0]; } } else { swizzle = desc->swizzle[chan]; } swizzles[chan] = swizzle; } return lp_build_swizzle_aos(bld, unswizzled, swizzles); }
/** * Wrapper around lp_build_swizzle_aos which translates swizzles to another * ordering. */ static LLVMValueRef swizzle_aos(struct lp_build_tgsi_aos_context *bld, LLVMValueRef a, unsigned swizzle_x, unsigned swizzle_y, unsigned swizzle_z, unsigned swizzle_w) { unsigned char swizzles[4]; assert(swizzle_x < 4); assert(swizzle_y < 4); assert(swizzle_z < 4); assert(swizzle_w < 4); swizzles[bld->inv_swizzles[0]] = bld->swizzles[swizzle_x]; swizzles[bld->inv_swizzles[1]] = bld->swizzles[swizzle_y]; swizzles[bld->inv_swizzles[2]] = bld->swizzles[swizzle_z]; swizzles[bld->inv_swizzles[3]] = bld->swizzles[swizzle_w]; return lp_build_swizzle_aos(&bld->base, a, swizzles); }