123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 |
- /**************************************************************************
- *
- * Copyright 2009 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
- /**
- * @file
- * Texture sampling -- common code.
- *
- * @author Jose Fonseca <jfonseca@vmware.com>
- */
-
- #include "pipe/p_defines.h"
- #include "pipe/p_state.h"
- #include "util/u_format.h"
- #include "util/u_math.h"
- #include "lp_bld_arit.h"
- #include "lp_bld_const.h"
- #include "lp_bld_debug.h"
- #include "lp_bld_flow.h"
- #include "lp_bld_sample.h"
- #include "lp_bld_swizzle.h"
- #include "lp_bld_type.h"
-
-
- /**
- * Does the given texture wrap mode allow sampling the texture border color?
- * XXX maybe move this into gallium util code.
- */
- boolean
- lp_sampler_wrap_mode_uses_border_color(unsigned mode,
- unsigned min_img_filter,
- unsigned mag_img_filter)
- {
- switch (mode) {
- case PIPE_TEX_WRAP_REPEAT:
- case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
- case PIPE_TEX_WRAP_MIRROR_REPEAT:
- case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
- return FALSE;
- case PIPE_TEX_WRAP_CLAMP:
- case PIPE_TEX_WRAP_MIRROR_CLAMP:
- if (min_img_filter == PIPE_TEX_FILTER_NEAREST &&
- mag_img_filter == PIPE_TEX_FILTER_NEAREST) {
- return FALSE;
- } else {
- return TRUE;
- }
- case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
- case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
- return TRUE;
- default:
- assert(0 && "unexpected wrap mode");
- return FALSE;
- }
- }
-
-
- /**
- * Initialize lp_sampler_static_state object with the gallium sampler
- * and texture state.
- * The former is considered to be static and the later dynamic.
- */
- void
- lp_sampler_static_state(struct lp_sampler_static_state *state,
- const struct pipe_sampler_view *view,
- const struct pipe_sampler_state *sampler)
- {
- const struct pipe_resource *texture = view->texture;
-
- memset(state, 0, sizeof *state);
-
- if(!texture)
- return;
-
- if(!sampler)
- return;
-
- /*
- * We don't copy sampler state over unless it is actually enabled, to avoid
- * spurious recompiles, as the sampler static state is part of the shader
- * key.
- *
- * Ideally the state tracker or cso_cache module would make all state
- * canonical, but until that happens it's better to be safe than sorry here.
- *
- * XXX: Actually there's much more than can be done here, especially
- * regarding 1D/2D/3D/CUBE textures, wrap modes, etc.
- */
-
- state->format = view->format;
- state->swizzle_r = view->swizzle_r;
- state->swizzle_g = view->swizzle_g;
- state->swizzle_b = view->swizzle_b;
- state->swizzle_a = view->swizzle_a;
-
- state->target = texture->target;
- state->pot_width = util_is_power_of_two(texture->width0);
- state->pot_height = util_is_power_of_two(texture->height0);
- state->pot_depth = util_is_power_of_two(texture->depth0);
-
- state->wrap_s = sampler->wrap_s;
- state->wrap_t = sampler->wrap_t;
- state->wrap_r = sampler->wrap_r;
- state->min_img_filter = sampler->min_img_filter;
- state->mag_img_filter = sampler->mag_img_filter;
- if (view->last_level) {
- state->min_mip_filter = sampler->min_mip_filter;
- } else {
- state->min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
- }
-
- /* If min_lod == max_lod we can greatly simplify mipmap selection.
- * This is a case that occurs during automatic mipmap generation.
- */
- if (sampler->min_lod == sampler->max_lod) {
- state->min_max_lod_equal = 1;
- }
-
- state->compare_mode = sampler->compare_mode;
- if (sampler->compare_mode != PIPE_TEX_COMPARE_NONE) {
- state->compare_func = sampler->compare_func;
- }
-
- state->normalized_coords = sampler->normalized_coords;
-
- /*
- * FIXME: Handle the remainder of pipe_sampler_view.
- */
- }
-
-
- /**
- * Generate code to compute texture level of detail (lambda).
- * \param ddx partial derivatives of (s, t, r, q) with respect to X
- * \param ddy partial derivatives of (s, t, r, q) with respect to 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
- *
- * XXX: The resulting lod is scalar, so ignore all but the first element of
- * derivatives, lod_bias, etc that are passed by the shader.
- */
- LLVMValueRef
- lp_build_lod_selector(struct lp_build_sample_context *bld,
- unsigned unit,
- const LLVMValueRef ddx[4],
- const LLVMValueRef ddy[4],
- LLVMValueRef lod_bias, /* optional */
- LLVMValueRef explicit_lod, /* optional */
- LLVMValueRef width,
- LLVMValueRef height,
- LLVMValueRef depth)
-
- {
- LLVMValueRef min_lod =
- bld->dynamic_state->min_lod(bld->dynamic_state, bld->builder, unit);
-
- if (bld->static_state->min_max_lod_equal) {
- /* User is forcing sampling from a particular mipmap level.
- * This is hit during mipmap generation.
- */
- return min_lod;
- }
- else {
- struct lp_build_context *float_bld = &bld->float_bld;
- LLVMValueRef sampler_lod_bias =
- bld->dynamic_state->lod_bias(bld->dynamic_state, bld->builder, unit);
- LLVMValueRef max_lod =
- bld->dynamic_state->max_lod(bld->dynamic_state, bld->builder, unit);
- LLVMValueRef index0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
- LLVMValueRef lod;
-
- if (explicit_lod) {
- lod = LLVMBuildExtractElement(bld->builder, explicit_lod,
- index0, "");
- }
- else {
- const int dims = texture_dims(bld->static_state->target);
- LLVMValueRef dsdx, dsdy;
- LLVMValueRef dtdx = NULL, dtdy = NULL, drdx = NULL, drdy = NULL;
- LLVMValueRef rho;
-
- dsdx = LLVMBuildExtractElement(bld->builder, ddx[0], index0, "dsdx");
- dsdx = lp_build_abs(float_bld, dsdx);
- dsdy = LLVMBuildExtractElement(bld->builder, ddy[0], index0, "dsdy");
- dsdy = lp_build_abs(float_bld, dsdy);
- if (dims > 1) {
- dtdx = LLVMBuildExtractElement(bld->builder, ddx[1], index0, "dtdx");
- dtdx = lp_build_abs(float_bld, dtdx);
- dtdy = LLVMBuildExtractElement(bld->builder, ddy[1], index0, "dtdy");
- dtdy = lp_build_abs(float_bld, dtdy);
- if (dims > 2) {
- drdx = LLVMBuildExtractElement(bld->builder, ddx[2], index0, "drdx");
- drdx = lp_build_abs(float_bld, drdx);
- drdy = LLVMBuildExtractElement(bld->builder, ddy[2], index0, "drdy");
- drdy = lp_build_abs(float_bld, drdy);
- }
- }
-
- /* Compute rho = max of all partial derivatives scaled by texture size.
- * XXX this could be vectorized somewhat
- */
- rho = LLVMBuildFMul(bld->builder,
- lp_build_max(float_bld, dsdx, dsdy),
- lp_build_int_to_float(float_bld, width), "");
- if (dims > 1) {
- LLVMValueRef max;
- max = LLVMBuildFMul(bld->builder,
- lp_build_max(float_bld, dtdx, dtdy),
- lp_build_int_to_float(float_bld, height), "");
- rho = lp_build_max(float_bld, rho, max);
- if (dims > 2) {
- max = LLVMBuildFMul(bld->builder,
- lp_build_max(float_bld, drdx, drdy),
- lp_build_int_to_float(float_bld, depth), "");
- rho = lp_build_max(float_bld, rho, max);
- }
- }
-
- /* compute lod = log2(rho) */
- lod = lp_build_log2(float_bld, rho);
-
- /* add shader lod bias */
- if (lod_bias) {
- lod_bias = LLVMBuildExtractElement(bld->builder, lod_bias,
- index0, "");
- lod = LLVMBuildFAdd(bld->builder, lod, lod_bias, "shader_lod_bias");
- }
- }
-
- /* add sampler lod bias */
- lod = LLVMBuildFAdd(bld->builder, lod, sampler_lod_bias, "sampler_lod_bias");
-
- /* clamp lod */
- lod = lp_build_clamp(float_bld, lod, min_lod, max_lod);
-
- return lod;
- }
- }
-
-
- /**
- * For PIPE_TEX_MIPFILTER_NEAREST, convert float LOD to integer
- * mipmap level index.
- * Note: this is all scalar code.
- * \param lod scalar float texture level of detail
- * \param level_out returns integer
- */
- void
- lp_build_nearest_mip_level(struct lp_build_sample_context *bld,
- unsigned unit,
- LLVMValueRef lod,
- LLVMValueRef *level_out)
- {
- struct lp_build_context *float_bld = &bld->float_bld;
- struct lp_build_context *int_bld = &bld->int_bld;
- LLVMValueRef last_level, level;
-
- LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, 0);
-
- last_level = bld->dynamic_state->last_level(bld->dynamic_state,
- bld->builder, unit);
-
- /* convert float lod to integer */
- level = lp_build_iround(float_bld, lod);
-
- /* clamp level to legal range of levels */
- *level_out = lp_build_clamp(int_bld, level, zero, last_level);
- }
-
-
- /**
- * For PIPE_TEX_MIPFILTER_LINEAR, convert float LOD to integer to
- * two (adjacent) mipmap level indexes. Later, we'll sample from those
- * two mipmap levels and interpolate between them.
- */
- void
- lp_build_linear_mip_levels(struct lp_build_sample_context *bld,
- unsigned unit,
- LLVMValueRef lod,
- LLVMValueRef *level0_out,
- LLVMValueRef *level1_out,
- LLVMValueRef *weight_out)
- {
- 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(float_bld, lod);
-
- /* compute level 0 and clamp to legal range of levels */
- *level0_out = lp_build_clamp(int_bld, level,
- int_bld->zero,
- last_level);
- /* compute level 1 and clamp to legal range of levels */
- level = lp_build_add(int_bld, level, int_bld->one);
- *level1_out = lp_build_clamp(int_bld, level,
- int_bld->zero,
- last_level);
-
- *weight_out = lp_build_fract(float_bld, lod);
- }
-
-
- /**
- * Return pointer to a single mipmap level.
- * \param data_array array of pointers to mipmap levels
- * \param level integer mipmap level
- */
- LLVMValueRef
- lp_build_get_mipmap_level(struct lp_build_sample_context *bld,
- LLVMValueRef data_array, LLVMValueRef level)
- {
- LLVMValueRef indexes[2], data_ptr;
- indexes[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
- indexes[1] = level;
- data_ptr = LLVMBuildGEP(bld->builder, data_array, indexes, 2, "");
- data_ptr = LLVMBuildLoad(bld->builder, data_ptr, "");
- return data_ptr;
- }
-
-
- LLVMValueRef
- lp_build_get_const_mipmap_level(struct lp_build_sample_context *bld,
- LLVMValueRef data_array, int level)
- {
- LLVMValueRef lvl = LLVMConstInt(LLVMInt32Type(), level, 0);
- return lp_build_get_mipmap_level(bld, data_array, lvl);
- }
-
-
- /**
- * Codegen equivalent for u_minify().
- * Return max(1, base_size >> level);
- */
- static LLVMValueRef
- lp_build_minify(struct lp_build_sample_context *bld,
- LLVMValueRef base_size,
- LLVMValueRef level)
- {
- if (level == bld->int_coord_bld.zero) {
- /* if we're using mipmap level zero, no minification is needed */
- return base_size;
- }
- else {
- LLVMValueRef size =
- LLVMBuildLShr(bld->builder, base_size, level, "minify");
- size = lp_build_max(&bld->int_coord_bld, size, bld->int_coord_bld.one);
- return size;
- }
- }
-
-
- /**
- * Dereference stride_array[mipmap_level] array to get a stride.
- * Return stride as a vector.
- */
- static LLVMValueRef
- lp_build_get_level_stride_vec(struct lp_build_sample_context *bld,
- LLVMValueRef stride_array, LLVMValueRef level)
- {
- LLVMValueRef indexes[2], stride;
- indexes[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
- indexes[1] = level;
- stride = LLVMBuildGEP(bld->builder, stride_array, indexes, 2, "");
- stride = LLVMBuildLoad(bld->builder, stride, "");
- stride = lp_build_broadcast_scalar(&bld->int_coord_bld, stride);
- return stride;
- }
-
-
- /**
- * When sampling a mipmap, we need to compute the width, height, depth
- * of the source levels from the level indexes. This helper function
- * does that.
- */
- void
- lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
- unsigned dims,
- LLVMValueRef width_vec,
- LLVMValueRef height_vec,
- LLVMValueRef depth_vec,
- LLVMValueRef ilevel0,
- LLVMValueRef ilevel1,
- LLVMValueRef row_stride_array,
- LLVMValueRef img_stride_array,
- LLVMValueRef *width0_vec,
- LLVMValueRef *width1_vec,
- LLVMValueRef *height0_vec,
- LLVMValueRef *height1_vec,
- LLVMValueRef *depth0_vec,
- LLVMValueRef *depth1_vec,
- LLVMValueRef *row_stride0_vec,
- LLVMValueRef *row_stride1_vec,
- LLVMValueRef *img_stride0_vec,
- LLVMValueRef *img_stride1_vec)
- {
- const unsigned mip_filter = bld->static_state->min_mip_filter;
- LLVMValueRef ilevel0_vec, ilevel1_vec;
-
- 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);
-
- /*
- * Compute width, height, depth 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_get_level_stride_vec(bld,
- row_stride_array,
- ilevel0);
- if (dims == 3 || bld->static_state->target == PIPE_TEXTURE_CUBE) {
- *img_stride0_vec = lp_build_get_level_stride_vec(bld,
- img_stride_array,
- ilevel0);
- 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_get_level_stride_vec(bld,
- row_stride_array,
- ilevel1);
- if (dims == 3 || bld->static_state->target == PIPE_TEXTURE_CUBE) {
- *img_stride1_vec = lp_build_get_level_stride_vec(bld,
- img_stride_array,
- ilevel1);
- if (dims == 3) {
- *depth1_vec = lp_build_minify(bld, depth_vec, ilevel1_vec);
- }
- }
- }
- }
- }
-
-
-
- /** Helper used by lp_build_cube_lookup() */
- static LLVMValueRef
- lp_build_cube_ima(struct lp_build_context *coord_bld, LLVMValueRef coord)
- {
- /* ima = -0.5 / abs(coord); */
- LLVMValueRef negHalf = lp_build_const_vec(coord_bld->type, -0.5);
- LLVMValueRef absCoord = lp_build_abs(coord_bld, coord);
- LLVMValueRef ima = lp_build_div(coord_bld, negHalf, absCoord);
- return ima;
- }
-
-
- /**
- * Helper used by lp_build_cube_lookup()
- * \param sign scalar +1 or -1
- * \param coord float vector
- * \param ima float vector
- */
- static LLVMValueRef
- lp_build_cube_coord(struct lp_build_context *coord_bld,
- LLVMValueRef sign, int negate_coord,
- LLVMValueRef coord, LLVMValueRef ima)
- {
- /* return negate(coord) * ima * sign + 0.5; */
- LLVMValueRef half = lp_build_const_vec(coord_bld->type, 0.5);
- LLVMValueRef res;
-
- assert(negate_coord == +1 || negate_coord == -1);
-
- if (negate_coord == -1) {
- coord = lp_build_negate(coord_bld, coord);
- }
-
- res = lp_build_mul(coord_bld, coord, ima);
- if (sign) {
- sign = lp_build_broadcast_scalar(coord_bld, sign);
- res = lp_build_mul(coord_bld, res, sign);
- }
- res = lp_build_add(coord_bld, res, half);
-
- return res;
- }
-
-
- /** Helper used by lp_build_cube_lookup()
- * Return (major_coord >= 0) ? pos_face : neg_face;
- */
- static LLVMValueRef
- lp_build_cube_face(struct lp_build_sample_context *bld,
- LLVMValueRef major_coord,
- unsigned pos_face, unsigned neg_face)
- {
- LLVMValueRef cmp = LLVMBuildFCmp(bld->builder, LLVMRealUGE,
- major_coord,
- bld->float_bld.zero, "");
- LLVMValueRef pos = LLVMConstInt(LLVMInt32Type(), pos_face, 0);
- LLVMValueRef neg = LLVMConstInt(LLVMInt32Type(), neg_face, 0);
- LLVMValueRef res = LLVMBuildSelect(bld->builder, cmp, pos, neg, "");
- return res;
- }
-
-
-
- /**
- * Generate code to do cube face selection and compute per-face texcoords.
- */
- void
- lp_build_cube_lookup(struct lp_build_sample_context *bld,
- LLVMValueRef s,
- LLVMValueRef t,
- LLVMValueRef r,
- LLVMValueRef *face,
- LLVMValueRef *face_s,
- LLVMValueRef *face_t)
- {
- struct lp_build_context *float_bld = &bld->float_bld;
- struct lp_build_context *coord_bld = &bld->coord_bld;
- LLVMValueRef rx, ry, rz;
- LLVMValueRef arx, ary, arz;
- LLVMValueRef c25 = LLVMConstReal(LLVMFloatType(), 0.25);
- LLVMValueRef arx_ge_ary, arx_ge_arz;
- LLVMValueRef ary_ge_arx, ary_ge_arz;
- LLVMValueRef arx_ge_ary_arz, ary_ge_arx_arz;
- LLVMValueRef rx_pos, ry_pos, rz_pos;
-
- assert(bld->coord_bld.type.length == 4);
-
- /*
- * Use the average of the four pixel's texcoords to choose the face.
- */
- rx = lp_build_mul(float_bld, c25,
- lp_build_sum_vector(&bld->coord_bld, s));
- ry = lp_build_mul(float_bld, c25,
- lp_build_sum_vector(&bld->coord_bld, t));
- rz = lp_build_mul(float_bld, c25,
- lp_build_sum_vector(&bld->coord_bld, r));
-
- arx = lp_build_abs(float_bld, rx);
- ary = lp_build_abs(float_bld, ry);
- arz = lp_build_abs(float_bld, rz);
-
- /*
- * Compare sign/magnitude of rx,ry,rz to determine face
- */
- arx_ge_ary = LLVMBuildFCmp(bld->builder, LLVMRealUGE, arx, ary, "");
- arx_ge_arz = LLVMBuildFCmp(bld->builder, LLVMRealUGE, arx, arz, "");
- ary_ge_arx = LLVMBuildFCmp(bld->builder, LLVMRealUGE, ary, arx, "");
- ary_ge_arz = LLVMBuildFCmp(bld->builder, LLVMRealUGE, ary, arz, "");
-
- arx_ge_ary_arz = LLVMBuildAnd(bld->builder, arx_ge_ary, arx_ge_arz, "");
- ary_ge_arx_arz = LLVMBuildAnd(bld->builder, ary_ge_arx, ary_ge_arz, "");
-
- rx_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, rx, float_bld->zero, "");
- ry_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, ry, float_bld->zero, "");
- rz_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, rz, float_bld->zero, "");
-
- {
- struct lp_build_flow_context *flow_ctx;
- struct lp_build_if_state if_ctx;
-
- flow_ctx = lp_build_flow_create(bld->builder);
- lp_build_flow_scope_begin(flow_ctx);
-
- *face_s = bld->coord_bld.undef;
- *face_t = bld->coord_bld.undef;
- *face = bld->int_bld.undef;
-
- lp_build_name(*face_s, "face_s");
- lp_build_name(*face_t, "face_t");
- lp_build_name(*face, "face");
-
- lp_build_flow_scope_declare(flow_ctx, face_s);
- lp_build_flow_scope_declare(flow_ctx, face_t);
- lp_build_flow_scope_declare(flow_ctx, face);
-
- lp_build_if(&if_ctx, flow_ctx, bld->builder, arx_ge_ary_arz);
- {
- /* +/- X face */
- LLVMValueRef sign = lp_build_sgn(float_bld, rx);
- LLVMValueRef ima = lp_build_cube_ima(coord_bld, s);
- *face_s = lp_build_cube_coord(coord_bld, sign, +1, r, ima);
- *face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
- *face = lp_build_cube_face(bld, rx,
- PIPE_TEX_FACE_POS_X,
- PIPE_TEX_FACE_NEG_X);
- }
- lp_build_else(&if_ctx);
- {
- struct lp_build_flow_context *flow_ctx2;
- struct lp_build_if_state if_ctx2;
-
- LLVMValueRef face_s2 = bld->coord_bld.undef;
- LLVMValueRef face_t2 = bld->coord_bld.undef;
- LLVMValueRef face2 = bld->int_bld.undef;
-
- flow_ctx2 = lp_build_flow_create(bld->builder);
- lp_build_flow_scope_begin(flow_ctx2);
- lp_build_flow_scope_declare(flow_ctx2, &face_s2);
- lp_build_flow_scope_declare(flow_ctx2, &face_t2);
- lp_build_flow_scope_declare(flow_ctx2, &face2);
-
- ary_ge_arx_arz = LLVMBuildAnd(bld->builder, ary_ge_arx, ary_ge_arz, "");
-
- lp_build_if(&if_ctx2, flow_ctx2, bld->builder, ary_ge_arx_arz);
- {
- /* +/- Y face */
- LLVMValueRef sign = lp_build_sgn(float_bld, ry);
- LLVMValueRef ima = lp_build_cube_ima(coord_bld, t);
- face_s2 = lp_build_cube_coord(coord_bld, NULL, -1, s, ima);
- face_t2 = lp_build_cube_coord(coord_bld, sign, -1, r, ima);
- face2 = lp_build_cube_face(bld, ry,
- PIPE_TEX_FACE_POS_Y,
- PIPE_TEX_FACE_NEG_Y);
- }
- lp_build_else(&if_ctx2);
- {
- /* +/- Z face */
- LLVMValueRef sign = lp_build_sgn(float_bld, rz);
- LLVMValueRef ima = lp_build_cube_ima(coord_bld, r);
- face_s2 = lp_build_cube_coord(coord_bld, sign, -1, s, ima);
- face_t2 = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
- face2 = lp_build_cube_face(bld, rz,
- PIPE_TEX_FACE_POS_Z,
- PIPE_TEX_FACE_NEG_Z);
- }
- lp_build_endif(&if_ctx2);
- lp_build_flow_scope_end(flow_ctx2);
- lp_build_flow_destroy(flow_ctx2);
- *face_s = face_s2;
- *face_t = face_t2;
- *face = face2;
- }
-
- lp_build_endif(&if_ctx);
- lp_build_flow_scope_end(flow_ctx);
- lp_build_flow_destroy(flow_ctx);
- }
- }
-
-
- /**
- * Compute the partial offset of a pixel block along an arbitrary axis.
- *
- * @param coord coordinate in pixels
- * @param stride number of bytes between rows of successive pixel blocks
- * @param block_length number of pixels in a pixels block along the coordinate
- * axis
- * @param out_offset resulting relative offset of the pixel block in bytes
- * @param out_subcoord resulting sub-block pixel coordinate
- */
- void
- lp_build_sample_partial_offset(struct lp_build_context *bld,
- unsigned block_length,
- LLVMValueRef coord,
- LLVMValueRef stride,
- LLVMValueRef *out_offset,
- LLVMValueRef *out_subcoord)
- {
- LLVMValueRef offset;
- LLVMValueRef subcoord;
-
- if (block_length == 1) {
- subcoord = bld->zero;
- }
- else {
- /*
- * Pixel blocks have power of two dimensions. LLVM should convert the
- * rem/div to bit arithmetic.
- * TODO: Verify this.
- * It does indeed BUT it does transform it to scalar (and back) when doing so
- * (using roughly extract, shift/and, mov, unpack) (llvm 2.7).
- * The generated code looks seriously unfunny and is quite expensive.
- */
- #if 0
- LLVMValueRef block_width = lp_build_const_int_vec(bld->type, block_length);
- subcoord = LLVMBuildURem(bld->builder, coord, block_width, "");
- coord = LLVMBuildUDiv(bld->builder, coord, block_width, "");
- #else
- unsigned logbase2 = util_unsigned_logbase2(block_length);
- LLVMValueRef block_shift = lp_build_const_int_vec(bld->type, logbase2);
- LLVMValueRef block_mask = lp_build_const_int_vec(bld->type, block_length - 1);
- subcoord = LLVMBuildAnd(bld->builder, coord, block_mask, "");
- coord = LLVMBuildLShr(bld->builder, coord, block_shift, "");
- #endif
- }
-
- offset = lp_build_mul(bld, coord, stride);
-
- assert(out_offset);
- assert(out_subcoord);
-
- *out_offset = offset;
- *out_subcoord = subcoord;
- }
-
-
- /**
- * Compute the offset of a pixel block.
- *
- * x, y, z, y_stride, z_stride are vectors, and they refer to pixels.
- *
- * Returns the relative offset and i,j sub-block coordinates
- */
- void
- lp_build_sample_offset(struct lp_build_context *bld,
- const struct util_format_description *format_desc,
- LLVMValueRef x,
- LLVMValueRef y,
- LLVMValueRef z,
- LLVMValueRef y_stride,
- LLVMValueRef z_stride,
- LLVMValueRef *out_offset,
- LLVMValueRef *out_i,
- LLVMValueRef *out_j)
- {
- LLVMValueRef x_stride;
- LLVMValueRef offset;
-
- x_stride = lp_build_const_vec(bld->type, format_desc->block.bits/8);
-
- lp_build_sample_partial_offset(bld,
- format_desc->block.width,
- x, x_stride,
- &offset, out_i);
-
- if (y && y_stride) {
- LLVMValueRef y_offset;
- lp_build_sample_partial_offset(bld,
- format_desc->block.height,
- y, y_stride,
- &y_offset, out_j);
- offset = lp_build_add(bld, offset, y_offset);
- }
- else {
- *out_j = bld->zero;
- }
-
- if (z && z_stride) {
- LLVMValueRef z_offset;
- LLVMValueRef k;
- lp_build_sample_partial_offset(bld,
- 1, /* pixel blocks are always 2D */
- z, z_stride,
- &z_offset, &k);
- offset = lp_build_add(bld, offset, z_offset);
- }
-
- *out_offset = offset;
- }
|