OSDN Git Service

r300g/swtcl: don't print an error when getting ClipVertex
[android-x86/external-mesa.git] / src / gallium / drivers / r300 / r300_vs_draw.c
1 /**************************************************************************
2  * 
3  * Copyright 2009 Marek Olšák <maraeo@gmail.com>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  * 
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  * 
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  * 
25  **************************************************************************/
26
27 /* This file contains the vertex shader tranformations for SW TCL needed
28  * to overcome the limitations of the r300 rasterizer.
29  *
30  * Transformations:
31  * 1) If the secondary color output is present, the primary color must be
32  *    inserted before it.
33  * 2) If any back-face color output is present, there must be all 4 color
34  *    outputs and missing ones must be inserted.
35  * 3) Insert a trailing texcoord output containing a copy of POS, for WPOS.
36  *
37  * I know this code is cumbersome, but I don't know of any nicer way
38  * of transforming TGSI shaders. ~ M.
39  */
40
41 #include "r300_vs.h"
42
43 #include <stdio.h>
44
45 #include "tgsi/tgsi_transform.h"
46 #include "tgsi/tgsi_dump.h"
47
48 #include "draw/draw_context.h"
49
50 struct vs_transform_context {
51     struct tgsi_transform_context base;
52
53     boolean color_used[2];
54     boolean bcolor_used[2];
55     boolean temp_used[128];
56
57     /* Index of the pos output, typically 0. */
58     unsigned pos_output;
59     /* Index of the pos temp where all writes of pos are redirected to. */
60     unsigned pos_temp;
61     /* The index of the last generic output, after which we insert a new
62      * output for WPOS. */
63     int last_generic;
64
65     unsigned num_outputs;
66     /* Used to shift output decl. indices when inserting new ones. */
67     unsigned decl_shift;
68     /* Used to remap writes to output decls if their indices changed. */
69     unsigned out_remap[32];
70
71     /* First instruction processed? */
72     boolean first_instruction;
73     /* End instruction processed? */
74     boolean end_instruction;
75 };
76
77 static void emit_temp(struct tgsi_transform_context *ctx, unsigned reg)
78 {
79     struct tgsi_full_declaration decl;
80
81     decl = tgsi_default_full_declaration();
82     decl.Declaration.File = TGSI_FILE_TEMPORARY;
83     decl.Range.First = decl.Range.Last = reg;
84     ctx->emit_declaration(ctx, &decl);
85 }
86
87 static void emit_output(struct tgsi_transform_context *ctx,
88                         unsigned name, unsigned index, unsigned interp,
89                         unsigned reg)
90 {
91     struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
92     struct tgsi_full_declaration decl;
93
94     decl = tgsi_default_full_declaration();
95     decl.Declaration.File = TGSI_FILE_OUTPUT;
96     decl.Declaration.Interpolate = interp;
97     decl.Declaration.Semantic = TRUE;
98     decl.Semantic.Name = name;
99     decl.Semantic.Index = index;
100     decl.Range.First = decl.Range.Last = reg;
101     ctx->emit_declaration(ctx, &decl);
102     ++vsctx->num_outputs;
103 }
104
105 static void insert_output(struct tgsi_transform_context *ctx,
106                           struct tgsi_full_declaration *before,
107                           unsigned name, unsigned index, unsigned interp)
108 {
109     struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
110     unsigned i;
111
112     /* Make a place for the new output. */
113     for (i = before->Range.First; i < Elements(vsctx->out_remap); i++) {
114         ++vsctx->out_remap[i];
115     }
116
117     /* Insert the new output. */
118     emit_output(ctx, name, index, interp, before->Range.First);
119
120     ++vsctx->decl_shift;
121 }
122
123 static void insert_trailing_bcolor(struct tgsi_transform_context *ctx,
124                                    struct tgsi_full_declaration *before)
125 {
126     struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
127
128     /* If BCOLOR0 is used, make sure BCOLOR1 is present too. Otherwise
129      * the rasterizer doesn't do the color selection correctly. */
130     if (vsctx->bcolor_used[0] && !vsctx->bcolor_used[1]) {
131         if (before) {
132             insert_output(ctx, before, TGSI_SEMANTIC_BCOLOR, 1,
133                           TGSI_INTERPOLATE_LINEAR);
134         } else {
135             emit_output(ctx, TGSI_SEMANTIC_BCOLOR, 1,
136                         TGSI_INTERPOLATE_LINEAR, vsctx->num_outputs);
137         }
138         vsctx->bcolor_used[1] = TRUE;
139     }
140 }
141
142 static void transform_decl(struct tgsi_transform_context *ctx,
143                            struct tgsi_full_declaration *decl)
144 {
145     struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
146     unsigned i;
147
148     if (decl->Declaration.File == TGSI_FILE_OUTPUT) {
149         switch (decl->Semantic.Name) {
150             case TGSI_SEMANTIC_POSITION:
151                 vsctx->pos_output = decl->Range.First;
152                 break;
153
154             case TGSI_SEMANTIC_COLOR:
155                 assert(decl->Semantic.Index < 2);
156                 vsctx->color_used[decl->Semantic.Index] = TRUE;
157
158                 /* We must rasterize the first color if the second one is
159                  * used, otherwise the rasterizer doesn't do the color
160                  * selection correctly. Declare it, but don't write to it. */
161                 if (decl->Semantic.Index == 1 && !vsctx->color_used[0]) {
162                     insert_output(ctx, decl, TGSI_SEMANTIC_COLOR, 0,
163                                   TGSI_INTERPOLATE_LINEAR);
164                     vsctx->color_used[0] = TRUE;
165                 }
166                 break;
167
168             case TGSI_SEMANTIC_BCOLOR:
169                 assert(decl->Semantic.Index < 2);
170                 vsctx->bcolor_used[decl->Semantic.Index] = TRUE;
171
172                 /* We must rasterize all 4 colors if back-face colors are
173                  * used, otherwise the rasterizer doesn't do the color
174                  * selection correctly. Declare it, but don't write to it. */
175                 if (!vsctx->color_used[0]) {
176                     insert_output(ctx, decl, TGSI_SEMANTIC_COLOR, 0,
177                                   TGSI_INTERPOLATE_LINEAR);
178                     vsctx->color_used[0] = TRUE;
179                 }
180                 if (!vsctx->color_used[1]) {
181                     insert_output(ctx, decl, TGSI_SEMANTIC_COLOR, 1,
182                                   TGSI_INTERPOLATE_LINEAR);
183                     vsctx->color_used[1] = TRUE;
184                 }
185                 if (decl->Semantic.Index == 1 && !vsctx->bcolor_used[0]) {
186                     insert_output(ctx, decl, TGSI_SEMANTIC_BCOLOR, 0,
187                                   TGSI_INTERPOLATE_LINEAR);
188                     vsctx->bcolor_used[0] = TRUE;
189                 }
190                 /* One more case is handled in insert_trailing_bcolor. */
191                 break;
192
193             case TGSI_SEMANTIC_GENERIC:
194                 vsctx->last_generic = MAX2(vsctx->last_generic, decl->Semantic.Index);
195                 break;
196         }
197
198         if (decl->Semantic.Name != TGSI_SEMANTIC_BCOLOR) {
199             /* Insert it as soon as possible. */
200             insert_trailing_bcolor(ctx, decl);
201         }
202
203         /* Since we're inserting new outputs in between, the following outputs
204          * should be moved to the right so that they don't overlap with
205          * the newly added ones. */
206         decl->Range.First += vsctx->decl_shift;
207         decl->Range.Last += vsctx->decl_shift;
208
209         ++vsctx->num_outputs;
210     } else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
211         for (i = decl->Range.First; i <= decl->Range.Last; i++) {
212            vsctx->temp_used[i] = TRUE;
213         }
214     }
215
216     ctx->emit_declaration(ctx, decl);
217 }
218
219 static void transform_inst(struct tgsi_transform_context *ctx,
220                            struct tgsi_full_instruction *inst)
221 {
222     struct vs_transform_context *vsctx = (struct vs_transform_context *) ctx;
223     struct tgsi_full_instruction new_inst;
224     unsigned i;
225
226     if (!vsctx->first_instruction) {
227         vsctx->first_instruction = TRUE;
228
229         /* The trailing BCOLOR should be inserted before the code
230          * if it hasn't already been done so. */
231         insert_trailing_bcolor(ctx, NULL);
232
233         /* Insert the generic output for WPOS. */
234         emit_output(ctx, TGSI_SEMANTIC_GENERIC, vsctx->last_generic + 1,
235                     TGSI_INTERPOLATE_PERSPECTIVE, vsctx->num_outputs);
236
237         /* Find a free temp for POSITION. */
238         for (i = 0; i < Elements(vsctx->temp_used); i++) {
239             if (!vsctx->temp_used[i]) {
240                 emit_temp(ctx, i);
241                 vsctx->pos_temp = i;
242                 break;
243             }
244         }
245     }
246
247     if (inst->Instruction.Opcode == TGSI_OPCODE_END) {
248         /* MOV OUT[pos_output], TEMP[pos_temp]; */
249         new_inst = tgsi_default_full_instruction();
250         new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
251         new_inst.Instruction.NumDstRegs = 1;
252         new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT;
253         new_inst.Dst[0].Register.Index = vsctx->pos_output;
254         new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
255         new_inst.Instruction.NumSrcRegs = 1;
256         new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
257         new_inst.Src[0].Register.Index = vsctx->pos_temp;
258         ctx->emit_instruction(ctx, &new_inst);
259
260         /* MOV OUT[n-1], TEMP[pos_temp]; */
261         new_inst = tgsi_default_full_instruction();
262         new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
263         new_inst.Instruction.NumDstRegs = 1;
264         new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT;
265         new_inst.Dst[0].Register.Index = vsctx->num_outputs - 1;
266         new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
267         new_inst.Instruction.NumSrcRegs = 1;
268         new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
269         new_inst.Src[0].Register.Index = vsctx->pos_temp;
270         ctx->emit_instruction(ctx, &new_inst);
271
272         vsctx->end_instruction = TRUE;
273     } else {
274         /* Not an END instruction. */
275         /* Fix writes to outputs. */
276         for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
277             struct tgsi_full_dst_register *dst = &inst->Dst[i];
278             if (dst->Register.File == TGSI_FILE_OUTPUT) {
279                 if (dst->Register.Index == vsctx->pos_output) {
280                     /* Replace writes to OUT[pos_output] with TEMP[pos_temp]. */
281                     dst->Register.File = TGSI_FILE_TEMPORARY;
282                     dst->Register.Index = vsctx->pos_temp;
283                 } else {
284                     /* Not a position, good...
285                      * Since we were changing the indices of output decls,
286                      * we must redirect writes into them too. */
287                     dst->Register.Index = vsctx->out_remap[dst->Register.Index];
288                 }
289             }
290         }
291
292         /* Inserting 2 instructions before the END opcode moves all following
293          * labels by 2. Subroutines are always after the END opcode so
294          * they're always moved. */
295         if (inst->Instruction.Opcode == TGSI_OPCODE_CAL) {
296             inst->Label.Label += 2;
297         }
298         /* The labels of the following opcodes are moved only after
299          * the END opcode. */
300         if (vsctx->end_instruction &&
301             (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
302              inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
303              inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP ||
304              inst->Instruction.Opcode == TGSI_OPCODE_ENDLOOP)) {
305             inst->Label.Label += 2;
306         }
307     }
308
309     ctx->emit_instruction(ctx, inst);
310 }
311
312 void r300_draw_init_vertex_shader(struct r300_context *r300,
313                                   struct r300_vertex_shader *vs)
314 {
315     struct draw_context *draw = r300->draw;
316     struct pipe_shader_state new_vs;
317     struct vs_transform_context transform;
318     const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100 /* XXX */;
319     unsigned i;
320
321     new_vs.tokens = tgsi_alloc_tokens(newLen);
322     if (new_vs.tokens == NULL)
323         return;
324
325     memset(&transform, 0, sizeof(transform));
326     for (i = 0; i < Elements(transform.out_remap); i++) {
327         transform.out_remap[i] = i;
328     }
329     transform.last_generic = -1;
330     transform.base.transform_instruction = transform_inst;
331     transform.base.transform_declaration = transform_decl;
332
333     tgsi_transform_shader(vs->state.tokens,
334                           (struct tgsi_token*)new_vs.tokens,
335                           newLen, &transform.base);
336
337 #if 0
338     printf("----------------------------------------------\norig shader:\n");
339     tgsi_dump(vs->state.tokens, 0);
340     printf("----------------------------------------------\nnew shader:\n");
341     tgsi_dump(new_vs.tokens, 0);
342     printf("----------------------------------------------\n");
343 #endif
344
345     /* Free old tokens. */
346     FREE((void*)vs->state.tokens);
347
348     vs->draw_vs = draw_create_vertex_shader(draw, &new_vs);
349
350     /* Instead of duplicating and freeing the tokens, copy the pointer directly. */
351     vs->state.tokens = new_vs.tokens;
352
353     /* Init the VS output table for the rasterizer. */
354     r300_init_vs_outputs(r300, vs);
355
356     /* Make the last generic be WPOS. */
357     vs->outputs.wpos = vs->outputs.generic[transform.last_generic + 1];
358     vs->outputs.generic[transform.last_generic + 1] = ATTR_UNUSED;
359 }