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