2b04becc8cbe587f07967edb650b5722c3e69558
[profile/ivi/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  */
34
35 #include "pipe/p_defines.h"
36 #include "pipe/p_state.h"
37 #include "util/u_debug.h"
38 #include "util/u_dump.h"
39 #include "util/u_memory.h"
40 #include "util/u_math.h"
41 #include "util/u_format.h"
42 #include "util/u_cpu_detect.h"
43 #include "lp_bld_debug.h"
44 #include "lp_bld_type.h"
45 #include "lp_bld_const.h"
46 #include "lp_bld_conv.h"
47 #include "lp_bld_arit.h"
48 #include "lp_bld_logic.h"
49 #include "lp_bld_swizzle.h"
50 #include "lp_bld_pack.h"
51 #include "lp_bld_format.h"
52 #include "lp_bld_sample.h"
53
54
55 /**
56  * Keep all information for sampling code generation in a single place.
57  */
58 struct lp_build_sample_context
59 {
60    LLVMBuilderRef builder;
61
62    const struct lp_sampler_static_state *static_state;
63
64    struct lp_sampler_dynamic_state *dynamic_state;
65
66    const struct util_format_description *format_desc;
67
68    /** Incoming coordinates type and build context */
69    struct lp_type coord_type;
70    struct lp_build_context coord_bld;
71
72    /** Unsigned integer coordinates */
73    struct lp_type uint_coord_type;
74    struct lp_build_context uint_coord_bld;
75
76    /** Signed integer coordinates */
77    struct lp_type int_coord_type;
78    struct lp_build_context int_coord_bld;
79
80    /** Output texels type and build context */
81    struct lp_type texel_type;
82    struct lp_build_context texel_bld;
83 };
84
85
86 /**
87  * Does the given texture wrap mode allow sampling the texture border color?
88  * XXX maybe move this into gallium util code.
89  */
90 static boolean
91 wrap_mode_uses_border_color(unsigned mode)
92 {
93    switch (mode) {
94    case PIPE_TEX_WRAP_REPEAT:
95    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
96    case PIPE_TEX_WRAP_MIRROR_REPEAT:
97    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
98       return FALSE;
99    case PIPE_TEX_WRAP_CLAMP:
100    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
101    case PIPE_TEX_WRAP_MIRROR_CLAMP:
102    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
103       return TRUE;
104    default:
105       assert(0 && "unexpected wrap mode");
106       return FALSE;
107    }
108 }
109
110
111
112 /**
113  * Gen code to fetch a texel from a texture at int coords (x, y).
114  * The result, texel, will be:
115  *   texel[0] = red values
116  *   texel[1] = green values
117  *   texel[2] = blue values
118  *   texel[3] = alpha values
119  */
120 static void
121 lp_build_sample_texel_soa(struct lp_build_sample_context *bld,
122                           LLVMValueRef width,
123                           LLVMValueRef height,
124                           LLVMValueRef x,
125                           LLVMValueRef y,
126                           LLVMValueRef y_stride,
127                           LLVMValueRef data_ptr,
128                           LLVMValueRef *texel)
129 {
130    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
131    LLVMValueRef offset;
132    LLVMValueRef packed;
133    LLVMValueRef use_border = NULL;
134
135    /* use_border = x < 0 || x >= width || y < 0 || y >= height */
136    if (wrap_mode_uses_border_color(bld->static_state->wrap_s)) {
137       LLVMValueRef b1, b2;
138       b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, x, int_coord_bld->zero);
139       b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, x, width);
140       use_border = LLVMBuildOr(bld->builder, b1, b2, "b1_or_b2");
141    }
142
143    if (wrap_mode_uses_border_color(bld->static_state->wrap_t)) {
144       LLVMValueRef b1, b2;
145       b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, y, int_coord_bld->zero);
146       b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, y, height);
147       if (use_border) {
148          use_border = LLVMBuildOr(bld->builder, use_border, b1, "ub_or_b1");
149          use_border = LLVMBuildOr(bld->builder, use_border, b2, "ub_or_b2");
150       }
151       else {
152          use_border = LLVMBuildOr(bld->builder, b1, b2, "b1_or_b2");
153       }
154    }
155
156    /*
157     * Note: if we find an app which frequently samples the texture border
158     * we might want to implement a true conditional here to avoid sampling
159     * the texture whenever possible (since that's quite a bit of code).
160     * Ex:
161     *   if (use_border) {
162     *      texel = border_color;
163     *   }
164     *   else {
165     *      texel = sample_texture(coord);
166     *   }
167     * As it is now, we always sample the texture, then selectively replace
168     * the texel color results with the border color.
169     */
170
171    /* convert x,y coords to linear offset from start of texture, in bytes */
172    offset = lp_build_sample_offset(&bld->uint_coord_bld,
173                                    bld->format_desc,
174                                    x, y, y_stride,
175                                    data_ptr);
176
177    assert(bld->format_desc->block.width == 1);
178    assert(bld->format_desc->block.height == 1);
179    assert(bld->format_desc->block.bits <= bld->texel_type.width);
180
181    /* gather the texels from the texture */
182    packed = lp_build_gather(bld->builder,
183                             bld->texel_type.length,
184                             bld->format_desc->block.bits,
185                             bld->texel_type.width,
186                             data_ptr, offset);
187
188    /* convert texels to float rgba */
189    lp_build_unpack_rgba_soa(bld->builder,
190                             bld->format_desc,
191                             bld->texel_type,
192                             packed, texel);
193
194    if (use_border) {
195       /* select texel color or border color depending on use_border */
196       int chan;
197       for (chan = 0; chan < 4; chan++) {
198          LLVMValueRef border_chan =
199             lp_build_const_scalar(bld->texel_type,
200                                   bld->static_state->border_color[chan]);
201          texel[chan] = lp_build_select(&bld->texel_bld, use_border,
202                                        border_chan, texel[chan]);
203       }
204    }
205 }
206
207
208 static LLVMValueRef
209 lp_build_sample_packed(struct lp_build_sample_context *bld,
210                        LLVMValueRef x,
211                        LLVMValueRef y,
212                        LLVMValueRef y_stride,
213                        LLVMValueRef data_ptr)
214 {
215    LLVMValueRef offset;
216
217    offset = lp_build_sample_offset(&bld->uint_coord_bld,
218                                    bld->format_desc,
219                                    x, y, y_stride,
220                                    data_ptr);
221
222    assert(bld->format_desc->block.width == 1);
223    assert(bld->format_desc->block.height == 1);
224    assert(bld->format_desc->block.bits <= bld->texel_type.width);
225
226    return lp_build_gather(bld->builder,
227                           bld->texel_type.length,
228                           bld->format_desc->block.bits,
229                           bld->texel_type.width,
230                           data_ptr, offset);
231 }
232
233
234 /**
235  * Helper to compute the mirror function for the PIPE_WRAP_MIRROR modes.
236  */
237 static LLVMValueRef
238 lp_build_coord_mirror(struct lp_build_sample_context *bld,
239                       LLVMValueRef coord)
240 {
241    struct lp_build_context *coord_bld = &bld->coord_bld;
242    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
243    LLVMValueRef fract, flr, isOdd;
244
245    /* fract = coord - floor(coord) */
246    fract = lp_build_sub(coord_bld, coord, lp_build_floor(coord_bld, coord));
247
248    /* flr = ifloor(coord); */
249    flr = lp_build_ifloor(coord_bld, coord);
250
251    /* isOdd = flr & 1 */
252    isOdd = LLVMBuildAnd(bld->builder, flr, int_coord_bld->one, "");
253
254    /* make coord positive or negative depending on isOdd */
255    coord = lp_build_set_sign(coord_bld, fract, isOdd);
256
257    /* convert isOdd to float */
258    isOdd = lp_build_int_to_float(coord_bld, isOdd);
259
260    /* add isOdd to coord */
261    coord = lp_build_add(coord_bld, coord, isOdd);
262
263    return coord;
264 }
265
266
267 /**
268  * We only support a few wrap modes in lp_build_sample_wrap_int() at this time.
269  * Return whether the given mode is supported by that function.
270  */
271 static boolean
272 is_simple_wrap_mode(unsigned mode)
273 {
274    switch (mode) {
275    case PIPE_TEX_WRAP_REPEAT:
276    case PIPE_TEX_WRAP_CLAMP:
277    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
278       return TRUE;
279    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
280    default:
281       return FALSE;
282    }
283 }
284
285
286 /**
287  * Build LLVM code for texture wrap mode, for scaled integer texcoords.
288  * \param coord  the incoming texcoord (s,t,r or q) scaled to the texture size
289  * \param length  the texture size along one dimension
290  * \param is_pot  if TRUE, length is a power of two
291  * \param wrap_mode  one of PIPE_TEX_WRAP_x
292  */
293 static LLVMValueRef
294 lp_build_sample_wrap_int(struct lp_build_sample_context *bld,
295                          LLVMValueRef coord,
296                          LLVMValueRef length,
297                          boolean is_pot,
298                          unsigned wrap_mode)
299 {
300    struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
301    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
302    LLVMValueRef length_minus_one;
303
304    length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one);
305
306    switch(wrap_mode) {
307    case PIPE_TEX_WRAP_REPEAT:
308       if(is_pot)
309          coord = LLVMBuildAnd(bld->builder, coord, length_minus_one, "");
310       else
311          /* Signed remainder won't give the right results for negative
312           * dividends but unsigned remainder does.*/
313          coord = LLVMBuildURem(bld->builder, coord, length, "");
314       break;
315
316    case PIPE_TEX_WRAP_CLAMP:
317    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
318    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
319       coord = lp_build_max(int_coord_bld, coord, int_coord_bld->zero);
320       coord = lp_build_min(int_coord_bld, coord, length_minus_one);
321       break;
322
323    case PIPE_TEX_WRAP_MIRROR_REPEAT:
324    case PIPE_TEX_WRAP_MIRROR_CLAMP:
325    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
326    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
327       /* FIXME */
328       _debug_printf("llvmpipe: failed to translate texture wrap mode %s\n",
329                     util_dump_tex_wrap(wrap_mode, TRUE));
330       coord = lp_build_max(uint_coord_bld, coord, uint_coord_bld->zero);
331       coord = lp_build_min(uint_coord_bld, coord, length_minus_one);
332       break;
333
334    default:
335       assert(0);
336    }
337
338    return coord;
339 }
340
341
342 /**
343  * Build LLVM code for texture wrap mode for linear filtering.
344  * \param x0_out  returns first integer texcoord
345  * \param x1_out  returns second integer texcoord
346  * \param weight_out  returns linear interpolation weight
347  */
348 static void
349 lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
350                             LLVMValueRef coord,
351                             LLVMValueRef length,
352                             boolean is_pot,
353                             unsigned wrap_mode,
354                             LLVMValueRef *x0_out,
355                             LLVMValueRef *x1_out,
356                             LLVMValueRef *weight_out)
357 {
358    struct lp_build_context *coord_bld = &bld->coord_bld;
359    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
360    struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
361    LLVMValueRef two = lp_build_const_scalar(coord_bld->type, 2.0);
362    LLVMValueRef half = lp_build_const_scalar(coord_bld->type, 0.5);
363    LLVMValueRef length_f = lp_build_int_to_float(coord_bld, length);
364    LLVMValueRef length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one);
365    LLVMValueRef length_f_minus_one = lp_build_sub(coord_bld, length_f, coord_bld->one);
366    LLVMValueRef coord0, coord1, weight;
367
368    switch(wrap_mode) {
369    case PIPE_TEX_WRAP_REPEAT:
370       /* mul by size and subtract 0.5 */
371       coord = lp_build_mul(coord_bld, coord, length_f);
372       coord = lp_build_sub(coord_bld, coord, half);
373       /* convert to int */
374       coord0 = lp_build_ifloor(coord_bld, coord);
375       coord1 = lp_build_add(uint_coord_bld, coord0, uint_coord_bld->one);
376       /* compute lerp weight */
377       weight = lp_build_fract(coord_bld, coord);
378       /* repeat wrap */
379       if (is_pot) {
380          coord0 = LLVMBuildAnd(bld->builder, coord0, length_minus_one, "");
381          coord1 = LLVMBuildAnd(bld->builder, coord1, length_minus_one, "");
382       }
383       else {
384          /* Signed remainder won't give the right results for negative
385           * dividends but unsigned remainder does.*/
386          coord0 = LLVMBuildURem(bld->builder, coord0, length, "");
387          coord1 = LLVMBuildURem(bld->builder, coord1, length, "");
388       }
389       break;
390
391    case PIPE_TEX_WRAP_CLAMP:
392       if (bld->static_state->normalized_coords) {
393          coord = lp_build_mul(coord_bld, coord, length_f);
394       }
395       weight = lp_build_fract(coord_bld, coord);
396       coord0 = lp_build_clamp(coord_bld, coord, coord_bld->zero,
397                               length_f_minus_one);
398       coord1 = lp_build_add(coord_bld, coord, coord_bld->one);
399       coord1 = lp_build_clamp(coord_bld, coord1, coord_bld->zero,
400                               length_f_minus_one);
401       coord0 = lp_build_ifloor(coord_bld, coord0);
402       coord1 = lp_build_ifloor(coord_bld, coord1);
403       break;
404
405    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
406       if (bld->static_state->normalized_coords) {
407          /* clamp to [0,1] */
408          coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, coord_bld->one);
409          /* mul by tex size and subtract 0.5 */
410          coord = lp_build_mul(coord_bld, coord, length_f);
411          coord = lp_build_sub(coord_bld, coord, half);
412       }
413       else {
414          LLVMValueRef min, max;
415          /* clamp to [0.5, length - 0.5] */
416          min = lp_build_const_scalar(coord_bld->type, 0.5F);
417          max = lp_build_sub(coord_bld, length_f, min);
418          coord = lp_build_clamp(coord_bld, coord, min, max);
419       }
420       /* compute lerp weight */
421       weight = lp_build_fract(coord_bld, coord);
422       /* coord0 = floor(coord); */
423       coord0 = lp_build_ifloor(coord_bld, coord);
424       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
425       /* coord0 = max(coord0, 0) */
426       coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero);
427       /* coord1 = min(coord1, length-1) */
428       coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
429       break;
430
431    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
432       {
433          LLVMValueRef min, max;
434          if (bld->static_state->normalized_coords) {
435             /* min = -1.0 / (2 * length) = -0.5 / length */
436             min = lp_build_mul(coord_bld,
437                                lp_build_const_scalar(coord_bld->type, -0.5F),
438                                lp_build_rcp(coord_bld, length_f));
439             /* max = 1.0 - min */
440             max = lp_build_sub(coord_bld, coord_bld->one, min);
441             /* coord = clamp(coord, min, max) */
442             coord = lp_build_clamp(coord_bld, coord, min, max);
443             /* scale coord to length (and sub 0.5?) */
444             coord = lp_build_mul(coord_bld, coord, length_f);
445             coord = lp_build_sub(coord_bld, coord, half);
446          }
447          else {
448             /* clamp to [-0.5, length + 0.5] */
449             min = lp_build_const_scalar(coord_bld->type, -0.5F);
450             max = lp_build_sub(coord_bld, length_f, min);
451             coord = lp_build_clamp(coord_bld, coord, min, max);
452             coord = lp_build_sub(coord_bld, coord, half);
453          }
454          /* compute lerp weight */
455          weight = lp_build_fract(coord_bld, coord);
456          /* convert to int */
457          coord0 = lp_build_ifloor(coord_bld, coord);
458          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
459       }
460       break;
461
462    case PIPE_TEX_WRAP_MIRROR_REPEAT:
463       /* compute mirror function */
464       coord = lp_build_coord_mirror(bld, coord);
465
466       /* scale coord to length */
467       coord = lp_build_mul(coord_bld, coord, length_f);
468       coord = lp_build_sub(coord_bld, coord, half);
469
470       /* compute lerp weight */
471       weight = lp_build_fract(coord_bld, coord);
472
473       /* convert to int coords */
474       coord0 = lp_build_ifloor(coord_bld, coord);
475       coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
476
477       /* coord0 = max(coord0, 0) */
478       coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero);
479       /* coord1 = min(coord1, length-1) */
480       coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
481       break;
482
483    case PIPE_TEX_WRAP_MIRROR_CLAMP:
484       {
485          LLVMValueRef min, max;
486          /* min = 1.0 / (2 * length) */
487          min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f));
488          /* max = 1.0 - min */
489          max = lp_build_sub(coord_bld, coord_bld->one, min);
490
491          coord = lp_build_abs(coord_bld, coord);
492          coord = lp_build_clamp(coord_bld, coord, min, max);
493          coord = lp_build_mul(coord_bld, coord, length_f);
494          if(0)coord = lp_build_sub(coord_bld, coord, half);
495          weight = lp_build_fract(coord_bld, coord);
496          coord0 = lp_build_ifloor(coord_bld, coord);
497          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
498       }
499       break;
500
501    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
502       {
503          LLVMValueRef min, max;
504          /* min = 1.0 / (2 * length) */
505          min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f));
506          /* max = 1.0 - min */
507          max = lp_build_sub(coord_bld, coord_bld->one, min);
508
509          coord = lp_build_abs(coord_bld, coord);
510          coord = lp_build_clamp(coord_bld, coord, min, max);
511          coord = lp_build_mul(coord_bld, coord, length_f);
512          coord = lp_build_sub(coord_bld, coord, half);
513          weight = lp_build_fract(coord_bld, coord);
514          coord0 = lp_build_ifloor(coord_bld, coord);
515          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
516       }
517       break;
518
519    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
520       {
521          LLVMValueRef min, max;
522          /* min = -1.0 / (2 * length) = -0.5 / length */
523          min = lp_build_mul(coord_bld,
524                             lp_build_const_scalar(coord_bld->type, -0.5F),
525                             lp_build_rcp(coord_bld, length_f));
526          /* max = 1.0 - min */
527          max = lp_build_sub(coord_bld, coord_bld->one, min);
528
529          coord = lp_build_abs(coord_bld, coord);
530          coord = lp_build_clamp(coord_bld, coord, min, max);
531          coord = lp_build_mul(coord_bld, coord, length_f);
532          coord = lp_build_sub(coord_bld, coord, half);
533          weight = lp_build_fract(coord_bld, coord);
534          coord0 = lp_build_ifloor(coord_bld, coord);
535          coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
536       }
537       break;
538
539    default:
540       assert(0);
541    }
542
543    *x0_out = coord0;
544    *x1_out = coord1;
545    *weight_out = weight;
546 }
547
548
549 /**
550  * Build LLVM code for texture wrap mode for nearest filtering.
551  * \param coord  the incoming texcoord (nominally in [0,1])
552  * \param length  the texture size along one dimension, as int
553  * \param is_pot  if TRUE, length is a power of two
554  * \param wrap_mode  one of PIPE_TEX_WRAP_x
555  */
556 static LLVMValueRef
557 lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
558                              LLVMValueRef coord,
559                              LLVMValueRef length,
560                              boolean is_pot,
561                              unsigned wrap_mode)
562 {
563    struct lp_build_context *coord_bld = &bld->coord_bld;
564    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
565    struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
566    LLVMValueRef two = lp_build_const_scalar(coord_bld->type, 2.0);
567    LLVMValueRef length_f = lp_build_int_to_float(coord_bld, length);
568    LLVMValueRef length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one);
569    LLVMValueRef length_f_minus_one = lp_build_sub(coord_bld, length_f, coord_bld->one);
570    LLVMValueRef icoord;
571    
572    switch(wrap_mode) {
573    case PIPE_TEX_WRAP_REPEAT:
574       coord = lp_build_mul(coord_bld, coord, length_f);
575       icoord = lp_build_ifloor(coord_bld, coord);
576       if (is_pot)
577          icoord = LLVMBuildAnd(bld->builder, icoord, length_minus_one, "");
578       else
579          /* Signed remainder won't give the right results for negative
580           * dividends but unsigned remainder does.*/
581          icoord = LLVMBuildURem(bld->builder, icoord, length, "");
582       break;
583
584    case PIPE_TEX_WRAP_CLAMP:
585       /* mul by size */
586       if (bld->static_state->normalized_coords) {
587          coord = lp_build_mul(coord_bld, coord, length_f);
588       }
589       /* floor */
590       icoord = lp_build_ifloor(coord_bld, coord);
591       /* clamp to [0, size-1].  Note: int coord builder type */
592       icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero,
593                               length_minus_one);
594       break;
595
596    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
597       {
598          LLVMValueRef min, max;
599          if (bld->static_state->normalized_coords) {
600             /* min = 1.0 / (2 * length) */
601             min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f));
602             /* max = length - min */
603             max = lp_build_sub(coord_bld, length_f, min);
604             /* scale coord to length */
605             coord = lp_build_mul(coord_bld, coord, length_f);
606          }
607          else {
608             /* clamp to [0.5, length - 0.5] */
609             min = lp_build_const_scalar(coord_bld->type, 0.5F);
610             max = lp_build_sub(coord_bld, length_f, min);
611          }
612          /* coord = clamp(coord, min, max) */
613          coord = lp_build_clamp(coord_bld, coord, min, max);
614          icoord = lp_build_ifloor(coord_bld, coord);
615       }
616       break;
617
618    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
619       /* Note: this is the same as CLAMP_TO_EDGE, except min = -min */
620       {
621          LLVMValueRef min, max;
622          if (bld->static_state->normalized_coords) {
623             /* min = -1.0 / (2 * length) = -0.5 / length */
624             min = lp_build_mul(coord_bld,
625                                lp_build_const_scalar(coord_bld->type, -0.5F),
626                                lp_build_rcp(coord_bld, length_f));
627             /* max = length - min */
628             max = lp_build_sub(coord_bld, length_f, min);
629             /* scale coord to length */
630             coord = lp_build_mul(coord_bld, coord, length_f);
631          }
632          else {
633             /* clamp to [-0.5, length + 0.5] */
634             min = lp_build_const_scalar(coord_bld->type, -0.5F);
635             max = lp_build_sub(coord_bld, length_f, min);
636          }
637          /* coord = clamp(coord, min, max) */
638          coord = lp_build_clamp(coord_bld, coord, min, max);
639          icoord = lp_build_ifloor(coord_bld, coord);
640       }
641       break;
642
643    case PIPE_TEX_WRAP_MIRROR_REPEAT:
644       {
645          LLVMValueRef min, max;
646          /* min = 1.0 / (2 * length) */
647          min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f));
648          /* max = length - min */
649          max = lp_build_sub(coord_bld, length_f, min);
650
651          /* compute mirror function */
652          coord = lp_build_coord_mirror(bld, coord);
653
654          /* scale coord to length */
655          coord = lp_build_mul(coord_bld, coord, length_f);
656
657          /* coord = clamp(coord, min, max) */
658          coord = lp_build_clamp(coord_bld, coord, min, max);
659          icoord = lp_build_ifloor(coord_bld, coord);
660       }
661       break;
662
663    case PIPE_TEX_WRAP_MIRROR_CLAMP:
664       coord = lp_build_abs(coord_bld, coord);
665       coord = lp_build_mul(coord_bld, coord, length_f);
666       coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, length_f_minus_one);
667       icoord = lp_build_ifloor(coord_bld, coord);
668       break;
669
670    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
671       {
672          LLVMValueRef min, max;
673          /* min = 1.0 / (2 * length) */
674          min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f));
675          /* max = length - min */
676          max = lp_build_sub(coord_bld, length_f, min);
677
678          coord = lp_build_abs(coord_bld, coord);
679          coord = lp_build_mul(coord_bld, coord, length_f);
680          coord = lp_build_clamp(coord_bld, coord, min, max);
681          icoord = lp_build_ifloor(coord_bld, coord);
682       }
683       break;
684
685    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
686       {
687          LLVMValueRef min, max;
688          /* min = 1.0 / (2 * length) */
689          min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f));
690          min = lp_build_negate(coord_bld, min);
691          /* max = length - min */
692          max = lp_build_sub(coord_bld, length_f, min);
693
694          coord = lp_build_abs(coord_bld, coord);
695          coord = lp_build_mul(coord_bld, coord, length_f);
696          coord = lp_build_clamp(coord_bld, coord, min, max);
697          icoord = lp_build_ifloor(coord_bld, coord);
698       }
699       break;
700
701    default:
702       assert(0);
703    }
704
705    return icoord;
706 }
707
708
709 /**
710  * Sample 2D texture with nearest filtering.
711  */
712 static void
713 lp_build_sample_2d_nearest_soa(struct lp_build_sample_context *bld,
714                                LLVMValueRef s,
715                                LLVMValueRef t,
716                                LLVMValueRef width,
717                                LLVMValueRef height,
718                                LLVMValueRef stride,
719                                LLVMValueRef data_ptr,
720                                LLVMValueRef *texel)
721 {
722    LLVMValueRef x, y;
723
724    x = lp_build_sample_wrap_nearest(bld, s, width,
725                                     bld->static_state->pot_width,
726                                     bld->static_state->wrap_s);
727    y = lp_build_sample_wrap_nearest(bld, t, height,
728                                     bld->static_state->pot_height,
729                                     bld->static_state->wrap_t);
730
731    lp_build_name(x, "tex.x.wrapped");
732    lp_build_name(y, "tex.y.wrapped");
733
734    lp_build_sample_texel_soa(bld, width, height, x, y, stride, data_ptr, texel);
735 }
736
737
738 /**
739  * Sample 2D texture with bilinear filtering.
740  */
741 static void
742 lp_build_sample_2d_linear_soa(struct lp_build_sample_context *bld,
743                               LLVMValueRef s,
744                               LLVMValueRef t,
745                               LLVMValueRef width,
746                               LLVMValueRef height,
747                               LLVMValueRef stride,
748                               LLVMValueRef data_ptr,
749                               LLVMValueRef *texel)
750 {
751    LLVMValueRef s_fpart;
752    LLVMValueRef t_fpart;
753    LLVMValueRef x0, x1;
754    LLVMValueRef y0, y1;
755    LLVMValueRef neighbors[2][2][4];
756    unsigned chan;
757
758    lp_build_sample_wrap_linear(bld, s, width, bld->static_state->pot_width,
759                                bld->static_state->wrap_s, &x0, &x1, &s_fpart);
760    lp_build_sample_wrap_linear(bld, t, height, bld->static_state->pot_height,
761                                bld->static_state->wrap_t, &y0, &y1, &t_fpart);
762
763    lp_build_sample_texel_soa(bld, width, height, x0, y0, stride, data_ptr, neighbors[0][0]);
764    lp_build_sample_texel_soa(bld, width, height, x1, y0, stride, data_ptr, neighbors[0][1]);
765    lp_build_sample_texel_soa(bld, width, height, x0, y1, stride, data_ptr, neighbors[1][0]);
766    lp_build_sample_texel_soa(bld, width, height, x1, y1, stride, data_ptr, neighbors[1][1]);
767
768    /* TODO: Don't interpolate missing channels */
769    for(chan = 0; chan < 4; ++chan) {
770       texel[chan] = lp_build_lerp_2d(&bld->texel_bld,
771                                      s_fpart, t_fpart,
772                                      neighbors[0][0][chan],
773                                      neighbors[0][1][chan],
774                                      neighbors[1][0][chan],
775                                      neighbors[1][1][chan]);
776    }
777 }
778
779
780 static void
781 lp_build_rgba8_to_f32_soa(LLVMBuilderRef builder,
782                           struct lp_type dst_type,
783                           LLVMValueRef packed,
784                           LLVMValueRef *rgba)
785 {
786    LLVMValueRef mask = lp_build_int_const_scalar(dst_type, 0xff);
787    unsigned chan;
788
789    /* Decode the input vector components */
790    for (chan = 0; chan < 4; ++chan) {
791       unsigned start = chan*8;
792       unsigned stop = start + 8;
793       LLVMValueRef input;
794
795       input = packed;
796
797       if(start)
798          input = LLVMBuildLShr(builder, input, lp_build_int_const_scalar(dst_type, start), "");
799
800       if(stop < 32)
801          input = LLVMBuildAnd(builder, input, mask, "");
802
803       input = lp_build_unsigned_norm_to_float(builder, 8, dst_type, input);
804
805       rgba[chan] = input;
806    }
807 }
808
809
810 static void
811 lp_build_sample_2d_linear_aos(struct lp_build_sample_context *bld,
812                               LLVMValueRef s,
813                               LLVMValueRef t,
814                               LLVMValueRef width,
815                               LLVMValueRef height,
816                               LLVMValueRef stride,
817                               LLVMValueRef data_ptr,
818                               LLVMValueRef *texel)
819 {
820    LLVMBuilderRef builder = bld->builder;
821    struct lp_build_context i32, h16, u8n;
822    LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
823    LLVMValueRef i32_c8, i32_c128, i32_c255;
824    LLVMValueRef s_ipart, s_fpart, s_fpart_lo, s_fpart_hi;
825    LLVMValueRef t_ipart, t_fpart, t_fpart_lo, t_fpart_hi;
826    LLVMValueRef x0, x1;
827    LLVMValueRef y0, y1;
828    LLVMValueRef neighbors[2][2];
829    LLVMValueRef neighbors_lo[2][2];
830    LLVMValueRef neighbors_hi[2][2];
831    LLVMValueRef packed, packed_lo, packed_hi;
832    LLVMValueRef unswizzled[4];
833
834    lp_build_context_init(&i32, builder, lp_type_int(32));
835    lp_build_context_init(&h16, builder, lp_type_ufixed(16));
836    lp_build_context_init(&u8n, builder, lp_type_unorm(8));
837
838    i32_vec_type = lp_build_vec_type(i32.type);
839    h16_vec_type = lp_build_vec_type(h16.type);
840    u8n_vec_type = lp_build_vec_type(u8n.type);
841
842    if (bld->static_state->normalized_coords) {
843       LLVMTypeRef coord_vec_type = lp_build_vec_type(bld->coord_type);
844       LLVMValueRef fp_width = LLVMBuildSIToFP(bld->builder, width, coord_vec_type, "");
845       LLVMValueRef fp_height = LLVMBuildSIToFP(bld->builder, height, coord_vec_type, "");
846       s = lp_build_mul(&bld->coord_bld, s, fp_width);
847       t = lp_build_mul(&bld->coord_bld, t, fp_height);
848    }
849
850    /* scale coords by 256 (8 fractional bits) */
851    s = lp_build_mul_imm(&bld->coord_bld, s, 256);
852    t = lp_build_mul_imm(&bld->coord_bld, t, 256);
853
854    /* convert float to int */
855    s = LLVMBuildFPToSI(builder, s, i32_vec_type, "");
856    t = LLVMBuildFPToSI(builder, t, i32_vec_type, "");
857
858    /* subtract 0.5 (add -128) */
859    i32_c128 = lp_build_int_const_scalar(i32.type, -128);
860    s = LLVMBuildAdd(builder, s, i32_c128, "");
861    t = LLVMBuildAdd(builder, t, i32_c128, "");
862
863    /* compute floor (shift right 8) */
864    i32_c8 = lp_build_int_const_scalar(i32.type, 8);
865    s_ipart = LLVMBuildAShr(builder, s, i32_c8, "");
866    t_ipart = LLVMBuildAShr(builder, t, i32_c8, "");
867
868    /* compute fractional part (AND with 0xff) */
869    i32_c255 = lp_build_int_const_scalar(i32.type, 255);
870    s_fpart = LLVMBuildAnd(builder, s, i32_c255, "");
871    t_fpart = LLVMBuildAnd(builder, t, i32_c255, "");
872
873    x0 = s_ipart;
874    y0 = t_ipart;
875
876    x1 = lp_build_add(&bld->int_coord_bld, x0, bld->int_coord_bld.one);
877    y1 = lp_build_add(&bld->int_coord_bld, y0, bld->int_coord_bld.one);
878
879    x0 = lp_build_sample_wrap_int(bld, x0, width,  bld->static_state->pot_width,
880                                  bld->static_state->wrap_s);
881    y0 = lp_build_sample_wrap_int(bld, y0, height, bld->static_state->pot_height,
882                                  bld->static_state->wrap_t);
883
884    x1 = lp_build_sample_wrap_int(bld, x1, width,  bld->static_state->pot_width,
885                                  bld->static_state->wrap_s);
886    y1 = lp_build_sample_wrap_int(bld, y1, height, bld->static_state->pot_height,
887                                  bld->static_state->wrap_t);
888
889    /*
890     * Transform 4 x i32 in
891     *
892     *   s_fpart = {s0, s1, s2, s3}
893     *
894     * into 8 x i16
895     *
896     *   s_fpart = {00, s0, 00, s1, 00, s2, 00, s3}
897     *
898     * into two 8 x i16
899     *
900     *   s_fpart_lo = {s0, s0, s0, s0, s1, s1, s1, s1}
901     *   s_fpart_hi = {s2, s2, s2, s2, s3, s3, s3, s3}
902     *
903     * and likewise for t_fpart. There is no risk of loosing precision here
904     * since the fractional parts only use the lower 8bits.
905     */
906
907    s_fpart = LLVMBuildBitCast(builder, s_fpart, h16_vec_type, "");
908    t_fpart = LLVMBuildBitCast(builder, t_fpart, h16_vec_type, "");
909
910    {
911       LLVMTypeRef elem_type = LLVMInt32Type();
912       LLVMValueRef shuffles_lo[LP_MAX_VECTOR_LENGTH];
913       LLVMValueRef shuffles_hi[LP_MAX_VECTOR_LENGTH];
914       LLVMValueRef shuffle_lo;
915       LLVMValueRef shuffle_hi;
916       unsigned i, j;
917
918       for(j = 0; j < h16.type.length; j += 4) {
919          unsigned subindex = util_cpu_caps.little_endian ? 0 : 1;
920          LLVMValueRef index;
921
922          index = LLVMConstInt(elem_type, j/2 + subindex, 0);
923          for(i = 0; i < 4; ++i)
924             shuffles_lo[j + i] = index;
925
926          index = LLVMConstInt(elem_type, h16.type.length/2 + j/2 + subindex, 0);
927          for(i = 0; i < 4; ++i)
928             shuffles_hi[j + i] = index;
929       }
930
931       shuffle_lo = LLVMConstVector(shuffles_lo, h16.type.length);
932       shuffle_hi = LLVMConstVector(shuffles_hi, h16.type.length);
933
934       s_fpart_lo = LLVMBuildShuffleVector(builder, s_fpart, h16.undef, shuffle_lo, "");
935       t_fpart_lo = LLVMBuildShuffleVector(builder, t_fpart, h16.undef, shuffle_lo, "");
936       s_fpart_hi = LLVMBuildShuffleVector(builder, s_fpart, h16.undef, shuffle_hi, "");
937       t_fpart_hi = LLVMBuildShuffleVector(builder, t_fpart, h16.undef, shuffle_hi, "");
938    }
939
940    /*
941     * Fetch the pixels as 4 x 32bit (rgba order might differ):
942     *
943     *   rgba0 rgba1 rgba2 rgba3
944     *
945     * bit cast them into 16 x u8
946     *
947     *   r0 g0 b0 a0 r1 g1 b1 a1 r2 g2 b2 a2 r3 g3 b3 a3
948     *
949     * unpack them into two 8 x i16:
950     *
951     *   r0 g0 b0 a0 r1 g1 b1 a1
952     *   r2 g2 b2 a2 r3 g3 b3 a3
953     *
954     * The higher 8 bits of the resulting elements will be zero.
955     */
956
957    neighbors[0][0] = lp_build_sample_packed(bld, x0, y0, stride, data_ptr);
958    neighbors[0][1] = lp_build_sample_packed(bld, x1, y0, stride, data_ptr);
959    neighbors[1][0] = lp_build_sample_packed(bld, x0, y1, stride, data_ptr);
960    neighbors[1][1] = lp_build_sample_packed(bld, x1, y1, stride, data_ptr);
961
962    neighbors[0][0] = LLVMBuildBitCast(builder, neighbors[0][0], u8n_vec_type, "");
963    neighbors[0][1] = LLVMBuildBitCast(builder, neighbors[0][1], u8n_vec_type, "");
964    neighbors[1][0] = LLVMBuildBitCast(builder, neighbors[1][0], u8n_vec_type, "");
965    neighbors[1][1] = LLVMBuildBitCast(builder, neighbors[1][1], u8n_vec_type, "");
966
967    lp_build_unpack2(builder, u8n.type, h16.type, neighbors[0][0], &neighbors_lo[0][0], &neighbors_hi[0][0]);
968    lp_build_unpack2(builder, u8n.type, h16.type, neighbors[0][1], &neighbors_lo[0][1], &neighbors_hi[0][1]);
969    lp_build_unpack2(builder, u8n.type, h16.type, neighbors[1][0], &neighbors_lo[1][0], &neighbors_hi[1][0]);
970    lp_build_unpack2(builder, u8n.type, h16.type, neighbors[1][1], &neighbors_lo[1][1], &neighbors_hi[1][1]);
971
972    /*
973     * Linear interpolate with 8.8 fixed point.
974     */
975
976    packed_lo = lp_build_lerp_2d(&h16,
977                                 s_fpart_lo, t_fpart_lo,
978                                 neighbors_lo[0][0],
979                                 neighbors_lo[0][1],
980                                 neighbors_lo[1][0],
981                                 neighbors_lo[1][1]);
982
983    packed_hi = lp_build_lerp_2d(&h16,
984                                 s_fpart_hi, t_fpart_hi,
985                                 neighbors_hi[0][0],
986                                 neighbors_hi[0][1],
987                                 neighbors_hi[1][0],
988                                 neighbors_hi[1][1]);
989
990    packed = lp_build_pack2(builder, h16.type, u8n.type, packed_lo, packed_hi);
991
992    /*
993     * Convert to SoA and swizzle.
994     */
995
996    packed = LLVMBuildBitCast(builder, packed, i32_vec_type, "");
997
998    lp_build_rgba8_to_f32_soa(bld->builder,
999                              bld->texel_type,
1000                              packed, unswizzled);
1001
1002    lp_build_format_swizzle_soa(bld->format_desc,
1003                                bld->texel_type, unswizzled,
1004                                texel);
1005 }
1006
1007
1008 static void
1009 lp_build_sample_compare(struct lp_build_sample_context *bld,
1010                         LLVMValueRef p,
1011                         LLVMValueRef *texel)
1012 {
1013    struct lp_build_context *texel_bld = &bld->texel_bld;
1014    LLVMValueRef res;
1015    unsigned chan;
1016
1017    if(bld->static_state->compare_mode == PIPE_TEX_COMPARE_NONE)
1018       return;
1019
1020    /* TODO: Compare before swizzling, to avoid redundant computations */
1021    res = NULL;
1022    for(chan = 0; chan < 4; ++chan) {
1023       LLVMValueRef cmp;
1024       cmp = lp_build_cmp(texel_bld, bld->static_state->compare_func, p, texel[chan]);
1025       cmp = lp_build_select(texel_bld, cmp, texel_bld->one, texel_bld->zero);
1026
1027       if(res)
1028          res = lp_build_add(texel_bld, res, cmp);
1029       else
1030          res = cmp;
1031    }
1032
1033    assert(res);
1034    res = lp_build_mul(texel_bld, res, lp_build_const_scalar(texel_bld->type, 0.25));
1035
1036    /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
1037    for(chan = 0; chan < 3; ++chan)
1038       texel[chan] = res;
1039    texel[3] = texel_bld->one;
1040 }
1041
1042
1043 /**
1044  * Build texture sampling code.
1045  * 'texel' will return a vector of four LLVMValueRefs corresponding to
1046  * R, G, B, A.
1047  */
1048 void
1049 lp_build_sample_soa(LLVMBuilderRef builder,
1050                     const struct lp_sampler_static_state *static_state,
1051                     struct lp_sampler_dynamic_state *dynamic_state,
1052                     struct lp_type type,
1053                     unsigned unit,
1054                     unsigned num_coords,
1055                     const LLVMValueRef *coords,
1056                     LLVMValueRef lodbias,
1057                     LLVMValueRef *texel)
1058 {
1059    struct lp_build_sample_context bld;
1060    LLVMValueRef width;
1061    LLVMValueRef height;
1062    LLVMValueRef stride;
1063    LLVMValueRef data_ptr;
1064    LLVMValueRef s;
1065    LLVMValueRef t;
1066    LLVMValueRef p;
1067
1068    /* Setup our build context */
1069    memset(&bld, 0, sizeof bld);
1070    bld.builder = builder;
1071    bld.static_state = static_state;
1072    bld.dynamic_state = dynamic_state;
1073    bld.format_desc = util_format_description(static_state->format);
1074    bld.coord_type = type;
1075    bld.uint_coord_type = lp_uint_type(type);
1076    bld.int_coord_type = lp_int_type(type);
1077    bld.texel_type = type;
1078    lp_build_context_init(&bld.coord_bld, builder, bld.coord_type);
1079    lp_build_context_init(&bld.uint_coord_bld, builder, bld.uint_coord_type);
1080    lp_build_context_init(&bld.int_coord_bld, builder, bld.int_coord_type);
1081    lp_build_context_init(&bld.texel_bld, builder, bld.texel_type);
1082
1083    /* Get the dynamic state */
1084    width = dynamic_state->width(dynamic_state, builder, unit);
1085    height = dynamic_state->height(dynamic_state, builder, unit);
1086    stride = dynamic_state->stride(dynamic_state, builder, unit);
1087    data_ptr = dynamic_state->data_ptr(dynamic_state, builder, unit);
1088
1089    s = coords[0];
1090    t = coords[1];
1091    p = coords[2];
1092
1093    width = lp_build_broadcast_scalar(&bld.uint_coord_bld, width);
1094    height = lp_build_broadcast_scalar(&bld.uint_coord_bld, height);
1095    stride = lp_build_broadcast_scalar(&bld.uint_coord_bld, stride);
1096
1097    if(static_state->target == PIPE_TEXTURE_1D)
1098       t = bld.coord_bld.zero;
1099
1100    switch (static_state->min_img_filter) {
1101    case PIPE_TEX_FILTER_NEAREST:
1102       lp_build_sample_2d_nearest_soa(&bld, s, t, width, height,
1103                                      stride, data_ptr, texel);
1104       break;
1105    case PIPE_TEX_FILTER_LINEAR:
1106       if(lp_format_is_rgba8(bld.format_desc) &&
1107          is_simple_wrap_mode(static_state->wrap_s) &&
1108          is_simple_wrap_mode(static_state->wrap_t))
1109          lp_build_sample_2d_linear_aos(&bld, s, t, width, height,
1110                                        stride, data_ptr, texel);
1111       else
1112          lp_build_sample_2d_linear_soa(&bld, s, t, width, height,
1113                                        stride, data_ptr, texel);
1114       break;
1115    default:
1116       assert(0);
1117    }
1118
1119    /* FIXME: respect static_state->min_mip_filter */;
1120    /* FIXME: respect static_state->mag_img_filter */;
1121
1122    lp_build_sample_compare(&bld, p, texel);
1123 }