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];
56 /* Index of the pos output, typically 0. */
58 /* Index of the pos temp where all writes of pos are redirected to. */
60 /* The index of the last generic output, after which we insert a new
65 /* Used to shift output decl. indices when inserting new ones. */
67 /* Used to remap writes to output decls if their indices changed. */
68 unsigned out_remap
[32];
70 /* First instruction processed? */
71 boolean first_instruction
;
72 /* End instruction processed? */
73 boolean end_instruction
;
75 boolean temp_used
[1024];
78 static void emit_temp(struct tgsi_transform_context
*ctx
, unsigned reg
)
80 struct tgsi_full_declaration decl
;
82 decl
= tgsi_default_full_declaration();
83 decl
.Declaration
.File
= TGSI_FILE_TEMPORARY
;
84 decl
.Range
.First
= decl
.Range
.Last
= reg
;
85 ctx
->emit_declaration(ctx
, &decl
);
88 static void emit_output(struct tgsi_transform_context
*ctx
,
89 unsigned name
, unsigned index
, unsigned interp
,
92 struct vs_transform_context
*vsctx
= (struct vs_transform_context
*)ctx
;
93 struct tgsi_full_declaration decl
;
95 decl
= tgsi_default_full_declaration();
96 decl
.Declaration
.File
= TGSI_FILE_OUTPUT
;
97 decl
.Declaration
.Interpolate
= interp
;
98 decl
.Declaration
.Semantic
= TRUE
;
99 decl
.Semantic
.Name
= name
;
100 decl
.Semantic
.Index
= index
;
101 decl
.Range
.First
= decl
.Range
.Last
= reg
;
102 ctx
->emit_declaration(ctx
, &decl
);
103 ++vsctx
->num_outputs
;
106 static void insert_output_before(struct tgsi_transform_context
*ctx
,
107 struct tgsi_full_declaration
*before
,
108 unsigned name
, unsigned index
, unsigned interp
)
110 struct vs_transform_context
*vsctx
= (struct vs_transform_context
*)ctx
;
113 /* Make a place for the new output. */
114 for (i
= before
->Range
.First
; i
< Elements(vsctx
->out_remap
); i
++) {
115 ++vsctx
->out_remap
[i
];
118 /* Insert the new output. */
119 emit_output(ctx
, name
, index
, interp
,
120 before
->Range
.First
+ vsctx
->decl_shift
);
125 static void insert_output_after(struct tgsi_transform_context
*ctx
,
126 struct tgsi_full_declaration
*after
,
127 unsigned name
, unsigned index
, unsigned interp
)
129 struct vs_transform_context
*vsctx
= (struct vs_transform_context
*)ctx
;
132 /* Make a place for the new output. */
133 for (i
= after
->Range
.First
+1; i
< Elements(vsctx
->out_remap
); i
++) {
134 ++vsctx
->out_remap
[i
];
137 /* Insert the new output. */
138 emit_output(ctx
, name
, index
, interp
,
139 after
->Range
.First
+ 1);
144 static void transform_decl(struct tgsi_transform_context
*ctx
,
145 struct tgsi_full_declaration
*decl
)
147 struct vs_transform_context
*vsctx
= (struct vs_transform_context
*)ctx
;
150 if (decl
->Declaration
.File
== TGSI_FILE_OUTPUT
) {
151 switch (decl
->Semantic
.Name
) {
152 case TGSI_SEMANTIC_POSITION
:
153 vsctx
->pos_output
= decl
->Range
.First
;
156 case TGSI_SEMANTIC_COLOR
:
157 assert(decl
->Semantic
.Index
< 2);
159 /* We must rasterize the first color if the second one is
160 * used, otherwise the rasterizer doesn't do the color
161 * selection correctly. Declare it, but don't write to it. */
162 if (decl
->Semantic
.Index
== 1 && !vsctx
->color_used
[0]) {
163 insert_output_before(ctx
, decl
, TGSI_SEMANTIC_COLOR
, 0,
164 TGSI_INTERPOLATE_LINEAR
);
165 vsctx
->color_used
[0] = TRUE
;
169 case TGSI_SEMANTIC_BCOLOR
:
170 assert(decl
->Semantic
.Index
< 2);
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_before(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_before(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_before(ctx
, decl
, TGSI_SEMANTIC_BCOLOR
, 0,
187 TGSI_INTERPOLATE_LINEAR
);
188 vsctx
->bcolor_used
[0] = TRUE
;
192 case TGSI_SEMANTIC_GENERIC
:
193 vsctx
->last_generic
= MAX2(vsctx
->last_generic
, decl
->Semantic
.Index
);
197 /* Since we're inserting new outputs in between, the following outputs
198 * should be moved to the right so that they don't overlap with
199 * the newly added ones. */
200 decl
->Range
.First
+= vsctx
->decl_shift
;
201 decl
->Range
.Last
+= vsctx
->decl_shift
;
203 ++vsctx
->num_outputs
;
204 } else if (decl
->Declaration
.File
== TGSI_FILE_TEMPORARY
) {
205 for (i
= decl
->Range
.First
; i
<= decl
->Range
.Last
; i
++) {
206 vsctx
->temp_used
[i
] = TRUE
;
210 ctx
->emit_declaration(ctx
, decl
);
212 /* Insert BCOLOR1 if needed. */
213 if (decl
->Declaration
.File
== TGSI_FILE_OUTPUT
&&
214 decl
->Semantic
.Name
== TGSI_SEMANTIC_BCOLOR
&&
215 !vsctx
->bcolor_used
[1]) {
216 insert_output_after(ctx
, decl
, TGSI_SEMANTIC_BCOLOR
, 1,
217 TGSI_INTERPOLATE_LINEAR
);
221 static void transform_inst(struct tgsi_transform_context
*ctx
,
222 struct tgsi_full_instruction
*inst
)
224 struct vs_transform_context
*vsctx
= (struct vs_transform_context
*) ctx
;
225 struct tgsi_full_instruction new_inst
;
228 if (!vsctx
->first_instruction
) {
229 vsctx
->first_instruction
= TRUE
;
231 /* Insert the generic output for WPOS. */
232 emit_output(ctx
, TGSI_SEMANTIC_GENERIC
, vsctx
->last_generic
+ 1,
233 TGSI_INTERPOLATE_PERSPECTIVE
, vsctx
->num_outputs
);
235 /* Find a free temp for POSITION. */
236 for (i
= 0; i
< Elements(vsctx
->temp_used
); i
++) {
237 if (!vsctx
->temp_used
[i
]) {
245 if (inst
->Instruction
.Opcode
== TGSI_OPCODE_END
) {
246 /* MOV OUT[pos_output], TEMP[pos_temp]; */
247 new_inst
= tgsi_default_full_instruction();
248 new_inst
.Instruction
.Opcode
= TGSI_OPCODE_MOV
;
249 new_inst
.Instruction
.NumDstRegs
= 1;
250 new_inst
.Dst
[0].Register
.File
= TGSI_FILE_OUTPUT
;
251 new_inst
.Dst
[0].Register
.Index
= vsctx
->pos_output
;
252 new_inst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_XYZW
;
253 new_inst
.Instruction
.NumSrcRegs
= 1;
254 new_inst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
255 new_inst
.Src
[0].Register
.Index
= vsctx
->pos_temp
;
256 ctx
->emit_instruction(ctx
, &new_inst
);
258 /* MOV OUT[n-1], TEMP[pos_temp]; */
259 new_inst
= tgsi_default_full_instruction();
260 new_inst
.Instruction
.Opcode
= TGSI_OPCODE_MOV
;
261 new_inst
.Instruction
.NumDstRegs
= 1;
262 new_inst
.Dst
[0].Register
.File
= TGSI_FILE_OUTPUT
;
263 new_inst
.Dst
[0].Register
.Index
= vsctx
->num_outputs
- 1;
264 new_inst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_XYZW
;
265 new_inst
.Instruction
.NumSrcRegs
= 1;
266 new_inst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
267 new_inst
.Src
[0].Register
.Index
= vsctx
->pos_temp
;
268 ctx
->emit_instruction(ctx
, &new_inst
);
270 vsctx
->end_instruction
= TRUE
;
272 /* Not an END instruction. */
273 /* Fix writes to outputs. */
274 for (i
= 0; i
< inst
->Instruction
.NumDstRegs
; i
++) {
275 struct tgsi_full_dst_register
*dst
= &inst
->Dst
[i
];
276 if (dst
->Register
.File
== TGSI_FILE_OUTPUT
) {
277 if (dst
->Register
.Index
== vsctx
->pos_output
) {
278 /* Replace writes to OUT[pos_output] with TEMP[pos_temp]. */
279 dst
->Register
.File
= TGSI_FILE_TEMPORARY
;
280 dst
->Register
.Index
= vsctx
->pos_temp
;
282 /* Not a position, good...
283 * Since we were changing the indices of output decls,
284 * we must redirect writes into them too. */
285 dst
->Register
.Index
= vsctx
->out_remap
[dst
->Register
.Index
];
290 /* Inserting 2 instructions before the END opcode moves all following
291 * labels by 2. Subroutines are always after the END opcode so
292 * they're always moved. */
293 if (inst
->Instruction
.Opcode
== TGSI_OPCODE_CAL
) {
294 inst
->Label
.Label
+= 2;
296 /* The labels of the following opcodes are moved only after
298 if (vsctx
->end_instruction
&&
299 (inst
->Instruction
.Opcode
== TGSI_OPCODE_IF
||
300 inst
->Instruction
.Opcode
== TGSI_OPCODE_ELSE
||
301 inst
->Instruction
.Opcode
== TGSI_OPCODE_BGNLOOP
||
302 inst
->Instruction
.Opcode
== TGSI_OPCODE_ENDLOOP
)) {
303 inst
->Label
.Label
+= 2;
307 ctx
->emit_instruction(ctx
, inst
);
310 void r300_draw_init_vertex_shader(struct r300_context
*r300
,
311 struct r300_vertex_shader
*vs
)
313 struct draw_context
*draw
= r300
->draw
;
314 struct pipe_shader_state new_vs
;
315 struct tgsi_shader_info info
;
316 struct vs_transform_context transform
;
317 const uint newLen
= tgsi_num_tokens(vs
->state
.tokens
) + 100 /* XXX */;
320 tgsi_scan_shader(vs
->state
.tokens
, &info
);
322 new_vs
.tokens
= tgsi_alloc_tokens(newLen
);
323 if (new_vs
.tokens
== NULL
)
326 memset(&transform
, 0, sizeof(transform
));
327 for (i
= 0; i
< Elements(transform
.out_remap
); i
++) {
328 transform
.out_remap
[i
] = i
;
330 transform
.last_generic
= -1;
331 transform
.base
.transform_instruction
= transform_inst
;
332 transform
.base
.transform_declaration
= transform_decl
;
334 for (i
= 0; i
< info
.num_outputs
; i
++) {
335 unsigned index
= info
.output_semantic_index
[i
];
337 switch (info
.output_semantic_name
[i
]) {
338 case TGSI_SEMANTIC_COLOR
:
340 transform
.color_used
[index
] = TRUE
;
343 case TGSI_SEMANTIC_BCOLOR
:
345 transform
.bcolor_used
[index
] = TRUE
;
350 tgsi_transform_shader(vs
->state
.tokens
,
351 (struct tgsi_token
*)new_vs
.tokens
,
352 newLen
, &transform
.base
);
355 printf("----------------------------------------------\norig shader:\n");
356 tgsi_dump(vs
->state
.tokens
, 0);
357 printf("----------------------------------------------\nnew shader:\n");
358 tgsi_dump(new_vs
.tokens
, 0);
359 printf("----------------------------------------------\n");
362 /* Free old tokens. */
363 FREE((void*)vs
->state
.tokens
);
365 vs
->draw_vs
= draw_create_vertex_shader(draw
, &new_vs
);
367 /* Instead of duplicating and freeing the tokens, copy the pointer directly. */
368 vs
->state
.tokens
= new_vs
.tokens
;
370 /* Init the VS output table for the rasterizer. */
371 r300_init_vs_outputs(r300
, vs
);
373 /* Make the last generic be WPOS. */
374 vs
->outputs
.wpos
= vs
->outputs
.generic
[transform
.last_generic
+ 1];
375 vs
->outputs
.generic
[transform
.last_generic
+ 1] = ATTR_UNUSED
;