From 67a2f98be79b368c316ebe6731112734d306b3f6 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 10 Mar 2010 18:07:52 -0700 Subject: [PATCH] gallivm: overhaul of texture sampling code The new lp_build_sample_general() function will handle all sampling modes for all texture types. Still incomplete, but a few additional sampling modes are now supported. 1D textures should work and most of the code for 3D textures is in place. No support for cube maps yet. No support for different min/mag filters. --- src/gallium/auxiliary/gallivm/lp_bld_sample.c | 24 +- src/gallium/auxiliary/gallivm/lp_bld_sample.h | 4 +- .../auxiliary/gallivm/lp_bld_sample_soa.c | 642 +++++++++++------- 3 files changed, 420 insertions(+), 250 deletions(-) diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.c b/src/gallium/auxiliary/gallivm/lp_bld_sample.c index 311c9f1b9e4..543fd5fea3f 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.c @@ -155,14 +155,16 @@ lp_build_gather(LLVMBuilderRef builder, /** * Compute the offset of a pixel. * - * x, y, y_stride are vectors + * x, y, z, y_stride, z_stride are vectors */ LLVMValueRef lp_build_sample_offset(struct lp_build_context *bld, const struct util_format_description *format_desc, LLVMValueRef x, LLVMValueRef y, - LLVMValueRef y_stride) + LLVMValueRef z, + LLVMValueRef y_stride, + LLVMValueRef z_stride) { LLVMValueRef x_stride; LLVMValueRef offset; @@ -178,6 +180,10 @@ lp_build_sample_offset(struct lp_build_context *bld, LLVMValueRef y_offset_lo, y_offset_hi; LLVMValueRef offset_lo, offset_hi; + /* XXX 1D & 3D addressing not done yet */ + assert(!z); + assert(!z_stride); + x_lo = LLVMBuildAnd(bld->builder, x, bld->one, ""); y_lo = LLVMBuildAnd(bld->builder, y, bld->one, ""); @@ -201,13 +207,17 @@ lp_build_sample_offset(struct lp_build_context *bld, offset = lp_build_add(bld, offset_hi, offset_lo); } else { - LLVMValueRef x_offset; - LLVMValueRef y_offset; + offset = lp_build_mul(bld, x, x_stride); - x_offset = lp_build_mul(bld, x, x_stride); - y_offset = lp_build_mul(bld, y, y_stride); + if (y && y_stride) { + LLVMValueRef y_offset = lp_build_mul(bld, y, y_stride); + offset = lp_build_add(bld, offset, y_offset); + } - offset = lp_build_add(bld, x_offset, y_offset); + if (z && z_stride) { + LLVMValueRef z_offset = lp_build_mul(bld, z, z_stride); + offset = lp_build_add(bld, offset, z_offset); + } } return offset; diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.h b/src/gallium/auxiliary/gallivm/lp_bld_sample.h index 68db91d6fd6..5b8da5dbf21 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.h @@ -148,7 +148,9 @@ lp_build_sample_offset(struct lp_build_context *bld, const struct util_format_description *format_desc, LLVMValueRef x, LLVMValueRef y, - LLVMValueRef y_stride); + LLVMValueRef z, + LLVMValueRef y_stride, + LLVMValueRef z_stride); void diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c index 2e6865a67b3..dadae61115b 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c @@ -138,8 +138,28 @@ lp_build_get_const_mipmap_level(struct lp_build_sample_context *bld, } +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; + } +} + + + /** - * Gen code to fetch a texel from a texture at int coords (x, y). + * Generate code to fetch a texel from a texture at int coords (x, y, z). + * The computation depends on whether the texture is 1D, 2D or 3D. * The result, texel, will be: * texel[0] = red values * texel[1] = green values @@ -150,12 +170,16 @@ static void lp_build_sample_texel_soa(struct lp_build_sample_context *bld, LLVMValueRef width, LLVMValueRef height, + LLVMValueRef depth, LLVMValueRef x, LLVMValueRef y, + LLVMValueRef z, LLVMValueRef y_stride, + LLVMValueRef z_stride, LLVMValueRef data_ptr, LLVMValueRef *texel) { + const int dims = texture_dims(bld->static_state->target); struct lp_build_context *int_coord_bld = &bld->int_coord_bld; LLVMValueRef offset; LLVMValueRef packed; @@ -169,7 +193,7 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld, use_border = LLVMBuildOr(bld->builder, b1, b2, "b1_or_b2"); } - if (wrap_mode_uses_border_color(bld->static_state->wrap_t)) { + if (dims >= 2 && wrap_mode_uses_border_color(bld->static_state->wrap_t)) { LLVMValueRef b1, b2; b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, y, int_coord_bld->zero); b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, y, height); @@ -182,6 +206,19 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld, } } + if (dims == 3 && wrap_mode_uses_border_color(bld->static_state->wrap_r)) { + LLVMValueRef b1, b2; + b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, z, int_coord_bld->zero); + b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, z, depth); + if (use_border) { + use_border = LLVMBuildOr(bld->builder, use_border, b1, "ub_or_b1"); + use_border = LLVMBuildOr(bld->builder, use_border, b2, "ub_or_b2"); + } + else { + use_border = LLVMBuildOr(bld->builder, b1, b2, "b1_or_b2"); + } + } + /* * Note: if we find an app which frequently samples the texture border * we might want to implement a true conditional here to avoid sampling @@ -197,10 +234,10 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld, * the texel color results with the border color. */ - /* convert x,y coords to linear offset from start of texture, in bytes */ + /* convert x,y,z coords to linear offset from start of texture, in bytes */ offset = lp_build_sample_offset(&bld->uint_coord_bld, bld->format_desc, - x, y, y_stride); + x, y, z, y_stride, z_stride); assert(bld->format_desc->block.width == 1); assert(bld->format_desc->block.height == 1); @@ -213,6 +250,8 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld, bld->texel_type.width, data_ptr, offset); + texel[0] = texel[1] = texel[2] = texel[3] = NULL; + /* convert texels to float rgba */ lp_build_unpack_rgba_soa(bld->builder, bld->format_desc, @@ -245,7 +284,7 @@ lp_build_sample_packed(struct lp_build_sample_context *bld, offset = lp_build_sample_offset(&bld->uint_coord_bld, bld->format_desc, - x, y, y_stride); + x, y, NULL, y_stride, NULL); assert(bld->format_desc->block.width == 1); assert(bld->format_desc->block.height == 1); @@ -756,24 +795,6 @@ lp_build_minify(struct lp_build_sample_context *bld, } -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 @@ -920,229 +941,406 @@ lp_build_linear_mip_levels(struct lp_build_sample_context *bld, LLVMValueRef *level1_out, LLVMValueRef *weight_out) { - struct lp_build_context *coord_bld = &bld->coord_bld; - struct lp_build_context *int_coord_bld = &bld->int_coord_bld; + struct lp_build_context *float_bld = &bld->float_bld; + struct lp_build_context *int_bld = &bld->int_bld; LLVMValueRef last_level, level; last_level = bld->dynamic_state->last_level(bld->dynamic_state, bld->builder, unit); /* convert float lod to integer */ - level = lp_build_ifloor(coord_bld, lod); + level = lp_build_ifloor(float_bld, lod); /* compute level 0 and clamp to legal range of levels */ - *level0_out = lp_build_clamp(int_coord_bld, level, - int_coord_bld->zero, + *level0_out = lp_build_clamp(int_bld, level, + int_bld->zero, last_level); /* compute level 1 and clamp to legal range of levels */ - *level1_out = lp_build_add(int_coord_bld, *level0_out, int_coord_bld->one); - *level1_out = lp_build_min(int_coord_bld, *level1_out, int_coord_bld->zero); + *level1_out = lp_build_add(int_bld, *level0_out, int_bld->one); + *level1_out = lp_build_min(int_bld, *level1_out, int_bld->zero); - *weight_out = lp_build_fract(coord_bld, lod); + *weight_out = lp_build_fract(float_bld, lod); } - /** - * Sample 2D texture with nearest filtering, no mipmapping. + * Generate code to sample a mipmap level with nearest filtering. */ static void -lp_build_sample_2d_nearest_soa(struct lp_build_sample_context *bld, - LLVMValueRef s, - LLVMValueRef t, - LLVMValueRef width, - LLVMValueRef height, - LLVMValueRef stride, - LLVMValueRef data_array, - LLVMValueRef *texel) +lp_build_sample_image_nearest(struct lp_build_sample_context *bld, + LLVMValueRef width_vec, + LLVMValueRef height_vec, + LLVMValueRef depth_vec, + LLVMValueRef row_stride_vec, + LLVMValueRef img_stride_vec, + LLVMValueRef data_ptr, + LLVMValueRef s, + LLVMValueRef t, + LLVMValueRef r, + LLVMValueRef colors_out[4]) { - LLVMValueRef x, y; - LLVMValueRef data_ptr; + const int dims = texture_dims(bld->static_state->target); + LLVMValueRef x, y, z; - x = lp_build_sample_wrap_nearest(bld, s, width, + /* + * Compute integer texcoords. + */ + x = lp_build_sample_wrap_nearest(bld, s, width_vec, bld->static_state->pot_width, bld->static_state->wrap_s); - y = lp_build_sample_wrap_nearest(bld, t, height, - bld->static_state->pot_height, - bld->static_state->wrap_t); - lp_build_name(x, "tex.x.wrapped"); - lp_build_name(y, "tex.y.wrapped"); - /* get pointer to mipmap level 0 data */ - data_ptr = lp_build_get_const_mipmap_level(bld, data_array, 0); + if (dims >= 2) { + y = lp_build_sample_wrap_nearest(bld, t, height_vec, + bld->static_state->pot_height, + bld->static_state->wrap_t); + lp_build_name(y, "tex.y.wrapped"); + + if (dims == 3) { + z = lp_build_sample_wrap_nearest(bld, r, depth_vec, + bld->static_state->pot_height, + bld->static_state->wrap_r); + lp_build_name(z, "tex.z.wrapped"); + } + else { + z = NULL; + } + } + else { + y = NULL; + } - lp_build_sample_texel_soa(bld, width, height, x, y, stride, data_ptr, texel); + /* + * Get texture colors. + */ + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x, y, z, + row_stride_vec, img_stride_vec, + data_ptr, colors_out); } /** - * Sample 2D texture with nearest filtering, nearest mipmap. + * Generate code to sample a mipmap level with linear filtering. + * 1D, 2D and 3D images are suppored. */ static void -lp_build_sample_2d_nearest_mip_nearest_soa(struct lp_build_sample_context *bld, - unsigned unit, - LLVMValueRef s, - LLVMValueRef t, - LLVMValueRef width, - LLVMValueRef height, - LLVMValueRef width_vec, - LLVMValueRef height_vec, - LLVMValueRef stride, - LLVMValueRef data_array, - LLVMValueRef *texel) +lp_build_sample_image_linear(struct lp_build_sample_context *bld, + LLVMValueRef width_vec, + LLVMValueRef height_vec, + LLVMValueRef depth_vec, + LLVMValueRef row_stride_vec, + LLVMValueRef img_stride_vec, + LLVMValueRef data_ptr, + LLVMValueRef s, + LLVMValueRef t, + LLVMValueRef r, + LLVMValueRef colors_out[4]) { - LLVMValueRef x, y; - LLVMValueRef lod, ilevel, ilevel_vec; - LLVMValueRef data_ptr; - - /* compute float LOD */ - lod = lp_build_lod_selector(bld, s, t, NULL, width, height, NULL); - - /* convert LOD to int */ - lp_build_nearest_mip_level(bld, unit, lod, &ilevel); - - ilevel_vec = lp_build_broadcast_scalar(&bld->int_coord_bld, ilevel); + const int dims = texture_dims(bld->static_state->target); + LLVMValueRef x0, y0, z0, x1, y1, z1; + LLVMValueRef s_fpart, t_fpart, r_fpart; + LLVMValueRef neighbors[2][2][4]; + int chan; - /* compute width_vec, height at mipmap level 'ilevel' */ - width_vec = lp_build_minify(bld, width_vec, ilevel_vec); - height_vec = lp_build_minify(bld, height_vec, ilevel_vec); - stride = lp_build_minify(bld, stride, ilevel_vec); + /* + * Compute integer texcoords. + */ + lp_build_sample_wrap_linear(bld, s, width_vec, + bld->static_state->pot_width, + bld->static_state->wrap_s, + &x0, &x1, &s_fpart); + lp_build_name(x0, "tex.x0.wrapped"); + lp_build_name(x1, "tex.x1.wrapped"); - x = lp_build_sample_wrap_nearest(bld, s, width_vec, - bld->static_state->pot_width, - bld->static_state->wrap_s); - y = lp_build_sample_wrap_nearest(bld, t, height_vec, - bld->static_state->pot_height, - bld->static_state->wrap_t); + if (dims >= 2) { + lp_build_sample_wrap_linear(bld, t, height_vec, + bld->static_state->pot_height, + bld->static_state->wrap_t, + &y0, &y1, &t_fpart); + lp_build_name(y0, "tex.y0.wrapped"); + lp_build_name(y1, "tex.y1.wrapped"); + + if (dims == 3) { + lp_build_sample_wrap_linear(bld, r, depth_vec, + bld->static_state->pot_depth, + bld->static_state->wrap_r, + &z0, &z1, &r_fpart); + lp_build_name(z0, "tex.z0.wrapped"); + lp_build_name(z1, "tex.z1.wrapped"); + } + else { + z0 = z1 = r_fpart = NULL; + } + } + else { + y0 = y1 = t_fpart = NULL; + } - lp_build_name(x, "tex.x.wrapped"); - lp_build_name(y, "tex.y.wrapped"); + /* + * Get texture colors. + */ + /* get x0/x1 texels */ + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x0, y0, z0, + row_stride_vec, img_stride_vec, + data_ptr, neighbors[0][0]); + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x1, y0, z0, + row_stride_vec, img_stride_vec, + data_ptr, neighbors[0][1]); + + if (dims == 1) { + /* Interpolate two samples from 1D image to produce one color */ + colors_out[chan] = lp_build_lerp(&bld->texel_bld, s_fpart, + neighbors[0][0][chan], + neighbors[0][1][chan]); + } + else { + /* 2D/3D texture */ + LLVMValueRef colors0[4]; + + /* get x0/x1 texels at y1 */ + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x0, y1, z0, + row_stride_vec, img_stride_vec, + data_ptr, neighbors[1][0]); + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x1, y1, z0, + row_stride_vec, img_stride_vec, + data_ptr, neighbors[1][1]); + + /* 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]); + } - /* get pointer to mipmap level [ilevel] data */ - data_ptr = lp_build_get_mipmap_level(bld, data_array, ilevel); + if (dims == 3) { + LLVMValueRef neighbors1[2][2][4]; + LLVMValueRef colors1[4]; + + /* get x0/x1/y0/y1 texels at z1 */ + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x0, y0, z1, + row_stride_vec, img_stride_vec, + data_ptr, neighbors1[0][0]); + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x1, y0, z1, + row_stride_vec, img_stride_vec, + data_ptr, neighbors1[0][1]); + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x0, y1, z1, + row_stride_vec, img_stride_vec, + data_ptr, neighbors1[1][0]); + lp_build_sample_texel_soa(bld, width_vec, height_vec, depth_vec, + x1, y1, z1, + row_stride_vec, img_stride_vec, + data_ptr, neighbors1[1][1]); + + /* 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, + s_fpart, t_fpart, + neighbors1[0][0][chan], + neighbors1[0][1][chan], + neighbors1[1][0][chan], + neighbors1[1][1][chan]); + } - lp_build_sample_texel_soa(bld, width_vec, height_vec, x, y, - stride, data_ptr, texel); + /* 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, + r_fpart, + colors0[chan], colors1[chan]); + } + } + else { + /* 2D tex */ + for (chan = 0; chan < 4; chan++) { + colors_out[chan] = colors0[chan]; + } + } + } } + /** - * Sample 2D texture with linear filtering, nearest mipmap. + * General texture sampling codegen. + * This function handles texture sampling for all texture targets (1D, + * 2D, 3D, cube) and all filtering modes. */ static void -lp_build_sample_2d_linear_mip_nearest_soa(struct lp_build_sample_context *bld, - unsigned unit, - LLVMValueRef s, - LLVMValueRef t, - LLVMValueRef width, - LLVMValueRef height, - LLVMValueRef width_vec, - LLVMValueRef height_vec, - LLVMValueRef stride, - LLVMValueRef data_array, - LLVMValueRef *texel) +lp_build_sample_general(struct lp_build_sample_context *bld, + unsigned unit, + LLVMValueRef s, + LLVMValueRef t, + LLVMValueRef r, + LLVMValueRef width, + LLVMValueRef height, + LLVMValueRef depth, + LLVMValueRef width_vec, + LLVMValueRef height_vec, + LLVMValueRef depth_vec, + LLVMValueRef row_stride_vec, + LLVMValueRef img_stride_vec, + LLVMValueRef data_array, + LLVMValueRef *colors_out) { - LLVMValueRef x0, y0, x1, y1, s_fpart, t_fpart; - LLVMValueRef lod, ilevel, ilevel_vec; - LLVMValueRef neighbors[2][2][4]; - LLVMValueRef data_ptr; + const unsigned mip_filter = bld->static_state->min_mip_filter; + const unsigned min_filter = bld->static_state->min_img_filter; + const unsigned mag_filter = bld->static_state->mag_img_filter; + const int dims = texture_dims(bld->static_state->target); + LLVMValueRef lod, lod_fpart; + LLVMValueRef ilevel0, ilevel1, ilevel0_vec, ilevel1_vec; + LLVMValueRef width0_vec, height0_vec, depth0_vec; + LLVMValueRef width1_vec, height1_vec, depth1_vec; + LLVMValueRef row_stride0_vec, row_stride1_vec; + LLVMValueRef img_stride0_vec, img_stride1_vec; + LLVMValueRef data_ptr0, data_ptr1; int chan; - /* compute float LOD */ - lod = lp_build_lod_selector(bld, s, t, NULL, width, height, NULL); - - /* convert LOD to int */ - lp_build_nearest_mip_level(bld, unit, lod, &ilevel); - - ilevel_vec = lp_build_broadcast_scalar(&bld->int_coord_bld, ilevel); + /* + printf("%s mip %d min %d mag %d\n", __FUNCTION__, + mip_filter, min_filter, mag_filter); + */ - /* compute width_vec, height at mipmap level 'ilevel' */ - width_vec = lp_build_minify(bld, width_vec, ilevel_vec); - height_vec = lp_build_minify(bld, height_vec, ilevel_vec); - stride = lp_build_minify(bld, stride, ilevel_vec); + /* + * Compute the level of detail (mipmap level index(es)). + */ + if (mip_filter == PIPE_TEX_MIPFILTER_NONE) { + /* always use mip level 0 */ + ilevel0 = LLVMConstInt(LLVMInt32Type(), 0, 0); + } + else { + /* compute float LOD */ + lod = lp_build_lod_selector(bld, s, t, r, width, height, depth); - lp_build_sample_wrap_linear(bld, s, width_vec, - bld->static_state->pot_width, - bld->static_state->wrap_s, &x0, &x1, &s_fpart); - lp_build_sample_wrap_linear(bld, t, height_vec, - bld->static_state->pot_height, - bld->static_state->wrap_t, &y0, &y1, &t_fpart); + if (mip_filter == PIPE_TEX_MIPFILTER_NEAREST) { + lp_build_nearest_mip_level(bld, unit, lod, &ilevel0); + } + else { + assert(mip_filter == PIPE_TEX_MIPFILTER_LINEAR); + lp_build_linear_mip_levels(bld, unit, lod, &ilevel0, &ilevel1, + &lod_fpart); + lod_fpart = lp_build_broadcast_scalar(&bld->coord_bld, lod_fpart); + } + } - lp_build_name(x0, "tex.x0.wrapped"); - lp_build_name(y0, "tex.y0.wrapped"); - lp_build_name(x1, "tex.x1.wrapped"); - lp_build_name(y1, "tex.y1.wrapped"); + /* + * Convert scalar integer mipmap levels into vectors. + */ + ilevel0_vec = lp_build_broadcast_scalar(&bld->int_coord_bld, ilevel0); + if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) + ilevel1_vec = lp_build_broadcast_scalar(&bld->int_coord_bld, ilevel1); - /* get pointer to mipmap level [ilevel] data */ - data_ptr = lp_build_get_mipmap_level(bld, data_array, ilevel); + /* + * Compute width, height at mipmap level 'ilevel0' + */ + width0_vec = lp_build_minify(bld, width_vec, ilevel0_vec); + if (dims >= 2) { + height0_vec = lp_build_minify(bld, height_vec, ilevel0_vec); + row_stride0_vec = lp_build_minify(bld, row_stride_vec, ilevel0_vec); + if (dims == 3) { + depth0_vec = lp_build_minify(bld, depth_vec, ilevel0_vec); + } + } + if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { + /* compute width, height, depth for second mipmap level at ilevel1 */ + width1_vec = lp_build_minify(bld, width_vec, ilevel1_vec); + if (dims >= 2) { + height1_vec = lp_build_minify(bld, height_vec, ilevel1_vec); + row_stride1_vec = lp_build_minify(bld, row_stride_vec, ilevel1_vec); + if (dims == 3) { + depth1_vec = lp_build_minify(bld, depth_vec, ilevel1_vec); + } + } + } - lp_build_sample_texel_soa(bld, width_vec, height_vec, x0, y0, - stride, data_ptr, neighbors[0][0]); - lp_build_sample_texel_soa(bld, width_vec, height_vec, x1, y0, - stride, data_ptr, neighbors[0][1]); - lp_build_sample_texel_soa(bld, width_vec, height_vec, x0, y1, - stride, data_ptr, neighbors[1][0]); - lp_build_sample_texel_soa(bld, width_vec, height_vec, x1, y1, - stride, data_ptr, neighbors[1][1]); + /* + * Choose cube face, recompute texcoords. + */ + if (bld->static_state->target == PIPE_TEXTURE_CUBE) { - for(chan = 0; chan < 4; ++chan) { - texel[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]); } -} + /* + * Get pointer(s) to image data for mipmap level(s). + */ + data_ptr0 = lp_build_get_mipmap_level(bld, data_array, ilevel0); + if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { + data_ptr1 = lp_build_get_mipmap_level(bld, data_array, ilevel1); + } -/** - * Sample 2D texture with bilinear filtering. - */ -static void -lp_build_sample_2d_linear_soa(struct lp_build_sample_context *bld, - LLVMValueRef s, - LLVMValueRef t, - LLVMValueRef width, - LLVMValueRef height, - LLVMValueRef stride, - LLVMValueRef data_array, - LLVMValueRef *texel) -{ - LLVMValueRef s_fpart; - LLVMValueRef t_fpart; - LLVMValueRef x0, x1; - LLVMValueRef y0, y1; - LLVMValueRef neighbors[2][2][4]; - LLVMValueRef data_ptr; - unsigned chan; + /* + * Get/interpolate texture colors. + */ + /* XXX temporarily force this path: */ + if (1 /*min_filter == mag_filter*/) { + /* same filter for minification or magnification */ + LLVMValueRef colors0[4], colors1[4]; + + if (min_filter == PIPE_TEX_FILTER_NEAREST) { + lp_build_sample_image_nearest(bld, + width0_vec, height0_vec, depth0_vec, + row_stride0_vec, img_stride0_vec, + data_ptr0, s, t, r, colors0); + + if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { + /* sample the second mipmap level, and interp */ + lp_build_sample_image_nearest(bld, + width1_vec, height1_vec, depth1_vec, + row_stride1_vec, img_stride1_vec, + data_ptr1, s, t, r, colors1); + } + } + else { + assert(min_filter == PIPE_TEX_FILTER_LINEAR); - lp_build_sample_wrap_linear(bld, s, width, bld->static_state->pot_width, - bld->static_state->wrap_s, &x0, &x1, &s_fpart); - lp_build_sample_wrap_linear(bld, t, height, bld->static_state->pot_height, - bld->static_state->wrap_t, &y0, &y1, &t_fpart); + lp_build_sample_image_linear(bld, + width0_vec, height0_vec, depth0_vec, + row_stride0_vec, img_stride0_vec, + data_ptr0, s, t, r, colors0); - /* get pointer to mipmap level 0 data */ - data_ptr = lp_build_get_const_mipmap_level(bld, data_array, 0); - lp_build_sample_texel_soa(bld, width, height, x0, y0, stride, data_ptr, neighbors[0][0]); - lp_build_sample_texel_soa(bld, width, height, x1, y0, stride, data_ptr, neighbors[0][1]); - lp_build_sample_texel_soa(bld, width, height, x0, y1, stride, data_ptr, neighbors[1][0]); - lp_build_sample_texel_soa(bld, width, height, x1, y1, stride, data_ptr, neighbors[1][1]); + if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { + /* sample the second mipmap level, and interp */ + lp_build_sample_image_linear(bld, + width1_vec, height1_vec, depth1_vec, + row_stride1_vec, img_stride1_vec, + data_ptr1, s, t, r, colors1); + } + } - /* TODO: Don't interpolate missing channels */ - for(chan = 0; chan < 4; ++chan) { - texel[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]); + if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { + /* interpolate samples from the two mipmap levels */ + for (chan = 0; chan < 4; chan++) { + colors_out[chan] = lp_build_lerp(&bld->texel_bld, lod_fpart, + colors0[chan], colors1[chan]); + } + } + else { + /* use first/only level's colors */ + for (chan = 0; chan < 4; chan++) { + colors_out[chan] = colors0[chan]; + } + } + } + else { + /* emit conditional to choose min image filter or mag image filter + * depending on the lod being >0 or <= 0, respectively. + */ + abort(); } } + static void lp_build_rgba8_to_f32_soa(LLVMBuilderRef builder, struct lp_type dst_type, @@ -1426,12 +1624,12 @@ lp_build_sample_soa(LLVMBuilderRef builder, struct lp_build_sample_context bld; LLVMValueRef width, width_vec; LLVMValueRef height, height_vec; + LLVMValueRef depth, depth_vec; LLVMValueRef stride, stride_vec; LLVMValueRef data_array; LLVMValueRef s; LLVMValueRef t; LLVMValueRef r; - boolean done = FALSE; (void) lp_build_lod_selector; /* temporary to silence warning */ (void) lp_build_nearest_mip_level; @@ -1462,6 +1660,7 @@ lp_build_sample_soa(LLVMBuilderRef builder, /* Get the dynamic state */ width = dynamic_state->width(dynamic_state, builder, unit); height = dynamic_state->height(dynamic_state, builder, unit); + depth = dynamic_state->depth(dynamic_state, builder, unit); stride = dynamic_state->stride(dynamic_state, builder, unit); data_array = dynamic_state->data_ptr(dynamic_state, builder, unit); /* Note that data_array is an array[level] of pointers to texture images */ @@ -1472,67 +1671,26 @@ lp_build_sample_soa(LLVMBuilderRef builder, width_vec = lp_build_broadcast_scalar(&bld.uint_coord_bld, width); height_vec = lp_build_broadcast_scalar(&bld.uint_coord_bld, height); + depth_vec = lp_build_broadcast_scalar(&bld.uint_coord_bld, depth); stride_vec = lp_build_broadcast_scalar(&bld.uint_coord_bld, stride); - if(static_state->target == PIPE_TEXTURE_1D) - t = bld.coord_bld.zero; - - switch (static_state->min_mip_filter) { - case PIPE_TEX_MIPFILTER_NONE: - break; - case PIPE_TEX_MIPFILTER_NEAREST: - - switch (static_state->min_img_filter) { - case PIPE_TEX_FILTER_LINEAR: - lp_build_sample_2d_linear_mip_nearest_soa(&bld, unit, - s, t, - width, height, - width_vec, height_vec, - stride_vec, - data_array, texel); - done = TRUE; - break; - case PIPE_TEX_FILTER_NEAREST: - lp_build_sample_2d_nearest_mip_nearest_soa(&bld, unit, - s, t, - width, height, - width_vec, height_vec, - stride_vec, - data_array, texel); - done = TRUE; - break; - } - - break; - case PIPE_TEX_MIPFILTER_LINEAR: - break; - default: - assert(0 && "invalid mip filter"); + if (lp_format_is_rgba8(bld.format_desc) && + static_state->min_img_filter == PIPE_TEX_FILTER_LINEAR && + static_state->mag_img_filter == PIPE_TEX_FILTER_LINEAR && + static_state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE && + is_simple_wrap_mode(static_state->wrap_s) && + is_simple_wrap_mode(static_state->wrap_t)) { + /* special case */ + lp_build_sample_2d_linear_aos(&bld, s, t, width_vec, height_vec, + stride_vec, data_array, texel); } - - if (!done) { - switch (static_state->min_img_filter) { - case PIPE_TEX_FILTER_NEAREST: - lp_build_sample_2d_nearest_soa(&bld, s, t, width_vec, height_vec, - stride_vec, data_array, texel); - break; - case PIPE_TEX_FILTER_LINEAR: - if(lp_format_is_rgba8(bld.format_desc) && - is_simple_wrap_mode(static_state->wrap_s) && - is_simple_wrap_mode(static_state->wrap_t)) - lp_build_sample_2d_linear_aos(&bld, s, t, width_vec, height_vec, - stride_vec, data_array, texel); - else - lp_build_sample_2d_linear_soa(&bld, s, t, width_vec, height_vec, - stride_vec, data_array, texel); - break; - default: - assert(0); - } + else { + lp_build_sample_general(&bld, unit, s, t, r, + width, height, depth, + width_vec, height_vec, depth_vec, + stride_vec, NULL, data_array, + texel); } - /* FIXME: respect static_state->min_mip_filter */; - /* FIXME: respect static_state->mag_img_filter */; - lp_build_sample_compare(&bld, r, texel); } -- 2.30.2