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