tgsi_ureg.c revision 75df599e30bda03b40c0442eff3e39ec84397ede
1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. 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 VMWARE, INC 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#include "pipe/p_context.h" 30#include "pipe/p_state.h" 31#include "tgsi/tgsi_ureg.h" 32#include "tgsi/tgsi_build.h" 33#include "tgsi/tgsi_info.h" 34#include "tgsi/tgsi_dump.h" 35#include "tgsi/tgsi_sanity.h" 36#include "util/u_memory.h" 37#include "util/u_math.h" 38 39union tgsi_any_token { 40 struct tgsi_version version; 41 struct tgsi_header header; 42 struct tgsi_processor processor; 43 struct tgsi_token token; 44 struct tgsi_declaration decl; 45 struct tgsi_declaration_range decl_range; 46 struct tgsi_declaration_semantic decl_semantic; 47 struct tgsi_immediate imm; 48 union tgsi_immediate_data imm_data; 49 struct tgsi_instruction insn; 50 struct tgsi_instruction_predicate insn_predicate; 51 struct tgsi_instruction_ext_label insn_ext_label; 52 struct tgsi_instruction_ext_texture insn_ext_texture; 53 struct tgsi_src_register src; 54 struct tgsi_src_register_ext_mod src_ext_mod; 55 struct tgsi_dimension dim; 56 struct tgsi_dst_register dst; 57 struct tgsi_dst_register_ext_modulate dst_ext_mod; 58 unsigned value; 59}; 60 61 62struct ureg_tokens { 63 union tgsi_any_token *tokens; 64 unsigned size; 65 unsigned order; 66 unsigned count; 67}; 68 69#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS 70#define UREG_MAX_OUTPUT PIPE_MAX_ATTRIBS 71#define UREG_MAX_CONSTANT_RANGE 32 72#define UREG_MAX_IMMEDIATE 32 73#define UREG_MAX_TEMP 256 74#define UREG_MAX_ADDR 2 75#define UREG_MAX_LOOP 1 76#define UREG_MAX_PRED 1 77 78#define DOMAIN_DECL 0 79#define DOMAIN_INSN 1 80 81struct ureg_program 82{ 83 unsigned processor; 84 struct pipe_context *pipe; 85 86 struct { 87 unsigned semantic_name; 88 unsigned semantic_index; 89 unsigned interp; 90 } fs_input[UREG_MAX_INPUT]; 91 unsigned nr_fs_inputs; 92 93 unsigned vs_inputs[UREG_MAX_INPUT/32]; 94 95 struct { 96 unsigned semantic_name; 97 unsigned semantic_index; 98 } output[UREG_MAX_OUTPUT]; 99 unsigned nr_outputs; 100 101 struct { 102 float v[4]; 103 unsigned nr; 104 } immediate[UREG_MAX_IMMEDIATE]; 105 unsigned nr_immediates; 106 107 struct ureg_src sampler[PIPE_MAX_SAMPLERS]; 108 unsigned nr_samplers; 109 110 unsigned temps_active[UREG_MAX_TEMP / 32]; 111 unsigned nr_temps; 112 113 struct { 114 unsigned first; 115 unsigned last; 116 } constant_range[UREG_MAX_CONSTANT_RANGE]; 117 unsigned nr_constant_ranges; 118 119 unsigned nr_addrs; 120 unsigned nr_preds; 121 unsigned nr_loops; 122 unsigned nr_instructions; 123 124 struct ureg_tokens domain[2]; 125}; 126 127static union tgsi_any_token error_tokens[32]; 128 129static void tokens_error( struct ureg_tokens *tokens ) 130{ 131 if (tokens->tokens && tokens->tokens != error_tokens) 132 FREE(tokens->tokens); 133 134 tokens->tokens = error_tokens; 135 tokens->size = Elements(error_tokens); 136 tokens->count = 0; 137} 138 139 140static void tokens_expand( struct ureg_tokens *tokens, 141 unsigned count ) 142{ 143 unsigned old_size = tokens->size * sizeof(unsigned); 144 145 if (tokens->tokens == error_tokens) { 146 return; 147 } 148 149 while (tokens->count + count > tokens->size) { 150 tokens->size = (1 << ++tokens->order); 151 } 152 153 tokens->tokens = REALLOC(tokens->tokens, 154 old_size, 155 tokens->size * sizeof(unsigned)); 156 if (tokens->tokens == NULL) { 157 tokens_error(tokens); 158 } 159} 160 161static void set_bad( struct ureg_program *ureg ) 162{ 163 tokens_error(&ureg->domain[0]); 164} 165 166 167 168static union tgsi_any_token *get_tokens( struct ureg_program *ureg, 169 unsigned domain, 170 unsigned count ) 171{ 172 struct ureg_tokens *tokens = &ureg->domain[domain]; 173 union tgsi_any_token *result; 174 175 if (tokens->count + count > tokens->size) 176 tokens_expand(tokens, count); 177 178 result = &tokens->tokens[tokens->count]; 179 tokens->count += count; 180 return result; 181} 182 183 184static union tgsi_any_token *retrieve_token( struct ureg_program *ureg, 185 unsigned domain, 186 unsigned nr ) 187{ 188 if (ureg->domain[domain].tokens == error_tokens) 189 return &error_tokens[0]; 190 191 return &ureg->domain[domain].tokens[nr]; 192} 193 194 195 196static INLINE struct ureg_dst 197ureg_dst_register( unsigned file, 198 unsigned index ) 199{ 200 struct ureg_dst dst; 201 202 dst.File = file; 203 dst.WriteMask = TGSI_WRITEMASK_XYZW; 204 dst.Indirect = 0; 205 dst.IndirectIndex = 0; 206 dst.IndirectSwizzle = 0; 207 dst.Saturate = 0; 208 dst.Predicate = 0; 209 dst.PredNegate = 0; 210 dst.PredSwizzleX = TGSI_SWIZZLE_X; 211 dst.PredSwizzleY = TGSI_SWIZZLE_Y; 212 dst.PredSwizzleZ = TGSI_SWIZZLE_Z; 213 dst.PredSwizzleW = TGSI_SWIZZLE_W; 214 dst.Index = index; 215 216 return dst; 217} 218 219static INLINE struct ureg_src 220ureg_src_register( unsigned file, 221 unsigned index ) 222{ 223 struct ureg_src src; 224 225 src.File = file; 226 src.SwizzleX = TGSI_SWIZZLE_X; 227 src.SwizzleY = TGSI_SWIZZLE_Y; 228 src.SwizzleZ = TGSI_SWIZZLE_Z; 229 src.SwizzleW = TGSI_SWIZZLE_W; 230 src.Pad = 0; 231 src.Indirect = 0; 232 src.IndirectIndex = 0; 233 src.IndirectSwizzle = 0; 234 src.Absolute = 0; 235 src.Index = index; 236 src.Negate = 0; 237 238 return src; 239} 240 241 242 243 244struct ureg_src 245ureg_DECL_fs_input( struct ureg_program *ureg, 246 unsigned name, 247 unsigned index, 248 unsigned interp_mode ) 249{ 250 unsigned i; 251 252 for (i = 0; i < ureg->nr_fs_inputs; i++) { 253 if (ureg->fs_input[i].semantic_name == name && 254 ureg->fs_input[i].semantic_index == index) 255 goto out; 256 } 257 258 if (ureg->nr_fs_inputs < UREG_MAX_INPUT) { 259 ureg->fs_input[i].semantic_name = name; 260 ureg->fs_input[i].semantic_index = index; 261 ureg->fs_input[i].interp = interp_mode; 262 ureg->nr_fs_inputs++; 263 } 264 else { 265 set_bad( ureg ); 266 } 267 268out: 269 return ureg_src_register( TGSI_FILE_INPUT, i ); 270} 271 272 273struct ureg_src 274ureg_DECL_vs_input( struct ureg_program *ureg, 275 unsigned index ) 276{ 277 assert(ureg->processor == TGSI_PROCESSOR_VERTEX); 278 279 ureg->vs_inputs[index/32] |= 1 << (index % 32); 280 return ureg_src_register( TGSI_FILE_INPUT, index ); 281} 282 283 284struct ureg_dst 285ureg_DECL_output( struct ureg_program *ureg, 286 unsigned name, 287 unsigned index ) 288{ 289 unsigned i; 290 291 for (i = 0; i < ureg->nr_outputs; i++) { 292 if (ureg->output[i].semantic_name == name && 293 ureg->output[i].semantic_index == index) 294 goto out; 295 } 296 297 if (ureg->nr_outputs < UREG_MAX_OUTPUT) { 298 ureg->output[i].semantic_name = name; 299 ureg->output[i].semantic_index = index; 300 ureg->nr_outputs++; 301 } 302 else { 303 set_bad( ureg ); 304 } 305 306out: 307 return ureg_dst_register( TGSI_FILE_OUTPUT, i ); 308} 309 310 311/* Returns a new constant register. Keep track of which have been 312 * referred to so that we can emit decls later. 313 * 314 * There is nothing in this code to bind this constant to any tracked 315 * value or manage any constant_buffer contents -- that's the 316 * resposibility of the calling code. 317 */ 318struct ureg_src ureg_DECL_constant(struct ureg_program *ureg, 319 unsigned index ) 320{ 321 unsigned minconst = index, maxconst = index; 322 unsigned i; 323 324 /* Inside existing range? 325 */ 326 for (i = 0; i < ureg->nr_constant_ranges; i++) { 327 if (ureg->constant_range[i].first <= index && 328 ureg->constant_range[i].last >= index) 329 goto out; 330 } 331 332 /* Extend existing range? 333 */ 334 for (i = 0; i < ureg->nr_constant_ranges; i++) { 335 if (ureg->constant_range[i].last == index - 1) { 336 ureg->constant_range[i].last = index; 337 goto out; 338 } 339 340 if (ureg->constant_range[i].first == index + 1) { 341 ureg->constant_range[i].first = index; 342 goto out; 343 } 344 345 minconst = MIN2(minconst, ureg->constant_range[i].first); 346 maxconst = MAX2(maxconst, ureg->constant_range[i].last); 347 } 348 349 /* Create new range? 350 */ 351 if (ureg->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) { 352 i = ureg->nr_constant_ranges++; 353 ureg->constant_range[i].first = index; 354 ureg->constant_range[i].last = index; 355 goto out; 356 } 357 358 /* Collapse all ranges down to one: 359 */ 360 i = 0; 361 ureg->constant_range[0].first = minconst; 362 ureg->constant_range[0].last = maxconst; 363 ureg->nr_constant_ranges = 1; 364 365out: 366 assert(i < ureg->nr_constant_ranges); 367 assert(ureg->constant_range[i].first <= index); 368 assert(ureg->constant_range[i].last >= index); 369 return ureg_src_register( TGSI_FILE_CONSTANT, index ); 370} 371 372 373/* Allocate a new temporary. Temporaries greater than UREG_MAX_TEMP 374 * are legal, but will not be released. 375 */ 376struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) 377{ 378 unsigned i; 379 380 for (i = 0; i < UREG_MAX_TEMP; i += 32) { 381 int bit = ffs(~ureg->temps_active[i/32]); 382 if (bit != 0) { 383 i += bit - 1; 384 goto out; 385 } 386 } 387 388 /* No reusable temps, so allocate a new one: 389 */ 390 i = ureg->nr_temps++; 391 392out: 393 if (i < UREG_MAX_TEMP) 394 ureg->temps_active[i/32] |= 1 << (i % 32); 395 396 if (i >= ureg->nr_temps) 397 ureg->nr_temps = i + 1; 398 399 return ureg_dst_register( TGSI_FILE_TEMPORARY, i ); 400} 401 402 403void ureg_release_temporary( struct ureg_program *ureg, 404 struct ureg_dst tmp ) 405{ 406 if(tmp.File == TGSI_FILE_TEMPORARY) 407 if (tmp.Index < UREG_MAX_TEMP) 408 ureg->temps_active[tmp.Index/32] &= ~(1 << (tmp.Index % 32)); 409} 410 411 412/* Allocate a new address register. 413 */ 414struct ureg_dst ureg_DECL_address( struct ureg_program *ureg ) 415{ 416 if (ureg->nr_addrs < UREG_MAX_ADDR) 417 return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ ); 418 419 assert( 0 ); 420 return ureg_dst_register( TGSI_FILE_ADDRESS, 0 ); 421} 422 423/* Allocate a new loop register. 424 */ 425struct ureg_dst 426ureg_DECL_loop(struct ureg_program *ureg) 427{ 428 if (ureg->nr_loops < UREG_MAX_LOOP) { 429 return ureg_dst_register(TGSI_FILE_LOOP, ureg->nr_loops++); 430 } 431 432 assert(0); 433 return ureg_dst_register(TGSI_FILE_LOOP, 0); 434} 435 436/* Allocate a new predicate register. 437 */ 438struct ureg_dst 439ureg_DECL_predicate(struct ureg_program *ureg) 440{ 441 if (ureg->nr_preds < UREG_MAX_PRED) { 442 return ureg_dst_register(TGSI_FILE_PREDICATE, ureg->nr_preds++); 443 } 444 445 assert(0); 446 return ureg_dst_register(TGSI_FILE_PREDICATE, 0); 447} 448 449/* Allocate a new sampler. 450 */ 451struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, 452 unsigned nr ) 453{ 454 unsigned i; 455 456 for (i = 0; i < ureg->nr_samplers; i++) 457 if (ureg->sampler[i].Index == nr) 458 return ureg->sampler[i]; 459 460 if (i < PIPE_MAX_SAMPLERS) { 461 ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); 462 ureg->nr_samplers++; 463 return ureg->sampler[i]; 464 } 465 466 assert( 0 ); 467 return ureg->sampler[0]; 468} 469 470 471 472 473static int match_or_expand_immediate( const float *v, 474 unsigned nr, 475 float *v2, 476 unsigned *nr2, 477 unsigned *swizzle ) 478{ 479 unsigned i, j; 480 481 *swizzle = 0; 482 483 for (i = 0; i < nr; i++) { 484 boolean found = FALSE; 485 486 for (j = 0; j < *nr2 && !found; j++) { 487 if (v[i] == v2[j]) { 488 *swizzle |= j << (i * 2); 489 found = TRUE; 490 } 491 } 492 493 if (!found) { 494 if (*nr2 >= 4) 495 return FALSE; 496 497 v2[*nr2] = v[i]; 498 *swizzle |= *nr2 << (i * 2); 499 (*nr2)++; 500 } 501 } 502 503 return TRUE; 504} 505 506 507 508 509struct ureg_src ureg_DECL_immediate( struct ureg_program *ureg, 510 const float *v, 511 unsigned nr ) 512{ 513 unsigned i, j; 514 unsigned swizzle; 515 516 /* Could do a first pass where we examine all existing immediates 517 * without expanding. 518 */ 519 520 for (i = 0; i < ureg->nr_immediates; i++) { 521 if (match_or_expand_immediate( v, 522 nr, 523 ureg->immediate[i].v, 524 &ureg->immediate[i].nr, 525 &swizzle )) 526 goto out; 527 } 528 529 if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { 530 i = ureg->nr_immediates++; 531 if (match_or_expand_immediate( v, 532 nr, 533 ureg->immediate[i].v, 534 &ureg->immediate[i].nr, 535 &swizzle )) 536 goto out; 537 } 538 539 set_bad( ureg ); 540 541out: 542 /* Make sure that all referenced elements are from this immediate. 543 * Has the effect of making size-one immediates into scalars. 544 */ 545 for (j = nr; j < 4; j++) 546 swizzle |= (swizzle & 0x3) << (j * 2); 547 548 return ureg_swizzle( ureg_src_register( TGSI_FILE_IMMEDIATE, i ), 549 (swizzle >> 0) & 0x3, 550 (swizzle >> 2) & 0x3, 551 (swizzle >> 4) & 0x3, 552 (swizzle >> 6) & 0x3); 553} 554 555 556void 557ureg_emit_src( struct ureg_program *ureg, 558 struct ureg_src src ) 559{ 560 unsigned size = (1 + 561 (src.Absolute ? 1 : 0) + 562 (src.Indirect ? 1 : 0)); 563 564 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 565 unsigned n = 0; 566 567 assert(src.File != TGSI_FILE_NULL); 568 assert(src.File != TGSI_FILE_OUTPUT); 569 assert(src.File < TGSI_FILE_COUNT); 570 571 out[n].value = 0; 572 out[n].src.File = src.File; 573 out[n].src.SwizzleX = src.SwizzleX; 574 out[n].src.SwizzleY = src.SwizzleY; 575 out[n].src.SwizzleZ = src.SwizzleZ; 576 out[n].src.SwizzleW = src.SwizzleW; 577 out[n].src.Index = src.Index; 578 out[n].src.Negate = src.Negate; 579 n++; 580 581 if (src.Absolute) { 582 out[0].src.Extended = 1; 583 out[0].src.Negate = 0; 584 out[n].value = 0; 585 out[n].src_ext_mod.Type = TGSI_SRC_REGISTER_EXT_TYPE_MOD; 586 out[n].src_ext_mod.Absolute = 1; 587 out[n].src_ext_mod.Negate = src.Negate; 588 n++; 589 } 590 591 if (src.Indirect) { 592 out[0].src.Indirect = 1; 593 out[n].value = 0; 594 out[n].src.File = TGSI_FILE_ADDRESS; 595 out[n].src.SwizzleX = src.IndirectSwizzle; 596 out[n].src.SwizzleY = src.IndirectSwizzle; 597 out[n].src.SwizzleZ = src.IndirectSwizzle; 598 out[n].src.SwizzleW = src.IndirectSwizzle; 599 out[n].src.Index = src.IndirectIndex; 600 n++; 601 } 602 603 assert(n == size); 604} 605 606 607void 608ureg_emit_dst( struct ureg_program *ureg, 609 struct ureg_dst dst ) 610{ 611 unsigned size = (1 + 612 (dst.Indirect ? 1 : 0)); 613 614 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 615 unsigned n = 0; 616 617 assert(dst.File != TGSI_FILE_NULL); 618 assert(dst.File != TGSI_FILE_CONSTANT); 619 assert(dst.File != TGSI_FILE_INPUT); 620 assert(dst.File != TGSI_FILE_SAMPLER); 621 assert(dst.File != TGSI_FILE_IMMEDIATE); 622 assert(dst.File < TGSI_FILE_COUNT); 623 624 out[n].value = 0; 625 out[n].dst.File = dst.File; 626 out[n].dst.WriteMask = dst.WriteMask; 627 out[n].dst.Indirect = dst.Indirect; 628 out[n].dst.Index = dst.Index; 629 n++; 630 631 if (dst.Indirect) { 632 out[n].value = 0; 633 out[n].src.File = TGSI_FILE_ADDRESS; 634 out[n].src.SwizzleX = dst.IndirectSwizzle; 635 out[n].src.SwizzleY = dst.IndirectSwizzle; 636 out[n].src.SwizzleZ = dst.IndirectSwizzle; 637 out[n].src.SwizzleW = dst.IndirectSwizzle; 638 out[n].src.Index = dst.IndirectIndex; 639 n++; 640 } 641 642 assert(n == size); 643} 644 645 646static void validate( unsigned opcode, 647 unsigned nr_dst, 648 unsigned nr_src ) 649{ 650#ifdef DEBUG 651 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); 652 assert(info); 653 if(info) { 654 assert(nr_dst == info->num_dst); 655 assert(nr_src == info->num_src); 656 } 657#endif 658} 659 660struct ureg_emit_insn_result 661ureg_emit_insn(struct ureg_program *ureg, 662 unsigned opcode, 663 boolean saturate, 664 boolean predicate, 665 boolean pred_negate, 666 unsigned pred_swizzle_x, 667 unsigned pred_swizzle_y, 668 unsigned pred_swizzle_z, 669 unsigned pred_swizzle_w, 670 unsigned num_dst, 671 unsigned num_src ) 672{ 673 union tgsi_any_token *out; 674 uint count = predicate ? 2 : 1; 675 struct ureg_emit_insn_result result; 676 677 validate( opcode, num_dst, num_src ); 678 679 out = get_tokens( ureg, DOMAIN_INSN, count ); 680 out[0].insn = tgsi_default_instruction(); 681 out[0].insn.Opcode = opcode; 682 out[0].insn.Saturate = saturate; 683 out[0].insn.NumDstRegs = num_dst; 684 out[0].insn.NumSrcRegs = num_src; 685 686 result.insn_token = ureg->domain[DOMAIN_INSN].count - count; 687 result.extended_token = result.insn_token; 688 689 if (predicate) { 690 out[0].insn.Predicate = 1; 691 out[1].insn_predicate = tgsi_default_instruction_predicate(); 692 out[1].insn_predicate.Negate = pred_negate; 693 out[1].insn_predicate.SwizzleX = pred_swizzle_x; 694 out[1].insn_predicate.SwizzleY = pred_swizzle_y; 695 out[1].insn_predicate.SwizzleZ = pred_swizzle_z; 696 out[1].insn_predicate.SwizzleW = pred_swizzle_w; 697 } 698 699 ureg->nr_instructions++; 700 701 return result; 702} 703 704 705void 706ureg_emit_label(struct ureg_program *ureg, 707 unsigned extended_token, 708 unsigned *label_token ) 709{ 710 union tgsi_any_token *out, *insn; 711 712 if(!label_token) 713 return; 714 715 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 716 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 717 718 insn->token.Extended = 1; 719 720 out[0].value = 0; 721 out[0].insn_ext_label.Type = TGSI_INSTRUCTION_EXT_TYPE_LABEL; 722 723 *label_token = ureg->domain[DOMAIN_INSN].count - 1; 724} 725 726/* Will return a number which can be used in a label to point to the 727 * next instruction to be emitted. 728 */ 729unsigned 730ureg_get_instruction_number( struct ureg_program *ureg ) 731{ 732 return ureg->nr_instructions; 733} 734 735/* Patch a given label (expressed as a token number) to point to a 736 * given instruction (expressed as an instruction number). 737 */ 738void 739ureg_fixup_label(struct ureg_program *ureg, 740 unsigned label_token, 741 unsigned instruction_number ) 742{ 743 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); 744 745 assert(out->insn_ext_label.Type == TGSI_INSTRUCTION_EXT_TYPE_LABEL); 746 out->insn_ext_label.Label = instruction_number; 747} 748 749 750void 751ureg_emit_texture(struct ureg_program *ureg, 752 unsigned extended_token, 753 unsigned target ) 754{ 755 union tgsi_any_token *out, *insn; 756 757 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 758 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 759 760 insn->token.Extended = 1; 761 762 out[0].value = 0; 763 out[0].insn_ext_texture.Type = TGSI_INSTRUCTION_EXT_TYPE_TEXTURE; 764 out[0].insn_ext_texture.Texture = target; 765} 766 767 768void 769ureg_fixup_insn_size(struct ureg_program *ureg, 770 unsigned insn ) 771{ 772 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); 773 774 assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 775 out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; 776} 777 778 779void 780ureg_insn(struct ureg_program *ureg, 781 unsigned opcode, 782 const struct ureg_dst *dst, 783 unsigned nr_dst, 784 const struct ureg_src *src, 785 unsigned nr_src ) 786{ 787 struct ureg_emit_insn_result insn; 788 unsigned i; 789 boolean saturate; 790 boolean predicate; 791 boolean negate; 792 unsigned swizzle[4]; 793 794 saturate = nr_dst ? dst[0].Saturate : FALSE; 795 predicate = nr_dst ? dst[0].Predicate : FALSE; 796 if (predicate) { 797 negate = dst[0].PredNegate; 798 swizzle[0] = dst[0].PredSwizzleX; 799 swizzle[1] = dst[0].PredSwizzleY; 800 swizzle[2] = dst[0].PredSwizzleZ; 801 swizzle[3] = dst[0].PredSwizzleW; 802 } 803 804 insn = ureg_emit_insn(ureg, 805 opcode, 806 saturate, 807 predicate, 808 negate, 809 swizzle[0], 810 swizzle[1], 811 swizzle[2], 812 swizzle[3], 813 nr_dst, 814 nr_src); 815 816 for (i = 0; i < nr_dst; i++) 817 ureg_emit_dst( ureg, dst[i] ); 818 819 for (i = 0; i < nr_src; i++) 820 ureg_emit_src( ureg, src[i] ); 821 822 ureg_fixup_insn_size( ureg, insn.insn_token ); 823} 824 825void 826ureg_tex_insn(struct ureg_program *ureg, 827 unsigned opcode, 828 const struct ureg_dst *dst, 829 unsigned nr_dst, 830 unsigned target, 831 const struct ureg_src *src, 832 unsigned nr_src ) 833{ 834 struct ureg_emit_insn_result insn; 835 unsigned i; 836 boolean saturate; 837 boolean predicate; 838 boolean negate; 839 unsigned swizzle[4]; 840 841 saturate = nr_dst ? dst[0].Saturate : FALSE; 842 predicate = nr_dst ? dst[0].Predicate : FALSE; 843 if (predicate) { 844 negate = dst[0].PredNegate; 845 swizzle[0] = dst[0].PredSwizzleX; 846 swizzle[1] = dst[0].PredSwizzleY; 847 swizzle[2] = dst[0].PredSwizzleZ; 848 swizzle[3] = dst[0].PredSwizzleW; 849 } 850 851 insn = ureg_emit_insn(ureg, 852 opcode, 853 saturate, 854 predicate, 855 negate, 856 swizzle[0], 857 swizzle[1], 858 swizzle[2], 859 swizzle[3], 860 nr_dst, 861 nr_src); 862 863 ureg_emit_texture( ureg, insn.extended_token, target ); 864 865 for (i = 0; i < nr_dst; i++) 866 ureg_emit_dst( ureg, dst[i] ); 867 868 for (i = 0; i < nr_src; i++) 869 ureg_emit_src( ureg, src[i] ); 870 871 ureg_fixup_insn_size( ureg, insn.insn_token ); 872} 873 874 875void 876ureg_label_insn(struct ureg_program *ureg, 877 unsigned opcode, 878 const struct ureg_src *src, 879 unsigned nr_src, 880 unsigned *label_token ) 881{ 882 struct ureg_emit_insn_result insn; 883 unsigned i; 884 885 insn = ureg_emit_insn(ureg, 886 opcode, 887 FALSE, 888 FALSE, 889 FALSE, 890 TGSI_SWIZZLE_X, 891 TGSI_SWIZZLE_Y, 892 TGSI_SWIZZLE_Z, 893 TGSI_SWIZZLE_W, 894 0, 895 nr_src); 896 897 ureg_emit_label( ureg, insn.extended_token, label_token ); 898 899 for (i = 0; i < nr_src; i++) 900 ureg_emit_src( ureg, src[i] ); 901 902 ureg_fixup_insn_size( ureg, insn.insn_token ); 903} 904 905 906 907static void emit_decl( struct ureg_program *ureg, 908 unsigned file, 909 unsigned index, 910 unsigned semantic_name, 911 unsigned semantic_index, 912 unsigned interp ) 913{ 914 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 915 916 out[0].value = 0; 917 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 918 out[0].decl.NrTokens = 3; 919 out[0].decl.File = file; 920 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 921 out[0].decl.Interpolate = interp; 922 out[0].decl.Semantic = 1; 923 924 out[1].value = 0; 925 out[1].decl_range.First = 926 out[1].decl_range.Last = index; 927 928 out[2].value = 0; 929 out[2].decl_semantic.SemanticName = semantic_name; 930 out[2].decl_semantic.SemanticIndex = semantic_index; 931 932} 933 934 935static void emit_decl_range( struct ureg_program *ureg, 936 unsigned file, 937 unsigned first, 938 unsigned count ) 939{ 940 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 941 942 out[0].value = 0; 943 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 944 out[0].decl.NrTokens = 2; 945 out[0].decl.File = file; 946 out[0].decl.UsageMask = 0xf; 947 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 948 out[0].decl.Semantic = 0; 949 950 out[1].value = 0; 951 out[1].decl_range.First = first; 952 out[1].decl_range.Last = first + count - 1; 953} 954 955static void emit_immediate( struct ureg_program *ureg, 956 const float *v ) 957{ 958 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); 959 960 out[0].value = 0; 961 out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; 962 out[0].imm.NrTokens = 5; 963 out[0].imm.DataType = TGSI_IMM_FLOAT32; 964 out[0].imm.Padding = 0; 965 out[0].imm.Extended = 0; 966 967 out[1].imm_data.Float = v[0]; 968 out[2].imm_data.Float = v[1]; 969 out[3].imm_data.Float = v[2]; 970 out[4].imm_data.Float = v[3]; 971} 972 973 974 975 976static void emit_decls( struct ureg_program *ureg ) 977{ 978 unsigned i; 979 980 if (ureg->processor == TGSI_PROCESSOR_VERTEX) { 981 for (i = 0; i < UREG_MAX_INPUT; i++) { 982 if (ureg->vs_inputs[i/32] & (1 << (i%32))) { 983 emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); 984 } 985 } 986 } 987 else { 988 for (i = 0; i < ureg->nr_fs_inputs; i++) { 989 emit_decl( ureg, 990 TGSI_FILE_INPUT, 991 i, 992 ureg->fs_input[i].semantic_name, 993 ureg->fs_input[i].semantic_index, 994 ureg->fs_input[i].interp ); 995 } 996 } 997 998 for (i = 0; i < ureg->nr_outputs; i++) { 999 emit_decl( ureg, 1000 TGSI_FILE_OUTPUT, 1001 i, 1002 ureg->output[i].semantic_name, 1003 ureg->output[i].semantic_index, 1004 TGSI_INTERPOLATE_CONSTANT ); 1005 } 1006 1007 for (i = 0; i < ureg->nr_samplers; i++) { 1008 emit_decl_range( ureg, 1009 TGSI_FILE_SAMPLER, 1010 ureg->sampler[i].Index, 1 ); 1011 } 1012 1013 if (ureg->nr_constant_ranges) { 1014 for (i = 0; i < ureg->nr_constant_ranges; i++) 1015 emit_decl_range( ureg, 1016 TGSI_FILE_CONSTANT, 1017 ureg->constant_range[i].first, 1018 (ureg->constant_range[i].last + 1 - 1019 ureg->constant_range[i].first) ); 1020 } 1021 1022 if (ureg->nr_temps) { 1023 emit_decl_range( ureg, 1024 TGSI_FILE_TEMPORARY, 1025 0, ureg->nr_temps ); 1026 } 1027 1028 if (ureg->nr_addrs) { 1029 emit_decl_range( ureg, 1030 TGSI_FILE_ADDRESS, 1031 0, ureg->nr_addrs ); 1032 } 1033 1034 if (ureg->nr_loops) { 1035 emit_decl_range(ureg, 1036 TGSI_FILE_LOOP, 1037 0, 1038 ureg->nr_loops); 1039 } 1040 1041 if (ureg->nr_preds) { 1042 emit_decl_range(ureg, 1043 TGSI_FILE_PREDICATE, 1044 0, 1045 ureg->nr_preds); 1046 } 1047 1048 for (i = 0; i < ureg->nr_immediates; i++) { 1049 emit_immediate( ureg, 1050 ureg->immediate[i].v ); 1051 } 1052} 1053 1054/* Append the instruction tokens onto the declarations to build a 1055 * contiguous stream suitable to send to the driver. 1056 */ 1057static void copy_instructions( struct ureg_program *ureg ) 1058{ 1059 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 1060 union tgsi_any_token *out = get_tokens( ureg, 1061 DOMAIN_DECL, 1062 nr_tokens ); 1063 1064 memcpy(out, 1065 ureg->domain[DOMAIN_INSN].tokens, 1066 nr_tokens * sizeof out[0] ); 1067} 1068 1069 1070static void 1071fixup_header_size(struct ureg_program *ureg) 1072{ 1073 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 1 ); 1074 1075 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3; 1076} 1077 1078 1079static void 1080emit_header( struct ureg_program *ureg ) 1081{ 1082 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 1083 1084 out[0].version.MajorVersion = 1; 1085 out[0].version.MinorVersion = 1; 1086 out[0].version.Padding = 0; 1087 1088 out[1].header.HeaderSize = 2; 1089 out[1].header.BodySize = 0; 1090 1091 out[2].processor.Processor = ureg->processor; 1092 out[2].processor.Padding = 0; 1093} 1094 1095 1096const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) 1097{ 1098 const struct tgsi_token *tokens; 1099 1100 emit_header( ureg ); 1101 emit_decls( ureg ); 1102 copy_instructions( ureg ); 1103 fixup_header_size( ureg ); 1104 1105 if (ureg->domain[0].tokens == error_tokens || 1106 ureg->domain[1].tokens == error_tokens) { 1107 debug_printf("%s: error in generated shader\n", __FUNCTION__); 1108 assert(0); 1109 return NULL; 1110 } 1111 1112 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1113 1114 if (0) { 1115 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 1116 ureg->domain[DOMAIN_DECL].count); 1117 tgsi_dump( tokens, 0 ); 1118 } 1119 1120#if DEBUG 1121 if (tokens && !tgsi_sanity_check(tokens)) { 1122 debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); 1123 tgsi_dump(tokens, 0); 1124 assert(0); 1125 } 1126#endif 1127 1128 1129 return tokens; 1130} 1131 1132 1133void *ureg_create_shader( struct ureg_program *ureg, 1134 struct pipe_context *pipe ) 1135{ 1136 struct pipe_shader_state state; 1137 1138 state.tokens = ureg_finalize(ureg); 1139 if(!state.tokens) 1140 return NULL; 1141 1142 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 1143 return pipe->create_vs_state( pipe, &state ); 1144 else 1145 return pipe->create_fs_state( pipe, &state ); 1146} 1147 1148 1149const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg, 1150 unsigned *nr_tokens ) 1151{ 1152 const struct tgsi_token *tokens; 1153 1154 ureg_finalize(ureg); 1155 1156 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1157 1158 if (nr_tokens) 1159 *nr_tokens = ureg->domain[DOMAIN_DECL].size; 1160 1161 ureg->domain[DOMAIN_DECL].tokens = 0; 1162 ureg->domain[DOMAIN_DECL].size = 0; 1163 ureg->domain[DOMAIN_DECL].order = 0; 1164 ureg->domain[DOMAIN_DECL].count = 0; 1165 1166 return tokens; 1167} 1168 1169 1170struct ureg_program *ureg_create( unsigned processor ) 1171{ 1172 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 1173 if (ureg == NULL) 1174 return NULL; 1175 1176 ureg->processor = processor; 1177 return ureg; 1178} 1179 1180 1181void ureg_destroy( struct ureg_program *ureg ) 1182{ 1183 unsigned i; 1184 1185 for (i = 0; i < Elements(ureg->domain); i++) { 1186 if (ureg->domain[i].tokens && 1187 ureg->domain[i].tokens != error_tokens) 1188 FREE(ureg->domain[i].tokens); 1189 } 1190 1191 FREE(ureg); 1192} 1193