gallivm: don't use URem/UDiv when calculating offsets for blocks
[profile/ivi/mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_sample.c
1 /**************************************************************************
2  *
3  * Copyright 2009 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27
28 /**
29  * @file
30  * Texture sampling -- common code.
31  *
32  * @author Jose Fonseca <jfonseca@vmware.com>
33  */
34
35 #include "pipe/p_defines.h"
36 #include "pipe/p_state.h"
37 #include "util/u_format.h"
38 #include "util/u_math.h"
39 #include "lp_bld_arit.h"
40 #include "lp_bld_const.h"
41 #include "lp_bld_debug.h"
42 #include "lp_bld_flow.h"
43 #include "lp_bld_sample.h"
44 #include "lp_bld_swizzle.h"
45 #include "lp_bld_type.h"
46
47
48 /**
49  * Initialize lp_sampler_static_state object with the gallium sampler
50  * and texture state.
51  * The former is considered to be static and the later dynamic.
52  */
53 void
54 lp_sampler_static_state(struct lp_sampler_static_state *state,
55                         const struct pipe_sampler_view *view,
56                         const struct pipe_sampler_state *sampler)
57 {
58    const struct pipe_resource *texture = view->texture;
59
60    memset(state, 0, sizeof *state);
61
62    if(!texture)
63       return;
64
65    if(!sampler)
66       return;
67
68    /*
69     * We don't copy sampler state over unless it is actually enabled, to avoid
70     * spurious recompiles, as the sampler static state is part of the shader
71     * key.
72     *
73     * Ideally the state tracker or cso_cache module would make all state
74     * canonical, but until that happens it's better to be safe than sorry here.
75     *
76     * XXX: Actually there's much more than can be done here, especially
77     * regarding 1D/2D/3D/CUBE textures, wrap modes, etc.
78     */
79
80    state->format            = view->format;
81    state->swizzle_r         = view->swizzle_r;
82    state->swizzle_g         = view->swizzle_g;
83    state->swizzle_b         = view->swizzle_b;
84    state->swizzle_a         = view->swizzle_a;
85
86    state->target            = texture->target;
87    state->pot_width         = util_is_power_of_two(texture->width0);
88    state->pot_height        = util_is_power_of_two(texture->height0);
89    state->pot_depth         = util_is_power_of_two(texture->depth0);
90
91    state->wrap_s            = sampler->wrap_s;
92    state->wrap_t            = sampler->wrap_t;
93    state->wrap_r            = sampler->wrap_r;
94    state->min_img_filter    = sampler->min_img_filter;
95    state->mag_img_filter    = sampler->mag_img_filter;
96    if (view->last_level) {
97       state->min_mip_filter = sampler->min_mip_filter;
98    } else {
99       state->min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
100    }
101
102    /* If min_lod == max_lod we can greatly simplify mipmap selection.
103     * This is a case that occurs during automatic mipmap generation.
104     */
105    if (sampler->min_lod == sampler->max_lod) {
106       state->min_max_lod_equal = 1;
107       state->min_max_lod = sampler->min_lod;
108    }
109
110    state->compare_mode      = sampler->compare_mode;
111    if (sampler->compare_mode != PIPE_TEX_COMPARE_NONE) {
112       state->compare_func   = sampler->compare_func;
113    }
114
115    state->normalized_coords = sampler->normalized_coords;
116
117    /*
118     * FIXME: Handle the remainder of pipe_sampler_view.
119     */
120 }
121
122
123 /**
124  * Generate code to compute texture level of detail (lambda).
125  * \param ddx  partial derivatives of (s, t, r, q) with respect to X
126  * \param ddy  partial derivatives of (s, t, r, q) with respect to Y
127  * \param lod_bias  optional float vector with the shader lod bias
128  * \param explicit_lod  optional float vector with the explicit lod
129  * \param width  scalar int texture width
130  * \param height  scalar int texture height
131  * \param depth  scalar int texture depth
132  *
133  * XXX: The resulting lod is scalar, so ignore all but the first element of
134  * derivatives, lod_bias, etc that are passed by the shader.
135  */
136 LLVMValueRef
137 lp_build_lod_selector(struct lp_build_sample_context *bld,
138                       unsigned unit,
139                       const LLVMValueRef ddx[4],
140                       const LLVMValueRef ddy[4],
141                       LLVMValueRef lod_bias, /* optional */
142                       LLVMValueRef explicit_lod, /* optional */
143                       LLVMValueRef width,
144                       LLVMValueRef height,
145                       LLVMValueRef depth)
146
147 {
148    if (bld->static_state->min_max_lod_equal) {
149       /* User is forcing sampling from a particular mipmap level.
150        * This is hit during mipmap generation.
151        */
152       return LLVMConstReal(LLVMFloatType(), bld->static_state->min_max_lod);
153    }
154    else {
155       struct lp_build_context *float_bld = &bld->float_bld;
156       LLVMValueRef sampler_lod_bias =
157          bld->dynamic_state->lod_bias(bld->dynamic_state, bld->builder, unit);
158       LLVMValueRef min_lod =
159          bld->dynamic_state->min_lod(bld->dynamic_state, bld->builder, unit);
160       LLVMValueRef max_lod =
161          bld->dynamic_state->max_lod(bld->dynamic_state, bld->builder, unit);
162       LLVMValueRef index0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
163       LLVMValueRef lod;
164
165       if (explicit_lod) {
166          lod = LLVMBuildExtractElement(bld->builder, explicit_lod,
167                                        index0, "");
168       }
169       else {
170          const int dims = texture_dims(bld->static_state->target);
171          LLVMValueRef dsdx, dsdy;
172          LLVMValueRef dtdx = NULL, dtdy = NULL, drdx = NULL, drdy = NULL;
173          LLVMValueRef rho;
174
175          dsdx = LLVMBuildExtractElement(bld->builder, ddx[0], index0, "dsdx");
176          dsdx = lp_build_abs(float_bld, dsdx);
177          dsdy = LLVMBuildExtractElement(bld->builder, ddy[0], index0, "dsdy");
178          dsdy = lp_build_abs(float_bld, dsdy);
179          if (dims > 1) {
180             dtdx = LLVMBuildExtractElement(bld->builder, ddx[1], index0, "dtdx");
181             dtdx = lp_build_abs(float_bld, dtdx);
182             dtdy = LLVMBuildExtractElement(bld->builder, ddy[1], index0, "dtdy");
183             dtdy = lp_build_abs(float_bld, dtdy);
184             if (dims > 2) {
185                drdx = LLVMBuildExtractElement(bld->builder, ddx[2], index0, "drdx");
186                drdx = lp_build_abs(float_bld, drdx);
187                drdy = LLVMBuildExtractElement(bld->builder, ddy[2], index0, "drdy");
188                drdy = lp_build_abs(float_bld, drdy);
189             }
190          }
191
192          /* Compute rho = max of all partial derivatives scaled by texture size.
193           * XXX this could be vectorized somewhat
194           */
195          rho = LLVMBuildFMul(bld->builder,
196                             lp_build_max(float_bld, dsdx, dsdy),
197                             lp_build_int_to_float(float_bld, width), "");
198          if (dims > 1) {
199             LLVMValueRef max;
200             max = LLVMBuildFMul(bld->builder,
201                                lp_build_max(float_bld, dtdx, dtdy),
202                                lp_build_int_to_float(float_bld, height), "");
203             rho = lp_build_max(float_bld, rho, max);
204             if (dims > 2) {
205                max = LLVMBuildFMul(bld->builder,
206                                   lp_build_max(float_bld, drdx, drdy),
207                                   lp_build_int_to_float(float_bld, depth), "");
208                rho = lp_build_max(float_bld, rho, max);
209             }
210          }
211
212          /* compute lod = log2(rho) */
213          lod = lp_build_log2(float_bld, rho);
214
215          /* add shader lod bias */
216          if (lod_bias) {
217             lod_bias = LLVMBuildExtractElement(bld->builder, lod_bias,
218                                                index0, "");
219             lod = LLVMBuildFAdd(bld->builder, lod, lod_bias, "shader_lod_bias");
220          }
221       }
222
223       /* add sampler lod bias */
224       lod = LLVMBuildFAdd(bld->builder, lod, sampler_lod_bias, "sampler_lod_bias");
225
226       /* clamp lod */
227       lod = lp_build_clamp(float_bld, lod, min_lod, max_lod);
228
229       return lod;
230    }
231 }
232
233
234 /**
235  * For PIPE_TEX_MIPFILTER_NEAREST, convert float LOD to integer
236  * mipmap level index.
237  * Note: this is all scalar code.
238  * \param lod  scalar float texture level of detail
239  * \param level_out  returns integer 
240  */
241 void
242 lp_build_nearest_mip_level(struct lp_build_sample_context *bld,
243                            unsigned unit,
244                            LLVMValueRef lod,
245                            LLVMValueRef *level_out)
246 {
247    struct lp_build_context *float_bld = &bld->float_bld;
248    struct lp_build_context *int_bld = &bld->int_bld;
249    LLVMValueRef last_level, level;
250
251    LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, 0);
252
253    last_level = bld->dynamic_state->last_level(bld->dynamic_state,
254                                                bld->builder, unit);
255
256    /* convert float lod to integer */
257    level = lp_build_iround(float_bld, lod);
258
259    /* clamp level to legal range of levels */
260    *level_out = lp_build_clamp(int_bld, level, zero, last_level);
261 }
262
263
264 /**
265  * For PIPE_TEX_MIPFILTER_LINEAR, convert float LOD to integer to
266  * two (adjacent) mipmap level indexes.  Later, we'll sample from those
267  * two mipmap levels and interpolate between them.
268  */
269 void
270 lp_build_linear_mip_levels(struct lp_build_sample_context *bld,
271                            unsigned unit,
272                            LLVMValueRef lod,
273                            LLVMValueRef *level0_out,
274                            LLVMValueRef *level1_out,
275                            LLVMValueRef *weight_out)
276 {
277    struct lp_build_context *float_bld = &bld->float_bld;
278    struct lp_build_context *int_bld = &bld->int_bld;
279    LLVMValueRef last_level, level;
280
281    last_level = bld->dynamic_state->last_level(bld->dynamic_state,
282                                                bld->builder, unit);
283
284    /* convert float lod to integer */
285    level = lp_build_ifloor(float_bld, lod);
286
287    /* compute level 0 and clamp to legal range of levels */
288    *level0_out = lp_build_clamp(int_bld, level,
289                                 int_bld->zero,
290                                 last_level);
291    /* compute level 1 and clamp to legal range of levels */
292    level = lp_build_add(int_bld, level, int_bld->one);
293    *level1_out = lp_build_clamp(int_bld, level,
294                                 int_bld->zero,
295                                 last_level);
296
297    *weight_out = lp_build_fract(float_bld, lod);
298 }
299
300
301 LLVMValueRef
302 lp_build_get_mipmap_level(struct lp_build_sample_context *bld,
303                           LLVMValueRef data_array, LLVMValueRef level)
304 {
305    LLVMValueRef indexes[2], data_ptr;
306    indexes[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
307    indexes[1] = level;
308    data_ptr = LLVMBuildGEP(bld->builder, data_array, indexes, 2, "");
309    data_ptr = LLVMBuildLoad(bld->builder, data_ptr, "");
310    return data_ptr;
311 }
312
313
314 LLVMValueRef
315 lp_build_get_const_mipmap_level(struct lp_build_sample_context *bld,
316                                 LLVMValueRef data_array, int level)
317 {
318    LLVMValueRef lvl = LLVMConstInt(LLVMInt32Type(), level, 0);
319    return lp_build_get_mipmap_level(bld, data_array, lvl);
320 }
321
322
323 /**
324  * Codegen equivalent for u_minify().
325  * Return max(1, base_size >> level);
326  */
327 static LLVMValueRef
328 lp_build_minify(struct lp_build_sample_context *bld,
329                 LLVMValueRef base_size,
330                 LLVMValueRef level)
331 {
332    LLVMValueRef size = LLVMBuildLShr(bld->builder, base_size, level, "minify");
333    size = lp_build_max(&bld->int_coord_bld, size, bld->int_coord_bld.one);
334    return size;
335 }
336
337
338 /**
339  * Dereference stride_array[mipmap_level] array to get a stride.
340  * Return stride as a vector.
341  */
342 static LLVMValueRef
343 lp_build_get_level_stride_vec(struct lp_build_sample_context *bld,
344                               LLVMValueRef stride_array, LLVMValueRef level)
345 {
346    LLVMValueRef indexes[2], stride;
347    indexes[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
348    indexes[1] = level;
349    stride = LLVMBuildGEP(bld->builder, stride_array, indexes, 2, "");
350    stride = LLVMBuildLoad(bld->builder, stride, "");
351    stride = lp_build_broadcast_scalar(&bld->int_coord_bld, stride);
352    return stride;
353 }
354
355
356 /**
357  * When sampling a mipmap, we need to compute the width, height, depth
358  * of the source levels from the level indexes.  This helper function
359  * does that.
360  */
361 void
362 lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
363                             unsigned dims,
364                             LLVMValueRef width_vec,
365                             LLVMValueRef height_vec,
366                             LLVMValueRef depth_vec,
367                             LLVMValueRef ilevel0,
368                             LLVMValueRef ilevel1,
369                             LLVMValueRef row_stride_array,
370                             LLVMValueRef img_stride_array,
371                             LLVMValueRef *width0_vec,
372                             LLVMValueRef *width1_vec,
373                             LLVMValueRef *height0_vec,
374                             LLVMValueRef *height1_vec,
375                             LLVMValueRef *depth0_vec,
376                             LLVMValueRef *depth1_vec,
377                             LLVMValueRef *row_stride0_vec,
378                             LLVMValueRef *row_stride1_vec,
379                             LLVMValueRef *img_stride0_vec,
380                             LLVMValueRef *img_stride1_vec)
381 {
382    const unsigned mip_filter = bld->static_state->min_mip_filter;
383    LLVMValueRef ilevel0_vec, ilevel1_vec;
384
385    ilevel0_vec = lp_build_broadcast_scalar(&bld->int_coord_bld, ilevel0);
386    if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR)
387       ilevel1_vec = lp_build_broadcast_scalar(&bld->int_coord_bld, ilevel1);
388
389    /*
390     * Compute width, height, depth at mipmap level 'ilevel0'
391     */
392    *width0_vec = lp_build_minify(bld, width_vec, ilevel0_vec);
393    if (dims >= 2) {
394       *height0_vec = lp_build_minify(bld, height_vec, ilevel0_vec);
395       *row_stride0_vec = lp_build_get_level_stride_vec(bld,
396                                                        row_stride_array,
397                                                        ilevel0);
398       if (dims == 3 || bld->static_state->target == PIPE_TEXTURE_CUBE) {
399          *img_stride0_vec = lp_build_get_level_stride_vec(bld,
400                                                           img_stride_array,
401                                                           ilevel0);
402          if (dims == 3) {
403             *depth0_vec = lp_build_minify(bld, depth_vec, ilevel0_vec);
404          }
405       }
406    }
407    if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
408       /* compute width, height, depth for second mipmap level at 'ilevel1' */
409       *width1_vec = lp_build_minify(bld, width_vec, ilevel1_vec);
410       if (dims >= 2) {
411          *height1_vec = lp_build_minify(bld, height_vec, ilevel1_vec);
412          *row_stride1_vec = lp_build_get_level_stride_vec(bld,
413                                                           row_stride_array,
414                                                           ilevel1);
415          if (dims == 3 || bld->static_state->target == PIPE_TEXTURE_CUBE) {
416             *img_stride1_vec = lp_build_get_level_stride_vec(bld,
417                                                              img_stride_array,
418                                                              ilevel1);
419             if (dims == 3) {
420                *depth1_vec = lp_build_minify(bld, depth_vec, ilevel1_vec);
421             }
422          }
423       }
424    }
425 }
426
427
428
429 /** Helper used by lp_build_cube_lookup() */
430 static LLVMValueRef
431 lp_build_cube_ima(struct lp_build_context *coord_bld, LLVMValueRef coord)
432 {
433    /* ima = -0.5 / abs(coord); */
434    LLVMValueRef negHalf = lp_build_const_vec(coord_bld->type, -0.5);
435    LLVMValueRef absCoord = lp_build_abs(coord_bld, coord);
436    LLVMValueRef ima = lp_build_div(coord_bld, negHalf, absCoord);
437    return ima;
438 }
439
440
441 /**
442  * Helper used by lp_build_cube_lookup()
443  * \param sign  scalar +1 or -1
444  * \param coord  float vector
445  * \param ima  float vector
446  */
447 static LLVMValueRef
448 lp_build_cube_coord(struct lp_build_context *coord_bld,
449                     LLVMValueRef sign, int negate_coord,
450                     LLVMValueRef coord, LLVMValueRef ima)
451 {
452    /* return negate(coord) * ima * sign + 0.5; */
453    LLVMValueRef half = lp_build_const_vec(coord_bld->type, 0.5);
454    LLVMValueRef res;
455
456    assert(negate_coord == +1 || negate_coord == -1);
457
458    if (negate_coord == -1) {
459       coord = lp_build_negate(coord_bld, coord);
460    }
461
462    res = lp_build_mul(coord_bld, coord, ima);
463    if (sign) {
464       sign = lp_build_broadcast_scalar(coord_bld, sign);
465       res = lp_build_mul(coord_bld, res, sign);
466    }
467    res = lp_build_add(coord_bld, res, half);
468
469    return res;
470 }
471
472
473 /** Helper used by lp_build_cube_lookup()
474  * Return (major_coord >= 0) ? pos_face : neg_face;
475  */
476 static LLVMValueRef
477 lp_build_cube_face(struct lp_build_sample_context *bld,
478                    LLVMValueRef major_coord,
479                    unsigned pos_face, unsigned neg_face)
480 {
481    LLVMValueRef cmp = LLVMBuildFCmp(bld->builder, LLVMRealUGE,
482                                     major_coord,
483                                     bld->float_bld.zero, "");
484    LLVMValueRef pos = LLVMConstInt(LLVMInt32Type(), pos_face, 0);
485    LLVMValueRef neg = LLVMConstInt(LLVMInt32Type(), neg_face, 0);
486    LLVMValueRef res = LLVMBuildSelect(bld->builder, cmp, pos, neg, "");
487    return res;
488 }
489
490
491
492 /**
493  * Generate code to do cube face selection and compute per-face texcoords.
494  */
495 void
496 lp_build_cube_lookup(struct lp_build_sample_context *bld,
497                      LLVMValueRef s,
498                      LLVMValueRef t,
499                      LLVMValueRef r,
500                      LLVMValueRef *face,
501                      LLVMValueRef *face_s,
502                      LLVMValueRef *face_t)
503 {
504    struct lp_build_context *float_bld = &bld->float_bld;
505    struct lp_build_context *coord_bld = &bld->coord_bld;
506    LLVMValueRef rx, ry, rz;
507    LLVMValueRef arx, ary, arz;
508    LLVMValueRef c25 = LLVMConstReal(LLVMFloatType(), 0.25);
509    LLVMValueRef arx_ge_ary, arx_ge_arz;
510    LLVMValueRef ary_ge_arx, ary_ge_arz;
511    LLVMValueRef arx_ge_ary_arz, ary_ge_arx_arz;
512    LLVMValueRef rx_pos, ry_pos, rz_pos;
513
514    assert(bld->coord_bld.type.length == 4);
515
516    /*
517     * Use the average of the four pixel's texcoords to choose the face.
518     */
519    rx = lp_build_mul(float_bld, c25,
520                      lp_build_sum_vector(&bld->coord_bld, s));
521    ry = lp_build_mul(float_bld, c25,
522                      lp_build_sum_vector(&bld->coord_bld, t));
523    rz = lp_build_mul(float_bld, c25,
524                      lp_build_sum_vector(&bld->coord_bld, r));
525
526    arx = lp_build_abs(float_bld, rx);
527    ary = lp_build_abs(float_bld, ry);
528    arz = lp_build_abs(float_bld, rz);
529
530    /*
531     * Compare sign/magnitude of rx,ry,rz to determine face
532     */
533    arx_ge_ary = LLVMBuildFCmp(bld->builder, LLVMRealUGE, arx, ary, "");
534    arx_ge_arz = LLVMBuildFCmp(bld->builder, LLVMRealUGE, arx, arz, "");
535    ary_ge_arx = LLVMBuildFCmp(bld->builder, LLVMRealUGE, ary, arx, "");
536    ary_ge_arz = LLVMBuildFCmp(bld->builder, LLVMRealUGE, ary, arz, "");
537
538    arx_ge_ary_arz = LLVMBuildAnd(bld->builder, arx_ge_ary, arx_ge_arz, "");
539    ary_ge_arx_arz = LLVMBuildAnd(bld->builder, ary_ge_arx, ary_ge_arz, "");
540
541    rx_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, rx, float_bld->zero, "");
542    ry_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, ry, float_bld->zero, "");
543    rz_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, rz, float_bld->zero, "");
544
545    {
546       struct lp_build_flow_context *flow_ctx;
547       struct lp_build_if_state if_ctx;
548
549       flow_ctx = lp_build_flow_create(bld->builder);
550       lp_build_flow_scope_begin(flow_ctx);
551
552       *face_s = bld->coord_bld.undef;
553       *face_t = bld->coord_bld.undef;
554       *face = bld->int_bld.undef;
555
556       lp_build_name(*face_s, "face_s");
557       lp_build_name(*face_t, "face_t");
558       lp_build_name(*face, "face");
559
560       lp_build_flow_scope_declare(flow_ctx, face_s);
561       lp_build_flow_scope_declare(flow_ctx, face_t);
562       lp_build_flow_scope_declare(flow_ctx, face);
563
564       lp_build_if(&if_ctx, flow_ctx, bld->builder, arx_ge_ary_arz);
565       {
566          /* +/- X face */
567          LLVMValueRef sign = lp_build_sgn(float_bld, rx);
568          LLVMValueRef ima = lp_build_cube_ima(coord_bld, s);
569          *face_s = lp_build_cube_coord(coord_bld, sign, +1, r, ima);
570          *face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
571          *face = lp_build_cube_face(bld, rx,
572                                     PIPE_TEX_FACE_POS_X,
573                                     PIPE_TEX_FACE_NEG_X);
574       }
575       lp_build_else(&if_ctx);
576       {
577          struct lp_build_flow_context *flow_ctx2;
578          struct lp_build_if_state if_ctx2;
579
580          LLVMValueRef face_s2 = bld->coord_bld.undef;
581          LLVMValueRef face_t2 = bld->coord_bld.undef;
582          LLVMValueRef face2 = bld->int_bld.undef;
583
584          flow_ctx2 = lp_build_flow_create(bld->builder);
585          lp_build_flow_scope_begin(flow_ctx2);
586          lp_build_flow_scope_declare(flow_ctx2, &face_s2);
587          lp_build_flow_scope_declare(flow_ctx2, &face_t2);
588          lp_build_flow_scope_declare(flow_ctx2, &face2);
589
590          ary_ge_arx_arz = LLVMBuildAnd(bld->builder, ary_ge_arx, ary_ge_arz, "");
591
592          lp_build_if(&if_ctx2, flow_ctx2, bld->builder, ary_ge_arx_arz);
593          {
594             /* +/- Y face */
595             LLVMValueRef sign = lp_build_sgn(float_bld, ry);
596             LLVMValueRef ima = lp_build_cube_ima(coord_bld, t);
597             face_s2 = lp_build_cube_coord(coord_bld, NULL, -1, s, ima);
598             face_t2 = lp_build_cube_coord(coord_bld, sign, -1, r, ima);
599             face2 = lp_build_cube_face(bld, ry,
600                                        PIPE_TEX_FACE_POS_Y,
601                                        PIPE_TEX_FACE_NEG_Y);
602          }
603          lp_build_else(&if_ctx2);
604          {
605             /* +/- Z face */
606             LLVMValueRef sign = lp_build_sgn(float_bld, rz);
607             LLVMValueRef ima = lp_build_cube_ima(coord_bld, r);
608             face_s2 = lp_build_cube_coord(coord_bld, sign, -1, s, ima);
609             face_t2 = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
610             face2 = lp_build_cube_face(bld, rz,
611                                        PIPE_TEX_FACE_POS_Z,
612                                        PIPE_TEX_FACE_NEG_Z);
613          }
614          lp_build_endif(&if_ctx2);
615          lp_build_flow_scope_end(flow_ctx2);
616          lp_build_flow_destroy(flow_ctx2);
617          *face_s = face_s2;
618          *face_t = face_t2;
619          *face = face2;
620       }
621
622       lp_build_endif(&if_ctx);
623       lp_build_flow_scope_end(flow_ctx);
624       lp_build_flow_destroy(flow_ctx);
625    }
626 }
627
628
629 /**
630  * Compute the partial offset of a pixel block along an arbitrary axis.
631  *
632  * @param coord   coordinate in pixels
633  * @param stride  number of bytes between rows of successive pixel blocks
634  * @param block_length  number of pixels in a pixels block along the coordinate
635  *                      axis
636  * @param out_offset    resulting relative offset of the pixel block in bytes
637  * @param out_subcoord  resulting sub-block pixel coordinate
638  */
639 void
640 lp_build_sample_partial_offset(struct lp_build_context *bld,
641                                unsigned block_length,
642                                LLVMValueRef coord,
643                                LLVMValueRef stride,
644                                LLVMValueRef *out_offset,
645                                LLVMValueRef *out_subcoord)
646 {
647    LLVMValueRef offset;
648    LLVMValueRef subcoord;
649
650    if (block_length == 1) {
651       subcoord = bld->zero;
652    }
653    else {
654       /*
655        * Pixel blocks have power of two dimensions. LLVM should convert the
656        * rem/div to bit arithmetic.
657        * TODO: Verify this.
658        * It does indeed BUT it does transform it to scalar (and back) when doing so
659        * (using roughly extract, shift/and, mov, unpack) (llvm 2.7).
660        * The generated code looks seriously unfunny and is quite expensive.
661        */
662 #if 0
663       LLVMValueRef block_width = lp_build_const_int_vec(bld->type, block_length);
664       subcoord = LLVMBuildURem(bld->builder, coord, block_width, "");
665       coord    = LLVMBuildUDiv(bld->builder, coord, block_width, "");
666 #else
667       unsigned logbase2 = util_unsigned_logbase2(block_length);
668       LLVMValueRef block_shift = lp_build_const_int_vec(bld->type, logbase2);
669       LLVMValueRef block_mask = lp_build_const_int_vec(bld->type, block_length - 1);
670       subcoord = LLVMBuildAnd(bld->builder, coord, block_mask, "");
671       coord = LLVMBuildLShr(bld->builder, coord, block_shift, "");
672 #endif
673    }
674
675    offset = lp_build_mul(bld, coord, stride);
676
677    assert(out_offset);
678    assert(out_subcoord);
679
680    *out_offset = offset;
681    *out_subcoord = subcoord;
682 }
683
684
685 /**
686  * Compute the offset of a pixel block.
687  *
688  * x, y, z, y_stride, z_stride are vectors, and they refer to pixels.
689  *
690  * Returns the relative offset and i,j sub-block coordinates
691  */
692 void
693 lp_build_sample_offset(struct lp_build_context *bld,
694                        const struct util_format_description *format_desc,
695                        LLVMValueRef x,
696                        LLVMValueRef y,
697                        LLVMValueRef z,
698                        LLVMValueRef y_stride,
699                        LLVMValueRef z_stride,
700                        LLVMValueRef *out_offset,
701                        LLVMValueRef *out_i,
702                        LLVMValueRef *out_j)
703 {
704    LLVMValueRef x_stride;
705    LLVMValueRef offset;
706
707    x_stride = lp_build_const_vec(bld->type, format_desc->block.bits/8);
708
709    lp_build_sample_partial_offset(bld,
710                                   format_desc->block.width,
711                                   x, x_stride,
712                                   &offset, out_i);
713
714    if (y && y_stride) {
715       LLVMValueRef y_offset;
716       lp_build_sample_partial_offset(bld,
717                                      format_desc->block.height,
718                                      y, y_stride,
719                                      &y_offset, out_j);
720       offset = lp_build_add(bld, offset, y_offset);
721    }
722    else {
723       *out_j = bld->zero;
724    }
725
726    if (z && z_stride) {
727       LLVMValueRef z_offset;
728       LLVMValueRef k;
729       lp_build_sample_partial_offset(bld,
730                                      1, /* pixel blocks are always 2D */
731                                      z, z_stride,
732                                      &z_offset, &k);
733       offset = lp_build_add(bld, offset, z_offset);
734    }
735
736    *out_offset = offset;
737 }