Merge branch 'mesa_7_6_branch'
[mesa.git] / src / gallium / drivers / llvmpipe / 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.
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_memory.h"
39 #include "util/u_math.h"
40 #include "util/u_format.h"
41 #include "lp_bld_debug.h"
42 #include "lp_bld_type.h"
43 #include "lp_bld_const.h"
44 #include "lp_bld_arit.h"
45 #include "lp_bld_logic.h"
46 #include "lp_bld_swizzle.h"
47 #include "lp_bld_format.h"
48 #include "lp_bld_sample.h"
49
50
51 void
52 lp_sampler_static_state(struct lp_sampler_static_state *state,
53 const struct pipe_texture *texture,
54 const struct pipe_sampler_state *sampler)
55 {
56 memset(state, 0, sizeof *state);
57
58 if(!texture)
59 return;
60
61 if(!sampler)
62 return;
63
64 state->format = texture->format;
65 state->target = texture->target;
66 state->pot_width = util_is_pot(texture->width[0]);
67 state->pot_height = util_is_pot(texture->height[0]);
68 state->pot_depth = util_is_pot(texture->depth[0]);
69
70 state->wrap_s = sampler->wrap_s;
71 state->wrap_t = sampler->wrap_t;
72 state->wrap_r = sampler->wrap_r;
73 state->min_img_filter = sampler->min_img_filter;
74 state->min_mip_filter = sampler->min_mip_filter;
75 state->mag_img_filter = sampler->mag_img_filter;
76 if(sampler->compare_mode) {
77 state->compare_mode = sampler->compare_mode;
78 state->compare_func = sampler->compare_func;
79 }
80 state->normalized_coords = sampler->normalized_coords;
81 state->prefilter = sampler->prefilter;
82 }
83
84
85
86 /**
87 * Keep all information for sampling code generation in a single place.
88 */
89 struct lp_build_sample_context
90 {
91 LLVMBuilderRef builder;
92
93 const struct lp_sampler_static_state *static_state;
94
95 struct lp_sampler_dynamic_state *dynamic_state;
96
97 const struct util_format_description *format_desc;
98
99 /** Incoming coordinates type and build context */
100 struct lp_type coord_type;
101 struct lp_build_context coord_bld;
102
103 /** Integer coordinates */
104 struct lp_type int_coord_type;
105 struct lp_build_context int_coord_bld;
106
107 /** Output texels type and build context */
108 struct lp_type texel_type;
109 struct lp_build_context texel_bld;
110 };
111
112
113 static void
114 lp_build_sample_texel(struct lp_build_sample_context *bld,
115 LLVMValueRef x,
116 LLVMValueRef y,
117 LLVMValueRef y_stride,
118 LLVMValueRef data_ptr,
119 LLVMValueRef *texel)
120 {
121 struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
122 LLVMValueRef x_stride;
123 LLVMValueRef offset;
124
125 x_stride = lp_build_const_scalar(bld->int_coord_type, bld->format_desc->block.bits/8);
126
127 if(bld->format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
128 LLVMValueRef x_lo, x_hi;
129 LLVMValueRef y_lo, y_hi;
130 LLVMValueRef x_stride_lo, x_stride_hi;
131 LLVMValueRef y_stride_lo, y_stride_hi;
132 LLVMValueRef x_offset_lo, x_offset_hi;
133 LLVMValueRef y_offset_lo, y_offset_hi;
134 LLVMValueRef offset_lo, offset_hi;
135
136 x_lo = LLVMBuildAnd(bld->builder, x, int_coord_bld->one, "");
137 y_lo = LLVMBuildAnd(bld->builder, y, int_coord_bld->one, "");
138
139 x_hi = LLVMBuildLShr(bld->builder, x, int_coord_bld->one, "");
140 y_hi = LLVMBuildLShr(bld->builder, y, int_coord_bld->one, "");
141
142 x_stride_lo = x_stride;
143 y_stride_lo = lp_build_const_scalar(bld->int_coord_type, 2*bld->format_desc->block.bits/8);
144
145 x_stride_hi = lp_build_const_scalar(bld->int_coord_type, 4*bld->format_desc->block.bits/8);
146 y_stride_hi = LLVMBuildShl(bld->builder, y_stride, int_coord_bld->one, "");
147
148 x_offset_lo = lp_build_mul(int_coord_bld, x_lo, x_stride_lo);
149 y_offset_lo = lp_build_mul(int_coord_bld, y_lo, y_stride_lo);
150 offset_lo = lp_build_add(int_coord_bld, x_offset_lo, y_offset_lo);
151
152 x_offset_hi = lp_build_mul(int_coord_bld, x_hi, x_stride_hi);
153 y_offset_hi = lp_build_mul(int_coord_bld, y_hi, y_stride_hi);
154 offset_hi = lp_build_add(int_coord_bld, x_offset_hi, y_offset_hi);
155
156 offset = lp_build_add(int_coord_bld, offset_hi, offset_lo);
157 }
158 else {
159 LLVMValueRef x_offset;
160 LLVMValueRef y_offset;
161
162 x_offset = lp_build_mul(int_coord_bld, x, x_stride);
163 y_offset = lp_build_mul(int_coord_bld, y, y_stride);
164
165 offset = lp_build_add(int_coord_bld, x_offset, y_offset);
166 }
167
168 lp_build_load_rgba_soa(bld->builder,
169 bld->format_desc,
170 bld->texel_type,
171 data_ptr,
172 offset,
173 texel);
174 }
175
176
177 static LLVMValueRef
178 lp_build_sample_wrap(struct lp_build_sample_context *bld,
179 LLVMValueRef coord,
180 LLVMValueRef length,
181 boolean is_pot,
182 unsigned wrap_mode)
183 {
184 struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
185 LLVMValueRef length_minus_one;
186
187 length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
188
189 switch(wrap_mode) {
190 case PIPE_TEX_WRAP_REPEAT:
191 if(is_pot)
192 coord = LLVMBuildAnd(bld->builder, coord, length_minus_one, "");
193 else
194 /* Signed remainder won't give the right results for negative
195 * dividends but unsigned remainder does.*/
196 coord = LLVMBuildURem(bld->builder, coord, length, "");
197 break;
198
199 case PIPE_TEX_WRAP_CLAMP:
200 coord = lp_build_max(int_coord_bld, coord, int_coord_bld->zero);
201 coord = lp_build_min(int_coord_bld, coord, length_minus_one);
202 break;
203
204 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
205 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
206 case PIPE_TEX_WRAP_MIRROR_REPEAT:
207 case PIPE_TEX_WRAP_MIRROR_CLAMP:
208 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
209 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
210 /* FIXME */
211 _debug_printf("warning: failed to translate texture wrap mode %u\n", wrap_mode);
212 coord = lp_build_max(int_coord_bld, coord, int_coord_bld->zero);
213 coord = lp_build_min(int_coord_bld, coord, length_minus_one);
214 break;
215
216 default:
217 assert(0);
218 }
219
220 return coord;
221 }
222
223
224 static void
225 lp_build_sample_2d_nearest_soa(struct lp_build_sample_context *bld,
226 LLVMValueRef s,
227 LLVMValueRef t,
228 LLVMValueRef width,
229 LLVMValueRef height,
230 LLVMValueRef stride,
231 LLVMValueRef data_ptr,
232 LLVMValueRef *texel)
233 {
234 LLVMValueRef x;
235 LLVMValueRef y;
236
237 x = lp_build_ifloor(&bld->coord_bld, s);
238 y = lp_build_ifloor(&bld->coord_bld, t);
239
240 x = lp_build_sample_wrap(bld, x, width, bld->static_state->pot_width, bld->static_state->wrap_s);
241 y = lp_build_sample_wrap(bld, y, height, bld->static_state->pot_height, bld->static_state->wrap_t);
242
243 lp_build_sample_texel(bld, x, y, stride, data_ptr, texel);
244 }
245
246
247 static void
248 lp_build_sample_2d_linear_soa(struct lp_build_sample_context *bld,
249 LLVMValueRef s,
250 LLVMValueRef t,
251 LLVMValueRef width,
252 LLVMValueRef height,
253 LLVMValueRef stride,
254 LLVMValueRef data_ptr,
255 LLVMValueRef *texel)
256 {
257 LLVMValueRef half;
258 LLVMValueRef s_ipart;
259 LLVMValueRef t_ipart;
260 LLVMValueRef s_fpart;
261 LLVMValueRef t_fpart;
262 LLVMValueRef x0, x1;
263 LLVMValueRef y0, y1;
264 LLVMValueRef neighbors[2][2][4];
265 unsigned chan;
266
267 half = lp_build_const_scalar(bld->coord_type, 0.5);
268 s = lp_build_sub(&bld->coord_bld, s, half);
269 t = lp_build_sub(&bld->coord_bld, t, half);
270
271 s_ipart = lp_build_floor(&bld->coord_bld, s);
272 t_ipart = lp_build_floor(&bld->coord_bld, t);
273
274 s_fpart = lp_build_sub(&bld->coord_bld, s, s_ipart);
275 t_fpart = lp_build_sub(&bld->coord_bld, t, t_ipart);
276
277 x0 = lp_build_int(&bld->coord_bld, s_ipart);
278 y0 = lp_build_int(&bld->coord_bld, t_ipart);
279
280 x0 = lp_build_sample_wrap(bld, x0, width, bld->static_state->pot_width, bld->static_state->wrap_s);
281 y0 = lp_build_sample_wrap(bld, y0, height, bld->static_state->pot_height, bld->static_state->wrap_t);
282
283 x1 = lp_build_add(&bld->int_coord_bld, x0, bld->int_coord_bld.one);
284 y1 = lp_build_add(&bld->int_coord_bld, y0, bld->int_coord_bld.one);
285
286 x1 = lp_build_sample_wrap(bld, x1, width, bld->static_state->pot_width, bld->static_state->wrap_s);
287 y1 = lp_build_sample_wrap(bld, y1, height, bld->static_state->pot_height, bld->static_state->wrap_t);
288
289 lp_build_sample_texel(bld, x0, y0, stride, data_ptr, neighbors[0][0]);
290 lp_build_sample_texel(bld, x1, y0, stride, data_ptr, neighbors[0][1]);
291 lp_build_sample_texel(bld, x0, y1, stride, data_ptr, neighbors[1][0]);
292 lp_build_sample_texel(bld, x1, y1, stride, data_ptr, neighbors[1][1]);
293
294 /* TODO: Don't interpolate missing channels */
295 for(chan = 0; chan < 4; ++chan) {
296 texel[chan] = lp_build_lerp_2d(&bld->texel_bld,
297 s_fpart, t_fpart,
298 neighbors[0][0][chan],
299 neighbors[0][1][chan],
300 neighbors[1][0][chan],
301 neighbors[1][1][chan]);
302 }
303 }
304
305
306 static void
307 lp_build_sample_compare(struct lp_build_sample_context *bld,
308 LLVMValueRef p,
309 LLVMValueRef *texel)
310 {
311 struct lp_build_context *texel_bld = &bld->texel_bld;
312 LLVMValueRef res;
313 unsigned chan;
314
315 if(!bld->static_state->compare_mode)
316 return;
317
318 /* TODO: Compare before swizzling, to avoid redundant computations */
319 res = NULL;
320 for(chan = 0; chan < 4; ++chan) {
321 LLVMValueRef cmp;
322 cmp = lp_build_cmp(texel_bld, bld->static_state->compare_func, p, texel[chan]);
323 cmp = lp_build_select(texel_bld, cmp, texel_bld->one, texel_bld->zero);
324
325 if(res)
326 res = lp_build_add(texel_bld, res, cmp);
327 else
328 res = cmp;
329 }
330
331 assert(res);
332 res = lp_build_mul(texel_bld, res, lp_build_const_scalar(texel_bld->type, 0.25));
333
334 /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
335 for(chan = 0; chan < 3; ++chan)
336 texel[chan] = res;
337 texel[3] = texel_bld->one;
338 }
339
340
341 void
342 lp_build_sample_soa(LLVMBuilderRef builder,
343 const struct lp_sampler_static_state *static_state,
344 struct lp_sampler_dynamic_state *dynamic_state,
345 struct lp_type type,
346 unsigned unit,
347 unsigned num_coords,
348 const LLVMValueRef *coords,
349 LLVMValueRef lodbias,
350 LLVMValueRef *texel)
351 {
352 struct lp_build_sample_context bld;
353 LLVMValueRef width;
354 LLVMValueRef height;
355 LLVMValueRef stride;
356 LLVMValueRef data_ptr;
357 LLVMValueRef s;
358 LLVMValueRef t;
359 LLVMValueRef p;
360
361 /* Setup our build context */
362 memset(&bld, 0, sizeof bld);
363 bld.builder = builder;
364 bld.static_state = static_state;
365 bld.dynamic_state = dynamic_state;
366 bld.format_desc = util_format_description(static_state->format);
367 bld.coord_type = type;
368 bld.int_coord_type = lp_int_type(type);
369 bld.texel_type = type;
370 lp_build_context_init(&bld.coord_bld, builder, bld.coord_type);
371 lp_build_context_init(&bld.int_coord_bld, builder, bld.int_coord_type);
372 lp_build_context_init(&bld.texel_bld, builder, bld.texel_type);
373
374 /* Get the dynamic state */
375 width = dynamic_state->width(dynamic_state, builder, unit);
376 height = dynamic_state->height(dynamic_state, builder, unit);
377 stride = dynamic_state->stride(dynamic_state, builder, unit);
378 data_ptr = dynamic_state->data_ptr(dynamic_state, builder, unit);
379
380 s = coords[0];
381 t = coords[1];
382 p = coords[2];
383
384 width = lp_build_broadcast_scalar(&bld.int_coord_bld, width);
385 height = lp_build_broadcast_scalar(&bld.int_coord_bld, height);
386 stride = lp_build_broadcast_scalar(&bld.int_coord_bld, stride);
387
388 if(static_state->target == PIPE_TEXTURE_1D)
389 t = bld.coord_bld.zero;
390
391 if(static_state->normalized_coords) {
392 LLVMTypeRef coord_vec_type = lp_build_vec_type(bld.coord_type);
393 LLVMValueRef fp_width = LLVMBuildSIToFP(builder, width, coord_vec_type, "");
394 LLVMValueRef fp_height = LLVMBuildSIToFP(builder, height, coord_vec_type, "");
395 s = lp_build_mul(&bld.coord_bld, s, fp_width);
396 t = lp_build_mul(&bld.coord_bld, t, fp_height);
397 }
398
399 switch (static_state->min_img_filter) {
400 case PIPE_TEX_FILTER_NEAREST:
401 lp_build_sample_2d_nearest_soa(&bld, s, t, width, height, stride, data_ptr, texel);
402 break;
403 case PIPE_TEX_FILTER_LINEAR:
404 case PIPE_TEX_FILTER_ANISO:
405 lp_build_sample_2d_linear_soa(&bld, s, t, width, height, stride, data_ptr, texel);
406 break;
407 default:
408 assert(0);
409 }
410
411 /* FIXME: respect static_state->min_mip_filter */;
412 /* FIXME: respect static_state->mag_img_filter */;
413 /* FIXME: respect static_state->prefilter */;
414
415 lp_build_sample_compare(&bld, p, texel);
416 }