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