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