OSDN Git Service

llvmpipe: Implement TXQ.
[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 "lp_bld_debug.h"
45 #include "lp_bld_type.h"
46 #include "lp_bld_const.h"
47 #include "lp_bld_conv.h"
48 #include "lp_bld_arit.h"
49 #include "lp_bld_bitarit.h"
50 #include "lp_bld_logic.h"
51 #include "lp_bld_printf.h"
52 #include "lp_bld_swizzle.h"
53 #include "lp_bld_flow.h"
54 #include "lp_bld_gather.h"
55 #include "lp_bld_format.h"
56 #include "lp_bld_sample.h"
57 #include "lp_bld_sample_aos.h"
58 #include "lp_bld_struct.h"
59 #include "lp_bld_quad.h"
60
61
62 /**
63  * Generate code to fetch a texel from a texture at int coords (x, y, z).
64  * The computation depends on whether the texture is 1D, 2D or 3D.
65  * The result, texel, will be float vectors:
66  *   texel[0] = red values
67  *   texel[1] = green values
68  *   texel[2] = blue values
69  *   texel[3] = alpha values
70  */
71 static void
72 lp_build_sample_texel_soa(struct lp_build_sample_context *bld,
73                           unsigned unit,
74                           LLVMValueRef width,
75                           LLVMValueRef height,
76                           LLVMValueRef depth,
77                           LLVMValueRef x,
78                           LLVMValueRef y,
79                           LLVMValueRef z,
80                           LLVMValueRef y_stride,
81                           LLVMValueRef z_stride,
82                           LLVMValueRef data_ptr,
83                           LLVMValueRef texel_out[4])
84 {
85    const struct lp_sampler_static_state *static_state = bld->static_state;
86    const unsigned dims = bld->dims;
87    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
88    LLVMBuilderRef builder = bld->gallivm->builder;
89    LLVMValueRef offset;
90    LLVMValueRef i, j;
91    LLVMValueRef use_border = NULL;
92
93    /* use_border = x < 0 || x >= width || y < 0 || y >= height */
94    if (lp_sampler_wrap_mode_uses_border_color(static_state->wrap_s,
95                                               static_state->min_img_filter,
96                                               static_state->mag_img_filter)) {
97       LLVMValueRef b1, b2;
98       b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, x, int_coord_bld->zero);
99       b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, x, width);
100       use_border = LLVMBuildOr(builder, b1, b2, "b1_or_b2");
101    }
102
103    if (dims >= 2 &&
104        lp_sampler_wrap_mode_uses_border_color(static_state->wrap_t,
105                                               static_state->min_img_filter,
106                                               static_state->mag_img_filter)) {
107       LLVMValueRef b1, b2;
108       b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, y, int_coord_bld->zero);
109       b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, y, height);
110       if (use_border) {
111          use_border = LLVMBuildOr(builder, use_border, b1, "ub_or_b1");
112          use_border = LLVMBuildOr(builder, use_border, b2, "ub_or_b2");
113       }
114       else {
115          use_border = LLVMBuildOr(builder, b1, b2, "b1_or_b2");
116       }
117    }
118
119    if (dims == 3 &&
120        lp_sampler_wrap_mode_uses_border_color(static_state->wrap_r,
121                                               static_state->min_img_filter,
122                                               static_state->mag_img_filter)) {
123       LLVMValueRef b1, b2;
124       b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, z, int_coord_bld->zero);
125       b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, z, depth);
126       if (use_border) {
127          use_border = LLVMBuildOr(builder, use_border, b1, "ub_or_b1");
128          use_border = LLVMBuildOr(builder, use_border, b2, "ub_or_b2");
129       }
130       else {
131          use_border = LLVMBuildOr(builder, b1, b2, "b1_or_b2");
132       }
133    }
134
135    /* convert x,y,z coords to linear offset from start of texture, in bytes */
136    lp_build_sample_offset(&bld->int_coord_bld,
137                           bld->format_desc,
138                           x, y, z, y_stride, z_stride,
139                           &offset, &i, &j);
140
141    if (use_border) {
142       /* If we can sample the border color, it means that texcoords may
143        * lie outside the bounds of the texture image.  We need to do
144        * something to prevent reading out of bounds and causing a segfault.
145        *
146        * Simply AND the texture coords with !use_border.  This will cause
147        * coords which are out of bounds to become zero.  Zero's guaranteed
148        * to be inside the texture image.
149        */
150       offset = lp_build_andnot(&bld->int_coord_bld, offset, use_border);
151    }
152
153    lp_build_fetch_rgba_soa(bld->gallivm,
154                            bld->format_desc,
155                            bld->texel_type,
156                            data_ptr, offset,
157                            i, j,
158                            texel_out);
159
160    /*
161     * Note: if we find an app which frequently samples the texture border
162     * we might want to implement a true conditional here to avoid sampling
163     * the texture whenever possible (since that's quite a bit of code).
164     * Ex:
165     *   if (use_border) {
166     *      texel = border_color;
167     *   }
168     *   else {
169     *      texel = sample_texture(coord);
170     *   }
171     * As it is now, we always sample the texture, then selectively replace
172     * the texel color results with the border color.
173     */
174
175    if (use_border) {
176       /* select texel color or border color depending on use_border */
177       LLVMValueRef border_color_ptr = 
178          bld->dynamic_state->border_color(bld->dynamic_state,
179                                           bld->gallivm, unit);
180       int chan;
181       for (chan = 0; chan < 4; chan++) {
182          LLVMValueRef border_chan =
183             lp_build_array_get(bld->gallivm, border_color_ptr,
184                                lp_build_const_int32(bld->gallivm, chan));
185          LLVMValueRef border_chan_vec =
186             lp_build_broadcast_scalar(&bld->float_vec_bld, border_chan);
187          texel_out[chan] = lp_build_select(&bld->texel_bld, use_border,
188                                            border_chan_vec, texel_out[chan]);
189       }
190    }
191 }
192
193
194 /**
195  * Helper to compute the mirror function for the PIPE_WRAP_MIRROR modes.
196  */
197 static LLVMValueRef
198 lp_build_coord_mirror(struct lp_build_sample_context *bld,
199                       LLVMValueRef coord)
200 {
201    struct lp_build_context *coord_bld = &bld->coord_bld;
202    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
203    LLVMValueRef fract, flr, isOdd;
204
205    lp_build_ifloor_fract(coord_bld, coord, &flr, &fract);
206
207    /* isOdd = flr & 1 */
208    isOdd = LLVMBuildAnd(bld->gallivm->builder, flr, int_coord_bld->one, "");
209
210    /* make coord positive or negative depending on isOdd */
211    coord = lp_build_set_sign(coord_bld, fract, isOdd);
212
213    /* convert isOdd to float */
214    isOdd = lp_build_int_to_float(coord_bld, isOdd);
215
216    /* add isOdd to coord */
217    coord = lp_build_add(coord_bld, coord, isOdd);
218
219    return coord;
220 }
221
222
223 /**
224  * Build LLVM code for texture wrap mode for linear filtering.
225  * \param x0_out  returns first integer texcoord
226  * \param x1_out  returns second integer texcoord
227  * \param weight_out  returns linear interpolation weight
228  */
229 static void
230 lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
231                             LLVMValueRef coord,
232                             LLVMValueRef length,
233                             LLVMValueRef length_f,
234                             boolean is_pot,
235                             unsigned wrap_mode,
236                             LLVMValueRef *x0_out,
237                             LLVMValueRef *x1_out,
238                             LLVMValueRef *weight_out)
239 {
240    struct lp_build_context *coord_bld = &bld->coord_bld;
241    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
242    LLVMBuilderRef builder = bld->gallivm->builder;
243    LLVMValueRef half = lp_build_const_vec(bld->gallivm, coord_bld->type, 0.5);
244    LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
245    LLVMValueRef coord0, coord1, weight;
246
247    switch(wrap_mode) {
248    case PIPE_TEX_WRAP_REPEAT:
249       /* mul by size and subtract 0.5 */
250       coord = lp_build_mul(coord_bld, coord, length_f);
251       coord = lp_build_sub(coord_bld, coord, half);
252       /* convert to int, compute lerp weight */
253       lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
254       /* repeat wrap */
255       if (is_pot) {
256          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
257          coord0 = LLVMBuildAnd(builder, coord0, length_minus_one, "");
258          coord1 = LLVMBuildAnd(builder, coord1, length_minus_one, "");
259       }
260       else {
261          /* Add a bias to the texcoord to handle negative coords */
262          LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
263          LLVMValueRef mask;
264          coord0 = LLVMBuildAdd(builder, coord0, bias, "");
265          coord0 = LLVMBuildURem(builder, coord0, length, "");
266          mask = lp_build_compare(bld->gallivm, int_coord_bld->type,
267                                  PIPE_FUNC_NOTEQUAL, coord0, length_minus_one);
268          coord1 = LLVMBuildAnd(builder,
269                               lp_build_add(int_coord_bld, coord0, int_coord_bld->one),
270                               mask, "");
271       }
272       break;
273
274    case PIPE_TEX_WRAP_CLAMP:
275       if (bld->static_state->normalized_coords) {
276          /* scale coord to length */
277          coord = lp_build_mul(coord_bld, coord, length_f);
278       }
279
280       /* clamp to [0, length] */
281       coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, length_f);
282
283       coord = lp_build_sub(coord_bld, coord, half);
284
285       /* convert to int, compute lerp weight */
286       lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
287       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
288       break;
289
290    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
291       {
292          struct lp_build_context abs_coord_bld = bld->coord_bld;
293          abs_coord_bld.type.sign = FALSE;
294
295          if (bld->static_state->normalized_coords) {
296             /* mul by tex size */
297             coord = lp_build_mul(coord_bld, coord, length_f);
298          }
299          /* clamp to length max */
300          coord = lp_build_min(coord_bld, coord, length_f);
301          /* subtract 0.5 */
302          coord = lp_build_sub(coord_bld, coord, half);
303          /* clamp to [0, length - 0.5] */
304          coord = lp_build_max(coord_bld, coord, coord_bld->zero);
305          /* convert to int, compute lerp weight */
306          lp_build_ifloor_fract(&abs_coord_bld, coord, &coord0, &weight);
307          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
308          /* coord1 = min(coord1, length-1) */
309          coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
310          break;
311       }
312
313    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
314       {
315          LLVMValueRef min;
316          if (bld->static_state->normalized_coords) {
317             /* scale coord to length */
318             coord = lp_build_mul(coord_bld, coord, length_f);
319          }
320          /* was: clamp to [-0.5, length + 0.5], then sub 0.5 */
321          coord = lp_build_sub(coord_bld, coord, half);
322          min = lp_build_const_vec(bld->gallivm, coord_bld->type, -1.0F);
323          coord = lp_build_clamp(coord_bld, coord, min, length_f);
324          /* convert to int, compute lerp weight */
325          lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
326          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
327       }
328       break;
329
330    case PIPE_TEX_WRAP_MIRROR_REPEAT:
331       /* compute mirror function */
332       coord = lp_build_coord_mirror(bld, coord);
333
334       /* scale coord to length */
335       coord = lp_build_mul(coord_bld, coord, length_f);
336       coord = lp_build_sub(coord_bld, coord, half);
337
338       /* convert to int, compute lerp weight */
339       lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
340       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
341
342       /* coord0 = max(coord0, 0) */
343       coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero);
344       /* coord1 = min(coord1, length-1) */
345       coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
346       break;
347
348    case PIPE_TEX_WRAP_MIRROR_CLAMP:
349       coord = lp_build_abs(coord_bld, coord);
350
351       if (bld->static_state->normalized_coords) {
352          /* scale coord to length */
353          coord = lp_build_mul(coord_bld, coord, length_f);
354       }
355
356       /* clamp to [0, length] */
357       coord = lp_build_min(coord_bld, coord, length_f);
358
359       coord = lp_build_sub(coord_bld, coord, half);
360
361       /* convert to int, compute lerp weight */
362       lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
363       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
364       break;
365
366    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
367       {
368          LLVMValueRef min, max;
369          struct lp_build_context abs_coord_bld = bld->coord_bld;
370          abs_coord_bld.type.sign = FALSE;
371          coord = lp_build_abs(coord_bld, coord);
372
373          if (bld->static_state->normalized_coords) {
374             /* scale coord to length */
375             coord = lp_build_mul(coord_bld, coord, length_f);
376          }
377
378          /* clamp to [0.5, length - 0.5] */
379          min = half;
380          max = lp_build_sub(coord_bld, length_f, min);
381          coord = lp_build_clamp(coord_bld, coord, min, max);
382
383          coord = lp_build_sub(coord_bld, coord, half);
384
385          /* convert to int, compute lerp weight */
386          lp_build_ifloor_fract(&abs_coord_bld, coord, &coord0, &weight);
387          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
388       }
389       break;
390
391    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
392       {
393          coord = lp_build_abs(coord_bld, coord);
394
395          if (bld->static_state->normalized_coords) {
396             /* scale coord to length */
397             coord = lp_build_mul(coord_bld, coord, length_f);
398          }
399
400          /* was: clamp to [-0.5, length + 0.5] then sub 0.5 */
401          /* skip -0.5 clamp (always positive), do sub first */
402          coord = lp_build_sub(coord_bld, coord, half);
403          coord = lp_build_min(coord_bld, coord, length_f);
404
405          /* convert to int, compute lerp weight */
406          lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
407          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
408       }
409       break;
410
411    default:
412       assert(0);
413       coord0 = NULL;
414       coord1 = NULL;
415       weight = NULL;
416    }
417
418    *x0_out = coord0;
419    *x1_out = coord1;
420    *weight_out = weight;
421 }
422
423
424 /**
425  * Build LLVM code for texture wrap mode for nearest filtering.
426  * \param coord  the incoming texcoord (nominally in [0,1])
427  * \param length  the texture size along one dimension, as int vector
428  * \param is_pot  if TRUE, length is a power of two
429  * \param wrap_mode  one of PIPE_TEX_WRAP_x
430  */
431 static LLVMValueRef
432 lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
433                              LLVMValueRef coord,
434                              LLVMValueRef length,
435                              LLVMValueRef length_f,
436                              boolean is_pot,
437                              unsigned wrap_mode)
438 {
439    struct lp_build_context *coord_bld = &bld->coord_bld;
440    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
441    LLVMBuilderRef builder = bld->gallivm->builder;
442    LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
443    LLVMValueRef icoord;
444    
445    switch(wrap_mode) {
446    case PIPE_TEX_WRAP_REPEAT:
447       coord = lp_build_mul(coord_bld, coord, length_f);
448       icoord = lp_build_ifloor(coord_bld, coord);
449       if (is_pot)
450          icoord = LLVMBuildAnd(builder, icoord, length_minus_one, "");
451       else {
452          /* Add a bias to the texcoord to handle negative coords */
453          LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
454          icoord = LLVMBuildAdd(builder, icoord, bias, "");
455          icoord = LLVMBuildURem(builder, icoord, length, "");
456       }
457       break;
458
459    case PIPE_TEX_WRAP_CLAMP:
460    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
461       if (bld->static_state->normalized_coords) {
462          /* scale coord to length */
463          coord = lp_build_mul(coord_bld, coord, length_f);
464       }
465
466       /* floor */
467       /* use itrunc instead since we clamp to 0 anyway */
468       icoord = lp_build_itrunc(coord_bld, coord);
469
470       /* clamp to [0, length - 1]. */
471       icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero,
472                               length_minus_one);
473       break;
474
475    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
476       /* Note: this is the same as CLAMP_TO_EDGE, except min = -min */
477       {
478          LLVMValueRef min, max;
479
480          if (bld->static_state->normalized_coords) {
481             /* scale coord to length */
482             coord = lp_build_mul(coord_bld, coord, length_f);
483          }
484
485          icoord = lp_build_ifloor(coord_bld, coord);
486
487          /* clamp to [-1, length] */
488          min = lp_build_negate(int_coord_bld, int_coord_bld->one);
489          max = length;
490          icoord = lp_build_clamp(int_coord_bld, icoord, min, max);
491       }
492       break;
493
494    case PIPE_TEX_WRAP_MIRROR_REPEAT:
495       /* compute mirror function */
496       coord = lp_build_coord_mirror(bld, coord);
497
498       /* scale coord to length */
499       assert(bld->static_state->normalized_coords);
500       coord = lp_build_mul(coord_bld, coord, length_f);
501
502       /* itrunc == ifloor here */
503       icoord = lp_build_itrunc(coord_bld, coord);
504
505       /* clamp to [0, length - 1] */
506       icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
507       break;
508
509    case PIPE_TEX_WRAP_MIRROR_CLAMP:
510    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
511       coord = lp_build_abs(coord_bld, coord);
512
513       if (bld->static_state->normalized_coords) {
514          /* scale coord to length */
515          coord = lp_build_mul(coord_bld, coord, length_f);
516       }
517
518       /* itrunc == ifloor here */
519       icoord = lp_build_itrunc(coord_bld, coord);
520
521       /* clamp to [0, length - 1] */
522       icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
523       break;
524
525    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
526       coord = lp_build_abs(coord_bld, coord);
527
528       if (bld->static_state->normalized_coords) {
529          /* scale coord to length */
530          coord = lp_build_mul(coord_bld, coord, length_f);
531       }
532
533       /* itrunc == ifloor here */
534       icoord = lp_build_itrunc(coord_bld, coord);
535
536       /* clamp to [0, length] */
537       icoord = lp_build_min(int_coord_bld, icoord, length);
538       break;
539
540    default:
541       assert(0);
542       icoord = NULL;
543    }
544
545    return icoord;
546 }
547
548
549 /**
550  * Generate code to sample a mipmap level with nearest filtering.
551  * If sampling a cube texture, r = cube face in [0,5].
552  */
553 static void
554 lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
555                               unsigned unit,
556                               LLVMValueRef size,
557                               LLVMValueRef row_stride_vec,
558                               LLVMValueRef img_stride_vec,
559                               LLVMValueRef data_ptr,
560                               LLVMValueRef s,
561                               LLVMValueRef t,
562                               LLVMValueRef r,
563                               LLVMValueRef colors_out[4])
564 {
565    const unsigned dims = bld->dims;
566    LLVMValueRef width_vec;
567    LLVMValueRef height_vec;
568    LLVMValueRef depth_vec;
569    LLVMValueRef flt_size;
570    LLVMValueRef flt_width_vec;
571    LLVMValueRef flt_height_vec;
572    LLVMValueRef flt_depth_vec;
573    LLVMValueRef x, y, z;
574
575    lp_build_extract_image_sizes(bld,
576                                 bld->int_size_type,
577                                 bld->int_coord_type,
578                                 size,
579                                 &width_vec, &height_vec, &depth_vec);
580
581    flt_size = lp_build_int_to_float(&bld->float_size_bld, size);
582
583    lp_build_extract_image_sizes(bld,
584                                 bld->float_size_type,
585                                 bld->coord_type,
586                                 flt_size,
587                                 &flt_width_vec, &flt_height_vec, &flt_depth_vec);
588
589    /*
590     * Compute integer texcoords.
591     */
592    x = lp_build_sample_wrap_nearest(bld, s, width_vec, flt_width_vec,
593                                     bld->static_state->pot_width,
594                                     bld->static_state->wrap_s);
595    lp_build_name(x, "tex.x.wrapped");
596
597    if (dims >= 2) {
598       y = lp_build_sample_wrap_nearest(bld, t, height_vec, flt_height_vec,
599                                        bld->static_state->pot_height,
600                                        bld->static_state->wrap_t);
601       lp_build_name(y, "tex.y.wrapped");
602
603       if (dims == 3) {
604          z = lp_build_sample_wrap_nearest(bld, r, depth_vec, flt_depth_vec,
605                                           bld->static_state->pot_depth,
606                                           bld->static_state->wrap_r);
607          lp_build_name(z, "tex.z.wrapped");
608       }
609       else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
610          z = r;
611       }
612       else {
613          z = NULL;
614       }
615    }
616    else {
617       y = z = NULL;
618    }
619
620    /*
621     * Get texture colors.
622     */
623    lp_build_sample_texel_soa(bld, unit,
624                              width_vec, height_vec, depth_vec,
625                              x, y, z,
626                              row_stride_vec, img_stride_vec,
627                              data_ptr, colors_out);
628 }
629
630
631 /**
632  * Generate code to sample a mipmap level with linear filtering.
633  * If sampling a cube texture, r = cube face in [0,5].
634  */
635 static void
636 lp_build_sample_image_linear(struct lp_build_sample_context *bld,
637                              unsigned unit,
638                              LLVMValueRef size,
639                              LLVMValueRef row_stride_vec,
640                              LLVMValueRef img_stride_vec,
641                              LLVMValueRef data_ptr,
642                              LLVMValueRef s,
643                              LLVMValueRef t,
644                              LLVMValueRef r,
645                              LLVMValueRef colors_out[4])
646 {
647    const unsigned dims = bld->dims;
648    LLVMValueRef width_vec;
649    LLVMValueRef height_vec;
650    LLVMValueRef depth_vec;
651    LLVMValueRef flt_size;
652    LLVMValueRef flt_width_vec;
653    LLVMValueRef flt_height_vec;
654    LLVMValueRef flt_depth_vec;
655    LLVMValueRef x0, y0, z0, x1, y1, z1;
656    LLVMValueRef s_fpart, t_fpart, r_fpart;
657    LLVMValueRef neighbors[2][2][4];
658    int chan;
659
660    lp_build_extract_image_sizes(bld,
661                                 bld->int_size_type,
662                                 bld->int_coord_type,
663                                 size,
664                                 &width_vec, &height_vec, &depth_vec);
665
666    flt_size = lp_build_int_to_float(&bld->float_size_bld, size);
667
668    lp_build_extract_image_sizes(bld,
669                                 bld->float_size_type,
670                                 bld->coord_type,
671                                 flt_size,
672                                 &flt_width_vec, &flt_height_vec, &flt_depth_vec);
673
674    /*
675     * Compute integer texcoords.
676     */
677    lp_build_sample_wrap_linear(bld, s, width_vec, flt_width_vec,
678                                bld->static_state->pot_width,
679                                bld->static_state->wrap_s,
680                                &x0, &x1, &s_fpart);
681    lp_build_name(x0, "tex.x0.wrapped");
682    lp_build_name(x1, "tex.x1.wrapped");
683
684    if (dims >= 2) {
685       lp_build_sample_wrap_linear(bld, t, height_vec, flt_height_vec,
686                                   bld->static_state->pot_height,
687                                   bld->static_state->wrap_t,
688                                   &y0, &y1, &t_fpart);
689       lp_build_name(y0, "tex.y0.wrapped");
690       lp_build_name(y1, "tex.y1.wrapped");
691
692       if (dims == 3) {
693          lp_build_sample_wrap_linear(bld, r, depth_vec, flt_depth_vec,
694                                      bld->static_state->pot_depth,
695                                      bld->static_state->wrap_r,
696                                      &z0, &z1, &r_fpart);
697          lp_build_name(z0, "tex.z0.wrapped");
698          lp_build_name(z1, "tex.z1.wrapped");
699       }
700       else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
701          z0 = z1 = r;  /* cube face */
702          r_fpart = NULL;
703       }
704       else {
705          z0 = z1 = NULL;
706          r_fpart = NULL;
707       }
708    }
709    else {
710       y0 = y1 = t_fpart = NULL;
711       z0 = z1 = r_fpart = NULL;
712    }
713
714    /*
715     * Get texture colors.
716     */
717    /* get x0/x1 texels */
718    lp_build_sample_texel_soa(bld, unit,
719                              width_vec, height_vec, depth_vec,
720                              x0, y0, z0,
721                              row_stride_vec, img_stride_vec,
722                              data_ptr, neighbors[0][0]);
723    lp_build_sample_texel_soa(bld, unit,
724                              width_vec, height_vec, depth_vec,
725                              x1, y0, z0,
726                              row_stride_vec, img_stride_vec,
727                              data_ptr, neighbors[0][1]);
728
729    if (dims == 1) {
730       /* Interpolate two samples from 1D image to produce one color */
731       for (chan = 0; chan < 4; chan++) {
732          colors_out[chan] = lp_build_lerp(&bld->texel_bld, s_fpart,
733                                           neighbors[0][0][chan],
734                                           neighbors[0][1][chan]);
735       }
736    }
737    else {
738       /* 2D/3D texture */
739       LLVMValueRef colors0[4];
740
741       /* get x0/x1 texels at y1 */
742       lp_build_sample_texel_soa(bld, unit,
743                                 width_vec, height_vec, depth_vec,
744                                 x0, y1, z0,
745                                 row_stride_vec, img_stride_vec,
746                                 data_ptr, neighbors[1][0]);
747       lp_build_sample_texel_soa(bld, unit,
748                                 width_vec, height_vec, depth_vec,
749                                 x1, y1, z0,
750                                 row_stride_vec, img_stride_vec,
751                                 data_ptr, neighbors[1][1]);
752
753       /* Bilinear interpolate the four samples from the 2D image / 3D slice */
754       for (chan = 0; chan < 4; chan++) {
755          colors0[chan] = lp_build_lerp_2d(&bld->texel_bld,
756                                           s_fpart, t_fpart,
757                                           neighbors[0][0][chan],
758                                           neighbors[0][1][chan],
759                                           neighbors[1][0][chan],
760                                           neighbors[1][1][chan]);
761       }
762
763       if (dims == 3) {
764          LLVMValueRef neighbors1[2][2][4];
765          LLVMValueRef colors1[4];
766
767          /* get x0/x1/y0/y1 texels at z1 */
768          lp_build_sample_texel_soa(bld, unit,
769                                    width_vec, height_vec, depth_vec,
770                                    x0, y0, z1,
771                                    row_stride_vec, img_stride_vec,
772                                    data_ptr, neighbors1[0][0]);
773          lp_build_sample_texel_soa(bld, unit,
774                                    width_vec, height_vec, depth_vec,
775                                    x1, y0, z1,
776                                    row_stride_vec, img_stride_vec,
777                                    data_ptr, neighbors1[0][1]);
778          lp_build_sample_texel_soa(bld, unit,
779                                    width_vec, height_vec, depth_vec,
780                                    x0, y1, z1,
781                                    row_stride_vec, img_stride_vec,
782                                    data_ptr, neighbors1[1][0]);
783          lp_build_sample_texel_soa(bld, unit,
784                                    width_vec, height_vec, depth_vec,
785                                    x1, y1, z1,
786                                    row_stride_vec, img_stride_vec,
787                                    data_ptr, neighbors1[1][1]);
788
789          /* Bilinear interpolate the four samples from the second Z slice */
790          for (chan = 0; chan < 4; chan++) {
791             colors1[chan] = lp_build_lerp_2d(&bld->texel_bld,
792                                              s_fpart, t_fpart,
793                                              neighbors1[0][0][chan],
794                                              neighbors1[0][1][chan],
795                                              neighbors1[1][0][chan],
796                                              neighbors1[1][1][chan]);
797          }
798
799          /* Linearly interpolate the two samples from the two 3D slices */
800          for (chan = 0; chan < 4; chan++) {
801             colors_out[chan] = lp_build_lerp(&bld->texel_bld,
802                                              r_fpart,
803                                              colors0[chan], colors1[chan]);
804          }
805       }
806       else {
807          /* 2D tex */
808          for (chan = 0; chan < 4; chan++) {
809             colors_out[chan] = colors0[chan];
810          }
811       }
812    }
813 }
814
815
816 /**
817  * Sample the texture/mipmap using given image filter and mip filter.
818  * data0_ptr and data1_ptr point to the two mipmap levels to sample
819  * from.  width0/1_vec, height0/1_vec, depth0/1_vec indicate their sizes.
820  * If we're using nearest miplevel sampling the '1' values will be null/unused.
821  */
822 static void
823 lp_build_sample_mipmap(struct lp_build_sample_context *bld,
824                        unsigned unit,
825                        unsigned img_filter,
826                        unsigned mip_filter,
827                        LLVMValueRef s,
828                        LLVMValueRef t,
829                        LLVMValueRef r,
830                        LLVMValueRef ilevel0,
831                        LLVMValueRef ilevel1,
832                        LLVMValueRef lod_fpart,
833                        LLVMValueRef *colors_out)
834 {
835    LLVMBuilderRef builder = bld->gallivm->builder;
836    LLVMValueRef size0 = NULL;
837    LLVMValueRef size1 = NULL;
838    LLVMValueRef row_stride0_vec = NULL;
839    LLVMValueRef row_stride1_vec = NULL;
840    LLVMValueRef img_stride0_vec = NULL;
841    LLVMValueRef img_stride1_vec = NULL;
842    LLVMValueRef data_ptr0 = NULL;
843    LLVMValueRef data_ptr1 = NULL;
844    LLVMValueRef colors0[4], colors1[4];
845    unsigned chan;
846
847    /* sample the first mipmap level */
848    lp_build_mipmap_level_sizes(bld, ilevel0,
849                                &size0,
850                                &row_stride0_vec, &img_stride0_vec);
851    data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
852    if (img_filter == PIPE_TEX_FILTER_NEAREST) {
853       lp_build_sample_image_nearest(bld, unit,
854                                     size0,
855                                     row_stride0_vec, img_stride0_vec,
856                                     data_ptr0, s, t, r,
857                                     colors0);
858    }
859    else {
860       assert(img_filter == PIPE_TEX_FILTER_LINEAR);
861       lp_build_sample_image_linear(bld, unit,
862                                    size0,
863                                    row_stride0_vec, img_stride0_vec,
864                                    data_ptr0, s, t, r,
865                                    colors0);
866    }
867
868    /* Store the first level's colors in the output variables */
869    for (chan = 0; chan < 4; chan++) {
870        LLVMBuildStore(builder, colors0[chan], colors_out[chan]);
871    }
872
873    if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
874       struct lp_build_if_state if_ctx;
875       LLVMValueRef need_lerp;
876
877       /* need_lerp = lod_fpart > 0 */
878       need_lerp = LLVMBuildFCmp(builder, LLVMRealUGT,
879                                 lod_fpart,
880                                 bld->float_bld.zero,
881                                 "need_lerp");
882
883       lp_build_if(&if_ctx, bld->gallivm, need_lerp);
884       {
885          /* sample the second mipmap level */
886          lp_build_mipmap_level_sizes(bld, ilevel1,
887                                      &size1,
888                                      &row_stride1_vec, &img_stride1_vec);
889          data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
890          if (img_filter == PIPE_TEX_FILTER_NEAREST) {
891             lp_build_sample_image_nearest(bld, unit,
892                                           size1,
893                                           row_stride1_vec, img_stride1_vec,
894                                           data_ptr1, s, t, r,
895                                           colors1);
896          }
897          else {
898             lp_build_sample_image_linear(bld, unit,
899                                          size1,
900                                          row_stride1_vec, img_stride1_vec,
901                                          data_ptr1, s, t, r,
902                                          colors1);
903          }
904
905          /* interpolate samples from the two mipmap levels */
906
907          lod_fpart = lp_build_broadcast_scalar(&bld->texel_bld, lod_fpart);
908
909          for (chan = 0; chan < 4; chan++) {
910             colors0[chan] = lp_build_lerp(&bld->texel_bld, lod_fpart,
911                                           colors0[chan], colors1[chan]);
912             LLVMBuildStore(builder, colors0[chan], colors_out[chan]);
913          }
914       }
915       lp_build_endif(&if_ctx);
916    }
917 }
918
919
920
921 /**
922  * General texture sampling codegen.
923  * This function handles texture sampling for all texture targets (1D,
924  * 2D, 3D, cube) and all filtering modes.
925  */
926 static void
927 lp_build_sample_general(struct lp_build_sample_context *bld,
928                         unsigned unit,
929                         LLVMValueRef s,
930                         LLVMValueRef t,
931                         LLVMValueRef r,
932                         const LLVMValueRef *ddx,
933                         const LLVMValueRef *ddy,
934                         LLVMValueRef lod_bias, /* optional */
935                         LLVMValueRef explicit_lod, /* optional */
936                         LLVMValueRef *colors_out)
937 {
938    struct lp_build_context *int_bld = &bld->int_bld;
939    LLVMBuilderRef builder = bld->gallivm->builder;
940    const unsigned mip_filter = bld->static_state->min_mip_filter;
941    const unsigned min_filter = bld->static_state->min_img_filter;
942    const unsigned mag_filter = bld->static_state->mag_img_filter;
943    LLVMValueRef lod_ipart = NULL, lod_fpart = NULL;
944    LLVMValueRef ilevel0, ilevel1 = NULL;
945    LLVMValueRef face_ddx[4], face_ddy[4];
946    LLVMValueRef texels[4];
947    LLVMValueRef first_level;
948    LLVMValueRef i32t_zero = lp_build_const_int32(bld->gallivm, 0);
949    unsigned chan;
950
951    /*
952    printf("%s mip %d  min %d  mag %d\n", __FUNCTION__,
953           mip_filter, min_filter, mag_filter);
954    */
955
956    /*
957     * Choose cube face, recompute texcoords and derivatives for the chosen face.
958     */
959    if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
960       LLVMValueRef face, face_s, face_t;
961       lp_build_cube_lookup(bld, s, t, r, &face, &face_s, &face_t);
962       s = face_s; /* vec */
963       t = face_t; /* vec */
964       /* use 'r' to indicate cube face */
965       r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */
966
967       /* recompute ddx, ddy using the new (s,t) face texcoords */
968       face_ddx[0] = lp_build_scalar_ddx(&bld->coord_bld, s);
969       face_ddx[1] = lp_build_scalar_ddx(&bld->coord_bld, t);
970       face_ddx[2] = NULL;
971       face_ddx[3] = NULL;
972       face_ddy[0] = lp_build_scalar_ddy(&bld->coord_bld, s);
973       face_ddy[1] = lp_build_scalar_ddy(&bld->coord_bld, t);
974       face_ddy[2] = NULL;
975       face_ddy[3] = NULL;
976       ddx = face_ddx;
977       ddy = face_ddy;
978    }
979
980    /*
981     * Compute the level of detail (float).
982     */
983    if (min_filter != mag_filter ||
984        mip_filter != PIPE_TEX_MIPFILTER_NONE) {
985       /* Need to compute lod either to choose mipmap levels or to
986        * distinguish between minification/magnification with one mipmap level.
987        */
988       lp_build_lod_selector(bld, unit, ddx, ddy,
989                             lod_bias, explicit_lod,
990                             mip_filter,
991                             &lod_ipart, &lod_fpart);
992    } else {
993       lod_ipart = i32t_zero;
994    }
995
996    /*
997     * Compute integer mipmap level(s) to fetch texels from: ilevel0, ilevel1
998     */
999    switch (mip_filter) {
1000    default:
1001       assert(0 && "bad mip_filter value in lp_build_sample_soa()");
1002       /* fall-through */
1003    case PIPE_TEX_MIPFILTER_NONE:
1004       /* always use mip level 0 */
1005       if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
1006          /* XXX this is a work-around for an apparent bug in LLVM 2.7.
1007           * We should be able to set ilevel0 = const(0) but that causes
1008           * bad x86 code to be emitted.
1009           */
1010          assert(lod_ipart);
1011          lp_build_nearest_mip_level(bld, unit, lod_ipart, &ilevel0);
1012       }
1013       else {
1014          first_level = bld->dynamic_state->first_level(bld->dynamic_state,
1015                                                        bld->gallivm, unit);
1016          ilevel0 = first_level;
1017       }
1018       break;
1019    case PIPE_TEX_MIPFILTER_NEAREST:
1020       assert(lod_ipart);
1021       lp_build_nearest_mip_level(bld, unit, lod_ipart, &ilevel0);
1022       break;
1023    case PIPE_TEX_MIPFILTER_LINEAR:
1024       assert(lod_ipart);
1025       assert(lod_fpart);
1026       lp_build_linear_mip_levels(bld, unit,
1027                                  lod_ipart, &lod_fpart,
1028                                  &ilevel0, &ilevel1);
1029       break;
1030    }
1031
1032    /*
1033     * Get/interpolate texture colors.
1034     */
1035
1036    for (chan = 0; chan < 4; ++chan) {
1037      texels[chan] = lp_build_alloca(bld->gallivm, bld->texel_bld.vec_type, "");
1038      lp_build_name(texels[chan], "sampler%u_texel_%c_var", unit, "xyzw"[chan]);
1039    }
1040
1041    if (min_filter == mag_filter) {
1042       /* no need to distinquish between minification and magnification */
1043       lp_build_sample_mipmap(bld, unit,
1044                              min_filter, mip_filter,
1045                              s, t, r,
1046                              ilevel0, ilevel1, lod_fpart,
1047                              texels);
1048    }
1049    else {
1050       /* Emit conditional to choose min image filter or mag image filter
1051        * depending on the lod being > 0 or <= 0, respectively.
1052        */
1053       struct lp_build_if_state if_ctx;
1054       LLVMValueRef minify;
1055
1056       /* minify = lod >= 0.0 */
1057       minify = LLVMBuildICmp(builder, LLVMIntSGE,
1058                              lod_ipart, int_bld->zero, "");
1059
1060       lp_build_if(&if_ctx, bld->gallivm, minify);
1061       {
1062          /* Use the minification filter */
1063          lp_build_sample_mipmap(bld, unit,
1064                                 min_filter, mip_filter,
1065                                 s, t, r,
1066                                 ilevel0, ilevel1, lod_fpart,
1067                                 texels);
1068       }
1069       lp_build_else(&if_ctx);
1070       {
1071          /* Use the magnification filter */
1072          lp_build_sample_mipmap(bld, unit,
1073                                 mag_filter, PIPE_TEX_MIPFILTER_NONE,
1074                                 s, t, r,
1075                                 ilevel0, NULL, NULL,
1076                                 texels);
1077       }
1078       lp_build_endif(&if_ctx);
1079    }
1080
1081    for (chan = 0; chan < 4; ++chan) {
1082      colors_out[chan] = LLVMBuildLoad(builder, texels[chan], "");
1083      lp_build_name(colors_out[chan], "sampler%u_texel_%c", unit, "xyzw"[chan]);
1084    }
1085 }
1086
1087
1088 /**
1089  * Do shadow test/comparison.
1090  * \param p  the texcoord Z (aka R, aka P) component
1091  * \param texel  the texel to compare against (use the X channel)
1092  */
1093 static void
1094 lp_build_sample_compare(struct lp_build_sample_context *bld,
1095                         LLVMValueRef p,
1096                         LLVMValueRef texel[4])
1097 {
1098    struct lp_build_context *texel_bld = &bld->texel_bld;
1099    LLVMBuilderRef builder = bld->gallivm->builder;
1100    LLVMValueRef res;
1101    const unsigned chan = 0;
1102
1103    if (bld->static_state->compare_mode == PIPE_TEX_COMPARE_NONE)
1104       return;
1105
1106    /* debug code */
1107    if (0) {
1108       LLVMValueRef indx = lp_build_const_int32(bld->gallivm, 0);
1109       LLVMValueRef coord = LLVMBuildExtractElement(builder, p, indx, "");
1110       LLVMValueRef tex = LLVMBuildExtractElement(builder, texel[chan], indx, "");
1111       lp_build_printf(bld->gallivm, "shadow compare coord %f to texture %f\n",
1112                       coord, tex);
1113    }
1114
1115    /* Clamp p coords to [0,1] */
1116    p = lp_build_clamp(&bld->coord_bld, p,
1117                       bld->coord_bld.zero,
1118                       bld->coord_bld.one);
1119
1120    /* result = (p FUNC texel) ? 1 : 0 */
1121    res = lp_build_cmp(texel_bld, bld->static_state->compare_func,
1122                       p, texel[chan]);
1123    res = lp_build_select(texel_bld, res, texel_bld->one, texel_bld->zero);
1124
1125    /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
1126    texel[0] =
1127    texel[1] =
1128    texel[2] = res;
1129    texel[3] = texel_bld->one;
1130 }
1131
1132
1133 /**
1134  * Just set texels to white instead of actually sampling the texture.
1135  * For debugging.
1136  */
1137 void
1138 lp_build_sample_nop(struct gallivm_state *gallivm, struct lp_type type,
1139                     LLVMValueRef texel_out[4])
1140 {
1141    LLVMValueRef one = lp_build_one(gallivm, type);
1142    unsigned chan;
1143
1144    for (chan = 0; chan < 4; chan++) {
1145       texel_out[chan] = one;
1146    }  
1147 }
1148
1149
1150 /**
1151  * Build texture sampling code.
1152  * 'texel' will return a vector of four LLVMValueRefs corresponding to
1153  * R, G, B, A.
1154  * \param type  vector float type to use for coords, etc.
1155  * \param ddx  partial derivatives of (s,t,r,q) with respect to x
1156  * \param ddy  partial derivatives of (s,t,r,q) with respect to y
1157  */
1158 void
1159 lp_build_sample_soa(struct gallivm_state *gallivm,
1160                     const struct lp_sampler_static_state *static_state,
1161                     struct lp_sampler_dynamic_state *dynamic_state,
1162                     struct lp_type type,
1163                     unsigned unit,
1164                     unsigned num_coords,
1165                     const LLVMValueRef *coords,
1166                     const LLVMValueRef ddx[4],
1167                     const LLVMValueRef ddy[4],
1168                     LLVMValueRef lod_bias, /* optional */
1169                     LLVMValueRef explicit_lod, /* optional */
1170                     LLVMValueRef texel_out[4])
1171 {
1172    unsigned dims = texture_dims(static_state->target);
1173    struct lp_build_sample_context bld;
1174    LLVMTypeRef i32t = LLVMInt32TypeInContext(gallivm->context);
1175    LLVMBuilderRef builder = gallivm->builder;
1176    LLVMValueRef s;
1177    LLVMValueRef t;
1178    LLVMValueRef r;
1179    struct lp_type float_vec_type;
1180
1181    if (0) {
1182       enum pipe_format fmt = static_state->format;
1183       debug_printf("Sample from %s\n", util_format_name(fmt));
1184    }
1185
1186    assert(type.floating);
1187
1188    /* Setup our build context */
1189    memset(&bld, 0, sizeof bld);
1190    bld.gallivm = gallivm;
1191    bld.static_state = static_state;
1192    bld.dynamic_state = dynamic_state;
1193    bld.format_desc = util_format_description(static_state->format);
1194    bld.dims = dims;
1195
1196    bld.float_type = lp_type_float(32);
1197    bld.int_type = lp_type_int(32);
1198    bld.coord_type = type;
1199    bld.int_coord_type = lp_int_type(type);
1200    bld.float_size_type = lp_type_float(32);
1201    bld.float_size_type.length = dims > 1 ? 4 : 1;
1202    bld.int_size_type = lp_int_type(bld.float_size_type);
1203    bld.texel_type = type;
1204
1205    float_vec_type = lp_type_float_vec(32);
1206
1207    lp_build_context_init(&bld.float_bld, gallivm, bld.float_type);
1208    lp_build_context_init(&bld.float_vec_bld, gallivm, float_vec_type);
1209    lp_build_context_init(&bld.int_bld, gallivm, bld.int_type);
1210    lp_build_context_init(&bld.coord_bld, gallivm, bld.coord_type);
1211    lp_build_context_init(&bld.int_coord_bld, gallivm, bld.int_coord_type);
1212    lp_build_context_init(&bld.int_size_bld, gallivm, bld.int_size_type);
1213    lp_build_context_init(&bld.float_size_bld, gallivm, bld.float_size_type);
1214    lp_build_context_init(&bld.texel_bld, gallivm, bld.texel_type);
1215
1216    /* Get the dynamic state */
1217    bld.width = dynamic_state->width(dynamic_state, gallivm, unit);
1218    bld.height = dynamic_state->height(dynamic_state, gallivm, unit);
1219    bld.depth = dynamic_state->depth(dynamic_state, gallivm, unit);
1220    bld.row_stride_array = dynamic_state->row_stride(dynamic_state, gallivm, unit);
1221    bld.img_stride_array = dynamic_state->img_stride(dynamic_state, gallivm, unit);
1222    bld.data_array = dynamic_state->data_ptr(dynamic_state, gallivm, unit);
1223    /* Note that data_array is an array[level] of pointers to texture images */
1224
1225    s = coords[0];
1226    t = coords[1];
1227    r = coords[2];
1228
1229    /* width, height, depth as single int vector */
1230    if (dims <= 1) {
1231       bld.int_size = bld.width;
1232    }
1233    else {
1234       bld.int_size = LLVMBuildInsertElement(builder, bld.int_size_bld.undef,
1235                                             bld.width, LLVMConstInt(i32t, 0, 0), "");
1236       if (dims >= 2) {
1237          bld.int_size = LLVMBuildInsertElement(builder, bld.int_size,
1238                                                bld.height, LLVMConstInt(i32t, 1, 0), "");
1239          if (dims >= 3) {
1240             bld.int_size = LLVMBuildInsertElement(builder, bld.int_size,
1241                                                   bld.depth, LLVMConstInt(i32t, 2, 0), "");
1242          }
1243       }
1244    }
1245
1246    if (0) {
1247       /* For debug: no-op texture sampling */
1248       lp_build_sample_nop(gallivm, bld.texel_type, texel_out);
1249    }
1250    else if (util_format_fits_8unorm(bld.format_desc) &&
1251             lp_is_simple_wrap_mode(static_state->wrap_s) &&
1252             lp_is_simple_wrap_mode(static_state->wrap_t)) {
1253       /* do sampling/filtering with fixed pt arithmetic */
1254       lp_build_sample_aos(&bld, unit, s, t, r, ddx, ddy,
1255                           lod_bias, explicit_lod,
1256                           texel_out);
1257    }
1258
1259    else {
1260       if ((gallivm_debug & GALLIVM_DEBUG_PERF) &&
1261           util_format_fits_8unorm(bld.format_desc)) {
1262          debug_printf("%s: using floating point linear filtering for %s\n",
1263                       __FUNCTION__, bld.format_desc->short_name);
1264          debug_printf("  min_img %d  mag_img %d  mip %d  wraps %d  wrapt %d\n",
1265                       static_state->min_img_filter,
1266                       static_state->mag_img_filter,
1267                       static_state->min_mip_filter,
1268                       static_state->wrap_s,
1269                       static_state->wrap_t);
1270       }
1271
1272       lp_build_sample_general(&bld, unit, s, t, r, ddx, ddy,
1273                               lod_bias, explicit_lod,
1274                               texel_out);
1275    }
1276
1277    lp_build_sample_compare(&bld, r, texel_out);
1278
1279    apply_sampler_swizzle(&bld, texel_out);
1280 }
1281
1282 void
1283 lp_build_size_query_soa(struct gallivm_state *gallivm,
1284                         const struct lp_sampler_static_state *static_state,
1285                         struct lp_sampler_dynamic_state *dynamic_state,
1286                         unsigned unit,
1287                         LLVMValueRef explicit_lod,
1288                         LLVMValueRef *sizes_out)
1289 {
1290    LLVMValueRef lod;
1291    LLVMValueRef size;
1292    int dims, i;
1293    struct lp_build_context bld_int_vec;
1294
1295    switch (static_state->target) {
1296    case PIPE_TEXTURE_1D:
1297    case PIPE_BUFFER:
1298       dims = 1;
1299       break;
1300    case PIPE_TEXTURE_2D:
1301    case PIPE_TEXTURE_CUBE:
1302    case PIPE_TEXTURE_RECT:
1303       dims = 2;
1304       break;
1305    case PIPE_TEXTURE_3D:
1306       dims = 3;
1307       break;
1308
1309    default:
1310       assert(0);
1311       return;
1312    }
1313
1314    lp_build_context_init(&bld_int_vec, gallivm, lp_type_int_vec(32));
1315
1316    if (explicit_lod) {
1317       LLVMValueRef first_level;
1318       lod = LLVMBuildExtractElement(gallivm->builder, explicit_lod, lp_build_const_int32(gallivm, 0), "");
1319       first_level = dynamic_state->first_level(dynamic_state, gallivm, unit);
1320       lod = lp_build_broadcast_scalar(&bld_int_vec,
1321                                       LLVMBuildAdd(gallivm->builder, lod, first_level, "lod"));
1322
1323    } else {
1324       lod = bld_int_vec.zero;
1325    }
1326
1327    size = bld_int_vec.undef;
1328
1329    size = LLVMBuildInsertElement(gallivm->builder, size,
1330                                  dynamic_state->width(dynamic_state, gallivm, unit),
1331                                  lp_build_const_int32(gallivm, 0), "");
1332
1333    if (dims >= 2) {
1334       size = LLVMBuildInsertElement(gallivm->builder, size,
1335                                     dynamic_state->height(dynamic_state, gallivm, unit),
1336                                     lp_build_const_int32(gallivm, 1), "");
1337    }
1338
1339    if (dims >= 3) {
1340       size = LLVMBuildInsertElement(gallivm->builder, size,
1341                                     dynamic_state->depth(dynamic_state, gallivm, unit),
1342                                     lp_build_const_int32(gallivm, 2), "");
1343    }
1344
1345    size = lp_build_minify(&bld_int_vec, size, lod);
1346
1347    for (i=0; i < dims; i++) {
1348       sizes_out[i] = lp_build_extract_broadcast(gallivm, bld_int_vec.type, bld_int_vec.type,
1349                                                 size,
1350                                                 lp_build_const_int32(gallivm, i));
1351    }
1352 }