st_mesa_to_tgsi.c revision 4295b34d25f40f38b8cfd3ebdc64aef29d0666db
1/************************************************************************** 2 * 3 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/* 29 * \author 30 * Michal Krol, 31 * Keith Whitwell 32 */ 33 34#include "pipe/p_compiler.h" 35#include "pipe/p_shader_tokens.h" 36#include "pipe/p_state.h" 37#include "tgsi/tgsi_ureg.h" 38#include "st_mesa_to_tgsi.h" 39#include "shader/prog_instruction.h" 40#include "shader/prog_parameter.h" 41#include "shader/prog_print.h" 42#include "util/u_debug.h" 43#include "util/u_math.h" 44#include "util/u_memory.h" 45 46struct label { 47 unsigned branch_target; 48 unsigned token; 49}; 50 51struct st_translate { 52 struct ureg_program *ureg; 53 54 struct ureg_dst temps[MAX_PROGRAM_TEMPS]; 55 struct ureg_src *constants; 56 struct ureg_dst outputs[PIPE_MAX_SHADER_OUTPUTS]; 57 struct ureg_src inputs[PIPE_MAX_SHADER_INPUTS]; 58 struct ureg_dst address[1]; 59 struct ureg_src samplers[PIPE_MAX_SAMPLERS]; 60 61 const GLuint *inputMapping; 62 const GLuint *outputMapping; 63 64 /* For every instruction that contains a label (eg CALL), keep 65 * details so that we can go back afterwards and emit the correct 66 * tgsi instruction number for each label. 67 */ 68 struct label *labels; 69 unsigned labels_size; 70 unsigned labels_count; 71 72 /* Keep a record of the tgsi instruction number that each mesa 73 * instruction starts at, will be used to fix up labels after 74 * translation. 75 */ 76 unsigned *insn; 77 unsigned insn_size; 78 unsigned insn_count; 79 80 GLenum procType; 81 82 boolean error; 83}; 84 85 86static unsigned *get_label( struct st_translate *t, 87 unsigned branch_target ) 88{ 89 unsigned i; 90 91 if (t->labels_count + 1 >= t->labels_size) { 92 unsigned old_size = t->labels_size; 93 t->labels_size = 1 << (util_logbase2(t->labels_size) + 1); 94 t->labels = REALLOC( t->labels, 95 old_size * sizeof t->labels[0], 96 t->labels_size * sizeof t->labels[0] ); 97 if (t->labels == NULL) { 98 static unsigned dummy; 99 t->error = TRUE; 100 return &dummy; 101 } 102 } 103 104 i = t->labels_count++; 105 t->labels[i].branch_target = branch_target; 106 return &t->labels[i].token; 107} 108 109 110static void set_insn_start( struct st_translate *t, 111 unsigned start ) 112{ 113 if (t->insn_count + 1 >= t->insn_size) { 114 unsigned old_size = t->insn_size; 115 t->insn_size = 1 << (util_logbase2(t->insn_size) + 1); 116 t->insn = REALLOC( t->insn, 117 old_size * sizeof t->insn[0], 118 t->insn_size * sizeof t->insn[0] ); 119 if (t->insn == NULL) { 120 t->error = TRUE; 121 return; 122 } 123 } 124 125 t->insn[t->insn_count++] = start; 126} 127 128 129 130/* 131 * Map mesa register file to TGSI register file. 132 */ 133static struct ureg_dst 134dst_register( struct st_translate *t, 135 gl_register_file file, 136 GLuint index ) 137{ 138 switch( file ) { 139 case PROGRAM_UNDEFINED: 140 return ureg_dst_undef(); 141 142 case PROGRAM_TEMPORARY: 143 if (ureg_dst_is_undef(t->temps[index])) 144 t->temps[index] = ureg_DECL_temporary( t->ureg ); 145 146 return t->temps[index]; 147 148 case PROGRAM_OUTPUT: 149 return t->outputs[t->outputMapping[index]]; 150 151 case PROGRAM_ADDRESS: 152 return t->address[index]; 153 154 default: 155 assert( 0 ); 156 return ureg_dst_undef(); 157 } 158} 159 160 161 162static struct ureg_src 163src_register( struct st_translate *t, 164 gl_register_file file, 165 GLuint index ) 166{ 167 switch( file ) { 168 case PROGRAM_UNDEFINED: 169 return ureg_src_undef(); 170 171 case PROGRAM_TEMPORARY: 172 if (ureg_dst_is_undef(t->temps[index])) 173 t->temps[index] = ureg_DECL_temporary( t->ureg ); 174 return ureg_src(t->temps[index]); 175 176 case PROGRAM_STATE_VAR: 177 case PROGRAM_NAMED_PARAM: 178 case PROGRAM_UNIFORM: 179 case PROGRAM_CONSTANT: 180 return t->constants[index]; 181 182 case PROGRAM_INPUT: 183 return t->inputs[t->inputMapping[index]]; 184 185 case PROGRAM_OUTPUT: 186 return ureg_src(t->outputs[t->outputMapping[index]]); /* not needed? */ 187 188 case PROGRAM_ADDRESS: 189 return ureg_src(t->address[index]); 190 191 default: 192 assert( 0 ); 193 return ureg_src_undef(); 194 } 195} 196 197 198/* 199 * Map mesa texture target to TGSI texture target. 200 */ 201static unsigned 202translate_texture_target( GLuint textarget, 203 GLboolean shadow ) 204{ 205 if (shadow) { 206 switch( textarget ) { 207 case TEXTURE_1D_INDEX: return TGSI_TEXTURE_SHADOW1D; 208 case TEXTURE_2D_INDEX: return TGSI_TEXTURE_SHADOW2D; 209 case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_SHADOWRECT; 210 default: break; 211 } 212 } 213 214 switch( textarget ) { 215 case TEXTURE_1D_INDEX: return TGSI_TEXTURE_1D; 216 case TEXTURE_2D_INDEX: return TGSI_TEXTURE_2D; 217 case TEXTURE_3D_INDEX: return TGSI_TEXTURE_3D; 218 case TEXTURE_CUBE_INDEX: return TGSI_TEXTURE_CUBE; 219 case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_RECT; 220 default: 221 assert( 0 ); 222 return TGSI_TEXTURE_1D; 223 } 224} 225 226 227 228static struct ureg_dst 229translate_dst( struct st_translate *t, 230 const struct prog_dst_register *DstReg, 231 boolean saturate ) 232{ 233 struct ureg_dst dst = dst_register( t, 234 DstReg->File, 235 DstReg->Index ); 236 237 dst = ureg_writemask( dst, 238 DstReg->WriteMask ); 239 240 if (saturate) 241 dst = ureg_saturate( dst ); 242 243 if (DstReg->RelAddr) 244 dst = ureg_dst_indirect( dst, ureg_src(t->address[0]) ); 245 246 return dst; 247} 248 249 250 251 252 253static struct ureg_src 254translate_src( struct st_translate *t, 255 const struct prog_src_register *SrcReg ) 256{ 257 struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index ); 258 259 src = ureg_swizzle( src, 260 GET_SWZ( SrcReg->Swizzle, 0 ) & 0x3, 261 GET_SWZ( SrcReg->Swizzle, 1 ) & 0x3, 262 GET_SWZ( SrcReg->Swizzle, 2 ) & 0x3, 263 GET_SWZ( SrcReg->Swizzle, 3 ) & 0x3); 264 265 if (SrcReg->Negate == NEGATE_XYZW) 266 src = ureg_negate(src); 267 268 if (SrcReg->Abs) 269 src = ureg_abs(src); 270 271 if (SrcReg->RelAddr) 272 src = ureg_src_indirect( src, ureg_src(t->address[0])); 273 274 return src; 275} 276 277static struct ureg_src swizzle_4v( struct ureg_src src, 278 const unsigned *swz ) 279{ 280 return ureg_swizzle( src, swz[0], swz[1], swz[2], swz[3] ); 281} 282 283 284/* Translate SWZ instructions into a single MAD. EG: 285 * 286 * SWZ dst, src.x-y10 287 * 288 * becomes: 289 * 290 * MAD dst {1,-1,0,0}, src.xyxx, {0,0,1,0} 291 */ 292static void emit_swz( struct st_translate *t, 293 struct ureg_dst dst, 294 const struct prog_src_register *SrcReg ) 295{ 296 struct ureg_program *ureg = t->ureg; 297 struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index ); 298 299 unsigned negate_mask = SrcReg->Negate; 300 301 unsigned one_mask = ((GET_SWZ(SrcReg->Swizzle, 0) == SWIZZLE_ONE) << 0 | 302 (GET_SWZ(SrcReg->Swizzle, 1) == SWIZZLE_ONE) << 1 | 303 (GET_SWZ(SrcReg->Swizzle, 2) == SWIZZLE_ONE) << 2 | 304 (GET_SWZ(SrcReg->Swizzle, 3) == SWIZZLE_ONE) << 3); 305 306 unsigned zero_mask = ((GET_SWZ(SrcReg->Swizzle, 0) == SWIZZLE_ZERO) << 0 | 307 (GET_SWZ(SrcReg->Swizzle, 1) == SWIZZLE_ZERO) << 1 | 308 (GET_SWZ(SrcReg->Swizzle, 2) == SWIZZLE_ZERO) << 2 | 309 (GET_SWZ(SrcReg->Swizzle, 3) == SWIZZLE_ZERO) << 3); 310 311 unsigned negative_one_mask = one_mask & negate_mask; 312 unsigned positive_one_mask = one_mask & ~negate_mask; 313 314 struct ureg_src imm; 315 unsigned i; 316 unsigned mul_swizzle[4] = {0,0,0,0}; 317 unsigned add_swizzle[4] = {0,0,0,0}; 318 unsigned src_swizzle[4] = {0,0,0,0}; 319 boolean need_add = FALSE; 320 boolean need_mul = FALSE; 321 322 if (dst.WriteMask == 0) 323 return; 324 325 /* Is this just a MOV? 326 */ 327 if (zero_mask == 0 && 328 one_mask == 0 && 329 (negate_mask == 0 || negate_mask == TGSI_WRITEMASK_XYZW)) 330 { 331 ureg_MOV( ureg, dst, translate_src( t, SrcReg )); 332 return; 333 } 334 335#define IMM_ZERO 0 336#define IMM_ONE 1 337#define IMM_NEG_ONE 2 338 339 imm = ureg_imm3f( ureg, 0, 1, -1 ); 340 341 for (i = 0; i < 4; i++) { 342 unsigned bit = 1 << i; 343 344 if (dst.WriteMask & bit) { 345 if (positive_one_mask & bit) { 346 mul_swizzle[i] = IMM_ZERO; 347 add_swizzle[i] = IMM_ONE; 348 need_add = TRUE; 349 } 350 else if (negative_one_mask & bit) { 351 mul_swizzle[i] = IMM_ZERO; 352 add_swizzle[i] = IMM_NEG_ONE; 353 need_add = TRUE; 354 } 355 else if (zero_mask & bit) { 356 mul_swizzle[i] = IMM_ZERO; 357 add_swizzle[i] = IMM_ZERO; 358 need_add = TRUE; 359 } 360 else { 361 add_swizzle[i] = IMM_ZERO; 362 src_swizzle[i] = GET_SWZ(SrcReg->Swizzle, i); 363 need_mul = TRUE; 364 if (negate_mask & bit) { 365 mul_swizzle[i] = IMM_NEG_ONE; 366 } 367 else { 368 mul_swizzle[i] = IMM_ONE; 369 } 370 } 371 } 372 } 373 374 if (need_mul && need_add) { 375 ureg_MAD( ureg, 376 dst, 377 swizzle_4v( src, src_swizzle ), 378 swizzle_4v( imm, mul_swizzle ), 379 swizzle_4v( imm, add_swizzle ) ); 380 } 381 else if (need_mul) { 382 ureg_MUL( ureg, 383 dst, 384 swizzle_4v( src, src_swizzle ), 385 swizzle_4v( imm, mul_swizzle ) ); 386 } 387 else if (need_add) { 388 ureg_MOV( ureg, 389 dst, 390 swizzle_4v( imm, add_swizzle ) ); 391 } 392 else { 393 assert(0); 394 } 395 396#undef IMM_ZERO 397#undef IMM_ONE 398#undef IMM_NEG_ONE 399} 400 401 402 403static unsigned 404translate_opcode( unsigned op ) 405{ 406 switch( op ) { 407 case OPCODE_ARL: 408 return TGSI_OPCODE_ARL; 409 case OPCODE_ABS: 410 return TGSI_OPCODE_ABS; 411 case OPCODE_ADD: 412 return TGSI_OPCODE_ADD; 413 case OPCODE_BGNLOOP: 414 return TGSI_OPCODE_BGNLOOP; 415 case OPCODE_BGNSUB: 416 return TGSI_OPCODE_BGNSUB; 417 case OPCODE_BRA: 418 return TGSI_OPCODE_BRA; 419 case OPCODE_BRK: 420 return TGSI_OPCODE_BRK; 421 case OPCODE_CAL: 422 return TGSI_OPCODE_CAL; 423 case OPCODE_CMP: 424 return TGSI_OPCODE_CMP; 425 case OPCODE_CONT: 426 return TGSI_OPCODE_CONT; 427 case OPCODE_COS: 428 return TGSI_OPCODE_COS; 429 case OPCODE_DDX: 430 return TGSI_OPCODE_DDX; 431 case OPCODE_DDY: 432 return TGSI_OPCODE_DDY; 433 case OPCODE_DP2: 434 return TGSI_OPCODE_DP2; 435 case OPCODE_DP2A: 436 return TGSI_OPCODE_DP2A; 437 case OPCODE_DP3: 438 return TGSI_OPCODE_DP3; 439 case OPCODE_DP4: 440 return TGSI_OPCODE_DP4; 441 case OPCODE_DPH: 442 return TGSI_OPCODE_DPH; 443 case OPCODE_DST: 444 return TGSI_OPCODE_DST; 445 case OPCODE_ELSE: 446 return TGSI_OPCODE_ELSE; 447 case OPCODE_ENDIF: 448 return TGSI_OPCODE_ENDIF; 449 case OPCODE_ENDLOOP: 450 return TGSI_OPCODE_ENDLOOP; 451 case OPCODE_ENDSUB: 452 return TGSI_OPCODE_ENDSUB; 453 case OPCODE_EX2: 454 return TGSI_OPCODE_EX2; 455 case OPCODE_EXP: 456 return TGSI_OPCODE_EXP; 457 case OPCODE_FLR: 458 return TGSI_OPCODE_FLR; 459 case OPCODE_FRC: 460 return TGSI_OPCODE_FRC; 461 case OPCODE_IF: 462 return TGSI_OPCODE_IF; 463 case OPCODE_TRUNC: 464 return TGSI_OPCODE_TRUNC; 465 case OPCODE_KIL: 466 return TGSI_OPCODE_KIL; 467 case OPCODE_KIL_NV: 468 return TGSI_OPCODE_KILP; 469 case OPCODE_LG2: 470 return TGSI_OPCODE_LG2; 471 case OPCODE_LOG: 472 return TGSI_OPCODE_LOG; 473 case OPCODE_LIT: 474 return TGSI_OPCODE_LIT; 475 case OPCODE_LRP: 476 return TGSI_OPCODE_LRP; 477 case OPCODE_MAD: 478 return TGSI_OPCODE_MAD; 479 case OPCODE_MAX: 480 return TGSI_OPCODE_MAX; 481 case OPCODE_MIN: 482 return TGSI_OPCODE_MIN; 483 case OPCODE_MOV: 484 return TGSI_OPCODE_MOV; 485 case OPCODE_MUL: 486 return TGSI_OPCODE_MUL; 487 case OPCODE_NOISE1: 488 return TGSI_OPCODE_NOISE1; 489 case OPCODE_NOISE2: 490 return TGSI_OPCODE_NOISE2; 491 case OPCODE_NOISE3: 492 return TGSI_OPCODE_NOISE3; 493 case OPCODE_NOISE4: 494 return TGSI_OPCODE_NOISE4; 495 case OPCODE_NOP: 496 return TGSI_OPCODE_NOP; 497 case OPCODE_NRM3: 498 return TGSI_OPCODE_NRM; 499 case OPCODE_NRM4: 500 return TGSI_OPCODE_NRM4; 501 case OPCODE_POW: 502 return TGSI_OPCODE_POW; 503 case OPCODE_RCP: 504 return TGSI_OPCODE_RCP; 505 case OPCODE_RET: 506 return TGSI_OPCODE_RET; 507 case OPCODE_RSQ: 508 return TGSI_OPCODE_RSQ; 509 case OPCODE_SCS: 510 return TGSI_OPCODE_SCS; 511 case OPCODE_SEQ: 512 return TGSI_OPCODE_SEQ; 513 case OPCODE_SGE: 514 return TGSI_OPCODE_SGE; 515 case OPCODE_SGT: 516 return TGSI_OPCODE_SGT; 517 case OPCODE_SIN: 518 return TGSI_OPCODE_SIN; 519 case OPCODE_SLE: 520 return TGSI_OPCODE_SLE; 521 case OPCODE_SLT: 522 return TGSI_OPCODE_SLT; 523 case OPCODE_SNE: 524 return TGSI_OPCODE_SNE; 525 case OPCODE_SSG: 526 return TGSI_OPCODE_SSG; 527 case OPCODE_SUB: 528 return TGSI_OPCODE_SUB; 529 case OPCODE_SWZ: 530 return TGSI_OPCODE_SWZ; 531 case OPCODE_TEX: 532 return TGSI_OPCODE_TEX; 533 case OPCODE_TXB: 534 return TGSI_OPCODE_TXB; 535 case OPCODE_TXD: 536 return TGSI_OPCODE_TXD; 537 case OPCODE_TXL: 538 return TGSI_OPCODE_TXL; 539 case OPCODE_TXP: 540 return TGSI_OPCODE_TXP; 541 case OPCODE_XPD: 542 return TGSI_OPCODE_XPD; 543 case OPCODE_END: 544 return TGSI_OPCODE_END; 545 default: 546 assert( 0 ); 547 return TGSI_OPCODE_NOP; 548 } 549} 550 551 552static void 553compile_instruction( 554 struct st_translate *t, 555 const struct prog_instruction *inst ) 556{ 557 struct ureg_program *ureg = t->ureg; 558 GLuint i; 559 struct ureg_dst dst[1]; 560 struct ureg_src src[4]; 561 unsigned num_dst; 562 unsigned num_src; 563 564 num_dst = _mesa_num_inst_dst_regs( inst->Opcode ); 565 num_src = _mesa_num_inst_src_regs( inst->Opcode ); 566 567 if (num_dst) 568 dst[0] = translate_dst( t, 569 &inst->DstReg, 570 inst->SaturateMode ); 571 572 for (i = 0; i < num_src; i++) 573 src[i] = translate_src( t, &inst->SrcReg[i] ); 574 575 switch( inst->Opcode ) { 576 case OPCODE_SWZ: 577 emit_swz( t, dst[0], &inst->SrcReg[0] ); 578 return; 579 580 case OPCODE_BGNLOOP: 581 case OPCODE_CAL: 582 case OPCODE_ELSE: 583 case OPCODE_ENDLOOP: 584 case OPCODE_IF: 585 assert(num_dst == 0); 586 587 /* Currently assuming a 1:1 relationship between mesa 588 * instructions and TGSI instructions. That won't always be the 589 * case, and to be generic we'll have to make a table of labels 590 * that get fixed up afterwards. Or make labels symbolic in 591 * TGSI. 592 */ 593 ureg_label_insn( ureg, 594 translate_opcode( inst->Opcode ), 595 src, num_src, 596 get_label( t, inst->BranchTarget )); 597 return; 598 599 case OPCODE_TEX: 600 case OPCODE_TXB: 601 case OPCODE_TXD: 602 case OPCODE_TXL: 603 case OPCODE_TXP: 604 src[num_src++] = t->samplers[inst->TexSrcUnit]; 605 ureg_tex_insn( ureg, 606 translate_opcode( inst->Opcode ), 607 dst, num_dst, 608 translate_texture_target( inst->TexSrcTarget, 609 inst->TexShadow ), 610 src, num_src ); 611 return; 612 613 614 case OPCODE_SCS: 615 dst[0] = ureg_writemask(dst[0], TGSI_WRITEMASK_XY ); 616 ureg_insn( ureg, 617 translate_opcode( inst->Opcode ), 618 dst, num_dst, 619 src, num_src ); 620 break; 621 622 case OPCODE_XPD: 623 dst[0] = ureg_writemask(dst[0], TGSI_WRITEMASK_XYZ ); 624 ureg_insn( ureg, 625 translate_opcode( inst->Opcode ), 626 dst, num_dst, 627 src, num_src ); 628 break; 629 630 default: 631 ureg_insn( ureg, 632 translate_opcode( inst->Opcode ), 633 dst, num_dst, 634 src, num_src ); 635 break; 636 } 637 638} 639 640 641 642 643 644 645 646/** 647 * Emit the TGSI instructions for inverting the WPOS y coordinate. 648 */ 649static void 650emit_inverted_wpos( struct st_translate *t, 651 const struct gl_program *program ) 652{ 653 struct ureg_program *ureg = t->ureg; 654 655 /* Fragment program uses fragment position input. 656 * Need to replace instances of INPUT[WPOS] with temp T 657 * where T = INPUT[WPOS] by y is inverted. 658 */ 659 static const gl_state_index winSizeState[STATE_LENGTH] 660 = { STATE_INTERNAL, STATE_FB_SIZE, 0, 0, 0 }; 661 662 /* XXX: note we are modifying the incoming shader here! Need to 663 * do this before emitting the constant decls below, or this 664 * will be missed: 665 */ 666 unsigned winHeightConst = _mesa_add_state_reference(program->Parameters, 667 winSizeState); 668 669 struct ureg_src winsize = ureg_DECL_constant( ureg, winHeightConst ); 670 struct ureg_dst wpos_temp = ureg_DECL_temporary( ureg ); 671 struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]]; 672 673 /* MOV wpos_temp, input[wpos] 674 */ 675 ureg_MOV( ureg, wpos_temp, wpos_input ); 676 677 /* SUB wpos_temp.y, winsize_const, wpos_input 678 */ 679 ureg_SUB( ureg, 680 ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ), 681 winsize, 682 wpos_input); 683 684 /* Use wpos_temp as position input from here on: 685 */ 686 t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]] = ureg_src(wpos_temp); 687} 688 689 690 691 692/** 693 * Translate Mesa program to TGSI format. 694 * \param program the program to translate 695 * \param numInputs number of input registers used 696 * \param inputMapping maps Mesa fragment program inputs to TGSI generic 697 * input indexes 698 * \param inputSemanticName the TGSI_SEMANTIC flag for each input 699 * \param inputSemanticIndex the semantic index (ex: which texcoord) for each input 700 * \param interpMode the TGSI_INTERPOLATE_LINEAR/PERSP mode for each input 701 702 * \param numOutputs number of output registers used 703 * \param outputMapping maps Mesa fragment program outputs to TGSI 704 * generic outputs 705 * \param outputSemanticName the TGSI_SEMANTIC flag for each output 706 * \param outputSemanticIndex the semantic index (ex: which texcoord) for each output 707 * 708 * \return array of translated tokens, caller's responsibility to free 709 */ 710const struct tgsi_token * 711st_translate_mesa_program( 712 GLcontext *ctx, 713 uint procType, 714 const struct gl_program *program, 715 GLuint numInputs, 716 const GLuint inputMapping[], 717 const ubyte inputSemanticName[], 718 const ubyte inputSemanticIndex[], 719 const GLuint interpMode[], 720 const GLbitfield inputFlags[], 721 GLuint numOutputs, 722 const GLuint outputMapping[], 723 const ubyte outputSemanticName[], 724 const ubyte outputSemanticIndex[], 725 const GLbitfield outputFlags[] ) 726{ 727 struct st_translate translate, *t; 728 struct ureg_program *ureg; 729 const struct tgsi_token *tokens = NULL; 730 unsigned i; 731 732 t = &translate; 733 memset(t, 0, sizeof *t); 734 735 t->procType = procType; 736 t->inputMapping = inputMapping; 737 t->outputMapping = outputMapping; 738 t->ureg = ureg_create( procType ); 739 if (t->ureg == NULL) 740 return NULL; 741 742 ureg = t->ureg; 743 744 _mesa_print_program(program); 745 746 /* 747 * Declare input attributes. 748 */ 749 if (procType == TGSI_PROCESSOR_FRAGMENT) { 750 for (i = 0; i < numInputs; i++) { 751 t->inputs[i] = ureg_DECL_fs_input(ureg, 752 inputSemanticName[i], 753 inputSemanticIndex[i], 754 interpMode[i]); 755 } 756 757 if (program->InputsRead & FRAG_BIT_WPOS) { 758 /* Must do this after setting up t->inputs, and before 759 * emitting constant references, below: 760 */ 761 emit_inverted_wpos( t, program ); 762 } 763 764 /* 765 * Declare output attributes. 766 */ 767 for (i = 0; i < numOutputs; i++) { 768 switch (outputSemanticName[i]) { 769 case TGSI_SEMANTIC_POSITION: 770 t->outputs[i] = ureg_DECL_output( ureg, 771 TGSI_SEMANTIC_POSITION, /* Z / Depth */ 772 outputSemanticIndex[i] ); 773 774 t->outputs[i] = ureg_writemask( t->outputs[i], 775 TGSI_WRITEMASK_Z ); 776 break; 777 case TGSI_SEMANTIC_COLOR: 778 t->outputs[i] = ureg_DECL_output( ureg, 779 TGSI_SEMANTIC_COLOR, 780 outputSemanticIndex[i] ); 781 break; 782 default: 783 assert(0); 784 return 0; 785 } 786 } 787 } 788 else { 789 for (i = 0; i < numInputs; i++) { 790 t->inputs[i] = ureg_DECL_vs_input(ureg, i); 791 } 792 793 for (i = 0; i < numOutputs; i++) { 794 t->outputs[i] = ureg_DECL_output( ureg, 795 outputSemanticName[i], 796 outputSemanticIndex[i] ); 797 } 798 } 799 800 /* Declare address register. 801 */ 802 if (program->NumAddressRegs > 0) { 803 assert( program->NumAddressRegs == 1 ); 804 t->address[0] = ureg_DECL_address( ureg ); 805 } 806 807 808 /* Emit constants and immediates. Mesa uses a single index space 809 * for these, so we put all the translated regs in t->constants. 810 */ 811 if (program->Parameters) { 812 813 t->constants = CALLOC( program->Parameters->NumParameters, 814 sizeof t->constants[0] ); 815 if (t->constants == NULL) 816 goto out; 817 818 for (i = 0; i < program->Parameters->NumParameters; i++) { 819 switch (program->Parameters->Parameters[i].Type) { 820 case PROGRAM_ENV_PARAM: 821 case PROGRAM_STATE_VAR: 822 case PROGRAM_NAMED_PARAM: 823 case PROGRAM_UNIFORM: 824 t->constants[i] = ureg_DECL_constant( ureg, i ); 825 break; 826 827 /* Emit immediates only when there is no address register 828 * in use. FIXME: Be smarter and recognize param arrays: 829 * indirect addressing is only valid within the referenced 830 * array. 831 */ 832 case PROGRAM_CONSTANT: 833 if (program->NumAddressRegs > 0) 834 t->constants[i] = ureg_DECL_constant( ureg, i ); 835 else 836 t->constants[i] = 837 ureg_DECL_immediate( ureg, 838 program->Parameters->ParameterValues[i], 839 4 ); 840 break; 841 default: 842 break; 843 } 844 } 845 } 846 847 /* texture samplers */ 848 for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) { 849 if (program->SamplersUsed & (1 << i)) { 850 t->samplers[i] = ureg_DECL_sampler( ureg, i ); 851 } 852 } 853 854 /* Emit each instruction in turn: 855 */ 856 for (i = 0; i < program->NumInstructions; i++) { 857 set_insn_start( t, ureg_get_instruction_number( ureg )); 858 compile_instruction( t, &program->Instructions[i] ); 859 } 860 861 /* Fix up all emitted labels: 862 */ 863 for (i = 0; i < t->labels_count; i++) { 864 ureg_fixup_label( ureg, 865 t->labels[i].token, 866 t->insn[t->labels[i].branch_target] ); 867 } 868 869 tokens = ureg_get_tokens( ureg, NULL ); 870 ureg_destroy( ureg ); 871 872out: 873 FREE(t->insn); 874 FREE(t->labels); 875 FREE(t->constants); 876 877 if (t->error) { 878 debug_printf("%s: translate error flag set\n", __FUNCTION__); 879 FREE((void *)tokens); 880 tokens = NULL; 881 } 882 883 if (!tokens) { 884 debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); 885 _mesa_print_program(program); 886 assert(0); 887 } 888 889 return tokens; 890} 891