tgsi_ureg.c revision 962ece954068646f8e2c0e9ea81395ab7eaf5ee8
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_ext_label insn_ext_label; 51 struct tgsi_instruction_ext_texture insn_ext_texture; 52 struct tgsi_instruction_ext_predicate insn_ext_predicate; 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_PRED 1 76 77#define DOMAIN_DECL 0 78#define DOMAIN_INSN 1 79 80struct ureg_program 81{ 82 unsigned processor; 83 struct pipe_context *pipe; 84 85 struct { 86 unsigned semantic_name; 87 unsigned semantic_index; 88 unsigned interp; 89 } fs_input[UREG_MAX_INPUT]; 90 unsigned nr_fs_inputs; 91 92 unsigned vs_inputs[UREG_MAX_INPUT/32]; 93 94 struct { 95 unsigned semantic_name; 96 unsigned semantic_index; 97 } output[UREG_MAX_OUTPUT]; 98 unsigned nr_outputs; 99 100 struct { 101 float v[4]; 102 unsigned nr; 103 } immediate[UREG_MAX_IMMEDIATE]; 104 unsigned nr_immediates; 105 106 struct ureg_src sampler[PIPE_MAX_SAMPLERS]; 107 unsigned nr_samplers; 108 109 unsigned temps_active[UREG_MAX_TEMP / 32]; 110 unsigned nr_temps; 111 112 struct { 113 unsigned first; 114 unsigned last; 115 } constant_range[UREG_MAX_CONSTANT_RANGE]; 116 unsigned nr_constant_ranges; 117 118 unsigned nr_addrs; 119 unsigned nr_preds; 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 goto fail; 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 goto fail; 155 156 return; 157 158fail: 159 tokens_error(tokens); 160} 161 162static void set_bad( struct ureg_program *ureg ) 163{ 164 tokens_error(&ureg->domain[0]); 165} 166 167 168 169static union tgsi_any_token *get_tokens( struct ureg_program *ureg, 170 unsigned domain, 171 unsigned count ) 172{ 173 struct ureg_tokens *tokens = &ureg->domain[domain]; 174 union tgsi_any_token *result; 175 176 if (tokens->count + count > tokens->size) 177 tokens_expand(tokens, count); 178 179 result = &tokens->tokens[tokens->count]; 180 tokens->count += count; 181 return result; 182} 183 184 185static union tgsi_any_token *retrieve_token( struct ureg_program *ureg, 186 unsigned domain, 187 unsigned nr ) 188{ 189 if (ureg->domain[domain].tokens == error_tokens) 190 return &error_tokens[0]; 191 192 return &ureg->domain[domain].tokens[nr]; 193} 194 195 196 197static INLINE struct ureg_dst 198ureg_dst_register( unsigned file, 199 unsigned index ) 200{ 201 struct ureg_dst dst; 202 203 dst.File = file; 204 dst.WriteMask = TGSI_WRITEMASK_XYZW; 205 dst.Indirect = 0; 206 dst.IndirectIndex = 0; 207 dst.IndirectSwizzle = 0; 208 dst.Saturate = 0; 209 dst.Index = index; 210 dst.Pad1 = 0; 211 dst.Pad2 = 0; 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 predicate register. 420 */ 421struct ureg_dst 422ureg_DECL_predicate(struct ureg_program *ureg) 423{ 424 if (ureg->nr_preds < UREG_MAX_PRED) { 425 return ureg_dst_register(TGSI_FILE_PREDICATE, ureg->nr_preds++); 426 } 427 428 assert(0); 429 return ureg_dst_register(TGSI_FILE_PREDICATE, 0); 430} 431 432/* Allocate a new sampler. 433 */ 434struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, 435 unsigned nr ) 436{ 437 unsigned i; 438 439 for (i = 0; i < ureg->nr_samplers; i++) 440 if (ureg->sampler[i].Index == nr) 441 return ureg->sampler[i]; 442 443 if (i < PIPE_MAX_SAMPLERS) { 444 ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); 445 ureg->nr_samplers++; 446 return ureg->sampler[i]; 447 } 448 449 assert( 0 ); 450 return ureg->sampler[0]; 451} 452 453 454 455 456static int match_or_expand_immediate( const float *v, 457 unsigned nr, 458 float *v2, 459 unsigned *nr2, 460 unsigned *swizzle ) 461{ 462 unsigned i, j; 463 464 *swizzle = 0; 465 466 for (i = 0; i < nr; i++) { 467 boolean found = FALSE; 468 469 for (j = 0; j < *nr2 && !found; j++) { 470 if (v[i] == v2[j]) { 471 *swizzle |= j << (i * 2); 472 found = TRUE; 473 } 474 } 475 476 if (!found) { 477 if (*nr2 >= 4) 478 return FALSE; 479 480 v2[*nr2] = v[i]; 481 *swizzle |= *nr2 << (i * 2); 482 (*nr2)++; 483 } 484 } 485 486 return TRUE; 487} 488 489 490 491 492struct ureg_src ureg_DECL_immediate( struct ureg_program *ureg, 493 const float *v, 494 unsigned nr ) 495{ 496 unsigned i, j; 497 unsigned swizzle; 498 499 /* Could do a first pass where we examine all existing immediates 500 * without expanding. 501 */ 502 503 for (i = 0; i < ureg->nr_immediates; i++) { 504 if (match_or_expand_immediate( v, 505 nr, 506 ureg->immediate[i].v, 507 &ureg->immediate[i].nr, 508 &swizzle )) 509 goto out; 510 } 511 512 if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { 513 i = ureg->nr_immediates++; 514 if (match_or_expand_immediate( v, 515 nr, 516 ureg->immediate[i].v, 517 &ureg->immediate[i].nr, 518 &swizzle )) 519 goto out; 520 } 521 522 set_bad( ureg ); 523 524out: 525 /* Make sure that all referenced elements are from this immediate. 526 * Has the effect of making size-one immediates into scalars. 527 */ 528 for (j = nr; j < 4; j++) 529 swizzle |= (swizzle & 0x3) << (j * 2); 530 531 return ureg_swizzle( ureg_src_register( TGSI_FILE_IMMEDIATE, i ), 532 (swizzle >> 0) & 0x3, 533 (swizzle >> 2) & 0x3, 534 (swizzle >> 4) & 0x3, 535 (swizzle >> 6) & 0x3); 536} 537 538 539void 540ureg_emit_src( struct ureg_program *ureg, 541 struct ureg_src src ) 542{ 543 unsigned size = (1 + 544 (src.Absolute ? 1 : 0) + 545 (src.Indirect ? 1 : 0)); 546 547 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 548 unsigned n = 0; 549 550 assert(src.File != TGSI_FILE_NULL); 551 assert(src.File != TGSI_FILE_OUTPUT); 552 assert(src.File < TGSI_FILE_COUNT); 553 554 out[n].value = 0; 555 out[n].src.File = src.File; 556 out[n].src.SwizzleX = src.SwizzleX; 557 out[n].src.SwizzleY = src.SwizzleY; 558 out[n].src.SwizzleZ = src.SwizzleZ; 559 out[n].src.SwizzleW = src.SwizzleW; 560 out[n].src.Index = src.Index; 561 out[n].src.Negate = src.Negate; 562 n++; 563 564 if (src.Absolute) { 565 out[0].src.Extended = 1; 566 out[0].src.Negate = 0; 567 out[n].value = 0; 568 out[n].src_ext_mod.Type = TGSI_SRC_REGISTER_EXT_TYPE_MOD; 569 out[n].src_ext_mod.Absolute = 1; 570 out[n].src_ext_mod.Negate = src.Negate; 571 n++; 572 } 573 574 if (src.Indirect) { 575 out[0].src.Indirect = 1; 576 out[n].value = 0; 577 out[n].src.File = TGSI_FILE_ADDRESS; 578 out[n].src.SwizzleX = src.IndirectSwizzle; 579 out[n].src.SwizzleY = src.IndirectSwizzle; 580 out[n].src.SwizzleZ = src.IndirectSwizzle; 581 out[n].src.SwizzleW = src.IndirectSwizzle; 582 out[n].src.Index = src.IndirectIndex; 583 n++; 584 } 585 586 assert(n == size); 587} 588 589 590void 591ureg_emit_dst( struct ureg_program *ureg, 592 struct ureg_dst dst ) 593{ 594 unsigned size = (1 + 595 (dst.Indirect ? 1 : 0)); 596 597 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 598 unsigned n = 0; 599 600 assert(dst.File != TGSI_FILE_NULL); 601 assert(dst.File != TGSI_FILE_CONSTANT); 602 assert(dst.File != TGSI_FILE_INPUT); 603 assert(dst.File != TGSI_FILE_SAMPLER); 604 assert(dst.File != TGSI_FILE_IMMEDIATE); 605 assert(dst.File < TGSI_FILE_COUNT); 606 607 out[n].value = 0; 608 out[n].dst.File = dst.File; 609 out[n].dst.WriteMask = dst.WriteMask; 610 out[n].dst.Indirect = dst.Indirect; 611 out[n].dst.Index = dst.Index; 612 n++; 613 614 if (dst.Indirect) { 615 out[n].value = 0; 616 out[n].src.File = TGSI_FILE_ADDRESS; 617 out[n].src.SwizzleX = dst.IndirectSwizzle; 618 out[n].src.SwizzleY = dst.IndirectSwizzle; 619 out[n].src.SwizzleZ = dst.IndirectSwizzle; 620 out[n].src.SwizzleW = dst.IndirectSwizzle; 621 out[n].src.Index = dst.IndirectIndex; 622 n++; 623 } 624 625 assert(n == size); 626} 627 628 629static void validate( unsigned opcode, 630 unsigned nr_dst, 631 unsigned nr_src ) 632{ 633#ifdef DEBUG 634 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); 635 assert(info); 636 if(info) { 637 assert(nr_dst == info->num_dst); 638 assert(nr_src == info->num_src); 639 } 640#endif 641} 642 643unsigned 644ureg_emit_insn(struct ureg_program *ureg, 645 unsigned opcode, 646 boolean saturate, 647 boolean predicate, 648 unsigned num_dst, 649 unsigned num_src ) 650{ 651 union tgsi_any_token *out; 652 uint count = predicate ? 2 : 1; 653 654 validate( opcode, num_dst, num_src ); 655 656 out = get_tokens( ureg, DOMAIN_INSN, count ); 657 out[0].value = 0; 658 out[0].insn.Type = TGSI_TOKEN_TYPE_INSTRUCTION; 659 out[0].insn.NrTokens = 0; 660 out[0].insn.Opcode = opcode; 661 out[0].insn.Saturate = saturate; 662 out[0].insn.NumDstRegs = num_dst; 663 out[0].insn.NumSrcRegs = num_src; 664 out[0].insn.Padding = 0; 665 666 if (predicate) { 667 out[0].insn.Extended = 1; 668 out[1].insn_ext_predicate = tgsi_default_instruction_ext_predicate(); 669 } else { 670 out[0].insn.Extended = 0; 671 } 672 673 ureg->nr_instructions++; 674 675 return ureg->domain[DOMAIN_INSN].count - count; 676} 677 678 679void 680ureg_emit_label(struct ureg_program *ureg, 681 unsigned insn_token, 682 unsigned *label_token ) 683{ 684 union tgsi_any_token *out, *insn; 685 686 if(!label_token) 687 return; 688 689 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 690 insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); 691 692 insn->insn.Extended = 1; 693 694 out[0].value = 0; 695 out[0].insn_ext_label.Type = TGSI_INSTRUCTION_EXT_TYPE_LABEL; 696 697 *label_token = ureg->domain[DOMAIN_INSN].count - 1; 698} 699 700/* Will return a number which can be used in a label to point to the 701 * next instruction to be emitted. 702 */ 703unsigned 704ureg_get_instruction_number( struct ureg_program *ureg ) 705{ 706 return ureg->nr_instructions; 707} 708 709/* Patch a given label (expressed as a token number) to point to a 710 * given instruction (expressed as an instruction number). 711 */ 712void 713ureg_fixup_label(struct ureg_program *ureg, 714 unsigned label_token, 715 unsigned instruction_number ) 716{ 717 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); 718 719 assert(out->insn_ext_label.Type == TGSI_INSTRUCTION_EXT_TYPE_LABEL); 720 out->insn_ext_label.Label = instruction_number; 721} 722 723 724void 725ureg_emit_texture(struct ureg_program *ureg, 726 unsigned insn_token, 727 unsigned target ) 728{ 729 union tgsi_any_token *out, *insn; 730 731 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 732 insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); 733 734 insn->insn.Extended = 1; 735 736 out[0].value = 0; 737 out[0].insn_ext_texture.Type = TGSI_INSTRUCTION_EXT_TYPE_TEXTURE; 738 out[0].insn_ext_texture.Texture = target; 739} 740 741 742void 743ureg_fixup_insn_size(struct ureg_program *ureg, 744 unsigned insn ) 745{ 746 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); 747 748 assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 749 out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; 750} 751 752 753void 754ureg_insn(struct ureg_program *ureg, 755 unsigned opcode, 756 const struct ureg_dst *dst, 757 unsigned nr_dst, 758 const struct ureg_src *src, 759 unsigned nr_src ) 760{ 761 unsigned insn, i; 762 boolean saturate; 763 boolean predicate; 764 765 saturate = nr_dst ? dst[0].Saturate : FALSE; 766 predicate = nr_dst ? dst[0].Predicate : FALSE; 767 768 insn = ureg_emit_insn( ureg, opcode, saturate, predicate, nr_dst, nr_src ); 769 770 for (i = 0; i < nr_dst; i++) 771 ureg_emit_dst( ureg, dst[i] ); 772 773 for (i = 0; i < nr_src; i++) 774 ureg_emit_src( ureg, src[i] ); 775 776 ureg_fixup_insn_size( ureg, insn ); 777} 778 779void 780ureg_tex_insn(struct ureg_program *ureg, 781 unsigned opcode, 782 const struct ureg_dst *dst, 783 unsigned nr_dst, 784 unsigned target, 785 const struct ureg_src *src, 786 unsigned nr_src ) 787{ 788 unsigned insn, i; 789 boolean saturate; 790 boolean predicate; 791 792 saturate = nr_dst ? dst[0].Saturate : FALSE; 793 predicate = nr_dst ? dst[0].Predicate : FALSE; 794 795 insn = ureg_emit_insn( ureg, opcode, saturate, predicate, nr_dst, nr_src ); 796 797 ureg_emit_texture( ureg, insn, target ); 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 ); 806} 807 808 809void 810ureg_label_insn(struct ureg_program *ureg, 811 unsigned opcode, 812 const struct ureg_src *src, 813 unsigned nr_src, 814 unsigned *label_token ) 815{ 816 unsigned insn, i; 817 818 insn = ureg_emit_insn( ureg, opcode, FALSE, FALSE, 0, nr_src ); 819 820 ureg_emit_label( ureg, insn, label_token ); 821 822 for (i = 0; i < nr_src; i++) 823 ureg_emit_src( ureg, src[i] ); 824 825 ureg_fixup_insn_size( ureg, insn ); 826} 827 828 829 830static void emit_decl( struct ureg_program *ureg, 831 unsigned file, 832 unsigned index, 833 unsigned semantic_name, 834 unsigned semantic_index, 835 unsigned interp ) 836{ 837 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 838 839 out[0].value = 0; 840 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 841 out[0].decl.NrTokens = 3; 842 out[0].decl.File = file; 843 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 844 out[0].decl.Interpolate = interp; 845 out[0].decl.Semantic = 1; 846 847 out[1].value = 0; 848 out[1].decl_range.First = 849 out[1].decl_range.Last = index; 850 851 out[2].value = 0; 852 out[2].decl_semantic.SemanticName = semantic_name; 853 out[2].decl_semantic.SemanticIndex = semantic_index; 854 855} 856 857 858static void emit_decl_range( struct ureg_program *ureg, 859 unsigned file, 860 unsigned first, 861 unsigned count ) 862{ 863 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 864 865 out[0].value = 0; 866 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 867 out[0].decl.NrTokens = 2; 868 out[0].decl.File = file; 869 out[0].decl.UsageMask = 0xf; 870 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 871 out[0].decl.Semantic = 0; 872 873 out[1].value = 0; 874 out[1].decl_range.First = first; 875 out[1].decl_range.Last = first + count - 1; 876} 877 878static void emit_immediate( struct ureg_program *ureg, 879 const float *v ) 880{ 881 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); 882 883 out[0].value = 0; 884 out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; 885 out[0].imm.NrTokens = 5; 886 out[0].imm.DataType = TGSI_IMM_FLOAT32; 887 out[0].imm.Padding = 0; 888 out[0].imm.Extended = 0; 889 890 out[1].imm_data.Float = v[0]; 891 out[2].imm_data.Float = v[1]; 892 out[3].imm_data.Float = v[2]; 893 out[4].imm_data.Float = v[3]; 894} 895 896 897 898 899static void emit_decls( struct ureg_program *ureg ) 900{ 901 unsigned i; 902 903 if (ureg->processor == TGSI_PROCESSOR_VERTEX) { 904 for (i = 0; i < UREG_MAX_INPUT; i++) { 905 if (ureg->vs_inputs[i/32] & (1 << (i%32))) { 906 emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); 907 } 908 } 909 } 910 else { 911 for (i = 0; i < ureg->nr_fs_inputs; i++) { 912 emit_decl( ureg, 913 TGSI_FILE_INPUT, 914 i, 915 ureg->fs_input[i].semantic_name, 916 ureg->fs_input[i].semantic_index, 917 ureg->fs_input[i].interp ); 918 } 919 } 920 921 for (i = 0; i < ureg->nr_outputs; i++) { 922 emit_decl( ureg, 923 TGSI_FILE_OUTPUT, 924 i, 925 ureg->output[i].semantic_name, 926 ureg->output[i].semantic_index, 927 TGSI_INTERPOLATE_CONSTANT ); 928 } 929 930 for (i = 0; i < ureg->nr_samplers; i++) { 931 emit_decl_range( ureg, 932 TGSI_FILE_SAMPLER, 933 ureg->sampler[i].Index, 1 ); 934 } 935 936 if (ureg->nr_constant_ranges) { 937 for (i = 0; i < ureg->nr_constant_ranges; i++) 938 emit_decl_range( ureg, 939 TGSI_FILE_CONSTANT, 940 ureg->constant_range[i].first, 941 (ureg->constant_range[i].last + 1 - 942 ureg->constant_range[i].first) ); 943 } 944 945 if (ureg->nr_temps) { 946 emit_decl_range( ureg, 947 TGSI_FILE_TEMPORARY, 948 0, ureg->nr_temps ); 949 } 950 951 if (ureg->nr_addrs) { 952 emit_decl_range( ureg, 953 TGSI_FILE_ADDRESS, 954 0, ureg->nr_addrs ); 955 } 956 957 if (ureg->nr_preds) { 958 emit_decl_range(ureg, 959 TGSI_FILE_PREDICATE, 960 0, 961 ureg->nr_preds); 962 } 963 964 for (i = 0; i < ureg->nr_immediates; i++) { 965 emit_immediate( ureg, 966 ureg->immediate[i].v ); 967 } 968} 969 970/* Append the instruction tokens onto the declarations to build a 971 * contiguous stream suitable to send to the driver. 972 */ 973static void copy_instructions( struct ureg_program *ureg ) 974{ 975 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 976 union tgsi_any_token *out = get_tokens( ureg, 977 DOMAIN_DECL, 978 nr_tokens ); 979 980 memcpy(out, 981 ureg->domain[DOMAIN_INSN].tokens, 982 nr_tokens * sizeof out[0] ); 983} 984 985 986static void 987fixup_header_size(struct ureg_program *ureg) 988{ 989 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 1 ); 990 991 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3; 992} 993 994 995static void 996emit_header( struct ureg_program *ureg ) 997{ 998 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 999 1000 out[0].version.MajorVersion = 1; 1001 out[0].version.MinorVersion = 1; 1002 out[0].version.Padding = 0; 1003 1004 out[1].header.HeaderSize = 2; 1005 out[1].header.BodySize = 0; 1006 1007 out[2].processor.Processor = ureg->processor; 1008 out[2].processor.Padding = 0; 1009} 1010 1011 1012const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) 1013{ 1014 const struct tgsi_token *tokens; 1015 1016 emit_header( ureg ); 1017 emit_decls( ureg ); 1018 copy_instructions( ureg ); 1019 fixup_header_size( ureg ); 1020 1021 if (ureg->domain[0].tokens == error_tokens || 1022 ureg->domain[1].tokens == error_tokens) { 1023 debug_printf("%s: error in generated shader\n", __FUNCTION__); 1024 assert(0); 1025 return NULL; 1026 } 1027 1028 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1029 1030 if (0) { 1031 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 1032 ureg->domain[DOMAIN_DECL].count); 1033 tgsi_dump( tokens, 0 ); 1034 } 1035 1036#if DEBUG 1037 if (tokens && !tgsi_sanity_check(tokens)) { 1038 debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); 1039 tgsi_dump(tokens, 0); 1040 assert(0); 1041 } 1042#endif 1043 1044 1045 return tokens; 1046} 1047 1048 1049void *ureg_create_shader( struct ureg_program *ureg, 1050 struct pipe_context *pipe ) 1051{ 1052 struct pipe_shader_state state; 1053 1054 state.tokens = ureg_finalize(ureg); 1055 if(!state.tokens) 1056 return NULL; 1057 1058 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 1059 return pipe->create_vs_state( pipe, &state ); 1060 else 1061 return pipe->create_fs_state( pipe, &state ); 1062} 1063 1064 1065const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg, 1066 unsigned *nr_tokens ) 1067{ 1068 const struct tgsi_token *tokens; 1069 1070 ureg_finalize(ureg); 1071 1072 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1073 1074 if (nr_tokens) 1075 *nr_tokens = ureg->domain[DOMAIN_DECL].size; 1076 1077 ureg->domain[DOMAIN_DECL].tokens = 0; 1078 ureg->domain[DOMAIN_DECL].size = 0; 1079 ureg->domain[DOMAIN_DECL].order = 0; 1080 ureg->domain[DOMAIN_DECL].count = 0; 1081 1082 return tokens; 1083} 1084 1085 1086struct ureg_program *ureg_create( unsigned processor ) 1087{ 1088 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 1089 if (ureg == NULL) 1090 return NULL; 1091 1092 ureg->processor = processor; 1093 return ureg; 1094} 1095 1096 1097void ureg_destroy( struct ureg_program *ureg ) 1098{ 1099 unsigned i; 1100 1101 for (i = 0; i < Elements(ureg->domain); i++) { 1102 if (ureg->domain[i].tokens && 1103 ureg->domain[i].tokens != error_tokens) 1104 FREE(ureg->domain[i].tokens); 1105 } 1106 1107 FREE(ureg); 1108} 1109