OSDN Git Service

Merge remote branch 'origin/master' into lp-binning
[android-x86/external-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_parse.h"
41 #include "lp_bld_debug.h"
42 #include "lp_bld_const.h"
43 #include "lp_bld_arit.h"
44 #include "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       unsigned mask = bld->mask[attrib];
104       unsigned mode = bld->mode[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 = NULL;
109             LLVMValueRef dadx = NULL;
110             LLVMValueRef dady = NULL;
111
112             switch( mode ) {
113             case TGSI_INTERPOLATE_PERSPECTIVE:
114                /* fall-through */
115
116             case TGSI_INTERPOLATE_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 TGSI_INTERPOLATE_CONSTANT:
126                a0 = LLVMBuildLoad(builder, LLVMBuildGEP(builder, a0_ptr, &index, 1, ""), "");
127                a0 = lp_build_broadcast_scalar(&bld->base, a0);
128                attrib_name(a0, attrib, chan, ".a0");
129                break;
130
131             default:
132                assert(0);
133                break;
134             }
135
136             bld->a0  [attrib][chan] = a0;
137             bld->dadx[attrib][chan] = dadx;
138             bld->dady[attrib][chan] = dady;
139          }
140       }
141    }
142 }
143
144
145 /**
146  * Emit LLVM code to compute the fragment shader input attribute values.
147  * For example, for a color input, we'll compute red, green, blue and alpha
148  * values for the four pixels in a quad.
149  * Recall that we're operating on 4-element vectors so each arithmetic
150  * operation is operating on the four pixels in a quad.
151  */
152 static void
153 attribs_init(struct lp_build_interp_soa_context *bld)
154 {
155    LLVMValueRef x = bld->pos[0];
156    LLVMValueRef y = bld->pos[1];
157    LLVMValueRef oow = NULL;
158    unsigned attrib;
159    unsigned chan;
160
161    for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
162       unsigned mask = bld->mask[attrib];
163       unsigned mode = bld->mode[attrib];
164       for(chan = 0; chan < NUM_CHANNELS; ++chan) {
165          if(mask & (1 << chan)) {
166             LLVMValueRef a0   = bld->a0  [attrib][chan];
167             LLVMValueRef dadx = bld->dadx[attrib][chan];
168             LLVMValueRef dady = bld->dady[attrib][chan];
169             LLVMValueRef res;
170
171             res = a0;
172
173             if (mode != TGSI_INTERPOLATE_CONSTANT) {
174                /* res = res + x * dadx */
175                res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, x, dadx));
176                /* res = res + y * dady */
177                res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, y, dady));
178             }
179
180             /* Keep the value of the attribue before perspective divide for faster updates */
181             bld->attribs_pre[attrib][chan] = res;
182
183             if (mode == TGSI_INTERPOLATE_PERSPECTIVE) {
184                LLVMValueRef w = bld->pos[3];
185                assert(attrib != 0);
186                if(!oow)
187                   oow = lp_build_rcp(&bld->base, w);
188                res = lp_build_mul(&bld->base, res, oow);
189             }
190
191             attrib_name(res, attrib, chan, "");
192
193             bld->attribs[attrib][chan] = res;
194          }
195       }
196    }
197 }
198
199
200 /**
201  * Increment the shader input attribute values.
202  * This is called when we move from one quad to the next.
203  */
204 static void
205 attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
206 {
207    LLVMValueRef oow = NULL;
208    unsigned attrib;
209    unsigned chan;
210
211    assert(quad_index < 4);
212
213    for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
214       unsigned mask = bld->mask[attrib];
215       unsigned mode = bld->mode[attrib];
216
217       if (mode != TGSI_INTERPOLATE_CONSTANT) {
218          for(chan = 0; chan < NUM_CHANNELS; ++chan) {
219             if(mask & (1 << chan)) {
220                LLVMValueRef dadx = bld->dadx[attrib][chan];
221                LLVMValueRef dady = bld->dady[attrib][chan];
222                LLVMValueRef res;
223
224                res = bld->attribs_pre[attrib][chan];
225
226                if (quad_index == 1 || quad_index == 3) {
227                   /* top-right or bottom-right quad */
228                   /* build res = res + dadx + dadx */
229                   res = lp_build_add(&bld->base, res, dadx);
230                   res = lp_build_add(&bld->base, res, dadx);
231                }
232
233                if (quad_index == 2 || quad_index == 3) {
234                   /* bottom-left or bottom-right quad */
235                   /* build res = res + dady + dady */
236                   res = lp_build_add(&bld->base, res, dady);
237                   res = lp_build_add(&bld->base, res, dady);
238                }
239
240                //XXX bld->attribs_pre[attrib][chan] = res;
241
242                if (mode == TGSI_INTERPOLATE_PERSPECTIVE) {
243                   LLVMValueRef w = bld->pos[3];
244                   assert(attrib != 0);
245                   if(!oow)
246                      oow = lp_build_rcp(&bld->base, w);
247                   res = lp_build_mul(&bld->base, res, oow);
248                }
249
250                attrib_name(res, attrib, chan, "");
251
252                bld->attribs[attrib][chan] = res;
253             }
254          }
255       }
256    }
257 }
258
259
260 /**
261  * Generate the position vectors.
262  *
263  * Parameter x0, y0 are the integer values with the quad upper left coordinates.
264  */
265 static void
266 pos_init(struct lp_build_interp_soa_context *bld,
267          LLVMValueRef x0,
268          LLVMValueRef y0)
269 {
270    lp_build_name(x0, "pos.x");
271    lp_build_name(y0, "pos.y");
272
273    bld->attribs[0][0] = x0;
274    bld->attribs[0][1] = y0;
275 }
276
277
278 /**
279  * Update quad position values when moving to the next quad.
280  */
281 static void
282 pos_update(struct lp_build_interp_soa_context *bld, int quad_index)
283 {
284    LLVMValueRef x = bld->attribs[0][0];
285    LLVMValueRef y = bld->attribs[0][1];
286    const int xstep = 2, ystep = 2;
287
288    if (quad_index == 1 || quad_index == 3) {
289       /* top-right or bottom-right quad in block */
290       /* build x += xstep */
291       x = lp_build_add(&bld->base, x,
292                        lp_build_const_scalar(bld->base.type, xstep));
293    }
294
295    if (quad_index == 2) {
296       /* bottom-left quad in block */
297       /* build y += ystep */
298       y = lp_build_add(&bld->base, y,
299                        lp_build_const_scalar(bld->base.type, ystep));
300       /* build x -= xstep */
301       x = lp_build_sub(&bld->base, x,
302                        lp_build_const_scalar(bld->base.type, xstep));
303    }
304
305    lp_build_name(x, "pos.x");
306    lp_build_name(y, "pos.y");
307
308    bld->attribs[0][0] = x;
309    bld->attribs[0][1] = y;
310 }
311
312
313 /**
314  * Initialize fragment shader input attribute info.
315  */
316 void
317 lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
318                          const struct tgsi_token *tokens,
319                          LLVMBuilderRef builder,
320                          struct lp_type type,
321                          LLVMValueRef a0_ptr,
322                          LLVMValueRef dadx_ptr,
323                          LLVMValueRef dady_ptr,
324                          LLVMValueRef x0,
325                          LLVMValueRef y0)
326 {
327    struct tgsi_parse_context parse;
328    struct tgsi_full_declaration *decl;
329
330    memset(bld, 0, sizeof *bld);
331
332    lp_build_context_init(&bld->base, builder, type);
333
334    /* For convenience */
335    bld->pos = bld->attribs[0];
336    bld->inputs = (const LLVMValueRef (*)[NUM_CHANNELS]) bld->attribs[1];
337
338    /* Position */
339    bld->num_attribs = 1;
340    bld->mask[0] = TGSI_WRITEMASK_ZW;
341    bld->mode[0] = TGSI_INTERPOLATE_LINEAR;
342
343    /* Inputs */
344    tgsi_parse_init( &parse, tokens );
345    while( !tgsi_parse_end_of_tokens( &parse ) ) {
346       tgsi_parse_token( &parse );
347
348       switch( parse.FullToken.Token.Type ) {
349       case TGSI_TOKEN_TYPE_DECLARATION:
350          decl = &parse.FullToken.FullDeclaration;
351          if( decl->Declaration.File == TGSI_FILE_INPUT ) {
352             unsigned first, last, mask;
353             unsigned attrib;
354
355             first = decl->Range.First;
356             last = decl->Range.Last;
357             mask = decl->Declaration.UsageMask;
358
359             for( attrib = first; attrib <= last; ++attrib ) {
360                bld->mask[1 + attrib] = mask;
361                bld->mode[1 + attrib] = decl->Declaration.Interpolate;
362             }
363
364             bld->num_attribs = MAX2(bld->num_attribs, 1 + last + 1);
365          }
366          break;
367
368       case TGSI_TOKEN_TYPE_INSTRUCTION:
369       case TGSI_TOKEN_TYPE_IMMEDIATE:
370          break;
371
372       default:
373          assert( 0 );
374       }
375    }
376    tgsi_parse_free( &parse );
377
378    coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr);
379
380    pos_init(bld, x0, y0);
381
382    attribs_init(bld);
383 }
384
385
386 /**
387  * Advance the position and inputs to the given quad within the block.
388  */
389 void
390 lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
391                            int quad_index)
392 {
393    assert(quad_index < 4);
394
395    pos_update(bld, quad_index);
396
397    attribs_update(bld, quad_index);
398 }