r300_vs_draw.c revision 3262554bb375230a39e155ad712740bdcd657d4c
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
50struct 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
77static 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
87static 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
105static 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
123static 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
142static 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->color_used[2] = 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
219static 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
312void r300_draw_init_vertex_shader(struct draw_context *draw,
313                                  struct r300_vertex_shader *vs)
314{
315    struct pipe_shader_state new_vs;
316    struct vs_transform_context transform;
317    const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100 /* XXX */;
318    unsigned i;
319
320    new_vs.tokens = tgsi_alloc_tokens(newLen);
321    if (new_vs.tokens == NULL)
322        return;
323
324    memset(&transform, 0, sizeof(transform));
325    for (i = 0; i < Elements(transform.out_remap); i++) {
326        transform.out_remap[i] = i;
327    }
328    transform.last_generic = -1;
329    transform.base.transform_instruction = transform_inst;
330    transform.base.transform_declaration = transform_decl;
331
332    tgsi_transform_shader(vs->state.tokens,
333                          (struct tgsi_token*)new_vs.tokens,
334                          newLen, &transform.base);
335
336#if 0
337    printf("----------------------------------------------\norig shader:\n");
338    tgsi_dump(vs->state.tokens, 0);
339    printf("----------------------------------------------\nnew shader:\n");
340    tgsi_dump(new_vs.tokens, 0);
341    printf("----------------------------------------------\n");
342#endif
343
344    /* Free old tokens. */
345    FREE((void*)vs->state.tokens);
346
347    vs->draw_vs = draw_create_vertex_shader(draw, &new_vs);
348
349    /* Instead of duplicating and freeing the tokens, copy the pointer directly. */
350    vs->state.tokens = new_vs.tokens;
351
352    /* Init the VS output table for the rasterizer. */
353    r300_init_vs_outputs(vs);
354
355    /* Make the last generic be WPOS. */
356    vs->outputs.wpos = vs->outputs.generic[transform.last_generic + 1];
357    vs->outputs.generic[transform.last_generic + 1] = ATTR_UNUSED;
358}
359