tgsi_ureg.c revision cdb6849fc1fa0c6e360c89a6388dc8bf19a746ca
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 goto out; 353 } 354 355 /* Collapse all ranges down to one: 356 */ 357 i = 0; 358 ureg->constant_range[0].first = minconst; 359 ureg->constant_range[0].last = maxconst; 360 ureg->nr_constant_ranges = 1; 361 362out: 363 assert(i < ureg->nr_constant_ranges); 364 assert(ureg->constant_range[i].first <= index); 365 assert(ureg->constant_range[i].last >= index); 366 return ureg_src_register( TGSI_FILE_CONSTANT, index ); 367} 368 369 370/* Allocate a new temporary. Temporaries greater than UREG_MAX_TEMP 371 * are legal, but will not be released. 372 */ 373struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) 374{ 375 unsigned i; 376 377 for (i = 0; i < UREG_MAX_TEMP; i += 32) { 378 int bit = ffs(~ureg->temps_active[i/32]); 379 if (bit != 0) { 380 i += bit - 1; 381 goto out; 382 } 383 } 384 385 /* No reusable temps, so allocate a new one: 386 */ 387 i = ureg->nr_temps++; 388 389out: 390 if (i < UREG_MAX_TEMP) 391 ureg->temps_active[i/32] |= 1 << (i % 32); 392 393 if (i >= ureg->nr_temps) 394 ureg->nr_temps = i + 1; 395 396 return ureg_dst_register( TGSI_FILE_TEMPORARY, i ); 397} 398 399 400void ureg_release_temporary( struct ureg_program *ureg, 401 struct ureg_dst tmp ) 402{ 403 if(tmp.File == TGSI_FILE_TEMPORARY) 404 if (tmp.Index < UREG_MAX_TEMP) 405 ureg->temps_active[tmp.Index/32] &= ~(1 << (tmp.Index % 32)); 406} 407 408 409/* Allocate a new address register. 410 */ 411struct ureg_dst ureg_DECL_address( struct ureg_program *ureg ) 412{ 413 if (ureg->nr_addrs < UREG_MAX_ADDR) 414 return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ ); 415 416 assert( 0 ); 417 return ureg_dst_register( TGSI_FILE_ADDRESS, 0 ); 418} 419 420/* Allocate a new loop register. 421 */ 422struct ureg_dst 423ureg_DECL_loop(struct ureg_program *ureg) 424{ 425 if (ureg->nr_loops < UREG_MAX_LOOP) { 426 return ureg_dst_register(TGSI_FILE_LOOP, ureg->nr_loops++); 427 } 428 429 assert(0); 430 return ureg_dst_register(TGSI_FILE_LOOP, 0); 431} 432 433/* Allocate a new predicate register. 434 */ 435struct ureg_dst 436ureg_DECL_predicate(struct ureg_program *ureg) 437{ 438 if (ureg->nr_preds < UREG_MAX_PRED) { 439 return ureg_dst_register(TGSI_FILE_PREDICATE, ureg->nr_preds++); 440 } 441 442 assert(0); 443 return ureg_dst_register(TGSI_FILE_PREDICATE, 0); 444} 445 446/* Allocate a new sampler. 447 */ 448struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, 449 unsigned nr ) 450{ 451 unsigned i; 452 453 for (i = 0; i < ureg->nr_samplers; i++) 454 if (ureg->sampler[i].Index == nr) 455 return ureg->sampler[i]; 456 457 if (i < PIPE_MAX_SAMPLERS) { 458 ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); 459 ureg->nr_samplers++; 460 return ureg->sampler[i]; 461 } 462 463 assert( 0 ); 464 return ureg->sampler[0]; 465} 466 467 468 469 470static int match_or_expand_immediate( const float *v, 471 unsigned nr, 472 float *v2, 473 unsigned *nr2, 474 unsigned *swizzle ) 475{ 476 unsigned i, j; 477 478 *swizzle = 0; 479 480 for (i = 0; i < nr; i++) { 481 boolean found = FALSE; 482 483 for (j = 0; j < *nr2 && !found; j++) { 484 if (v[i] == v2[j]) { 485 *swizzle |= j << (i * 2); 486 found = TRUE; 487 } 488 } 489 490 if (!found) { 491 if (*nr2 >= 4) 492 return FALSE; 493 494 v2[*nr2] = v[i]; 495 *swizzle |= *nr2 << (i * 2); 496 (*nr2)++; 497 } 498 } 499 500 return TRUE; 501} 502 503 504 505 506struct ureg_src ureg_DECL_immediate( struct ureg_program *ureg, 507 const float *v, 508 unsigned nr ) 509{ 510 unsigned i, j; 511 unsigned swizzle; 512 513 /* Could do a first pass where we examine all existing immediates 514 * without expanding. 515 */ 516 517 for (i = 0; i < ureg->nr_immediates; i++) { 518 if (match_or_expand_immediate( v, 519 nr, 520 ureg->immediate[i].v, 521 &ureg->immediate[i].nr, 522 &swizzle )) 523 goto out; 524 } 525 526 if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { 527 i = ureg->nr_immediates++; 528 if (match_or_expand_immediate( v, 529 nr, 530 ureg->immediate[i].v, 531 &ureg->immediate[i].nr, 532 &swizzle )) 533 goto out; 534 } 535 536 set_bad( ureg ); 537 538out: 539 /* Make sure that all referenced elements are from this immediate. 540 * Has the effect of making size-one immediates into scalars. 541 */ 542 for (j = nr; j < 4; j++) 543 swizzle |= (swizzle & 0x3) << (j * 2); 544 545 return ureg_swizzle( ureg_src_register( TGSI_FILE_IMMEDIATE, i ), 546 (swizzle >> 0) & 0x3, 547 (swizzle >> 2) & 0x3, 548 (swizzle >> 4) & 0x3, 549 (swizzle >> 6) & 0x3); 550} 551 552 553void 554ureg_emit_src( struct ureg_program *ureg, 555 struct ureg_src src ) 556{ 557 unsigned size = 1 + (src.Indirect ? 1 : 0); 558 559 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 560 unsigned n = 0; 561 562 assert(src.File != TGSI_FILE_NULL); 563 assert(src.File != TGSI_FILE_OUTPUT); 564 assert(src.File < TGSI_FILE_COUNT); 565 566 out[n].value = 0; 567 out[n].src.File = src.File; 568 out[n].src.SwizzleX = src.SwizzleX; 569 out[n].src.SwizzleY = src.SwizzleY; 570 out[n].src.SwizzleZ = src.SwizzleZ; 571 out[n].src.SwizzleW = src.SwizzleW; 572 out[n].src.Index = src.Index; 573 out[n].src.Negate = src.Negate; 574 out[0].src.Absolute = src.Absolute; 575 n++; 576 577 if (src.Indirect) { 578 out[0].src.Indirect = 1; 579 out[n].value = 0; 580 out[n].src.File = TGSI_FILE_ADDRESS; 581 out[n].src.SwizzleX = src.IndirectSwizzle; 582 out[n].src.SwizzleY = src.IndirectSwizzle; 583 out[n].src.SwizzleZ = src.IndirectSwizzle; 584 out[n].src.SwizzleW = src.IndirectSwizzle; 585 out[n].src.Index = src.IndirectIndex; 586 n++; 587 } 588 589 assert(n == size); 590} 591 592 593void 594ureg_emit_dst( struct ureg_program *ureg, 595 struct ureg_dst dst ) 596{ 597 unsigned size = (1 + 598 (dst.Indirect ? 1 : 0)); 599 600 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 601 unsigned n = 0; 602 603 assert(dst.File != TGSI_FILE_NULL); 604 assert(dst.File != TGSI_FILE_CONSTANT); 605 assert(dst.File != TGSI_FILE_INPUT); 606 assert(dst.File != TGSI_FILE_SAMPLER); 607 assert(dst.File != TGSI_FILE_IMMEDIATE); 608 assert(dst.File < TGSI_FILE_COUNT); 609 610 out[n].value = 0; 611 out[n].dst.File = dst.File; 612 out[n].dst.WriteMask = dst.WriteMask; 613 out[n].dst.Indirect = dst.Indirect; 614 out[n].dst.Index = dst.Index; 615 n++; 616 617 if (dst.Indirect) { 618 out[n].value = 0; 619 out[n].src.File = TGSI_FILE_ADDRESS; 620 out[n].src.SwizzleX = dst.IndirectSwizzle; 621 out[n].src.SwizzleY = dst.IndirectSwizzle; 622 out[n].src.SwizzleZ = dst.IndirectSwizzle; 623 out[n].src.SwizzleW = dst.IndirectSwizzle; 624 out[n].src.Index = dst.IndirectIndex; 625 n++; 626 } 627 628 assert(n == size); 629} 630 631 632static void validate( unsigned opcode, 633 unsigned nr_dst, 634 unsigned nr_src ) 635{ 636#ifdef DEBUG 637 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); 638 assert(info); 639 if(info) { 640 assert(nr_dst == info->num_dst); 641 assert(nr_src == info->num_src); 642 } 643#endif 644} 645 646struct ureg_emit_insn_result 647ureg_emit_insn(struct ureg_program *ureg, 648 unsigned opcode, 649 boolean saturate, 650 boolean predicate, 651 boolean pred_negate, 652 unsigned pred_swizzle_x, 653 unsigned pred_swizzle_y, 654 unsigned pred_swizzle_z, 655 unsigned pred_swizzle_w, 656 unsigned num_dst, 657 unsigned num_src ) 658{ 659 union tgsi_any_token *out; 660 uint count = predicate ? 2 : 1; 661 struct ureg_emit_insn_result result; 662 663 validate( opcode, num_dst, num_src ); 664 665 out = get_tokens( ureg, DOMAIN_INSN, count ); 666 out[0].insn = tgsi_default_instruction(); 667 out[0].insn.Opcode = opcode; 668 out[0].insn.Saturate = saturate; 669 out[0].insn.NumDstRegs = num_dst; 670 out[0].insn.NumSrcRegs = num_src; 671 672 result.insn_token = ureg->domain[DOMAIN_INSN].count - count; 673 result.extended_token = result.insn_token; 674 675 if (predicate) { 676 out[0].insn.Predicate = 1; 677 out[1].insn_predicate = tgsi_default_instruction_predicate(); 678 out[1].insn_predicate.Negate = pred_negate; 679 out[1].insn_predicate.SwizzleX = pred_swizzle_x; 680 out[1].insn_predicate.SwizzleY = pred_swizzle_y; 681 out[1].insn_predicate.SwizzleZ = pred_swizzle_z; 682 out[1].insn_predicate.SwizzleW = pred_swizzle_w; 683 } 684 685 ureg->nr_instructions++; 686 687 return result; 688} 689 690 691void 692ureg_emit_label(struct ureg_program *ureg, 693 unsigned extended_token, 694 unsigned *label_token ) 695{ 696 union tgsi_any_token *out, *insn; 697 698 if(!label_token) 699 return; 700 701 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 702 out[0].value = 0; 703 704 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 705 insn->insn.Label = 1; 706 707 *label_token = ureg->domain[DOMAIN_INSN].count - 1; 708} 709 710/* Will return a number which can be used in a label to point to the 711 * next instruction to be emitted. 712 */ 713unsigned 714ureg_get_instruction_number( struct ureg_program *ureg ) 715{ 716 return ureg->nr_instructions; 717} 718 719/* Patch a given label (expressed as a token number) to point to a 720 * given instruction (expressed as an instruction number). 721 */ 722void 723ureg_fixup_label(struct ureg_program *ureg, 724 unsigned label_token, 725 unsigned instruction_number ) 726{ 727 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); 728 729 out->insn_label.Label = instruction_number; 730} 731 732 733void 734ureg_emit_texture(struct ureg_program *ureg, 735 unsigned extended_token, 736 unsigned target ) 737{ 738 union tgsi_any_token *out, *insn; 739 740 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 741 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 742 743 insn->insn.Texture = 1; 744 745 out[0].value = 0; 746 out[0].insn_texture.Texture = target; 747} 748 749 750void 751ureg_fixup_insn_size(struct ureg_program *ureg, 752 unsigned insn ) 753{ 754 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); 755 756 assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 757 out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; 758} 759 760 761void 762ureg_insn(struct ureg_program *ureg, 763 unsigned opcode, 764 const struct ureg_dst *dst, 765 unsigned nr_dst, 766 const struct ureg_src *src, 767 unsigned nr_src ) 768{ 769 struct ureg_emit_insn_result insn; 770 unsigned i; 771 boolean saturate; 772 boolean predicate; 773 boolean negate; 774 unsigned swizzle[4]; 775 776 saturate = nr_dst ? dst[0].Saturate : FALSE; 777 predicate = nr_dst ? dst[0].Predicate : FALSE; 778 if (predicate) { 779 negate = dst[0].PredNegate; 780 swizzle[0] = dst[0].PredSwizzleX; 781 swizzle[1] = dst[0].PredSwizzleY; 782 swizzle[2] = dst[0].PredSwizzleZ; 783 swizzle[3] = dst[0].PredSwizzleW; 784 } 785 786 insn = ureg_emit_insn(ureg, 787 opcode, 788 saturate, 789 predicate, 790 negate, 791 swizzle[0], 792 swizzle[1], 793 swizzle[2], 794 swizzle[3], 795 nr_dst, 796 nr_src); 797 798 for (i = 0; i < nr_dst; i++) 799 ureg_emit_dst( ureg, dst[i] ); 800 801 for (i = 0; i < nr_src; i++) 802 ureg_emit_src( ureg, src[i] ); 803 804 ureg_fixup_insn_size( ureg, insn.insn_token ); 805} 806 807void 808ureg_tex_insn(struct ureg_program *ureg, 809 unsigned opcode, 810 const struct ureg_dst *dst, 811 unsigned nr_dst, 812 unsigned target, 813 const struct ureg_src *src, 814 unsigned nr_src ) 815{ 816 struct ureg_emit_insn_result insn; 817 unsigned i; 818 boolean saturate; 819 boolean predicate; 820 boolean negate; 821 unsigned swizzle[4]; 822 823 saturate = nr_dst ? dst[0].Saturate : FALSE; 824 predicate = nr_dst ? dst[0].Predicate : FALSE; 825 if (predicate) { 826 negate = dst[0].PredNegate; 827 swizzle[0] = dst[0].PredSwizzleX; 828 swizzle[1] = dst[0].PredSwizzleY; 829 swizzle[2] = dst[0].PredSwizzleZ; 830 swizzle[3] = dst[0].PredSwizzleW; 831 } 832 833 insn = ureg_emit_insn(ureg, 834 opcode, 835 saturate, 836 predicate, 837 negate, 838 swizzle[0], 839 swizzle[1], 840 swizzle[2], 841 swizzle[3], 842 nr_dst, 843 nr_src); 844 845 ureg_emit_texture( ureg, insn.extended_token, target ); 846 847 for (i = 0; i < nr_dst; i++) 848 ureg_emit_dst( ureg, dst[i] ); 849 850 for (i = 0; i < nr_src; i++) 851 ureg_emit_src( ureg, src[i] ); 852 853 ureg_fixup_insn_size( ureg, insn.insn_token ); 854} 855 856 857void 858ureg_label_insn(struct ureg_program *ureg, 859 unsigned opcode, 860 const struct ureg_src *src, 861 unsigned nr_src, 862 unsigned *label_token ) 863{ 864 struct ureg_emit_insn_result insn; 865 unsigned i; 866 867 insn = ureg_emit_insn(ureg, 868 opcode, 869 FALSE, 870 FALSE, 871 FALSE, 872 TGSI_SWIZZLE_X, 873 TGSI_SWIZZLE_Y, 874 TGSI_SWIZZLE_Z, 875 TGSI_SWIZZLE_W, 876 0, 877 nr_src); 878 879 ureg_emit_label( ureg, insn.extended_token, label_token ); 880 881 for (i = 0; i < nr_src; i++) 882 ureg_emit_src( ureg, src[i] ); 883 884 ureg_fixup_insn_size( ureg, insn.insn_token ); 885} 886 887 888 889static void emit_decl( struct ureg_program *ureg, 890 unsigned file, 891 unsigned index, 892 unsigned semantic_name, 893 unsigned semantic_index, 894 unsigned interp ) 895{ 896 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 897 898 out[0].value = 0; 899 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 900 out[0].decl.NrTokens = 3; 901 out[0].decl.File = file; 902 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 903 out[0].decl.Interpolate = interp; 904 out[0].decl.Semantic = 1; 905 906 out[1].value = 0; 907 out[1].decl_range.First = 908 out[1].decl_range.Last = index; 909 910 out[2].value = 0; 911 out[2].decl_semantic.Name = semantic_name; 912 out[2].decl_semantic.Index = semantic_index; 913 914} 915 916 917static void emit_decl_range( struct ureg_program *ureg, 918 unsigned file, 919 unsigned first, 920 unsigned count ) 921{ 922 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 923 924 out[0].value = 0; 925 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 926 out[0].decl.NrTokens = 2; 927 out[0].decl.File = file; 928 out[0].decl.UsageMask = 0xf; 929 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 930 out[0].decl.Semantic = 0; 931 932 out[1].value = 0; 933 out[1].decl_range.First = first; 934 out[1].decl_range.Last = first + count - 1; 935} 936 937static void emit_immediate( struct ureg_program *ureg, 938 const float *v ) 939{ 940 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); 941 942 out[0].value = 0; 943 out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; 944 out[0].imm.NrTokens = 5; 945 out[0].imm.DataType = TGSI_IMM_FLOAT32; 946 out[0].imm.Padding = 0; 947 948 out[1].imm_data.Float = v[0]; 949 out[2].imm_data.Float = v[1]; 950 out[3].imm_data.Float = v[2]; 951 out[4].imm_data.Float = v[3]; 952} 953 954 955 956 957static void emit_decls( struct ureg_program *ureg ) 958{ 959 unsigned i; 960 961 if (ureg->processor == TGSI_PROCESSOR_VERTEX) { 962 for (i = 0; i < UREG_MAX_INPUT; i++) { 963 if (ureg->vs_inputs[i/32] & (1 << (i%32))) { 964 emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); 965 } 966 } 967 } 968 else { 969 for (i = 0; i < ureg->nr_fs_inputs; i++) { 970 emit_decl( ureg, 971 TGSI_FILE_INPUT, 972 i, 973 ureg->fs_input[i].semantic_name, 974 ureg->fs_input[i].semantic_index, 975 ureg->fs_input[i].interp ); 976 } 977 } 978 979 for (i = 0; i < ureg->nr_outputs; i++) { 980 emit_decl( ureg, 981 TGSI_FILE_OUTPUT, 982 i, 983 ureg->output[i].semantic_name, 984 ureg->output[i].semantic_index, 985 TGSI_INTERPOLATE_CONSTANT ); 986 } 987 988 for (i = 0; i < ureg->nr_samplers; i++) { 989 emit_decl_range( ureg, 990 TGSI_FILE_SAMPLER, 991 ureg->sampler[i].Index, 1 ); 992 } 993 994 if (ureg->nr_constant_ranges) { 995 for (i = 0; i < ureg->nr_constant_ranges; i++) 996 emit_decl_range( ureg, 997 TGSI_FILE_CONSTANT, 998 ureg->constant_range[i].first, 999 (ureg->constant_range[i].last + 1 - 1000 ureg->constant_range[i].first) ); 1001 } 1002 1003 if (ureg->nr_temps) { 1004 emit_decl_range( ureg, 1005 TGSI_FILE_TEMPORARY, 1006 0, ureg->nr_temps ); 1007 } 1008 1009 if (ureg->nr_addrs) { 1010 emit_decl_range( ureg, 1011 TGSI_FILE_ADDRESS, 1012 0, ureg->nr_addrs ); 1013 } 1014 1015 if (ureg->nr_loops) { 1016 emit_decl_range(ureg, 1017 TGSI_FILE_LOOP, 1018 0, 1019 ureg->nr_loops); 1020 } 1021 1022 if (ureg->nr_preds) { 1023 emit_decl_range(ureg, 1024 TGSI_FILE_PREDICATE, 1025 0, 1026 ureg->nr_preds); 1027 } 1028 1029 for (i = 0; i < ureg->nr_immediates; i++) { 1030 emit_immediate( ureg, 1031 ureg->immediate[i].v ); 1032 } 1033} 1034 1035/* Append the instruction tokens onto the declarations to build a 1036 * contiguous stream suitable to send to the driver. 1037 */ 1038static void copy_instructions( struct ureg_program *ureg ) 1039{ 1040 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 1041 union tgsi_any_token *out = get_tokens( ureg, 1042 DOMAIN_DECL, 1043 nr_tokens ); 1044 1045 memcpy(out, 1046 ureg->domain[DOMAIN_INSN].tokens, 1047 nr_tokens * sizeof out[0] ); 1048} 1049 1050 1051static void 1052fixup_header_size(struct ureg_program *ureg) 1053{ 1054 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 0 ); 1055 1056 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3; 1057} 1058 1059 1060static void 1061emit_header( struct ureg_program *ureg ) 1062{ 1063 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 1064 1065 out[0].header.HeaderSize = 2; 1066 out[0].header.BodySize = 0; 1067 1068 out[1].processor.Processor = ureg->processor; 1069 out[1].processor.Padding = 0; 1070} 1071 1072 1073const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) 1074{ 1075 const struct tgsi_token *tokens; 1076 1077 emit_header( ureg ); 1078 emit_decls( ureg ); 1079 copy_instructions( ureg ); 1080 fixup_header_size( ureg ); 1081 1082 if (ureg->domain[0].tokens == error_tokens || 1083 ureg->domain[1].tokens == error_tokens) { 1084 debug_printf("%s: error in generated shader\n", __FUNCTION__); 1085 assert(0); 1086 return NULL; 1087 } 1088 1089 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1090 1091 if (0) { 1092 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 1093 ureg->domain[DOMAIN_DECL].count); 1094 tgsi_dump( tokens, 0 ); 1095 } 1096 1097#if DEBUG 1098 if (tokens && !tgsi_sanity_check(tokens)) { 1099 debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); 1100 tgsi_dump(tokens, 0); 1101 assert(0); 1102 } 1103#endif 1104 1105 1106 return tokens; 1107} 1108 1109 1110void *ureg_create_shader( struct ureg_program *ureg, 1111 struct pipe_context *pipe ) 1112{ 1113 struct pipe_shader_state state; 1114 1115 state.tokens = ureg_finalize(ureg); 1116 if(!state.tokens) 1117 return NULL; 1118 1119 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 1120 return pipe->create_vs_state( pipe, &state ); 1121 else 1122 return pipe->create_fs_state( pipe, &state ); 1123} 1124 1125 1126const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg, 1127 unsigned *nr_tokens ) 1128{ 1129 const struct tgsi_token *tokens; 1130 1131 ureg_finalize(ureg); 1132 1133 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1134 1135 if (nr_tokens) 1136 *nr_tokens = ureg->domain[DOMAIN_DECL].size; 1137 1138 ureg->domain[DOMAIN_DECL].tokens = 0; 1139 ureg->domain[DOMAIN_DECL].size = 0; 1140 ureg->domain[DOMAIN_DECL].order = 0; 1141 ureg->domain[DOMAIN_DECL].count = 0; 1142 1143 return tokens; 1144} 1145 1146 1147struct ureg_program *ureg_create( unsigned processor ) 1148{ 1149 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 1150 if (ureg == NULL) 1151 return NULL; 1152 1153 ureg->processor = processor; 1154 return ureg; 1155} 1156 1157 1158void ureg_destroy( struct ureg_program *ureg ) 1159{ 1160 unsigned i; 1161 1162 for (i = 0; i < Elements(ureg->domain); i++) { 1163 if (ureg->domain[i].tokens && 1164 ureg->domain[i].tokens != error_tokens) 1165 FREE(ureg->domain[i].tokens); 1166 } 1167 1168 FREE(ureg); 1169} 1170