OSDN Git Service

gallivm: fix border color for integer textures
[android-x86/external-mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_sample_soa.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 -- SoA.
31  *
32  * @author Jose Fonseca <jfonseca@vmware.com>
33  * @author Brian Paul <brianp@vmware.com>
34  */
35
36 #include "pipe/p_defines.h"
37 #include "pipe/p_state.h"
38 #include "pipe/p_shader_tokens.h"
39 #include "util/u_debug.h"
40 #include "util/u_dump.h"
41 #include "util/u_memory.h"
42 #include "util/u_math.h"
43 #include "util/u_format.h"
44 #include "util/u_cpu_detect.h"
45 #include "lp_bld_debug.h"
46 #include "lp_bld_type.h"
47 #include "lp_bld_const.h"
48 #include "lp_bld_conv.h"
49 #include "lp_bld_arit.h"
50 #include "lp_bld_bitarit.h"
51 #include "lp_bld_logic.h"
52 #include "lp_bld_printf.h"
53 #include "lp_bld_swizzle.h"
54 #include "lp_bld_flow.h"
55 #include "lp_bld_gather.h"
56 #include "lp_bld_format.h"
57 #include "lp_bld_sample.h"
58 #include "lp_bld_sample_aos.h"
59 #include "lp_bld_struct.h"
60 #include "lp_bld_quad.h"
61 #include "lp_bld_pack.h"
62
63
64 /**
65  * Generate code to fetch a texel from a texture at int coords (x, y, z).
66  * The computation depends on whether the texture is 1D, 2D or 3D.
67  * The result, texel, will be float vectors:
68  *   texel[0] = red values
69  *   texel[1] = green values
70  *   texel[2] = blue values
71  *   texel[3] = alpha values
72  */
73 static void
74 lp_build_sample_texel_soa(struct lp_build_sample_context *bld,
75                           unsigned unit,
76                           LLVMValueRef width,
77                           LLVMValueRef height,
78                           LLVMValueRef depth,
79                           LLVMValueRef x,
80                           LLVMValueRef y,
81                           LLVMValueRef z,
82                           LLVMValueRef y_stride,
83                           LLVMValueRef z_stride,
84                           LLVMValueRef data_ptr,
85                           LLVMValueRef mipoffsets,
86                           LLVMValueRef texel_out[4])
87 {
88    const struct lp_sampler_static_state *static_state = bld->static_state;
89    const unsigned dims = bld->dims;
90    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
91    LLVMBuilderRef builder = bld->gallivm->builder;
92    LLVMValueRef offset;
93    LLVMValueRef i, j;
94    LLVMValueRef use_border = NULL;
95
96    /* use_border = x < 0 || x >= width || y < 0 || y >= height */
97    if (lp_sampler_wrap_mode_uses_border_color(static_state->wrap_s,
98                                               static_state->min_img_filter,
99                                               static_state->mag_img_filter)) {
100       LLVMValueRef b1, b2;
101       b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, x, int_coord_bld->zero);
102       b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, x, width);
103       use_border = LLVMBuildOr(builder, b1, b2, "b1_or_b2");
104    }
105
106    if (dims >= 2 &&
107        lp_sampler_wrap_mode_uses_border_color(static_state->wrap_t,
108                                               static_state->min_img_filter,
109                                               static_state->mag_img_filter)) {
110       LLVMValueRef b1, b2;
111       b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, y, int_coord_bld->zero);
112       b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, y, height);
113       if (use_border) {
114          use_border = LLVMBuildOr(builder, use_border, b1, "ub_or_b1");
115          use_border = LLVMBuildOr(builder, use_border, b2, "ub_or_b2");
116       }
117       else {
118          use_border = LLVMBuildOr(builder, b1, b2, "b1_or_b2");
119       }
120    }
121
122    if (dims == 3 &&
123        lp_sampler_wrap_mode_uses_border_color(static_state->wrap_r,
124                                               static_state->min_img_filter,
125                                               static_state->mag_img_filter)) {
126       LLVMValueRef b1, b2;
127       b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, z, int_coord_bld->zero);
128       b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, z, depth);
129       if (use_border) {
130          use_border = LLVMBuildOr(builder, use_border, b1, "ub_or_b1");
131          use_border = LLVMBuildOr(builder, use_border, b2, "ub_or_b2");
132       }
133       else {
134          use_border = LLVMBuildOr(builder, b1, b2, "b1_or_b2");
135       }
136    }
137
138    /* convert x,y,z coords to linear offset from start of texture, in bytes */
139    lp_build_sample_offset(&bld->int_coord_bld,
140                           bld->format_desc,
141                           x, y, z, y_stride, z_stride,
142                           &offset, &i, &j);
143    if (mipoffsets) {
144       offset = lp_build_add(&bld->int_coord_bld, offset, mipoffsets);
145    }
146
147    if (use_border) {
148       /* If we can sample the border color, it means that texcoords may
149        * lie outside the bounds of the texture image.  We need to do
150        * something to prevent reading out of bounds and causing a segfault.
151        *
152        * Simply AND the texture coords with !use_border.  This will cause
153        * coords which are out of bounds to become zero.  Zero's guaranteed
154        * to be inside the texture image.
155        */
156       offset = lp_build_andnot(&bld->int_coord_bld, offset, use_border);
157    }
158
159    lp_build_fetch_rgba_soa(bld->gallivm,
160                            bld->format_desc,
161                            bld->texel_type,
162                            data_ptr, offset,
163                            i, j,
164                            texel_out);
165
166    /*
167     * Note: if we find an app which frequently samples the texture border
168     * we might want to implement a true conditional here to avoid sampling
169     * the texture whenever possible (since that's quite a bit of code).
170     * Ex:
171     *   if (use_border) {
172     *      texel = border_color;
173     *   }
174     *   else {
175     *      texel = sample_texture(coord);
176     *   }
177     * As it is now, we always sample the texture, then selectively replace
178     * the texel color results with the border color.
179     */
180
181    if (use_border) {
182       /* select texel color or border color depending on use_border */
183       LLVMValueRef border_color_ptr = 
184          bld->dynamic_state->border_color(bld->dynamic_state,
185                                           bld->gallivm, unit);
186       int chan;
187       for (chan = 0; chan < 4; chan++) {
188          LLVMValueRef border_chan =
189             lp_build_array_get(bld->gallivm, border_color_ptr,
190                                lp_build_const_int32(bld->gallivm, chan));
191          LLVMValueRef border_chan_vec =
192             lp_build_broadcast_scalar(&bld->float_vec_bld, border_chan);
193
194          if (!bld->texel_type.floating) {
195             border_chan_vec = LLVMBuildBitCast(builder, border_chan_vec,
196                                                bld->texel_bld.vec_type, "");
197          }
198          texel_out[chan] = lp_build_select(&bld->texel_bld, use_border,
199                                            border_chan_vec, texel_out[chan]);
200       }
201    }
202 }
203
204
205 /**
206  * Helper to compute the mirror function for the PIPE_WRAP_MIRROR modes.
207  */
208 static LLVMValueRef
209 lp_build_coord_mirror(struct lp_build_sample_context *bld,
210                       LLVMValueRef coord)
211 {
212    struct lp_build_context *coord_bld = &bld->coord_bld;
213    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
214    LLVMValueRef fract, flr, isOdd;
215
216    lp_build_ifloor_fract(coord_bld, coord, &flr, &fract);
217
218    /* isOdd = flr & 1 */
219    isOdd = LLVMBuildAnd(bld->gallivm->builder, flr, int_coord_bld->one, "");
220
221    /* make coord positive or negative depending on isOdd */
222    coord = lp_build_set_sign(coord_bld, fract, isOdd);
223
224    /* convert isOdd to float */
225    isOdd = lp_build_int_to_float(coord_bld, isOdd);
226
227    /* add isOdd to coord */
228    coord = lp_build_add(coord_bld, coord, isOdd);
229
230    return coord;
231 }
232
233
234 /**
235  * Helper to compute the first coord and the weight for
236  * linear wrap repeat npot textures
237  */
238 void
239 lp_build_coord_repeat_npot_linear(struct lp_build_sample_context *bld,
240                                   LLVMValueRef coord_f,
241                                   LLVMValueRef length_i,
242                                   LLVMValueRef length_f,
243                                   LLVMValueRef *coord0_i,
244                                   LLVMValueRef *weight_f)
245 {
246    struct lp_build_context *coord_bld = &bld->coord_bld;
247    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
248    LLVMValueRef half = lp_build_const_vec(bld->gallivm, coord_bld->type, 0.5);
249    LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length_i,
250                                                 int_coord_bld->one);
251    LLVMValueRef mask;
252    /* wrap with normalized floats is just fract */
253    coord_f = lp_build_fract(coord_bld, coord_f);
254    /* mul by size and subtract 0.5 */
255    coord_f = lp_build_mul(coord_bld, coord_f, length_f);
256    coord_f = lp_build_sub(coord_bld, coord_f, half);
257    /*
258     * we avoided the 0.5/length division before the repeat wrap,
259     * now need to fix up edge cases with selects
260     */
261    /* convert to int, compute lerp weight */
262    lp_build_ifloor_fract(coord_bld, coord_f, coord0_i, weight_f);
263    mask = lp_build_compare(int_coord_bld->gallivm, int_coord_bld->type,
264                            PIPE_FUNC_LESS, *coord0_i, int_coord_bld->zero);
265    *coord0_i = lp_build_select(int_coord_bld, mask, length_minus_one, *coord0_i);
266 }
267
268
269 /**
270  * Build LLVM code for texture wrap mode for linear filtering.
271  * \param x0_out  returns first integer texcoord
272  * \param x1_out  returns second integer texcoord
273  * \param weight_out  returns linear interpolation weight
274  */
275 static void
276 lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
277                             LLVMValueRef coord,
278                             LLVMValueRef length,
279                             LLVMValueRef length_f,
280                             boolean is_pot,
281                             unsigned wrap_mode,
282                             LLVMValueRef *x0_out,
283                             LLVMValueRef *x1_out,
284                             LLVMValueRef *weight_out)
285 {
286    struct lp_build_context *coord_bld = &bld->coord_bld;
287    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
288    LLVMBuilderRef builder = bld->gallivm->builder;
289    LLVMValueRef half = lp_build_const_vec(bld->gallivm, coord_bld->type, 0.5);
290    LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
291    LLVMValueRef coord0, coord1, weight;
292
293    switch(wrap_mode) {
294    case PIPE_TEX_WRAP_REPEAT:
295       if (is_pot) {
296          /* mul by size and subtract 0.5 */
297          coord = lp_build_mul(coord_bld, coord, length_f);
298          coord = lp_build_sub(coord_bld, coord, half);
299          /* convert to int, compute lerp weight */
300          lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
301          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
302          /* repeat wrap */
303          coord0 = LLVMBuildAnd(builder, coord0, length_minus_one, "");
304          coord1 = LLVMBuildAnd(builder, coord1, length_minus_one, "");
305       }
306       else {
307          LLVMValueRef mask;
308          lp_build_coord_repeat_npot_linear(bld, coord,
309                                            length, length_f,
310                                            &coord0, &weight);
311          mask = lp_build_compare(int_coord_bld->gallivm, int_coord_bld->type,
312                                  PIPE_FUNC_NOTEQUAL, coord0, length_minus_one);
313          coord1 = LLVMBuildAnd(builder,
314                                lp_build_add(int_coord_bld, coord0, int_coord_bld->one),
315                                mask, "");
316       }
317       break;
318
319    case PIPE_TEX_WRAP_CLAMP:
320       if (bld->static_state->normalized_coords) {
321          /* scale coord to length */
322          coord = lp_build_mul(coord_bld, coord, length_f);
323       }
324
325       /* clamp to [0, length] */
326       coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, length_f);
327
328       coord = lp_build_sub(coord_bld, coord, half);
329
330       /* convert to int, compute lerp weight */
331       lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
332       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
333       break;
334
335    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
336       {
337          struct lp_build_context abs_coord_bld = bld->coord_bld;
338          abs_coord_bld.type.sign = FALSE;
339
340          if (bld->static_state->normalized_coords) {
341             /* mul by tex size */
342             coord = lp_build_mul(coord_bld, coord, length_f);
343          }
344          /* clamp to length max */
345          coord = lp_build_min(coord_bld, coord, length_f);
346          /* subtract 0.5 */
347          coord = lp_build_sub(coord_bld, coord, half);
348          /* clamp to [0, length - 0.5] */
349          coord = lp_build_max(coord_bld, coord, coord_bld->zero);
350          /* convert to int, compute lerp weight */
351          lp_build_ifloor_fract(&abs_coord_bld, coord, &coord0, &weight);
352          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
353          /* coord1 = min(coord1, length-1) */
354          coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
355          break;
356       }
357
358    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
359       if (bld->static_state->normalized_coords) {
360          /* scale coord to length */
361          coord = lp_build_mul(coord_bld, coord, length_f);
362       }
363       /* was: clamp to [-0.5, length + 0.5], then sub 0.5 */
364       /* can skip clamp (though might not work for very large coord values */
365       coord = lp_build_sub(coord_bld, coord, half);
366       /* convert to int, compute lerp weight */
367       lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
368       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
369       break;
370
371    case PIPE_TEX_WRAP_MIRROR_REPEAT:
372       /* compute mirror function */
373       coord = lp_build_coord_mirror(bld, coord);
374
375       /* scale coord to length */
376       coord = lp_build_mul(coord_bld, coord, length_f);
377       coord = lp_build_sub(coord_bld, coord, half);
378
379       /* convert to int, compute lerp weight */
380       lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
381       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
382
383       /* coord0 = max(coord0, 0) */
384       coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero);
385       /* coord1 = min(coord1, length-1) */
386       coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
387       break;
388
389    case PIPE_TEX_WRAP_MIRROR_CLAMP:
390       coord = lp_build_abs(coord_bld, coord);
391
392       if (bld->static_state->normalized_coords) {
393          /* scale coord to length */
394          coord = lp_build_mul(coord_bld, coord, length_f);
395       }
396
397       /* clamp to [0, length] */
398       coord = lp_build_min(coord_bld, coord, length_f);
399
400       coord = lp_build_sub(coord_bld, coord, half);
401
402       /* convert to int, compute lerp weight */
403       lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
404       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
405       break;
406
407    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
408       {
409          LLVMValueRef min, max;
410          struct lp_build_context abs_coord_bld = bld->coord_bld;
411          abs_coord_bld.type.sign = FALSE;
412          coord = lp_build_abs(coord_bld, coord);
413
414          if (bld->static_state->normalized_coords) {
415             /* scale coord to length */
416             coord = lp_build_mul(coord_bld, coord, length_f);
417          }
418
419          /* clamp to [0.5, length - 0.5] */
420          min = half;
421          max = lp_build_sub(coord_bld, length_f, min);
422          coord = lp_build_clamp(coord_bld, coord, min, max);
423
424          coord = lp_build_sub(coord_bld, coord, half);
425
426          /* convert to int, compute lerp weight */
427          lp_build_ifloor_fract(&abs_coord_bld, coord, &coord0, &weight);
428          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
429       }
430       break;
431
432    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
433       {
434          coord = lp_build_abs(coord_bld, coord);
435
436          if (bld->static_state->normalized_coords) {
437             /* scale coord to length */
438             coord = lp_build_mul(coord_bld, coord, length_f);
439          }
440
441          /* was: clamp to [-0.5, length + 0.5] then sub 0.5 */
442          /* skip clamp - always positive, and other side
443             only potentially matters for very large coords */
444          coord = lp_build_sub(coord_bld, coord, half);
445
446          /* convert to int, compute lerp weight */
447          lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
448          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
449       }
450       break;
451
452    default:
453       assert(0);
454       coord0 = NULL;
455       coord1 = NULL;
456       weight = NULL;
457    }
458
459    *x0_out = coord0;
460    *x1_out = coord1;
461    *weight_out = weight;
462 }
463
464
465 /**
466  * Build LLVM code for texture wrap mode for nearest filtering.
467  * \param coord  the incoming texcoord (nominally in [0,1])
468  * \param length  the texture size along one dimension, as int vector
469  * \param is_pot  if TRUE, length is a power of two
470  * \param wrap_mode  one of PIPE_TEX_WRAP_x
471  */
472 static LLVMValueRef
473 lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
474                              LLVMValueRef coord,
475                              LLVMValueRef length,
476                              LLVMValueRef length_f,
477                              boolean is_pot,
478                              unsigned wrap_mode)
479 {
480    struct lp_build_context *coord_bld = &bld->coord_bld;
481    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
482    LLVMBuilderRef builder = bld->gallivm->builder;
483    LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
484    LLVMValueRef icoord;
485    
486    switch(wrap_mode) {
487    case PIPE_TEX_WRAP_REPEAT:
488       if (is_pot) {
489          coord = lp_build_mul(coord_bld, coord, length_f);
490          icoord = lp_build_ifloor(coord_bld, coord);
491          icoord = LLVMBuildAnd(builder, icoord, length_minus_one, "");
492       }
493       else {
494           /* take fraction, unnormalize */
495           coord = lp_build_fract_safe(coord_bld, coord);
496           coord = lp_build_mul(coord_bld, coord, length_f);
497           icoord = lp_build_itrunc(coord_bld, coord);
498       }
499       break;
500
501    case PIPE_TEX_WRAP_CLAMP:
502    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
503       if (bld->static_state->normalized_coords) {
504          /* scale coord to length */
505          coord = lp_build_mul(coord_bld, coord, length_f);
506       }
507
508       /* floor */
509       /* use itrunc instead since we clamp to 0 anyway */
510       icoord = lp_build_itrunc(coord_bld, coord);
511
512       /* clamp to [0, length - 1]. */
513       icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero,
514                               length_minus_one);
515       break;
516
517    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
518       if (bld->static_state->normalized_coords) {
519          /* scale coord to length */
520          coord = lp_build_mul(coord_bld, coord, length_f);
521       }
522       /* no clamp necessary, border masking will handle this */
523       icoord = lp_build_ifloor(coord_bld, coord);
524       break;
525
526    case PIPE_TEX_WRAP_MIRROR_REPEAT:
527       /* compute mirror function */
528       coord = lp_build_coord_mirror(bld, coord);
529
530       /* scale coord to length */
531       assert(bld->static_state->normalized_coords);
532       coord = lp_build_mul(coord_bld, coord, length_f);
533
534       /* itrunc == ifloor here */
535       icoord = lp_build_itrunc(coord_bld, coord);
536
537       /* clamp to [0, length - 1] */
538       icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
539       break;
540
541    case PIPE_TEX_WRAP_MIRROR_CLAMP:
542    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
543       coord = lp_build_abs(coord_bld, coord);
544
545       if (bld->static_state->normalized_coords) {
546          /* scale coord to length */
547          coord = lp_build_mul(coord_bld, coord, length_f);
548       }
549
550       /* itrunc == ifloor here */
551       icoord = lp_build_itrunc(coord_bld, coord);
552
553       /* clamp to [0, length - 1] */
554       icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
555       break;
556
557    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
558       coord = lp_build_abs(coord_bld, coord);
559
560       if (bld->static_state->normalized_coords) {
561          /* scale coord to length */
562          coord = lp_build_mul(coord_bld, coord, length_f);
563       }
564
565       /* itrunc == ifloor here */
566       icoord = lp_build_itrunc(coord_bld, coord);
567       break;
568
569    default:
570       assert(0);
571       icoord = NULL;
572    }
573
574    return icoord;
575 }
576
577
578 /**
579  * Generate code to sample a mipmap level with nearest filtering.
580  * If sampling a cube texture, r = cube face in [0,5].
581  */
582 static void
583 lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
584                               unsigned unit,
585                               LLVMValueRef size,
586                               LLVMValueRef row_stride_vec,
587                               LLVMValueRef img_stride_vec,
588                               LLVMValueRef data_ptr,
589                               LLVMValueRef mipoffsets,
590                               LLVMValueRef s,
591                               LLVMValueRef t,
592                               LLVMValueRef r,
593                               LLVMValueRef colors_out[4])
594 {
595    const unsigned dims = bld->dims;
596    LLVMValueRef width_vec;
597    LLVMValueRef height_vec;
598    LLVMValueRef depth_vec;
599    LLVMValueRef flt_size;
600    LLVMValueRef flt_width_vec;
601    LLVMValueRef flt_height_vec;
602    LLVMValueRef flt_depth_vec;
603    LLVMValueRef x, y = NULL, z = NULL;
604
605    lp_build_extract_image_sizes(bld,
606                                 &bld->int_size_bld,
607                                 bld->int_coord_type,
608                                 size,
609                                 &width_vec, &height_vec, &depth_vec);
610
611    flt_size = lp_build_int_to_float(&bld->float_size_bld, size);
612
613    lp_build_extract_image_sizes(bld,
614                                 &bld->float_size_bld,
615                                 bld->coord_type,
616                                 flt_size,
617                                 &flt_width_vec, &flt_height_vec, &flt_depth_vec);
618
619    /*
620     * Compute integer texcoords.
621     */
622    x = lp_build_sample_wrap_nearest(bld, s, width_vec, flt_width_vec,
623                                     bld->static_state->pot_width,
624                                     bld->static_state->wrap_s);
625    lp_build_name(x, "tex.x.wrapped");
626
627    if (dims >= 2) {
628       y = lp_build_sample_wrap_nearest(bld, t, height_vec, flt_height_vec,
629                                        bld->static_state->pot_height,
630                                        bld->static_state->wrap_t);
631       lp_build_name(y, "tex.y.wrapped");
632
633       if (dims == 3) {
634          z = lp_build_sample_wrap_nearest(bld, r, depth_vec, flt_depth_vec,
635                                           bld->static_state->pot_depth,
636                                           bld->static_state->wrap_r);
637          lp_build_name(z, "tex.z.wrapped");
638       }
639    }
640    if (bld->static_state->target == PIPE_TEXTURE_CUBE ||
641        bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
642        bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
643       z = r;
644       lp_build_name(z, "tex.z.layer");
645    }
646
647    /*
648     * Get texture colors.
649     */
650    lp_build_sample_texel_soa(bld, unit,
651                              width_vec, height_vec, depth_vec,
652                              x, y, z,
653                              row_stride_vec, img_stride_vec,
654                              data_ptr, mipoffsets, colors_out);
655 }
656
657
658 /**
659  * Generate code to sample a mipmap level with linear filtering.
660  * If sampling a cube texture, r = cube face in [0,5].
661  */
662 static void
663 lp_build_sample_image_linear(struct lp_build_sample_context *bld,
664                              unsigned unit,
665                              LLVMValueRef size,
666                              LLVMValueRef row_stride_vec,
667                              LLVMValueRef img_stride_vec,
668                              LLVMValueRef data_ptr,
669                              LLVMValueRef mipoffsets,
670                              LLVMValueRef s,
671                              LLVMValueRef t,
672                              LLVMValueRef r,
673                              LLVMValueRef colors_out[4])
674 {
675    const unsigned dims = bld->dims;
676    LLVMValueRef width_vec;
677    LLVMValueRef height_vec;
678    LLVMValueRef depth_vec;
679    LLVMValueRef flt_size;
680    LLVMValueRef flt_width_vec;
681    LLVMValueRef flt_height_vec;
682    LLVMValueRef flt_depth_vec;
683    LLVMValueRef x0, y0 = NULL, z0 = NULL, x1, y1 = NULL, z1 = NULL;
684    LLVMValueRef s_fpart, t_fpart = NULL, r_fpart = NULL;
685    LLVMValueRef neighbors[2][2][4];
686    int chan;
687
688    lp_build_extract_image_sizes(bld,
689                                 &bld->int_size_bld,
690                                 bld->int_coord_type,
691                                 size,
692                                 &width_vec, &height_vec, &depth_vec);
693
694    flt_size = lp_build_int_to_float(&bld->float_size_bld, size);
695
696    lp_build_extract_image_sizes(bld,
697                                 &bld->float_size_bld,
698                                 bld->coord_type,
699                                 flt_size,
700                                 &flt_width_vec, &flt_height_vec, &flt_depth_vec);
701
702    /*
703     * Compute integer texcoords.
704     */
705    lp_build_sample_wrap_linear(bld, s, width_vec, flt_width_vec,
706                                bld->static_state->pot_width,
707                                bld->static_state->wrap_s,
708                                &x0, &x1, &s_fpart);
709    lp_build_name(x0, "tex.x0.wrapped");
710    lp_build_name(x1, "tex.x1.wrapped");
711
712    if (dims >= 2) {
713       lp_build_sample_wrap_linear(bld, t, height_vec, flt_height_vec,
714                                   bld->static_state->pot_height,
715                                   bld->static_state->wrap_t,
716                                   &y0, &y1, &t_fpart);
717       lp_build_name(y0, "tex.y0.wrapped");
718       lp_build_name(y1, "tex.y1.wrapped");
719
720       if (dims == 3) {
721          lp_build_sample_wrap_linear(bld, r, depth_vec, flt_depth_vec,
722                                      bld->static_state->pot_depth,
723                                      bld->static_state->wrap_r,
724                                      &z0, &z1, &r_fpart);
725          lp_build_name(z0, "tex.z0.wrapped");
726          lp_build_name(z1, "tex.z1.wrapped");
727       }
728    }
729    if (bld->static_state->target == PIPE_TEXTURE_CUBE ||
730        bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
731        bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
732       z0 = z1 = r;  /* cube face or array layer */
733       lp_build_name(z0, "tex.z0.layer");
734       lp_build_name(z1, "tex.z1.layer");
735    }
736
737
738    /*
739     * Get texture colors.
740     */
741    /* get x0/x1 texels */
742    lp_build_sample_texel_soa(bld, unit,
743                              width_vec, height_vec, depth_vec,
744                              x0, y0, z0,
745                              row_stride_vec, img_stride_vec,
746                              data_ptr, mipoffsets, neighbors[0][0]);
747    lp_build_sample_texel_soa(bld, unit,
748                              width_vec, height_vec, depth_vec,
749                              x1, y0, z0,
750                              row_stride_vec, img_stride_vec,
751                              data_ptr, mipoffsets, neighbors[0][1]);
752
753    if (dims == 1) {
754       /* Interpolate two samples from 1D image to produce one color */
755       for (chan = 0; chan < 4; chan++) {
756          colors_out[chan] = lp_build_lerp(&bld->texel_bld, s_fpart,
757                                           neighbors[0][0][chan],
758                                           neighbors[0][1][chan]);
759       }
760    }
761    else {
762       /* 2D/3D texture */
763       LLVMValueRef colors0[4];
764
765       /* get x0/x1 texels at y1 */
766       lp_build_sample_texel_soa(bld, unit,
767                                 width_vec, height_vec, depth_vec,
768                                 x0, y1, z0,
769                                 row_stride_vec, img_stride_vec,
770                                 data_ptr, mipoffsets, neighbors[1][0]);
771       lp_build_sample_texel_soa(bld, unit,
772                                 width_vec, height_vec, depth_vec,
773                                 x1, y1, z0,
774                                 row_stride_vec, img_stride_vec,
775                                 data_ptr, mipoffsets, neighbors[1][1]);
776
777       /* Bilinear interpolate the four samples from the 2D image / 3D slice */
778       for (chan = 0; chan < 4; chan++) {
779          colors0[chan] = lp_build_lerp_2d(&bld->texel_bld,
780                                           s_fpart, t_fpart,
781                                           neighbors[0][0][chan],
782                                           neighbors[0][1][chan],
783                                           neighbors[1][0][chan],
784                                           neighbors[1][1][chan]);
785       }
786
787       if (dims == 3) {
788          LLVMValueRef neighbors1[2][2][4];
789          LLVMValueRef colors1[4];
790
791          /* get x0/x1/y0/y1 texels at z1 */
792          lp_build_sample_texel_soa(bld, unit,
793                                    width_vec, height_vec, depth_vec,
794                                    x0, y0, z1,
795                                    row_stride_vec, img_stride_vec,
796                                    data_ptr, mipoffsets, neighbors1[0][0]);
797          lp_build_sample_texel_soa(bld, unit,
798                                    width_vec, height_vec, depth_vec,
799                                    x1, y0, z1,
800                                    row_stride_vec, img_stride_vec,
801                                    data_ptr, mipoffsets, neighbors1[0][1]);
802          lp_build_sample_texel_soa(bld, unit,
803                                    width_vec, height_vec, depth_vec,
804                                    x0, y1, z1,
805                                    row_stride_vec, img_stride_vec,
806                                    data_ptr, mipoffsets, neighbors1[1][0]);
807          lp_build_sample_texel_soa(bld, unit,
808                                    width_vec, height_vec, depth_vec,
809                                    x1, y1, z1,
810                                    row_stride_vec, img_stride_vec,
811                                    data_ptr, mipoffsets, neighbors1[1][1]);
812
813          /* Bilinear interpolate the four samples from the second Z slice */
814          for (chan = 0; chan < 4; chan++) {
815             colors1[chan] = lp_build_lerp_2d(&bld->texel_bld,
816                                              s_fpart, t_fpart,
817                                              neighbors1[0][0][chan],
818                                              neighbors1[0][1][chan],
819                                              neighbors1[1][0][chan],
820                                              neighbors1[1][1][chan]);
821          }
822
823          /* Linearly interpolate the two samples from the two 3D slices */
824          for (chan = 0; chan < 4; chan++) {
825             colors_out[chan] = lp_build_lerp(&bld->texel_bld,
826                                              r_fpart,
827                                              colors0[chan], colors1[chan]);
828          }
829       }
830       else {
831          /* 2D tex */
832          for (chan = 0; chan < 4; chan++) {
833             colors_out[chan] = colors0[chan];
834          }
835       }
836    }
837 }
838
839
840 /**
841  * Sample the texture/mipmap using given image filter and mip filter.
842  * data0_ptr and data1_ptr point to the two mipmap levels to sample
843  * from.  width0/1_vec, height0/1_vec, depth0/1_vec indicate their sizes.
844  * If we're using nearest miplevel sampling the '1' values will be null/unused.
845  */
846 static void
847 lp_build_sample_mipmap(struct lp_build_sample_context *bld,
848                        unsigned unit,
849                        unsigned img_filter,
850                        unsigned mip_filter,
851                        LLVMValueRef s,
852                        LLVMValueRef t,
853                        LLVMValueRef r,
854                        LLVMValueRef ilevel0,
855                        LLVMValueRef ilevel1,
856                        LLVMValueRef lod_fpart,
857                        LLVMValueRef *colors_out)
858 {
859    LLVMBuilderRef builder = bld->gallivm->builder;
860    LLVMValueRef size0 = NULL;
861    LLVMValueRef size1 = NULL;
862    LLVMValueRef row_stride0_vec = NULL;
863    LLVMValueRef row_stride1_vec = NULL;
864    LLVMValueRef img_stride0_vec = NULL;
865    LLVMValueRef img_stride1_vec = NULL;
866    LLVMValueRef data_ptr0 = NULL;
867    LLVMValueRef data_ptr1 = NULL;
868    LLVMValueRef mipoff0 = NULL;
869    LLVMValueRef mipoff1 = NULL;
870    LLVMValueRef colors0[4], colors1[4];
871    unsigned chan;
872
873    /* sample the first mipmap level */
874    lp_build_mipmap_level_sizes(bld, ilevel0,
875                                &size0,
876                                &row_stride0_vec, &img_stride0_vec);
877    if (bld->num_lods == 1) {
878       data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
879    }
880    else {
881       /* This path should work for num_lods 1 too but slightly less efficient */
882       data_ptr0 = bld->base_ptr;
883       mipoff0 = lp_build_get_mip_offsets(bld, ilevel0);
884    }
885    if (img_filter == PIPE_TEX_FILTER_NEAREST) {
886       lp_build_sample_image_nearest(bld, unit,
887                                     size0,
888                                     row_stride0_vec, img_stride0_vec,
889                                     data_ptr0, mipoff0, s, t, r,
890                                     colors0);
891    }
892    else {
893       assert(img_filter == PIPE_TEX_FILTER_LINEAR);
894       lp_build_sample_image_linear(bld, unit,
895                                    size0,
896                                    row_stride0_vec, img_stride0_vec,
897                                    data_ptr0, mipoff0, s, t, r,
898                                    colors0);
899    }
900
901    /* Store the first level's colors in the output variables */
902    for (chan = 0; chan < 4; chan++) {
903        LLVMBuildStore(builder, colors0[chan], colors_out[chan]);
904    }
905
906    if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
907       struct lp_build_if_state if_ctx;
908       LLVMValueRef need_lerp;
909       unsigned num_quads = bld->coord_bld.type.length / 4;
910
911       /* need_lerp = lod_fpart > 0 */
912       if (num_quads == 1) {
913          need_lerp = LLVMBuildFCmp(builder, LLVMRealUGT,
914                                    lod_fpart, bld->perquadf_bld.zero,
915                                    "need_lerp");
916       }
917       else {
918          /*
919           * We'll do mip filtering if any of the quads need it.
920           * It might be better to split the vectors here and only fetch/filter
921           * quads which need it.
922           */
923          /*
924           * We unfortunately need to clamp lod_fpart here since we can get
925           * negative values which would screw up filtering if not all
926           * lod_fpart values have same sign.
927           */
928          lod_fpart = lp_build_max(&bld->perquadf_bld, lod_fpart,
929                                   bld->perquadf_bld.zero);
930          need_lerp = lp_build_compare(bld->gallivm, bld->perquadf_bld.type,
931                                       PIPE_FUNC_GREATER,
932                                       lod_fpart, bld->perquadf_bld.zero);
933          need_lerp = lp_build_any_true_range(&bld->perquadi_bld, num_quads, need_lerp);
934      }
935
936       lp_build_if(&if_ctx, bld->gallivm, need_lerp);
937       {
938          /* sample the second mipmap level */
939          lp_build_mipmap_level_sizes(bld, ilevel1,
940                                      &size1,
941                                      &row_stride1_vec, &img_stride1_vec);
942          if (bld->num_lods == 1) {
943             data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
944          }
945          else {
946             data_ptr1 = bld->base_ptr;
947             mipoff1 = lp_build_get_mip_offsets(bld, ilevel1);
948          }
949          if (img_filter == PIPE_TEX_FILTER_NEAREST) {
950             lp_build_sample_image_nearest(bld, unit,
951                                           size1,
952                                           row_stride1_vec, img_stride1_vec,
953                                           data_ptr1, mipoff1, s, t, r,
954                                           colors1);
955          }
956          else {
957             lp_build_sample_image_linear(bld, unit,
958                                          size1,
959                                          row_stride1_vec, img_stride1_vec,
960                                          data_ptr1, mipoff1, s, t, r,
961                                          colors1);
962          }
963
964          /* interpolate samples from the two mipmap levels */
965
966          lod_fpart = lp_build_unpack_broadcast_aos_scalars(bld->gallivm,
967                                                            bld->perquadf_bld.type,
968                                                            bld->texel_bld.type,
969                                                            lod_fpart);
970
971          for (chan = 0; chan < 4; chan++) {
972             colors0[chan] = lp_build_lerp(&bld->texel_bld, lod_fpart,
973                                           colors0[chan], colors1[chan]);
974             LLVMBuildStore(builder, colors0[chan], colors_out[chan]);
975          }
976       }
977       lp_build_endif(&if_ctx);
978    }
979 }
980
981
982 /**
983  * Clamp layer coord to valid values.
984  */
985 static LLVMValueRef
986 lp_build_layer_coord(struct lp_build_sample_context *bld,
987                      unsigned unit,
988                      LLVMValueRef layer)
989 {
990    LLVMValueRef maxlayer;
991
992    maxlayer = bld->dynamic_state->depth(bld->dynamic_state,
993                                         bld->gallivm, unit);
994    maxlayer = lp_build_sub(&bld->int_bld, maxlayer, bld->int_bld.one);
995    maxlayer = lp_build_broadcast_scalar(&bld->int_coord_bld, maxlayer);
996    return lp_build_clamp(&bld->int_coord_bld, layer,
997                          bld->int_coord_bld.zero, maxlayer);
998
999 }
1000
1001
1002 /**
1003  * Calculate cube face, lod, mip levels.
1004  */
1005 static void
1006 lp_build_sample_common(struct lp_build_sample_context *bld,
1007                        unsigned unit,
1008                        LLVMValueRef *s,
1009                        LLVMValueRef *t,
1010                        LLVMValueRef *r,
1011                        const struct lp_derivatives *derivs,
1012                        LLVMValueRef lod_bias, /* optional */
1013                        LLVMValueRef explicit_lod, /* optional */
1014                        LLVMValueRef *lod_ipart,
1015                        LLVMValueRef *lod_fpart,
1016                        LLVMValueRef *ilevel0,
1017                        LLVMValueRef *ilevel1)
1018 {
1019    const unsigned mip_filter = bld->static_state->min_mip_filter;
1020    const unsigned min_filter = bld->static_state->min_img_filter;
1021    const unsigned mag_filter = bld->static_state->mag_img_filter;
1022    const unsigned target = bld->static_state->target;
1023    LLVMValueRef first_level;
1024    struct lp_derivatives face_derivs;
1025
1026    /*
1027    printf("%s mip %d  min %d  mag %d\n", __FUNCTION__,
1028           mip_filter, min_filter, mag_filter);
1029    */
1030
1031    /*
1032     * Choose cube face, recompute texcoords and derivatives for the chosen face.
1033     */
1034    if (target == PIPE_TEXTURE_CUBE) {
1035       LLVMValueRef face, face_s, face_t;
1036       lp_build_cube_lookup(bld, *s, *t, *r, &face, &face_s, &face_t);
1037       *s = face_s; /* vec */
1038       *t = face_t; /* vec */
1039       /* use 'r' to indicate cube face */
1040       *r = face; /* vec */
1041
1042       /* recompute ddx, ddy using the new (s,t) face texcoords */
1043       face_derivs.ddx_ddy[0] = lp_build_packed_ddx_ddy_twocoord(&bld->coord_bld, *s, *t);
1044       face_derivs.ddx_ddy[1] = NULL;
1045       derivs = &face_derivs;
1046    }
1047    else if (target == PIPE_TEXTURE_1D_ARRAY) {
1048       *r = lp_build_iround(&bld->coord_bld, *t);
1049       *r = lp_build_layer_coord(bld, unit, *r);
1050    }
1051    else if (target == PIPE_TEXTURE_2D_ARRAY) {
1052       *r = lp_build_iround(&bld->coord_bld, *r);
1053       *r = lp_build_layer_coord(bld, unit, *r);
1054    }
1055
1056    /*
1057     * Compute the level of detail (float).
1058     */
1059    if (min_filter != mag_filter ||
1060        mip_filter != PIPE_TEX_MIPFILTER_NONE) {
1061       /* Need to compute lod either to choose mipmap levels or to
1062        * distinguish between minification/magnification with one mipmap level.
1063        */
1064       lp_build_lod_selector(bld, unit, derivs,
1065                             lod_bias, explicit_lod,
1066                             mip_filter,
1067                             lod_ipart, lod_fpart);
1068    } else {
1069       *lod_ipart = bld->perquadi_bld.zero;
1070    }
1071
1072    /*
1073     * Compute integer mipmap level(s) to fetch texels from: ilevel0, ilevel1
1074     */
1075    switch (mip_filter) {
1076    default:
1077       assert(0 && "bad mip_filter value in lp_build_sample_soa()");
1078       /* fall-through */
1079    case PIPE_TEX_MIPFILTER_NONE:
1080       /* always use mip level 0 */
1081       if (target == PIPE_TEXTURE_CUBE) {
1082          /* XXX this is a work-around for an apparent bug in LLVM 2.7.
1083           * We should be able to set ilevel0 = const(0) but that causes
1084           * bad x86 code to be emitted.
1085           * XXX should probably disable that on other llvm versions.
1086           */
1087          assert(*lod_ipart);
1088          lp_build_nearest_mip_level(bld, unit, *lod_ipart, ilevel0);
1089       }
1090       else {
1091          first_level = bld->dynamic_state->first_level(bld->dynamic_state,
1092                                                        bld->gallivm, unit);
1093          first_level = lp_build_broadcast_scalar(&bld->perquadi_bld, first_level);
1094          *ilevel0 = first_level;
1095       }
1096       break;
1097    case PIPE_TEX_MIPFILTER_NEAREST:
1098       assert(*lod_ipart);
1099       lp_build_nearest_mip_level(bld, unit, *lod_ipart, ilevel0);
1100       break;
1101    case PIPE_TEX_MIPFILTER_LINEAR:
1102       assert(*lod_ipart);
1103       assert(*lod_fpart);
1104       lp_build_linear_mip_levels(bld, unit,
1105                                  *lod_ipart, lod_fpart,
1106                                  ilevel0, ilevel1);
1107       break;
1108    }
1109 }
1110
1111 /**
1112  * General texture sampling codegen.
1113  * This function handles texture sampling for all texture targets (1D,
1114  * 2D, 3D, cube) and all filtering modes.
1115  */
1116 static void
1117 lp_build_sample_general(struct lp_build_sample_context *bld,
1118                         unsigned unit,
1119                         LLVMValueRef s,
1120                         LLVMValueRef t,
1121                         LLVMValueRef r,
1122                         LLVMValueRef lod_ipart,
1123                         LLVMValueRef lod_fpart,
1124                         LLVMValueRef ilevel0,
1125                         LLVMValueRef ilevel1,
1126                         LLVMValueRef *colors_out)
1127 {
1128    struct lp_build_context *int_bld = &bld->int_bld;
1129    LLVMBuilderRef builder = bld->gallivm->builder;
1130    const unsigned mip_filter = bld->static_state->min_mip_filter;
1131    const unsigned min_filter = bld->static_state->min_img_filter;
1132    const unsigned mag_filter = bld->static_state->mag_img_filter;
1133    LLVMValueRef texels[4];
1134    unsigned chan;
1135
1136    /*
1137     * Get/interpolate texture colors.
1138     */
1139
1140    for (chan = 0; chan < 4; ++chan) {
1141      texels[chan] = lp_build_alloca(bld->gallivm, bld->texel_bld.vec_type, "");
1142      lp_build_name(texels[chan], "sampler%u_texel_%c_var", unit, "xyzw"[chan]);
1143    }
1144
1145    if (min_filter == mag_filter) {
1146       /* no need to distinguish between minification and magnification */
1147       lp_build_sample_mipmap(bld, unit,
1148                              min_filter, mip_filter,
1149                              s, t, r,
1150                              ilevel0, ilevel1, lod_fpart,
1151                              texels);
1152    }
1153    else {
1154       /* Emit conditional to choose min image filter or mag image filter
1155        * depending on the lod being > 0 or <= 0, respectively.
1156        */
1157       struct lp_build_if_state if_ctx;
1158       LLVMValueRef minify;
1159
1160       /*
1161        * XXX this should to all lods into account, if some are min
1162        * some max probably could hack up the coords/weights in the linear
1163        * path with selects to work for nearest.
1164        * If that's just two quads sitting next to each other it seems
1165        * quite ok to do the same filtering method on both though, at
1166        * least unless we have explicit lod (and who uses different
1167        * min/mag filter with that?)
1168        */
1169       if (bld->num_lods > 1)
1170          lod_ipart = LLVMBuildExtractElement(builder, lod_ipart,
1171                                              lp_build_const_int32(bld->gallivm, 0), "");
1172
1173       /* minify = lod >= 0.0 */
1174       minify = LLVMBuildICmp(builder, LLVMIntSGE,
1175                              lod_ipart, int_bld->zero, "");
1176
1177       lp_build_if(&if_ctx, bld->gallivm, minify);
1178       {
1179          /* Use the minification filter */
1180          lp_build_sample_mipmap(bld, unit,
1181                                 min_filter, mip_filter,
1182                                 s, t, r,
1183                                 ilevel0, ilevel1, lod_fpart,
1184                                 texels);
1185       }
1186       lp_build_else(&if_ctx);
1187       {
1188          /* Use the magnification filter */
1189          lp_build_sample_mipmap(bld, unit,
1190                                 mag_filter, PIPE_TEX_MIPFILTER_NONE,
1191                                 s, t, r,
1192                                 ilevel0, NULL, NULL,
1193                                 texels);
1194       }
1195       lp_build_endif(&if_ctx);
1196    }
1197
1198    for (chan = 0; chan < 4; ++chan) {
1199      colors_out[chan] = LLVMBuildLoad(builder, texels[chan], "");
1200      lp_build_name(colors_out[chan], "sampler%u_texel_%c", unit, "xyzw"[chan]);
1201    }
1202 }
1203
1204
1205 /**
1206  * Texel fetch function.
1207  * In contrast to general sampling there is no filtering, no coord minification,
1208  * lod (if any) is always explicit uint, coords are uints (in terms of texel units)
1209  * directly to be applied to the selected mip level (after adding texel offsets).
1210  * This function handles texel fetch for all targets where texel fetch is supported
1211  * (no cube maps, but 1d, 2d, 3d are supported, arrays and buffers should be too).
1212  */
1213 static void
1214 lp_build_fetch_texel(struct lp_build_sample_context *bld,
1215                      unsigned unit,
1216                      const LLVMValueRef *coords,
1217                      LLVMValueRef explicit_lod,
1218                      const LLVMValueRef *offsets,
1219                      LLVMValueRef *colors_out)
1220 {
1221    struct lp_build_context *perquadi_bld = &bld->perquadi_bld;
1222    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
1223    unsigned dims = bld->dims, chan;
1224    unsigned target = bld->static_state->target;
1225    LLVMValueRef size, ilevel;
1226    LLVMValueRef row_stride_vec = NULL, img_stride_vec = NULL;
1227    LLVMValueRef x = coords[0], y = coords[1], z = coords[2];
1228    LLVMValueRef width, height, depth, i, j;
1229    LLVMValueRef offset, out_of_bounds, out1;
1230
1231    /* XXX just like ordinary sampling, we don't handle per-pixel lod (yet). */
1232    if (explicit_lod && bld->static_state->target != PIPE_BUFFER) {
1233       ilevel = lp_build_pack_aos_scalars(bld->gallivm, int_coord_bld->type,
1234                                          perquadi_bld->type, explicit_lod, 0);
1235       lp_build_nearest_mip_level(bld, unit, ilevel, &ilevel);
1236    }
1237    else {
1238       bld->num_lods = 1;
1239       ilevel = lp_build_const_int32(bld->gallivm, 0);
1240    }
1241    lp_build_mipmap_level_sizes(bld, ilevel,
1242                                &size,
1243                                &row_stride_vec, &img_stride_vec);
1244    lp_build_extract_image_sizes(bld, &bld->int_size_bld, int_coord_bld->type,
1245                                 size, &width, &height, &depth);
1246
1247    if (target == PIPE_TEXTURE_1D_ARRAY ||
1248        target == PIPE_TEXTURE_2D_ARRAY) {
1249       if (target == PIPE_TEXTURE_1D_ARRAY) {
1250          z = lp_build_layer_coord(bld, unit, y);
1251       }
1252       else {
1253          z = lp_build_layer_coord(bld, unit, z);
1254       }
1255    }
1256
1257    /* This is a lot like border sampling */
1258    if (offsets[0]) {
1259       /* XXX coords are really unsigned, offsets are signed */
1260       x = lp_build_add(int_coord_bld, x, offsets[0]);
1261    }
1262    out_of_bounds = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, x, int_coord_bld->zero);
1263    out1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, x, width);
1264    out_of_bounds = lp_build_or(int_coord_bld, out_of_bounds, out1);
1265
1266    if (dims >= 2) {
1267       if (offsets[1]) {
1268          y = lp_build_add(int_coord_bld, y, offsets[1]);
1269       }
1270       out1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, y, int_coord_bld->zero);
1271       out_of_bounds = lp_build_or(int_coord_bld, out_of_bounds, out1);
1272       out1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, y, height);
1273       out_of_bounds = lp_build_or(int_coord_bld, out_of_bounds, out1);
1274
1275       if (dims >= 3) {
1276          if (offsets[2]) {
1277             z = lp_build_add(int_coord_bld, z, offsets[2]);
1278          }
1279          out1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, z, int_coord_bld->zero);
1280          out_of_bounds = lp_build_or(int_coord_bld, out_of_bounds, out1);
1281          out1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, z, depth);
1282          out_of_bounds = lp_build_or(int_coord_bld, out_of_bounds, out1);
1283       }
1284    }
1285
1286    lp_build_sample_offset(int_coord_bld,
1287                           bld->format_desc,
1288                           x, y, z, row_stride_vec, img_stride_vec,
1289                           &offset, &i, &j);
1290
1291    if (bld->static_state->target != PIPE_BUFFER) {
1292       offset = lp_build_add(int_coord_bld, offset,
1293                             lp_build_get_mip_offsets(bld, ilevel));
1294    }
1295
1296    offset = lp_build_andnot(int_coord_bld, offset, out_of_bounds);
1297
1298    lp_build_fetch_rgba_soa(bld->gallivm,
1299                            bld->format_desc,
1300                            bld->texel_type,
1301                            bld->base_ptr, offset,
1302                            i, j,
1303                            colors_out);
1304
1305    if (0) {
1306       /*
1307        * Not needed except for ARB_robust_buffer_access_behavior.
1308        * Could use min/max above instead of out-of-bounds comparisons
1309        * (in fact cast to unsigned and min only is sufficient)
1310        * if we don't care about the result returned for out-of-bounds.
1311        */
1312       for (chan = 0; chan < 4; chan++) {
1313          colors_out[chan] = lp_build_select(&bld->texel_bld, out_of_bounds,
1314                                             bld->texel_bld.zero, colors_out[chan]);
1315       }
1316    }
1317 }
1318
1319
1320 /**
1321  * Do shadow test/comparison.
1322  * \param coords  incoming texcoords
1323  * \param texel  the texel to compare against (use the X channel)
1324  * Ideally this should really be done per-sample.
1325  */
1326 static void
1327 lp_build_sample_compare(struct lp_build_sample_context *bld,
1328                         const LLVMValueRef *coords,
1329                         LLVMValueRef texel[4])
1330 {
1331    struct lp_build_context *texel_bld = &bld->texel_bld;
1332    LLVMBuilderRef builder = bld->gallivm->builder;
1333    LLVMValueRef res, p;
1334    const unsigned chan = 0;
1335
1336    if (bld->static_state->compare_mode == PIPE_TEX_COMPARE_NONE)
1337       return;
1338
1339    if (bld->static_state->target == PIPE_TEXTURE_2D_ARRAY ||
1340        bld->static_state->target == PIPE_TEXTURE_CUBE) {
1341       p = coords[3];
1342    }
1343    else {
1344       p = coords[2];
1345    }
1346
1347    /* debug code */
1348    if (0) {
1349       LLVMValueRef indx = lp_build_const_int32(bld->gallivm, 0);
1350       LLVMValueRef coord = LLVMBuildExtractElement(builder, p, indx, "");
1351       LLVMValueRef tex = LLVMBuildExtractElement(builder, texel[chan], indx, "");
1352       lp_build_printf(bld->gallivm, "shadow compare coord %f to texture %f\n",
1353                       coord, tex);
1354    }
1355
1356    /* Clamp p coords to [0,1] */
1357    p = lp_build_clamp(&bld->coord_bld, p,
1358                       bld->coord_bld.zero,
1359                       bld->coord_bld.one);
1360
1361    /* result = (p FUNC texel) ? 1 : 0 */
1362    res = lp_build_cmp(texel_bld, bld->static_state->compare_func,
1363                       p, texel[chan]);
1364    res = lp_build_select(texel_bld, res, texel_bld->one, texel_bld->zero);
1365
1366    /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
1367    texel[0] =
1368    texel[1] =
1369    texel[2] = res;
1370    texel[3] = texel_bld->one;
1371 }
1372
1373
1374 /**
1375  * Just set texels to white instead of actually sampling the texture.
1376  * For debugging.
1377  */
1378 void
1379 lp_build_sample_nop(struct gallivm_state *gallivm,
1380                     struct lp_type type,
1381                     const LLVMValueRef *coords,
1382                     LLVMValueRef texel_out[4])
1383 {
1384    LLVMValueRef one = lp_build_one(gallivm, type);
1385    unsigned chan;
1386
1387    for (chan = 0; chan < 4; chan++) {
1388       texel_out[chan] = one;
1389    }  
1390 }
1391
1392
1393 /**
1394  * Build texture sampling code.
1395  * 'texel' will return a vector of four LLVMValueRefs corresponding to
1396  * R, G, B, A.
1397  * \param type  vector float type to use for coords, etc.
1398  * \param is_fetch  if this is a texel fetch instruction.
1399  * \param derivs  partial derivatives of (s,t,r,q) with respect to x and y
1400  */
1401 void
1402 lp_build_sample_soa(struct gallivm_state *gallivm,
1403                     const struct lp_sampler_static_state *static_state,
1404                     struct lp_sampler_dynamic_state *dynamic_state,
1405                     struct lp_type type,
1406                     boolean is_fetch,
1407                     unsigned unit,
1408                     const LLVMValueRef *coords,
1409                     const LLVMValueRef *offsets,
1410                     const struct lp_derivatives *derivs,
1411                     LLVMValueRef lod_bias, /* optional */
1412                     LLVMValueRef explicit_lod, /* optional */
1413                     LLVMValueRef texel_out[4])
1414 {
1415    unsigned dims = texture_dims(static_state->target);
1416    unsigned num_quads = type.length / 4;
1417    unsigned mip_filter = static_state->min_mip_filter;
1418    struct lp_build_sample_context bld;
1419    LLVMTypeRef i32t = LLVMInt32TypeInContext(gallivm->context);
1420    LLVMBuilderRef builder = gallivm->builder;
1421    LLVMValueRef tex_width, tex_height, tex_depth;
1422    LLVMValueRef s;
1423    LLVMValueRef t;
1424    LLVMValueRef r;
1425
1426    if (0) {
1427       enum pipe_format fmt = static_state->format;
1428       debug_printf("Sample from %s\n", util_format_name(fmt));
1429    }
1430
1431    assert(type.floating);
1432
1433    /* Setup our build context */
1434    memset(&bld, 0, sizeof bld);
1435    bld.gallivm = gallivm;
1436    bld.static_state = static_state;
1437    bld.dynamic_state = dynamic_state;
1438    bld.format_desc = util_format_description(static_state->format);
1439    bld.dims = dims;
1440
1441    bld.vector_width = lp_type_width(type);
1442
1443    bld.float_type = lp_type_float(32);
1444    bld.int_type = lp_type_int(32);
1445    bld.coord_type = type;
1446    bld.int_coord_type = lp_int_type(type);
1447    bld.float_size_in_type = lp_type_float(32);
1448    bld.float_size_in_type.length = dims > 1 ? 4 : 1;
1449    bld.int_size_in_type = lp_int_type(bld.float_size_in_type);
1450    bld.texel_type = type;
1451    bld.perquadf_type = type;
1452    /* we want native vector size to be able to use our intrinsics */
1453    bld.perquadf_type.length = type.length > 4 ? ((type.length + 15) / 16) * 4 : 1;
1454    bld.perquadi_type = lp_int_type(bld.perquadf_type);
1455
1456    /* always using the first channel hopefully should be safe,
1457     * if not things WILL break in other places anyway.
1458     */
1459    if (bld.format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB &&
1460        bld.format_desc->channel[0].pure_integer) {
1461       if (bld.format_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) {
1462          bld.texel_type = lp_type_int_vec(type.width, type.width * type.length);
1463       }
1464       else if (bld.format_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED) {
1465          bld.texel_type = lp_type_uint_vec(type.width, type.width * type.length);
1466       }
1467    }
1468
1469    /*
1470     * There are other situations where at least the multiple int lods could be
1471     * avoided like min and max lod being equal.
1472     */
1473    if ((is_fetch && explicit_lod && bld.static_state->target != PIPE_BUFFER) ||
1474        (!is_fetch && mip_filter != PIPE_TEX_MIPFILTER_NONE)) {
1475       bld.num_lods = num_quads;
1476    }
1477    else {
1478       bld.num_lods = 1;
1479    }
1480
1481    bld.float_size_type = bld.float_size_in_type;
1482    bld.float_size_type.length = bld.num_lods > 1 ? type.length :
1483                                    bld.float_size_in_type.length;
1484    bld.int_size_type = lp_int_type(bld.float_size_type);
1485
1486    lp_build_context_init(&bld.float_bld, gallivm, bld.float_type);
1487    lp_build_context_init(&bld.float_vec_bld, gallivm, type);
1488    lp_build_context_init(&bld.int_bld, gallivm, bld.int_type);
1489    lp_build_context_init(&bld.coord_bld, gallivm, bld.coord_type);
1490    lp_build_context_init(&bld.int_coord_bld, gallivm, bld.int_coord_type);
1491    lp_build_context_init(&bld.int_size_in_bld, gallivm, bld.int_size_in_type);
1492    lp_build_context_init(&bld.float_size_in_bld, gallivm, bld.float_size_in_type);
1493    lp_build_context_init(&bld.int_size_bld, gallivm, bld.int_size_type);
1494    lp_build_context_init(&bld.float_size_bld, gallivm, bld.float_size_type);
1495    lp_build_context_init(&bld.texel_bld, gallivm, bld.texel_type);
1496    lp_build_context_init(&bld.perquadf_bld, gallivm, bld.perquadf_type);
1497    lp_build_context_init(&bld.perquadi_bld, gallivm, bld.perquadi_type);
1498
1499    /* Get the dynamic state */
1500    tex_width = dynamic_state->width(dynamic_state, gallivm, unit);
1501    tex_height = dynamic_state->height(dynamic_state, gallivm, unit);
1502    tex_depth = dynamic_state->depth(dynamic_state, gallivm, unit);
1503    bld.row_stride_array = dynamic_state->row_stride(dynamic_state, gallivm, unit);
1504    bld.img_stride_array = dynamic_state->img_stride(dynamic_state, gallivm, unit);
1505    bld.base_ptr = dynamic_state->base_ptr(dynamic_state, gallivm, unit);
1506    bld.mip_offsets = dynamic_state->mip_offsets(dynamic_state, gallivm, unit);
1507    /* Note that mip_offsets is an array[level] of offsets to texture images */
1508
1509    s = coords[0];
1510    t = coords[1];
1511    r = coords[2];
1512
1513    /* width, height, depth as single int vector */
1514    if (dims <= 1) {
1515       bld.int_size = tex_width;
1516    }
1517    else {
1518       bld.int_size = LLVMBuildInsertElement(builder, bld.int_size_in_bld.undef,
1519                                             tex_width, LLVMConstInt(i32t, 0, 0), "");
1520       if (dims >= 2) {
1521          bld.int_size = LLVMBuildInsertElement(builder, bld.int_size,
1522                                                tex_height, LLVMConstInt(i32t, 1, 0), "");
1523          if (dims >= 3) {
1524             bld.int_size = LLVMBuildInsertElement(builder, bld.int_size,
1525                                                   tex_depth, LLVMConstInt(i32t, 2, 0), "");
1526          }
1527       }
1528    }
1529
1530    if (0) {
1531       /* For debug: no-op texture sampling */
1532       lp_build_sample_nop(gallivm,
1533                           bld.texel_type,
1534                           coords,
1535                           texel_out);
1536    }
1537
1538    else if (is_fetch) {
1539       lp_build_fetch_texel(&bld, unit, coords,
1540                            explicit_lod, offsets,
1541                            texel_out);
1542    }
1543
1544    else {
1545       LLVMValueRef lod_ipart = NULL, lod_fpart = NULL;
1546       LLVMValueRef ilevel0 = NULL, ilevel1 = NULL;
1547       boolean use_aos = util_format_fits_8unorm(bld.format_desc) &&
1548                         lp_is_simple_wrap_mode(static_state->wrap_s) &&
1549                         lp_is_simple_wrap_mode(static_state->wrap_t);
1550
1551       if ((gallivm_debug & GALLIVM_DEBUG_PERF) &&
1552           !use_aos && util_format_fits_8unorm(bld.format_desc)) {
1553          debug_printf("%s: using floating point linear filtering for %s\n",
1554                       __FUNCTION__, bld.format_desc->short_name);
1555          debug_printf("  min_img %d  mag_img %d  mip %d  wraps %d  wrapt %d\n",
1556                       static_state->min_img_filter,
1557                       static_state->mag_img_filter,
1558                       static_state->min_mip_filter,
1559                       static_state->wrap_s,
1560                       static_state->wrap_t);
1561       }
1562
1563       lp_build_sample_common(&bld, unit,
1564                              &s, &t, &r,
1565                              derivs, lod_bias, explicit_lod,
1566                              &lod_ipart, &lod_fpart,
1567                              &ilevel0, &ilevel1);
1568
1569       /*
1570        * we only try 8-wide sampling with soa as it appears to
1571        * be a loss with aos with AVX (but it should work).
1572        * (It should be faster if we'd support avx2)
1573        */
1574       if (num_quads == 1 || !use_aos) {
1575
1576          if (num_quads > 1) {
1577             if (mip_filter == PIPE_TEX_MIPFILTER_NONE) {
1578                LLVMValueRef index0 = lp_build_const_int32(gallivm, 0);
1579                /*
1580                 * These parameters are the same for all quads,
1581                 * could probably simplify.
1582                 */
1583                lod_ipart = LLVMBuildExtractElement(builder, lod_ipart, index0, "");
1584                ilevel0 = LLVMBuildExtractElement(builder, ilevel0, index0, "");
1585             }
1586          }
1587          if (use_aos) {
1588             /* do sampling/filtering with fixed pt arithmetic */
1589             lp_build_sample_aos(&bld, unit,
1590                                 s, t, r,
1591                                 lod_ipart, lod_fpart,
1592                                 ilevel0, ilevel1,
1593                                 texel_out);
1594          }
1595
1596          else {
1597             lp_build_sample_general(&bld, unit,
1598                                     s, t, r,
1599                                     lod_ipart, lod_fpart,
1600                                     ilevel0, ilevel1,
1601                                     texel_out);
1602          }
1603       }
1604       else {
1605          unsigned j;
1606          struct lp_build_sample_context bld4;
1607          struct lp_type type4 = type;
1608          unsigned i;
1609          LLVMValueRef texelout4[4];
1610          LLVMValueRef texelouttmp[4][LP_MAX_VECTOR_LENGTH/16];
1611
1612          type4.length = 4;
1613
1614          /* Setup our build context */
1615          memset(&bld4, 0, sizeof bld4);
1616          bld4.gallivm = bld.gallivm;
1617          bld4.static_state = bld.static_state;
1618          bld4.dynamic_state = bld.dynamic_state;
1619          bld4.format_desc = bld.format_desc;
1620          bld4.dims = bld.dims;
1621          bld4.row_stride_array = bld.row_stride_array;
1622          bld4.img_stride_array = bld.img_stride_array;
1623          bld4.base_ptr = bld.base_ptr;
1624          bld4.mip_offsets = bld.mip_offsets;
1625          bld4.int_size = bld.int_size;
1626
1627          bld4.vector_width = lp_type_width(type4);
1628
1629          bld4.float_type = lp_type_float(32);
1630          bld4.int_type = lp_type_int(32);
1631          bld4.coord_type = type4;
1632          bld4.int_coord_type = lp_int_type(type4);
1633          bld4.float_size_in_type = lp_type_float(32);
1634          bld4.float_size_in_type.length = dims > 1 ? 4 : 1;
1635          bld4.int_size_in_type = lp_int_type(bld4.float_size_in_type);
1636          bld4.texel_type = bld.texel_type;
1637          bld4.texel_type.length = 4;
1638          bld4.perquadf_type = type4;
1639          /* we want native vector size to be able to use our intrinsics */
1640          bld4.perquadf_type.length = 1;
1641          bld4.perquadi_type = lp_int_type(bld4.perquadf_type);
1642
1643          bld4.num_lods = 1;
1644          bld4.int_size_type = bld4.int_size_in_type;
1645          bld4.float_size_type = bld4.float_size_in_type;
1646
1647          lp_build_context_init(&bld4.float_bld, gallivm, bld4.float_type);
1648          lp_build_context_init(&bld4.float_vec_bld, gallivm, type4);
1649          lp_build_context_init(&bld4.int_bld, gallivm, bld4.int_type);
1650          lp_build_context_init(&bld4.coord_bld, gallivm, bld4.coord_type);
1651          lp_build_context_init(&bld4.int_coord_bld, gallivm, bld4.int_coord_type);
1652          lp_build_context_init(&bld4.int_size_in_bld, gallivm, bld4.int_size_in_type);
1653          lp_build_context_init(&bld4.float_size_in_bld, gallivm, bld4.float_size_in_type);
1654          lp_build_context_init(&bld4.int_size_bld, gallivm, bld4.int_size_type);
1655          lp_build_context_init(&bld4.float_size_bld, gallivm, bld4.float_size_type);
1656          lp_build_context_init(&bld4.texel_bld, gallivm, bld4.texel_type);
1657          lp_build_context_init(&bld4.perquadf_bld, gallivm, bld4.perquadf_type);
1658          lp_build_context_init(&bld4.perquadi_bld, gallivm, bld4.perquadi_type);
1659
1660          for (i = 0; i < num_quads; i++) {
1661             LLVMValueRef s4, t4, r4;
1662             LLVMValueRef lod_iparts, lod_fparts = NULL;
1663             LLVMValueRef ilevel0s, ilevel1s = NULL;
1664             LLVMValueRef indexi = lp_build_const_int32(gallivm, i);
1665
1666             s4 = lp_build_extract_range(gallivm, s, 4*i, 4);
1667             t4 = lp_build_extract_range(gallivm, t, 4*i, 4);
1668             r4 = lp_build_extract_range(gallivm, r, 4*i, 4);
1669             lod_iparts = LLVMBuildExtractElement(builder, lod_ipart, indexi, "");
1670             ilevel0s = LLVMBuildExtractElement(builder, ilevel0, indexi, "");
1671             if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
1672                ilevel1s = LLVMBuildExtractElement(builder, ilevel1, indexi, "");
1673                lod_fparts = LLVMBuildExtractElement(builder, lod_fpart, indexi, "");
1674             }
1675
1676             if (use_aos) {
1677                /* do sampling/filtering with fixed pt arithmetic */
1678                lp_build_sample_aos(&bld4, unit,
1679                                    s4, t4, r4,
1680                                    lod_iparts, lod_fparts,
1681                                    ilevel0s, ilevel1s,
1682                                    texelout4);
1683             }
1684
1685             else {
1686                lp_build_sample_general(&bld4, unit,
1687                                        s4, t4, r4,
1688                                        lod_iparts, lod_fparts,
1689                                        ilevel0s, ilevel1s,
1690                                        texelout4);
1691             }
1692             for (j = 0; j < 4; j++) {
1693                texelouttmp[j][i] = texelout4[j];
1694             }
1695          }
1696
1697          for (j = 0; j < 4; j++) {
1698             texel_out[j] = lp_build_concat(gallivm, texelouttmp[j], type4, num_quads);
1699          }
1700       }
1701
1702       lp_build_sample_compare(&bld, coords, texel_out);
1703    }
1704
1705    if (static_state->target != PIPE_BUFFER) {
1706       apply_sampler_swizzle(&bld, texel_out);
1707    }
1708
1709    /*
1710     * texel type can be a (32bit) int/uint (for pure int formats only),
1711     * however we are expected to always return floats (storage is untyped).
1712     */
1713    if (!bld.texel_type.floating) {
1714       unsigned chan;
1715       for (chan = 0; chan < 4; chan++) {
1716          texel_out[chan] = LLVMBuildBitCast(builder, texel_out[chan],
1717                                             lp_build_vec_type(gallivm, type), "");
1718       }
1719    }
1720 }
1721
1722 void
1723 lp_build_size_query_soa(struct gallivm_state *gallivm,
1724                         const struct lp_sampler_static_state *static_state,
1725                         struct lp_sampler_dynamic_state *dynamic_state,
1726                         struct lp_type int_type,
1727                         unsigned unit,
1728                         LLVMValueRef explicit_lod,
1729                         LLVMValueRef *sizes_out)
1730 {
1731    LLVMValueRef lod;
1732    LLVMValueRef size;
1733    int dims, i;
1734    boolean has_array = FALSE;
1735    struct lp_build_context bld_int_vec;
1736
1737    switch (static_state->target) {
1738    case PIPE_TEXTURE_1D:
1739    case PIPE_BUFFER:
1740       dims = 1;
1741       break;
1742    case PIPE_TEXTURE_1D_ARRAY:
1743       dims = 1;
1744       has_array = TRUE;
1745       break;
1746    case PIPE_TEXTURE_2D:
1747    case PIPE_TEXTURE_CUBE:
1748    case PIPE_TEXTURE_RECT:
1749       dims = 2;
1750       break;
1751    case PIPE_TEXTURE_3D:
1752       dims = 3;
1753       break;
1754    case PIPE_TEXTURE_2D_ARRAY:
1755       dims = 2;
1756       has_array = TRUE;
1757       break;
1758    default:
1759       assert(0);
1760       return;
1761    }
1762
1763    assert(!int_type.floating);
1764
1765    lp_build_context_init(&bld_int_vec, gallivm, lp_type_int_vec(32, 128));
1766
1767    if (explicit_lod) {
1768       LLVMValueRef first_level;
1769       lod = LLVMBuildExtractElement(gallivm->builder, explicit_lod, lp_build_const_int32(gallivm, 0), "");
1770       first_level = dynamic_state->first_level(dynamic_state, gallivm, unit);
1771       lod = lp_build_broadcast_scalar(&bld_int_vec,
1772                                       LLVMBuildAdd(gallivm->builder, lod, first_level, "lod"));
1773
1774    } else {
1775       lod = bld_int_vec.zero;
1776    }
1777
1778    size = bld_int_vec.undef;
1779
1780    size = LLVMBuildInsertElement(gallivm->builder, size,
1781                                  dynamic_state->width(dynamic_state, gallivm, unit),
1782                                  lp_build_const_int32(gallivm, 0), "");
1783
1784    if (dims >= 2) {
1785       size = LLVMBuildInsertElement(gallivm->builder, size,
1786                                     dynamic_state->height(dynamic_state, gallivm, unit),
1787                                     lp_build_const_int32(gallivm, 1), "");
1788    }
1789
1790    if (dims >= 3) {
1791       size = LLVMBuildInsertElement(gallivm->builder, size,
1792                                     dynamic_state->depth(dynamic_state, gallivm, unit),
1793                                     lp_build_const_int32(gallivm, 2), "");
1794    }
1795
1796    size = lp_build_minify(&bld_int_vec, size, lod);
1797  
1798    if (has_array)
1799       size = LLVMBuildInsertElement(gallivm->builder, size,
1800                                     dynamic_state->depth(dynamic_state, gallivm, unit),
1801                                     lp_build_const_int32(gallivm, dims), "");
1802
1803    for (i = 0; i < dims + (has_array ? 1 : 0); i++) {
1804       sizes_out[i] = lp_build_extract_broadcast(gallivm, bld_int_vec.type, int_type,
1805                                                 size,
1806                                                 lp_build_const_int32(gallivm, i));
1807    }
1808 }