bld->texel_type,
data_ptr, offset,
i, j,
+ bld->cache,
texel_out);
/*
break;
case PIPE_TEX_WRAP_MIRROR_REPEAT:
+ if (offset) {
+ offset = lp_build_int_to_float(coord_bld, offset);
+ offset = lp_build_div(coord_bld, offset, length_f);
+ coord = lp_build_add(coord_bld, coord, offset);
+ }
/* compute mirror function */
coord = lp_build_coord_mirror(bld, coord);
/* scale coord to length */
coord = lp_build_mul(coord_bld, coord, length_f);
coord = lp_build_sub(coord_bld, coord, half);
- if (offset) {
- offset = lp_build_int_to_float(coord_bld, offset);
- coord = lp_build_add(coord_bld, coord, offset);
- }
/* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
coord = lp_build_mul(coord_bld, coord, length_f);
}
+ if (offset) {
+ offset = lp_build_int_to_float(coord_bld, offset);
+ coord = lp_build_add(coord_bld, coord, offset);
+ }
/* floor */
/* use itrunc instead since we clamp to 0 anyway */
icoord = lp_build_itrunc(coord_bld, coord);
- if (offset) {
- icoord = lp_build_add(int_coord_bld, icoord, offset);
- }
/* clamp to [0, length - 1]. */
icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero,
*/
static void
lp_build_sample_image_linear(struct lp_build_sample_context *bld,
+ boolean is_gather,
LLVMValueRef size,
LLVMValueRef linear_mask,
LLVMValueRef row_stride_vec,
LLVMBuilderRef builder = bld->gallivm->builder;
struct lp_build_context *ivec_bld = &bld->int_coord_bld;
struct lp_build_context *coord_bld = &bld->coord_bld;
+ struct lp_build_context *texel_bld = &bld->texel_bld;
const unsigned dims = bld->dims;
LLVMValueRef width_vec;
LLVMValueRef height_vec;
seamless_cube_filter = (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
bld->static_texture_state->target == PIPE_TEXTURE_CUBE_ARRAY) &&
bld->static_sampler_state->seamless_cube_map;
- accurate_cube_corners = ACCURATE_CUBE_CORNERS && seamless_cube_filter;
+ /*
+ * XXX I don't know how this is really supposed to work with gather. From GL
+ * spec wording (not gather specific) it sounds like the 4th missing texel
+ * should be an average of the other 3, hence for gather could return this.
+ * This is however NOT how the code here works, which just fixes up the
+ * weights used for filtering instead. And of course for gather there is
+ * no filter to tweak...
+ */
+ accurate_cube_corners = ACCURATE_CUBE_CORNERS && seamless_cube_filter &&
+ !is_gather;
lp_build_extract_image_sizes(bld,
&bld->int_size_bld,
data_ptr, mipoffsets, neighbors[0][1]);
if (dims == 1) {
+ assert(!is_gather);
if (bld->static_sampler_state->compare_mode == PIPE_TEX_COMPARE_NONE) {
/* Interpolate two samples from 1D image to produce one color */
for (chan = 0; chan < 4; chan++) {
- colors_out[chan] = lp_build_lerp(&bld->texel_bld, s_fpart,
+ colors_out[chan] = lp_build_lerp(texel_bld, s_fpart,
neighbors[0][0][chan],
neighbors[0][1][chan],
0);
cmpval0 = lp_build_sample_comparefunc(bld, coords[4], neighbors[0][0][0]);
cmpval1 = lp_build_sample_comparefunc(bld, coords[4], neighbors[0][1][0]);
/* simplified lerp, AND mask with weight and add */
- colors_out[0] = lp_build_masklerp(&bld->texel_bld, s_fpart,
+ colors_out[0] = lp_build_masklerp(texel_bld, s_fpart,
cmpval0, cmpval1);
colors_out[1] = colors_out[2] = colors_out[3] = colors_out[0];
}
}
if (bld->static_sampler_state->compare_mode == PIPE_TEX_COMPARE_NONE) {
- /* Bilinear interpolate the four samples from the 2D image / 3D slice */
- for (chan = 0; chan < 4; chan++) {
- colors0[chan] = lp_build_lerp_2d(&bld->texel_bld,
- s_fpart, t_fpart,
- neighbors[0][0][chan],
- neighbors[0][1][chan],
- neighbors[1][0][chan],
- neighbors[1][1][chan],
- 0);
+ if (is_gather) {
+ /*
+ * Just assign the red channel (no component selection yet).
+ * This is a bit hackish, we usually do the swizzle at the
+ * end of sampling (much less values to swizzle), but this
+ * obviously cannot work when using gather.
+ */
+ unsigned chan_swiz = bld->static_texture_state->swizzle_r;
+ colors0[0] = lp_build_swizzle_soa_channel(texel_bld,
+ neighbors[1][0],
+ chan_swiz);
+ colors0[1] = lp_build_swizzle_soa_channel(texel_bld,
+ neighbors[1][1],
+ chan_swiz);
+ colors0[2] = lp_build_swizzle_soa_channel(texel_bld,
+ neighbors[0][1],
+ chan_swiz);
+ colors0[3] = lp_build_swizzle_soa_channel(texel_bld,
+ neighbors[0][0],
+ chan_swiz);
+ }
+ else {
+ /* Bilinear interpolate the four samples from the 2D image / 3D slice */
+ for (chan = 0; chan < 4; chan++) {
+ colors0[chan] = lp_build_lerp_2d(texel_bld,
+ s_fpart, t_fpart,
+ neighbors[0][0][chan],
+ neighbors[0][1][chan],
+ neighbors[1][0][chan],
+ neighbors[1][1][chan],
+ 0);
+ }
}
}
else {
cmpval01 = lp_build_sample_comparefunc(bld, coords[4], neighbors[0][1][0]);
cmpval10 = lp_build_sample_comparefunc(bld, coords[4], neighbors[1][0][0]);
cmpval11 = lp_build_sample_comparefunc(bld, coords[4], neighbors[1][1][0]);
- colors0[0] = lp_build_masklerp2d(&bld->texel_bld, s_fpart, t_fpart,
- cmpval00, cmpval01, cmpval10, cmpval11);
- colors0[1] = colors0[2] = colors0[3] = colors0[0];
+
+ if (is_gather) {
+ /* more hacks for swizzling, should be X, ONE or ZERO... */
+ unsigned chan_swiz = bld->static_texture_state->swizzle_r;
+ if (chan_swiz <= PIPE_SWIZZLE_ALPHA) {
+ colors0[0] = lp_build_select(texel_bld, cmpval10,
+ texel_bld->one, texel_bld->zero);
+ colors0[1] = lp_build_select(texel_bld, cmpval11,
+ texel_bld->one, texel_bld->zero);
+ colors0[2] = lp_build_select(texel_bld, cmpval01,
+ texel_bld->one, texel_bld->zero);
+ colors0[3] = lp_build_select(texel_bld, cmpval00,
+ texel_bld->one, texel_bld->zero);
+ }
+ else if (chan_swiz == PIPE_SWIZZLE_ZERO) {
+ colors0[0] = colors0[1] = colors0[2] = colors0[3] =
+ texel_bld->zero;
+ }
+ else {
+ colors0[0] = colors0[1] = colors0[2] = colors0[3] =
+ texel_bld->one;
+ }
+ }
+ else {
+ colors0[0] = lp_build_masklerp2d(texel_bld, s_fpart, t_fpart,
+ cmpval00, cmpval01, cmpval10, cmpval11);
+ colors0[1] = colors0[2] = colors0[3] = colors0[0];
+ }
}
if (accurate_cube_corners) {
LLVMValueRef neighbors1[2][2][4];
LLVMValueRef colors1[4];
+ assert(!is_gather);
+
/* get x0/x1/y0/y1 texels at z1 */
lp_build_sample_texel_soa(bld,
width_vec, height_vec, depth_vec,
if (bld->static_sampler_state->compare_mode == PIPE_TEX_COMPARE_NONE) {
/* Bilinear interpolate the four samples from the second Z slice */
for (chan = 0; chan < 4; chan++) {
- colors1[chan] = lp_build_lerp_2d(&bld->texel_bld,
+ colors1[chan] = lp_build_lerp_2d(texel_bld,
s_fpart, t_fpart,
neighbors1[0][0][chan],
neighbors1[0][1][chan],
}
/* Linearly interpolate the two samples from the two 3D slices */
for (chan = 0; chan < 4; chan++) {
- colors_out[chan] = lp_build_lerp(&bld->texel_bld,
+ colors_out[chan] = lp_build_lerp(texel_bld,
r_fpart,
colors0[chan], colors1[chan],
0);
cmpval01 = lp_build_sample_comparefunc(bld, coords[4], neighbors[0][1][0]);
cmpval10 = lp_build_sample_comparefunc(bld, coords[4], neighbors[1][0][0]);
cmpval11 = lp_build_sample_comparefunc(bld, coords[4], neighbors[1][1][0]);
- colors1[0] = lp_build_masklerp2d(&bld->texel_bld, s_fpart, t_fpart,
+ colors1[0] = lp_build_masklerp2d(texel_bld, s_fpart, t_fpart,
cmpval00, cmpval01, cmpval10, cmpval11);
/* Linearly interpolate the two samples from the two 3D slices */
- colors_out[0] = lp_build_lerp(&bld->texel_bld,
- r_fpart,
- colors0[0], colors1[0],
- 0);
+ colors_out[0] = lp_build_lerp(texel_bld,
+ r_fpart,
+ colors0[0], colors1[0],
+ 0);
colors_out[1] = colors_out[2] = colors_out[3] = colors_out[0];
}
}
lp_build_sample_mipmap(struct lp_build_sample_context *bld,
unsigned img_filter,
unsigned mip_filter,
+ boolean is_gather,
LLVMValueRef *coords,
const LLVMValueRef *offsets,
LLVMValueRef ilevel0,
}
else {
assert(img_filter == PIPE_TEX_FILTER_LINEAR);
- lp_build_sample_image_linear(bld, size0, NULL,
+ lp_build_sample_image_linear(bld, is_gather, size0, NULL,
row_stride0_vec, img_stride0_vec,
data_ptr0, mipoff0, coords, offsets,
colors0);
colors1);
}
else {
- lp_build_sample_image_linear(bld, size1, NULL,
+ lp_build_sample_image_linear(bld, FALSE, size1, NULL,
row_stride1_vec, img_stride1_vec,
data_ptr1, mipoff1, coords, offsets,
colors1);
mipoff0 = lp_build_get_mip_offsets(bld, ilevel0);
}
- lp_build_sample_image_linear(bld, size0, linear_mask,
+ lp_build_sample_image_linear(bld, FALSE, size0, linear_mask,
row_stride0_vec, img_stride0_vec,
data_ptr0, mipoff0, coords, offsets,
colors0);
mipoff1 = lp_build_get_mip_offsets(bld, ilevel1);
}
- lp_build_sample_image_linear(bld, size1, linear_mask,
+ lp_build_sample_image_linear(bld, FALSE, size1, linear_mask,
row_stride1_vec, img_stride1_vec,
data_ptr1, mipoff1, coords, offsets,
colors1);
LLVMPointerType(vec4_bld.vec_type, 0), "");
border_color = LLVMBuildLoad(builder, border_color_ptr, "");
/* we don't have aligned type in the dynamic state unfortunately */
- lp_set_load_alignment(border_color, 4);
+ LLVMSetAlignment(border_color, 4);
/*
* Instead of having some incredibly complex logic which will try to figure out
static void
lp_build_sample_general(struct lp_build_sample_context *bld,
unsigned sampler_unit,
+ boolean is_gather,
LLVMValueRef *coords,
const LLVMValueRef *offsets,
LLVMValueRef lod_positive,
if (min_filter == mag_filter) {
/* no need to distinguish between minification and magnification */
lp_build_sample_mipmap(bld, min_filter, mip_filter,
+ is_gather,
coords, offsets,
ilevel0, ilevel1, lod_fpart,
texels);
lp_build_if(&if_ctx, bld->gallivm, lod_positive);
{
/* Use the minification filter */
- lp_build_sample_mipmap(bld, min_filter, mip_filter,
+ lp_build_sample_mipmap(bld, min_filter, mip_filter, FALSE,
coords, offsets,
ilevel0, ilevel1, lod_fpart,
texels);
{
/* Use the magnification filter */
lp_build_sample_mipmap(bld, mag_filter, PIPE_TEX_MIPFILTER_NONE,
+ FALSE,
coords, offsets,
ilevel0, NULL, NULL,
texels);
* All pixels require just nearest filtering, which is way
* cheaper than linear, hence do a separate path for that.
*/
- lp_build_sample_mipmap(bld, PIPE_TEX_FILTER_NEAREST,
+ lp_build_sample_mipmap(bld, PIPE_TEX_FILTER_NEAREST, FALSE,
mip_filter_for_nearest,
coords, offsets,
ilevel0, ilevel1, lod_fpart,
bld->texel_type,
bld->base_ptr, offset,
i, j,
+ bld->cache,
colors_out);
if (out_of_bound_ret_zero) {
unsigned texture_index,
unsigned sampler_index,
LLVMValueRef context_ptr,
+ LLVMValueRef thread_data_ptr,
const LLVMValueRef *coords,
const LLVMValueRef *offsets,
const struct lp_derivatives *derivs, /* optional */
* all zero as mandated by d3d10 in this case.
*/
unsigned chan;
- LLVMValueRef zero = lp_build_const_vec(gallivm, type, 0.0F);
+ LLVMValueRef zero = lp_build_zero(gallivm, type);
for (chan = 0; chan < 4; chan++) {
texel_out[chan] = zero;
}
} else {
derived_sampler_state.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
}
+ if (op_type == LP_SAMPLER_OP_GATHER) {
+ /*
+ * gather4 is exactly like GL_LINEAR filtering but in the end skipping
+ * the actual filtering. Using mostly the same paths, so cube face
+ * selection, coord wrapping etc. all naturally uses the same code.
+ */
+ derived_sampler_state.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+ derived_sampler_state.min_img_filter = PIPE_TEX_FILTER_LINEAR;
+ derived_sampler_state.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
+ }
mip_filter = derived_sampler_state.min_mip_filter;
if (0) {
derived_sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
derived_sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
}
+ /*
+ * We could force CLAMP to CLAMP_TO_EDGE here if min/mag filter is nearest,
+ * so AoS path could be used. Not sure it's worth the trouble...
+ */
min_img_filter = derived_sampler_state.min_img_filter;
mag_img_filter = derived_sampler_state.mag_img_filter;
context_ptr, texture_index);
/* Note that mip_offsets is an array[level] of offsets to texture images */
+ if (dynamic_state->cache_ptr && thread_data_ptr) {
+ bld.cache = dynamic_state->cache_ptr(dynamic_state, gallivm,
+ thread_data_ptr, texture_index);
+ }
+
/* width, height, depth as single int vector */
if (dims <= 1) {
bld.int_size = tex_width;
else {
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 */
- derived_sampler_state.compare_mode == PIPE_TEX_COMPARE_NONE &&
- lp_is_simple_wrap_mode(derived_sampler_state.wrap_s);
+ boolean use_aos;
+
+ if (util_format_is_pure_integer(static_texture_state->format) &&
+ !util_format_has_depth(bld.format_desc) &&
+ (static_sampler_state->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR ||
+ static_sampler_state->min_img_filter == PIPE_TEX_FILTER_LINEAR ||
+ static_sampler_state->mag_img_filter == PIPE_TEX_FILTER_LINEAR)) {
+ /*
+ * Bail if impossible filtering is specified (the awkard additional
+ * depth check is because it is legal in gallium to have things like S8Z24
+ * here which would say it's pure int despite such formats should sample
+ * the depth component).
+ * In GL such filters make the texture incomplete, this makes it robust
+ * against state trackers which set this up regardless (we'd crash in the
+ * lerp later (except for gather)).
+ * Must do this after fetch_texel code since with GL state tracker we'll
+ * get some junk sampler for buffer textures.
+ */
+ unsigned chan;
+ LLVMValueRef zero = lp_build_zero(gallivm, type);
+ for (chan = 0; chan < 4; chan++) {
+ texel_out[chan] = zero;
+ }
+ return;
+ }
+
+ use_aos = util_format_fits_8unorm(bld.format_desc) &&
+ op_is_tex &&
+ /* not sure this is strictly needed or simply impossible */
+ derived_sampler_state.compare_mode == PIPE_TEX_COMPARE_NONE &&
+ lp_is_simple_wrap_mode(derived_sampler_state.wrap_s);
use_aos &= bld.num_lods <= num_quads ||
derived_sampler_state.min_img_filter ==
else {
lp_build_sample_general(&bld, sampler_index,
+ op_type == LP_SAMPLER_OP_GATHER,
newcoords, offsets,
lod_positive, lod_fpart,
ilevel0, ilevel1,
bld4.base_ptr = bld.base_ptr;
bld4.mip_offsets = bld.mip_offsets;
bld4.int_size = bld.int_size;
+ bld4.cache = bld.cache;
bld4.vector_width = lp_type_width(type4);
newcoords4[4] = lp_build_extract_range(gallivm, newcoords[4], 4*i, 4);
lp_build_sample_general(&bld4, sampler_index,
+ op_type == LP_SAMPLER_OP_GATHER,
newcoords4, offsets4,
lod_positive4, lod_fpart4,
ilevel04, ilevel14,
}
}
- if (target != PIPE_BUFFER) {
+ if (target != PIPE_BUFFER && op_type != LP_SAMPLER_OP_GATHER) {
apply_sampler_swizzle(&bld, texel_out);
}
LLVMValueRef offsets[3] = { NULL };
LLVMValueRef lod = NULL;
LLVMValueRef context_ptr;
+ LLVMValueRef thread_data_ptr = NULL;
LLVMValueRef texel_out[4];
struct lp_derivatives derivs;
struct lp_derivatives *deriv_ptr = NULL;
unsigned num_param = 0;
unsigned i, num_coords, num_derivs, num_offsets, layer;
enum lp_sampler_lod_control lod_control;
+ boolean need_cache = FALSE;
lod_control = (sample_key & LP_SAMPLER_LOD_CONTROL_MASK) >>
LP_SAMPLER_LOD_CONTROL_SHIFT;
get_target_info(static_texture_state->target,
&num_coords, &num_derivs, &num_offsets, &layer);
+ if (dynamic_state->cache_ptr) {
+ const struct util_format_description *format_desc;
+ format_desc = util_format_description(static_texture_state->format);
+ if (format_desc && format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
+ need_cache = TRUE;
+ }
+ }
+
/* "unpack" arguments */
context_ptr = LLVMGetParam(function, num_param++);
+ if (need_cache) {
+ thread_data_ptr = LLVMGetParam(function, num_param++);
+ }
for (i = 0; i < num_coords; i++) {
coords[i] = LLVMGetParam(function, num_param++);
}
texture_index,
sampler_index,
context_ptr,
+ thread_data_ptr,
coords,
offsets,
deriv_ptr,
const LLVMValueRef *offsets = params->offsets;
const struct lp_derivatives *derivs = params->derivs;
enum lp_sampler_lod_control lod_control;
+ boolean need_cache = FALSE;
lod_control = (sample_key & LP_SAMPLER_LOD_CONTROL_MASK) >>
LP_SAMPLER_LOD_CONTROL_SHIFT;
get_target_info(static_texture_state->target,
&num_coords, &num_derivs, &num_offsets, &layer);
+ if (dynamic_state->cache_ptr) {
+ const struct util_format_description *format_desc;
+ format_desc = util_format_description(static_texture_state->format);
+ if (format_desc && format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
+ /*
+ * This is not 100% correct, if we have cache but the
+ * util_format_s3tc_prefer is true the cache won't get used
+ * regardless (could hook up the block decode there...) */
+ need_cache = TRUE;
+ }
+ }
/*
* texture function matches are found by name.
* Thus the name has to include both the texture and sampler unit
*/
arg_types[num_param++] = LLVMTypeOf(params->context_ptr);
+ if (need_cache) {
+ arg_types[num_param++] = LLVMTypeOf(params->thread_data_ptr);
+ }
for (i = 0; i < num_coords; i++) {
arg_types[num_param++] = LLVMTypeOf(coords[0]);
assert(LLVMTypeOf(coords[0]) == LLVMTypeOf(coords[i]));
num_args = 0;
args[num_args++] = params->context_ptr;
+ if (need_cache) {
+ args[num_args++] = params->thread_data_ptr;
+ }
for (i = 0; i < num_coords; i++) {
args[num_args++] = coords[i];
}
struct gallivm_state *gallivm,
const struct lp_sampler_params *params)
{
+ boolean use_tex_func = FALSE;
+
+ /*
+ * Do not use a function call if the sampling is "simple enough".
+ * We define this by
+ * a) format
+ * b) no mips (either one level only or no mip filter)
+ * No mips will definitely make the code smaller, though
+ * the format requirement is a bit iffy - there's some (SoA) formats
+ * which definitely generate less code. This does happen to catch
+ * some important cases though which are hurt quite a bit by using
+ * a call (though not really because of the call overhead but because
+ * they are reusing the same texture unit with some of the same
+ * parameters).
+ * Ideally we'd let llvm recognize this stuff by doing IPO passes.
+ */
+
if (USE_TEX_FUNC_CALL) {
+ const struct util_format_description *format_desc;
+ boolean simple_format;
+ boolean simple_tex;
+ enum lp_sampler_op_type op_type;
+ format_desc = util_format_description(static_texture_state->format);
+ simple_format = !format_desc ||
+ (util_format_is_rgba8_variant(format_desc) &&
+ format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB);
+
+ op_type = (params->sample_key & LP_SAMPLER_OP_TYPE_MASK) >>
+ LP_SAMPLER_OP_TYPE_SHIFT;
+ simple_tex =
+ op_type != LP_SAMPLER_OP_TEXTURE ||
+ ((static_sampler_state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE ||
+ static_texture_state->level_zero_only == TRUE) &&
+ static_sampler_state->min_img_filter == static_sampler_state->mag_img_filter);
+
+ use_tex_func = format_desc && !(simple_format && simple_tex);
+ }
+
+ if (use_tex_func) {
lp_build_sample_soa_func(gallivm,
static_texture_state,
static_sampler_state,
params->texture_index,
params->sampler_index,
params->context_ptr,
+ params->thread_data_ptr,
params->coords,
params->offsets,
params->derivs,