e73733e51c472181a67e488f6b013ceaa5c93d41
[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 const unsigned char quad_offset_x[4] = {0, 1, 0, 1};
79 static const unsigned char quad_offset_y[4] = {0, 0, 1, 1};
80
81
82 static void
83 attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix)
84 {
85 if(attrib == 0)
86 lp_build_name(val, "pos.%c%s", "xyzw"[chan], suffix);
87 else
88 lp_build_name(val, "input%u.%c%s", attrib - 1, "xyzw"[chan], suffix);
89 }
90
91
92 /**
93 * Initialize the bld->a0, dadx, dady fields. This involves fetching
94 * those values from the arrays which are passed into the JIT function.
95 */
96 static void
97 coeffs_init(struct lp_build_interp_soa_context *bld,
98 LLVMValueRef a0_ptr,
99 LLVMValueRef dadx_ptr,
100 LLVMValueRef dady_ptr)
101 {
102 struct lp_build_context *coeff_bld = &bld->coeff_bld;
103 LLVMBuilderRef builder = coeff_bld->builder;
104 LLVMValueRef zero = LLVMConstNull(coeff_bld->elem_type);
105 LLVMValueRef one = LLVMConstReal(coeff_bld->elem_type, 1.0);
106 LLVMValueRef i0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
107 LLVMValueRef i1 = LLVMConstInt(LLVMInt32Type(), 1, 0);
108 LLVMValueRef i2 = LLVMConstInt(LLVMInt32Type(), 2, 0);
109 LLVMValueRef i3 = LLVMConstInt(LLVMInt32Type(), 3, 0);
110 LLVMValueRef oow = NULL;
111 unsigned attrib;
112 unsigned chan;
113
114 /* TODO: Use more vector operations */
115
116 for (attrib = 0; attrib < bld->num_attribs; ++attrib) {
117 const unsigned mask = bld->mask[attrib];
118 const unsigned interp = bld->interp[attrib];
119 for (chan = 0; chan < NUM_CHANNELS; ++chan) {
120 if (mask & (1 << chan)) {
121 LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), attrib*NUM_CHANNELS + chan, 0);
122 LLVMValueRef a0 = zero;
123 LLVMValueRef dadx = zero;
124 LLVMValueRef dady = zero;
125 LLVMValueRef dadxy = zero;
126 LLVMValueRef dadq;
127 LLVMValueRef dadq2;
128 LLVMValueRef a;
129
130 switch (interp) {
131 case LP_INTERP_PERSPECTIVE:
132 /* fall-through */
133
134 case LP_INTERP_LINEAR:
135 if (attrib == 0 && chan == 0) {
136 dadxy = dadx = one;
137 }
138 else if (attrib == 0 && chan == 1) {
139 dadxy = dady = one;
140 }
141 else {
142 dadx = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dadx_ptr, &index, 1, ""), "");
143 dady = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dady_ptr, &index, 1, ""), "");
144 dadxy = LLVMBuildAdd(builder, dadx, dady, "");
145 attrib_name(dadx, attrib, chan, ".dadx");
146 attrib_name(dady, attrib, chan, ".dady");
147 attrib_name(dadxy, attrib, chan, ".dadxy");
148 }
149 /* fall-through */
150
151 case LP_INTERP_CONSTANT:
152 case LP_INTERP_FACING:
153 a0 = LLVMBuildLoad(builder, LLVMBuildGEP(builder, a0_ptr, &index, 1, ""), "");
154 attrib_name(a0, attrib, chan, ".a0");
155 break;
156
157 case LP_INTERP_POSITION:
158 /* Nothing to do as the position coeffs are already setup in slot 0 */
159 continue;
160
161 default:
162 assert(0);
163 break;
164 }
165
166 /*
167 * dadq = {0, dadx, dady, dadx + dady}
168 */
169
170 dadq = coeff_bld->undef;
171 dadq = LLVMBuildInsertElement(builder, dadq, zero, i0, "");
172 dadq = LLVMBuildInsertElement(builder, dadq, dadx, i1, "");
173 dadq = LLVMBuildInsertElement(builder, dadq, dady, i2, "");
174 dadq = LLVMBuildInsertElement(builder, dadq, dadxy, i3, "");
175
176 /*
177 * dadq2 = 2 * dq
178 */
179
180 dadq2 = LLVMBuildAdd(builder, dadq, dadq, "");
181
182 /*
183 * a = a0 + x * dadx + y * dady
184 */
185
186 if (attrib == 0 && chan == 0) {
187 a = bld->x;
188 }
189 else if (attrib == 0 && chan == 1) {
190 a = bld->y;
191 }
192 else {
193 a = a0;
194 if (interp != LP_INTERP_CONSTANT &&
195 interp != LP_INTERP_FACING) {
196 a = LLVMBuildAdd(builder, a,
197 LLVMBuildMul(builder, bld->x, dadx, ""),
198 "");
199 a = LLVMBuildAdd(builder, a,
200 LLVMBuildMul(builder, bld->y, dady, ""),
201 "");
202 }
203 }
204
205 /*
206 * a = {a, a, a, a}
207 */
208
209 a = lp_build_broadcast(builder, coeff_bld->vec_type, a);
210
211 /*
212 * Compute the attrib values on the upper-left corner of each quad.
213 */
214
215 a = LLVMBuildAdd(builder, a, dadq2, "");
216
217 /*
218 * a *= 1 / w
219 * dadq *= 1 / w
220 */
221
222 if (interp == LP_INTERP_PERSPECTIVE) {
223 LLVMValueRef w = bld->a[0][3];
224 assert(attrib != 0);
225 assert(bld->mask[0] & TGSI_WRITEMASK_W);
226 if (!oow) {
227 oow = lp_build_rcp(coeff_bld, w);
228 lp_build_name(oow, "oow");
229 }
230 a = lp_build_mul(coeff_bld, a, oow);
231 dadq = lp_build_mul(coeff_bld, dadq, oow);
232 }
233
234 attrib_name(a, attrib, chan, ".a");
235 attrib_name(dadq, attrib, chan, ".dadq");
236
237 bld->a [attrib][chan] = a;
238 bld->dadq[attrib][chan] = dadq;
239 }
240 }
241 }
242 }
243
244
245 /**
246 * Increment the shader input attribute values.
247 * This is called when we move from one quad to the next.
248 */
249 static void
250 attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
251 {
252 struct lp_build_context *coeff_bld = &bld->coeff_bld;
253 LLVMValueRef shuffle = lp_build_const_int_vec(coeff_bld->type, quad_index);
254 unsigned attrib;
255 unsigned chan;
256
257 assert(quad_index < 4);
258
259 for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
260 const unsigned mask = bld->mask[attrib];
261 const unsigned interp = bld->interp[attrib];
262 for(chan = 0; chan < NUM_CHANNELS; ++chan) {
263 if(mask & (1 << chan)) {
264 LLVMValueRef a = coeff_bld->undef;
265 if (interp == LP_INTERP_CONSTANT &&
266 interp == LP_INTERP_FACING) {
267 a = bld->a[attrib][chan];
268 }
269 else if (interp == LP_INTERP_POSITION) {
270 assert(attrib > 0);
271 a = bld->attribs[0][chan];
272 }
273 else {
274 a = bld->a[attrib][chan];
275
276 /*
277 * Broadcast the attribute value for this quad into all elements
278 */
279
280 a = LLVMBuildShuffleVector(coeff_bld->builder,
281 a, coeff_bld->undef, shuffle, "");
282
283 /*
284 * Add the derivatives
285 */
286
287 a = lp_build_add(coeff_bld, a, bld->dadq[attrib][chan]);
288
289 attrib_name(a, attrib, chan, "");
290 }
291 bld->attribs[attrib][chan] = a;
292 }
293 }
294 }
295 }
296
297
298 /**
299 * Generate the position vectors.
300 *
301 * Parameter x0, y0 are the integer values with upper left coordinates.
302 */
303 static void
304 pos_init(struct lp_build_interp_soa_context *bld,
305 LLVMValueRef x0,
306 LLVMValueRef y0)
307 {
308 struct lp_build_context *coeff_bld = &bld->coeff_bld;
309
310 bld->x = LLVMBuildSIToFP(coeff_bld->builder, x0, coeff_bld->elem_type, "");
311 bld->y = LLVMBuildSIToFP(coeff_bld->builder, y0, coeff_bld->elem_type, "");
312 }
313
314
315 /**
316 * Initialize fragment shader input attribute info.
317 */
318 void
319 lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
320 unsigned num_inputs,
321 const struct lp_shader_input *inputs,
322 LLVMBuilderRef builder,
323 struct lp_type type,
324 LLVMValueRef a0_ptr,
325 LLVMValueRef dadx_ptr,
326 LLVMValueRef dady_ptr,
327 LLVMValueRef x0,
328 LLVMValueRef y0)
329 {
330 struct lp_type coeff_type;
331 unsigned attrib;
332 unsigned chan;
333
334 memset(bld, 0, sizeof *bld);
335
336 memset(&coeff_type, 0, sizeof coeff_type);
337 coeff_type.floating = TRUE;
338 coeff_type.sign = TRUE;
339 coeff_type.width = 32;
340 coeff_type.length = QUAD_SIZE;
341
342 /* XXX: we don't support interpolating into any other types */
343 assert(memcmp(&coeff_type, &type, sizeof &coeff_type) == 0);
344
345 lp_build_context_init(&bld->coeff_bld, builder, coeff_type);
346
347 /* For convenience */
348 bld->pos = bld->attribs[0];
349 bld->inputs = (const LLVMValueRef (*)[NUM_CHANNELS]) bld->attribs[1];
350
351 /* Position */
352 bld->num_attribs = 1;
353 bld->mask[0] = TGSI_WRITEMASK_XYZW;
354 bld->interp[0] = LP_INTERP_LINEAR;
355
356 /* Inputs */
357 for (attrib = 0; attrib < num_inputs; ++attrib) {
358 bld->mask[1 + attrib] = inputs[attrib].usage_mask;
359 bld->interp[1 + attrib] = inputs[attrib].interp;
360 }
361 bld->num_attribs = 1 + num_inputs;
362
363 /* Ensure all masked out input channels have a valid value */
364 for (attrib = 0; attrib < bld->num_attribs; ++attrib) {
365 for (chan = 0; chan < NUM_CHANNELS; ++chan) {
366 bld->attribs[attrib][chan] = bld->coeff_bld.undef;
367 }
368 }
369
370 pos_init(bld, x0, y0);
371
372 coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr);
373
374 attribs_update(bld, 0);
375 }
376
377
378 /**
379 * Advance the position and inputs to the given quad within the block.
380 */
381 void
382 lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
383 int quad_index)
384 {
385 assert(quad_index < 4);
386
387 attribs_update(bld, quad_index);
388 }