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