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