Merge commit 'origin/master' into glsl-pp-rework-2
[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 union lp_type coord_type;
101 struct lp_build_context coord_bld;
102
103 /** Integer coordinates */
104 union lp_type int_coord_type;
105 struct lp_build_context int_coord_bld;
106
107 /** Output texels type and build context */
108 union 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 default:
212 assert(0);
213 }
214
215 return coord;
216 }
217
218
219 static void
220 lp_build_sample_2d_nearest_soa(struct lp_build_sample_context *bld,
221 LLVMValueRef s,
222 LLVMValueRef t,
223 LLVMValueRef width,
224 LLVMValueRef height,
225 LLVMValueRef stride,
226 LLVMValueRef data_ptr,
227 LLVMValueRef *texel)
228 {
229 LLVMValueRef x;
230 LLVMValueRef y;
231
232 x = lp_build_ifloor(&bld->coord_bld, s);
233 y = lp_build_ifloor(&bld->coord_bld, t);
234
235 x = lp_build_sample_wrap(bld, x, width, bld->static_state->pot_width, bld->static_state->wrap_s);
236 y = lp_build_sample_wrap(bld, y, height, bld->static_state->pot_height, bld->static_state->wrap_t);
237
238 lp_build_sample_texel(bld, x, y, stride, data_ptr, texel);
239 }
240
241
242 static void
243 lp_build_sample_2d_linear_soa(struct lp_build_sample_context *bld,
244 LLVMValueRef s,
245 LLVMValueRef t,
246 LLVMValueRef width,
247 LLVMValueRef height,
248 LLVMValueRef stride,
249 LLVMValueRef data_ptr,
250 LLVMValueRef *texel)
251 {
252 LLVMValueRef half;
253 LLVMValueRef s_ipart;
254 LLVMValueRef t_ipart;
255 LLVMValueRef s_fpart;
256 LLVMValueRef t_fpart;
257 LLVMValueRef x0, x1;
258 LLVMValueRef y0, y1;
259 LLVMValueRef neighbors[2][2][4];
260 unsigned chan;
261
262 half = lp_build_const_scalar(bld->coord_type, 0.5);
263 s = lp_build_sub(&bld->coord_bld, s, half);
264 t = lp_build_sub(&bld->coord_bld, t, half);
265
266 s_ipart = lp_build_floor(&bld->coord_bld, s);
267 t_ipart = lp_build_floor(&bld->coord_bld, t);
268
269 s_fpart = lp_build_sub(&bld->coord_bld, s, s_ipart);
270 t_fpart = lp_build_sub(&bld->coord_bld, t, t_ipart);
271
272 x0 = lp_build_int(&bld->coord_bld, s_ipart);
273 y0 = lp_build_int(&bld->coord_bld, t_ipart);
274
275 x0 = lp_build_sample_wrap(bld, x0, width, bld->static_state->pot_width, bld->static_state->wrap_s);
276 y0 = lp_build_sample_wrap(bld, y0, height, bld->static_state->pot_height, bld->static_state->wrap_t);
277
278 x1 = lp_build_add(&bld->int_coord_bld, x0, bld->int_coord_bld.one);
279 y1 = lp_build_add(&bld->int_coord_bld, y0, bld->int_coord_bld.one);
280
281 x1 = lp_build_sample_wrap(bld, x1, width, bld->static_state->pot_width, bld->static_state->wrap_s);
282 y1 = lp_build_sample_wrap(bld, y1, height, bld->static_state->pot_height, bld->static_state->wrap_t);
283
284 lp_build_sample_texel(bld, x0, y0, stride, data_ptr, neighbors[0][0]);
285 lp_build_sample_texel(bld, x1, y0, stride, data_ptr, neighbors[0][1]);
286 lp_build_sample_texel(bld, x0, y1, stride, data_ptr, neighbors[1][0]);
287 lp_build_sample_texel(bld, x1, y1, stride, data_ptr, neighbors[1][1]);
288
289 /* TODO: Don't interpolate missing channels */
290 for(chan = 0; chan < 4; ++chan) {
291 texel[chan] = lp_build_lerp_2d(&bld->texel_bld,
292 s_fpart, t_fpart,
293 neighbors[0][0][chan],
294 neighbors[0][1][chan],
295 neighbors[1][0][chan],
296 neighbors[1][1][chan]);
297 }
298 }
299
300
301 static void
302 lp_build_sample_compare(struct lp_build_sample_context *bld,
303 LLVMValueRef p,
304 LLVMValueRef *texel)
305 {
306 struct lp_build_context *texel_bld = &bld->texel_bld;
307 LLVMValueRef res;
308 unsigned chan;
309
310 if(!bld->static_state->compare_mode)
311 return;
312
313 /* TODO: Compare before swizzling, to avoid redundant computations */
314 res = NULL;
315 for(chan = 0; chan < 4; ++chan) {
316 LLVMValueRef cmp;
317 cmp = lp_build_cmp(texel_bld, bld->static_state->compare_func, p, texel[chan]);
318 cmp = lp_build_select(texel_bld, cmp, texel_bld->one, texel_bld->zero);
319
320 if(res)
321 res = lp_build_add(texel_bld, res, cmp);
322 else
323 res = cmp;
324 }
325
326 assert(res);
327 res = lp_build_mul(texel_bld, res, lp_build_const_scalar(texel_bld->type, 0.25));
328
329 /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
330 for(chan = 0; chan < 3; ++chan)
331 texel[chan] = res;
332 texel[3] = texel_bld->one;
333 }
334
335
336 void
337 lp_build_sample_soa(LLVMBuilderRef builder,
338 const struct lp_sampler_static_state *static_state,
339 struct lp_sampler_dynamic_state *dynamic_state,
340 union lp_type type,
341 unsigned unit,
342 unsigned num_coords,
343 const LLVMValueRef *coords,
344 LLVMValueRef lodbias,
345 LLVMValueRef *texel)
346 {
347 struct lp_build_sample_context bld;
348 LLVMValueRef width;
349 LLVMValueRef height;
350 LLVMValueRef stride;
351 LLVMValueRef data_ptr;
352 LLVMValueRef s;
353 LLVMValueRef t;
354 LLVMValueRef p;
355
356 /* Setup our build context */
357 memset(&bld, 0, sizeof bld);
358 bld.builder = builder;
359 bld.static_state = static_state;
360 bld.dynamic_state = dynamic_state;
361 bld.format_desc = util_format_description(static_state->format);
362 bld.coord_type = type;
363 bld.int_coord_type = lp_int_type(type);
364 bld.texel_type = type;
365 lp_build_context_init(&bld.coord_bld, builder, bld.coord_type);
366 lp_build_context_init(&bld.int_coord_bld, builder, bld.int_coord_type);
367 lp_build_context_init(&bld.texel_bld, builder, bld.texel_type);
368
369 /* Get the dynamic state */
370 width = dynamic_state->width(dynamic_state, builder, unit);
371 height = dynamic_state->height(dynamic_state, builder, unit);
372 stride = dynamic_state->stride(dynamic_state, builder, unit);
373 data_ptr = dynamic_state->data_ptr(dynamic_state, builder, unit);
374
375 s = coords[0];
376 t = coords[1];
377 p = coords[2];
378
379 width = lp_build_broadcast_scalar(&bld.int_coord_bld, width);
380 height = lp_build_broadcast_scalar(&bld.int_coord_bld, height);
381 stride = lp_build_broadcast_scalar(&bld.int_coord_bld, stride);
382
383 if(static_state->target == PIPE_TEXTURE_1D)
384 t = bld.coord_bld.zero;
385
386 if(static_state->normalized_coords) {
387 LLVMTypeRef coord_vec_type = lp_build_vec_type(bld.coord_type);
388 LLVMValueRef fp_width = LLVMBuildSIToFP(builder, width, coord_vec_type, "");
389 LLVMValueRef fp_height = LLVMBuildSIToFP(builder, height, coord_vec_type, "");
390 s = lp_build_mul(&bld.coord_bld, s, fp_width);
391 t = lp_build_mul(&bld.coord_bld, t, fp_height);
392 }
393
394 switch (static_state->min_img_filter) {
395 case PIPE_TEX_FILTER_NEAREST:
396 lp_build_sample_2d_nearest_soa(&bld, s, t, width, height, stride, data_ptr, texel);
397 break;
398 case PIPE_TEX_FILTER_LINEAR:
399 case PIPE_TEX_FILTER_ANISO:
400 lp_build_sample_2d_linear_soa(&bld, s, t, width, height, stride, data_ptr, texel);
401 break;
402 default:
403 assert(0);
404 }
405
406 /* FIXME: respect static_state->min_mip_filter */;
407 /* FIXME: respect static_state->mag_img_filter */;
408 /* FIXME: respect static_state->prefilter */;
409
410 lp_build_sample_compare(&bld, p, texel);
411 }