llvmpipe: Use struct lp_shader_input in the interpolator.
[mesa.git] / src / gallium / drivers / llvmpipe / lp_bld_interp.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.
4 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 /**
30 * @file
31 * Position and shader input interpolation.
32 *
33 * @author Jose Fonseca <jfonseca@vmware.com>
34 */
35
36 #include "pipe/p_shader_tokens.h"
37 #include "util/u_debug.h"
38 #include "util/u_memory.h"
39 #include "util/u_math.h"
40 #include "tgsi/tgsi_scan.h"
41 #include "gallivm/lp_bld_debug.h"
42 #include "gallivm/lp_bld_const.h"
43 #include "gallivm/lp_bld_arit.h"
44 #include "gallivm/lp_bld_swizzle.h"
45 #include "lp_bld_interp.h"
46
47
48 /*
49 * The shader JIT function operates on blocks of quads.
50 * Each block has 2x2 quads and each quad has 2x2 pixels.
51 *
52 * We iterate over the quads in order 0, 1, 2, 3:
53 *
54 * #################
55 * # | # | #
56 * #---0---#---1---#
57 * # | # | #
58 * #################
59 * # | # | #
60 * #---2---#---3---#
61 * # | # | #
62 * #################
63 *
64 * Within each quad, we have four pixels which are represented in SOA
65 * order:
66 *
67 * #########
68 * # 0 | 1 #
69 * #---+---#
70 * # 2 | 3 #
71 * #########
72 *
73 * So the green channel (for example) of the four pixels is stored in
74 * a single vector register: {g0, g1, g2, g3}.
75 */
76
77
78 static void
79 attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix)
80 {
81 if(attrib == 0)
82 lp_build_name(val, "pos.%c%s", "xyzw"[chan], suffix);
83 else
84 lp_build_name(val, "input%u.%c%s", attrib - 1, "xyzw"[chan], suffix);
85 }
86
87
88 /**
89 * Initialize the bld->a0, dadx, dady fields. This involves fetching
90 * those values from the arrays which are passed into the JIT function.
91 */
92 static void
93 coeffs_init(struct lp_build_interp_soa_context *bld,
94 LLVMValueRef a0_ptr,
95 LLVMValueRef dadx_ptr,
96 LLVMValueRef dady_ptr)
97 {
98 LLVMBuilderRef builder = bld->base.builder;
99 unsigned attrib;
100 unsigned chan;
101
102 for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
103 const unsigned mask = bld->mask[attrib];
104 const unsigned interp = bld->interp[attrib];
105 for(chan = 0; chan < NUM_CHANNELS; ++chan) {
106 if(mask & (1 << chan)) {
107 LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), attrib*NUM_CHANNELS + chan, 0);
108 LLVMValueRef a0 = bld->base.undef;
109 LLVMValueRef dadx = bld->base.undef;
110 LLVMValueRef dady = bld->base.undef;
111
112 switch( interp ) {
113 case LP_INTERP_PERSPECTIVE:
114 /* fall-through */
115
116 case LP_INTERP_LINEAR:
117 dadx = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dadx_ptr, &index, 1, ""), "");
118 dady = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dady_ptr, &index, 1, ""), "");
119 dadx = lp_build_broadcast_scalar(&bld->base, dadx);
120 dady = lp_build_broadcast_scalar(&bld->base, dady);
121 attrib_name(dadx, attrib, chan, ".dadx");
122 attrib_name(dady, attrib, chan, ".dady");
123 /* fall-through */
124
125 case LP_INTERP_CONSTANT:
126 case LP_INTERP_FACING:
127 a0 = LLVMBuildLoad(builder, LLVMBuildGEP(builder, a0_ptr, &index, 1, ""), "");
128 a0 = lp_build_broadcast_scalar(&bld->base, a0);
129 attrib_name(a0, attrib, chan, ".a0");
130 break;
131
132 case LP_INTERP_POSITION:
133 /* Nothing to do as the position coeffs are already setup in slot 0 */
134 break;
135
136 default:
137 assert(0);
138 break;
139 }
140
141 bld->a0 [attrib][chan] = a0;
142 bld->dadx[attrib][chan] = dadx;
143 bld->dady[attrib][chan] = dady;
144 }
145 }
146 }
147 }
148
149
150 /**
151 * Emit LLVM code to compute the fragment shader input attribute values.
152 * For example, for a color input, we'll compute red, green, blue and alpha
153 * values for the four pixels in a quad.
154 * Recall that we're operating on 4-element vectors so each arithmetic
155 * operation is operating on the four pixels in a quad.
156 */
157 static void
158 attribs_init(struct lp_build_interp_soa_context *bld)
159 {
160 LLVMValueRef x = bld->pos[0];
161 LLVMValueRef y = bld->pos[1];
162 LLVMValueRef oow = NULL;
163 unsigned attrib;
164 unsigned chan;
165
166 for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
167 const unsigned mask = bld->mask[attrib];
168 const unsigned interp = bld->interp[attrib];
169 for(chan = 0; chan < NUM_CHANNELS; ++chan) {
170 if(mask & (1 << chan)) {
171 if (interp == LP_INTERP_POSITION) {
172 assert(attrib > 0);
173 bld->attribs[attrib][chan] = bld->attribs[0][chan];
174 }
175 else {
176 LLVMValueRef a0 = bld->a0 [attrib][chan];
177 LLVMValueRef dadx = bld->dadx[attrib][chan];
178 LLVMValueRef dady = bld->dady[attrib][chan];
179 LLVMValueRef res;
180
181 res = a0;
182
183 if (interp != LP_INTERP_CONSTANT &&
184 interp != LP_INTERP_FACING) {
185 /* res = res + x * dadx */
186 res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, x, dadx));
187 /* res = res + y * dady */
188 res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, y, dady));
189 }
190
191 /* Keep the value of the attribute before perspective divide
192 * for faster updates.
193 */
194 bld->attribs_pre[attrib][chan] = res;
195
196 if (interp == LP_INTERP_PERSPECTIVE) {
197 LLVMValueRef w = bld->pos[3];
198 assert(attrib != 0);
199 assert(bld->mask[0] & TGSI_WRITEMASK_W);
200 if(!oow)
201 oow = lp_build_rcp(&bld->base, w);
202 res = lp_build_mul(&bld->base, res, oow);
203 }
204
205 attrib_name(res, attrib, chan, "");
206
207 bld->attribs[attrib][chan] = res;
208 }
209 }
210 }
211 }
212 }
213
214
215 /**
216 * Increment the shader input attribute values.
217 * This is called when we move from one quad to the next.
218 */
219 static void
220 attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
221 {
222 LLVMValueRef oow = NULL;
223 unsigned attrib;
224 unsigned chan;
225
226 assert(quad_index < 4);
227
228 for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
229 const unsigned mask = bld->mask[attrib];
230 const unsigned interp = bld->interp[attrib];
231
232 if (interp != LP_INTERP_CONSTANT &&
233 interp != LP_INTERP_FACING) {
234 for(chan = 0; chan < NUM_CHANNELS; ++chan) {
235 if(mask & (1 << chan)) {
236 if (interp == LP_INTERP_POSITION) {
237 assert(attrib > 0);
238 bld->attribs[attrib][chan] = bld->attribs[0][chan];
239 }
240 else {
241 LLVMValueRef dadx = bld->dadx[attrib][chan];
242 LLVMValueRef dady = bld->dady[attrib][chan];
243 LLVMValueRef res;
244
245 res = bld->attribs_pre[attrib][chan];
246
247 if (quad_index == 1 || quad_index == 3) {
248 /* top-right or bottom-right quad */
249 /* build res = res + dadx + dadx */
250 res = lp_build_add(&bld->base, res, dadx);
251 res = lp_build_add(&bld->base, res, dadx);
252 }
253
254 if (quad_index == 2 || quad_index == 3) {
255 /* bottom-left or bottom-right quad */
256 /* build res = res + dady + dady */
257 res = lp_build_add(&bld->base, res, dady);
258 res = lp_build_add(&bld->base, res, dady);
259 }
260
261 if (interp == LP_INTERP_PERSPECTIVE) {
262 LLVMValueRef w = bld->pos[3];
263 assert(attrib != 0);
264 assert(bld->mask[0] & TGSI_WRITEMASK_W);
265 if(!oow)
266 oow = lp_build_rcp(&bld->base, w);
267 res = lp_build_mul(&bld->base, res, oow);
268 }
269
270 attrib_name(res, attrib, chan, "");
271
272 bld->attribs[attrib][chan] = res;
273 }
274 }
275 }
276 }
277 }
278 }
279
280
281 /**
282 * Generate the position vectors.
283 *
284 * Parameter x0, y0 are the integer values with the quad upper left coordinates.
285 */
286 static void
287 pos_init(struct lp_build_interp_soa_context *bld,
288 LLVMValueRef x0,
289 LLVMValueRef y0)
290 {
291 lp_build_name(x0, "pos.x");
292 lp_build_name(y0, "pos.y");
293
294 bld->attribs[0][0] = x0;
295 bld->attribs[0][1] = y0;
296 }
297
298
299 /**
300 * Update quad position values when moving to the next quad.
301 */
302 static void
303 pos_update(struct lp_build_interp_soa_context *bld, int quad_index)
304 {
305 LLVMValueRef x = bld->attribs[0][0];
306 LLVMValueRef y = bld->attribs[0][1];
307 const int xstep = 2, ystep = 2;
308
309 if (quad_index == 1 || quad_index == 3) {
310 /* top-right or bottom-right quad in block */
311 /* build x += xstep */
312 x = lp_build_add(&bld->base, x,
313 lp_build_const_vec(bld->base.type, xstep));
314 }
315
316 if (quad_index == 2) {
317 /* bottom-left quad in block */
318 /* build y += ystep */
319 y = lp_build_add(&bld->base, y,
320 lp_build_const_vec(bld->base.type, ystep));
321 /* build x -= xstep */
322 x = lp_build_sub(&bld->base, x,
323 lp_build_const_vec(bld->base.type, xstep));
324 }
325
326 lp_build_name(x, "pos.x");
327 lp_build_name(y, "pos.y");
328
329 bld->attribs[0][0] = x;
330 bld->attribs[0][1] = y;
331 }
332
333
334 /**
335 * Initialize fragment shader input attribute info.
336 */
337 void
338 lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
339 unsigned num_inputs,
340 const struct lp_shader_input *inputs,
341 LLVMBuilderRef builder,
342 struct lp_type type,
343 LLVMValueRef a0_ptr,
344 LLVMValueRef dadx_ptr,
345 LLVMValueRef dady_ptr,
346 LLVMValueRef x0,
347 LLVMValueRef y0)
348 {
349 unsigned attrib;
350 unsigned chan;
351
352 memset(bld, 0, sizeof *bld);
353
354 lp_build_context_init(&bld->base, builder, type);
355
356 /* For convenience */
357 bld->pos = bld->attribs[0];
358 bld->inputs = (const LLVMValueRef (*)[NUM_CHANNELS]) bld->attribs[1];
359
360 /* Position */
361 bld->num_attribs = 1;
362 bld->mask[0] = TGSI_WRITEMASK_ZW;
363 bld->interp[0] = LP_INTERP_LINEAR;
364
365 /* Inputs */
366 for (attrib = 0; attrib < num_inputs; ++attrib) {
367 bld->mask[1 + attrib] = inputs[attrib].usage_mask;
368 bld->interp[1 + attrib] = inputs[attrib].interp;
369 }
370 bld->num_attribs = 1 + num_inputs;
371
372 /* Ensure all masked out input channels have a valid value */
373 for (attrib = 0; attrib < bld->num_attribs; ++attrib) {
374 for (chan = 0; chan < NUM_CHANNELS; ++chan) {
375 bld->attribs[attrib][chan] = bld->base.undef;
376 }
377 }
378
379 coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr);
380
381 pos_init(bld, x0, y0);
382
383 attribs_init(bld);
384 }
385
386
387 /**
388 * Advance the position and inputs to the given quad within the block.
389 */
390 void
391 lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
392 int quad_index)
393 {
394 assert(quad_index < 4);
395
396 pos_update(bld, quad_index);
397
398 attribs_update(bld, quad_index);
399 }