1 /**************************************************************************
3 * Copyright 2009 Marek Olšák <maraeo@gmail.com>
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:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
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.
25 **************************************************************************/
27 /* This file contains the vertex shader tranformations for SW TCL needed
28 * to overcome the limitations of the r300 rasterizer.
31 * 1) If the secondary color output is present, the primary color must be
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.
37 * I know this code is cumbersome, but I don't know of any nicer way
38 * of transforming TGSI shaders. ~ M.
45 #include "tgsi/tgsi_transform.h"
46 #include "tgsi/tgsi_dump.h"
48 #include "draw/draw_context.h"
50 struct vs_transform_context {
51 struct tgsi_transform_context base;
53 boolean color_used[2];
54 boolean bcolor_used[2];
55 boolean temp_used[128];
57 /* Index of the pos output, typically 0. */
59 /* Index of the pos temp where all writes of pos are redirected to. */
61 /* The index of the last generic output, after which we insert a new
66 /* Used to shift output decl. indices when inserting new ones. */
68 /* Used to remap writes to output decls if their indices changed. */
69 unsigned out_remap[32];
71 /* First instruction processed? */
72 boolean first_instruction;
73 /* End instruction processed? */
74 boolean end_instruction;
77 static void emit_temp(struct tgsi_transform_context *ctx, unsigned reg)
79 struct tgsi_full_declaration decl;
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);
87 static void emit_output(struct tgsi_transform_context *ctx,
88 unsigned name, unsigned index, unsigned interp,
91 struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
92 struct tgsi_full_declaration decl;
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;
105 static void insert_output(struct tgsi_transform_context *ctx,
106 struct tgsi_full_declaration *before,
107 unsigned name, unsigned index, unsigned interp)
109 struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
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];
117 /* Insert the new output. */
118 emit_output(ctx, name, index, interp, before->Range.First);
123 static void insert_trailing_bcolor(struct tgsi_transform_context *ctx,
124 struct tgsi_full_declaration *before)
126 struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
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]) {
132 insert_output(ctx, before, TGSI_SEMANTIC_BCOLOR, 1,
133 TGSI_INTERPOLATE_LINEAR);
135 emit_output(ctx, TGSI_SEMANTIC_BCOLOR, 1,
136 TGSI_INTERPOLATE_LINEAR, vsctx->num_outputs);
138 vsctx->bcolor_used[1] = TRUE;
142 static void transform_decl(struct tgsi_transform_context *ctx,
143 struct tgsi_full_declaration *decl)
145 struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
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;
154 case TGSI_SEMANTIC_COLOR:
155 assert(decl->Semantic.Index < 2);
156 vsctx->color_used[decl->Semantic.Index] = TRUE;
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;
168 case TGSI_SEMANTIC_BCOLOR:
169 assert(decl->Semantic.Index < 2);
170 vsctx->bcolor_used[decl->Semantic.Index] = TRUE;
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;
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;
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;
190 /* One more case is handled in insert_trailing_bcolor. */
193 case TGSI_SEMANTIC_GENERIC:
194 vsctx->last_generic = MAX2(vsctx->last_generic, decl->Semantic.Index);
198 if (decl->Semantic.Name != TGSI_SEMANTIC_BCOLOR) {
199 /* Insert it as soon as possible. */
200 insert_trailing_bcolor(ctx, decl);
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;
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;
216 ctx->emit_declaration(ctx, decl);
219 static void transform_inst(struct tgsi_transform_context *ctx,
220 struct tgsi_full_instruction *inst)
222 struct vs_transform_context *vsctx = (struct vs_transform_context *) ctx;
223 struct tgsi_full_instruction new_inst;
226 if (!vsctx->first_instruction) {
227 vsctx->first_instruction = TRUE;
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);
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);
237 /* Find a free temp for POSITION. */
238 for (i = 0; i < Elements(vsctx->temp_used); i++) {
239 if (!vsctx->temp_used[i]) {
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);
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);
272 vsctx->end_instruction = TRUE;
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;
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];
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;
298 /* The labels of the following opcodes are moved only after
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;
309 ctx->emit_instruction(ctx, inst);
312 void r300_draw_init_vertex_shader(struct r300_context *r300,
313 struct r300_vertex_shader *vs)
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 */;
321 new_vs.tokens = tgsi_alloc_tokens(newLen);
322 if (new_vs.tokens == NULL)
325 memset(&transform, 0, sizeof(transform));
326 for (i = 0; i < Elements(transform.out_remap); i++) {
327 transform.out_remap[i] = i;
329 transform.last_generic = -1;
330 transform.base.transform_instruction = transform_inst;
331 transform.base.transform_declaration = transform_decl;
333 tgsi_transform_shader(vs->state.tokens,
334 (struct tgsi_token*)new_vs.tokens,
335 newLen, &transform.base);
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");
345 /* Free old tokens. */
346 FREE((void*)vs->state.tokens);
348 vs->draw_vs = draw_create_vertex_shader(draw, &new_vs);
350 /* Instead of duplicating and freeing the tokens, copy the pointer directly. */
351 vs->state.tokens = new_vs.tokens;
353 /* Init the VS output table for the rasterizer. */
354 r300_init_vs_outputs(r300, vs);
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;