tgsi_ureg.c revision 5ee0d9f632383339088cc33005b7794b0915d4e0
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_ext_label insn_ext_label; 52 struct tgsi_instruction_ext_texture insn_ext_texture; 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].insn = tgsi_default_instruction(); 665 out[0].insn.Opcode = opcode; 666 out[0].insn.Saturate = saturate; 667 out[0].insn.NumDstRegs = num_dst; 668 out[0].insn.NumSrcRegs = num_src; 669 670 result.insn_token = ureg->domain[DOMAIN_INSN].count - count; 671 result.extended_token = result.insn_token; 672 673 if (predicate) { 674 out[0].insn.Predicate = 1; 675 out[1].insn_predicate = tgsi_default_instruction_predicate(); 676 out[1].insn_predicate.Negate = pred_negate; 677 out[1].insn_predicate.SwizzleX = pred_swizzle_x; 678 out[1].insn_predicate.SwizzleY = pred_swizzle_y; 679 out[1].insn_predicate.SwizzleZ = pred_swizzle_z; 680 out[1].insn_predicate.SwizzleW = pred_swizzle_w; 681 } 682 683 ureg->nr_instructions++; 684 685 return result; 686} 687 688 689void 690ureg_emit_label(struct ureg_program *ureg, 691 unsigned extended_token, 692 unsigned *label_token ) 693{ 694 union tgsi_any_token *out, *insn; 695 696 if(!label_token) 697 return; 698 699 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 700 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 701 702 insn->token.Extended = 1; 703 704 out[0].value = 0; 705 out[0].insn_ext_label.Type = TGSI_INSTRUCTION_EXT_TYPE_LABEL; 706 707 *label_token = ureg->domain[DOMAIN_INSN].count - 1; 708} 709 710/* Will return a number which can be used in a label to point to the 711 * next instruction to be emitted. 712 */ 713unsigned 714ureg_get_instruction_number( struct ureg_program *ureg ) 715{ 716 return ureg->nr_instructions; 717} 718 719/* Patch a given label (expressed as a token number) to point to a 720 * given instruction (expressed as an instruction number). 721 */ 722void 723ureg_fixup_label(struct ureg_program *ureg, 724 unsigned label_token, 725 unsigned instruction_number ) 726{ 727 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); 728 729 assert(out->insn_ext_label.Type == TGSI_INSTRUCTION_EXT_TYPE_LABEL); 730 out->insn_ext_label.Label = instruction_number; 731} 732 733 734void 735ureg_emit_texture(struct ureg_program *ureg, 736 unsigned extended_token, 737 unsigned target ) 738{ 739 union tgsi_any_token *out, *insn; 740 741 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 742 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 743 744 insn->token.Extended = 1; 745 746 out[0].value = 0; 747 out[0].insn_ext_texture.Type = TGSI_INSTRUCTION_EXT_TYPE_TEXTURE; 748 out[0].insn_ext_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 out[0].imm.Extended = 0; 950 951 out[1].imm_data.Float = v[0]; 952 out[2].imm_data.Float = v[1]; 953 out[3].imm_data.Float = v[2]; 954 out[4].imm_data.Float = v[3]; 955} 956 957 958 959 960static void emit_decls( struct ureg_program *ureg ) 961{ 962 unsigned i; 963 964 if (ureg->processor == TGSI_PROCESSOR_VERTEX) { 965 for (i = 0; i < UREG_MAX_INPUT; i++) { 966 if (ureg->vs_inputs[i/32] & (1 << (i%32))) { 967 emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); 968 } 969 } 970 } 971 else { 972 for (i = 0; i < ureg->nr_fs_inputs; i++) { 973 emit_decl( ureg, 974 TGSI_FILE_INPUT, 975 i, 976 ureg->fs_input[i].semantic_name, 977 ureg->fs_input[i].semantic_index, 978 ureg->fs_input[i].interp ); 979 } 980 } 981 982 for (i = 0; i < ureg->nr_outputs; i++) { 983 emit_decl( ureg, 984 TGSI_FILE_OUTPUT, 985 i, 986 ureg->output[i].semantic_name, 987 ureg->output[i].semantic_index, 988 TGSI_INTERPOLATE_CONSTANT ); 989 } 990 991 for (i = 0; i < ureg->nr_samplers; i++) { 992 emit_decl_range( ureg, 993 TGSI_FILE_SAMPLER, 994 ureg->sampler[i].Index, 1 ); 995 } 996 997 if (ureg->nr_constant_ranges) { 998 for (i = 0; i < ureg->nr_constant_ranges; i++) 999 emit_decl_range( ureg, 1000 TGSI_FILE_CONSTANT, 1001 ureg->constant_range[i].first, 1002 (ureg->constant_range[i].last + 1 - 1003 ureg->constant_range[i].first) ); 1004 } 1005 1006 if (ureg->nr_temps) { 1007 emit_decl_range( ureg, 1008 TGSI_FILE_TEMPORARY, 1009 0, ureg->nr_temps ); 1010 } 1011 1012 if (ureg->nr_addrs) { 1013 emit_decl_range( ureg, 1014 TGSI_FILE_ADDRESS, 1015 0, ureg->nr_addrs ); 1016 } 1017 1018 if (ureg->nr_preds) { 1019 emit_decl_range(ureg, 1020 TGSI_FILE_PREDICATE, 1021 0, 1022 ureg->nr_preds); 1023 } 1024 1025 for (i = 0; i < ureg->nr_immediates; i++) { 1026 emit_immediate( ureg, 1027 ureg->immediate[i].v ); 1028 } 1029} 1030 1031/* Append the instruction tokens onto the declarations to build a 1032 * contiguous stream suitable to send to the driver. 1033 */ 1034static void copy_instructions( struct ureg_program *ureg ) 1035{ 1036 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 1037 union tgsi_any_token *out = get_tokens( ureg, 1038 DOMAIN_DECL, 1039 nr_tokens ); 1040 1041 memcpy(out, 1042 ureg->domain[DOMAIN_INSN].tokens, 1043 nr_tokens * sizeof out[0] ); 1044} 1045 1046 1047static void 1048fixup_header_size(struct ureg_program *ureg) 1049{ 1050 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 1 ); 1051 1052 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3; 1053} 1054 1055 1056static void 1057emit_header( struct ureg_program *ureg ) 1058{ 1059 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 1060 1061 out[0].version.MajorVersion = 1; 1062 out[0].version.MinorVersion = 1; 1063 out[0].version.Padding = 0; 1064 1065 out[1].header.HeaderSize = 2; 1066 out[1].header.BodySize = 0; 1067 1068 out[2].processor.Processor = ureg->processor; 1069 out[2].processor.Padding = 0; 1070} 1071 1072 1073const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) 1074{ 1075 const struct tgsi_token *tokens; 1076 1077 emit_header( ureg ); 1078 emit_decls( ureg ); 1079 copy_instructions( ureg ); 1080 fixup_header_size( ureg ); 1081 1082 if (ureg->domain[0].tokens == error_tokens || 1083 ureg->domain[1].tokens == error_tokens) { 1084 debug_printf("%s: error in generated shader\n", __FUNCTION__); 1085 assert(0); 1086 return NULL; 1087 } 1088 1089 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1090 1091 if (0) { 1092 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 1093 ureg->domain[DOMAIN_DECL].count); 1094 tgsi_dump( tokens, 0 ); 1095 } 1096 1097#if DEBUG 1098 if (tokens && !tgsi_sanity_check(tokens)) { 1099 debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); 1100 tgsi_dump(tokens, 0); 1101 assert(0); 1102 } 1103#endif 1104 1105 1106 return tokens; 1107} 1108 1109 1110void *ureg_create_shader( struct ureg_program *ureg, 1111 struct pipe_context *pipe ) 1112{ 1113 struct pipe_shader_state state; 1114 1115 state.tokens = ureg_finalize(ureg); 1116 if(!state.tokens) 1117 return NULL; 1118 1119 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 1120 return pipe->create_vs_state( pipe, &state ); 1121 else 1122 return pipe->create_fs_state( pipe, &state ); 1123} 1124 1125 1126const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg, 1127 unsigned *nr_tokens ) 1128{ 1129 const struct tgsi_token *tokens; 1130 1131 ureg_finalize(ureg); 1132 1133 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1134 1135 if (nr_tokens) 1136 *nr_tokens = ureg->domain[DOMAIN_DECL].size; 1137 1138 ureg->domain[DOMAIN_DECL].tokens = 0; 1139 ureg->domain[DOMAIN_DECL].size = 0; 1140 ureg->domain[DOMAIN_DECL].order = 0; 1141 ureg->domain[DOMAIN_DECL].count = 0; 1142 1143 return tokens; 1144} 1145 1146 1147struct ureg_program *ureg_create( unsigned processor ) 1148{ 1149 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 1150 if (ureg == NULL) 1151 return NULL; 1152 1153 ureg->processor = processor; 1154 return ureg; 1155} 1156 1157 1158void ureg_destroy( struct ureg_program *ureg ) 1159{ 1160 unsigned i; 1161 1162 for (i = 0; i < Elements(ureg->domain); i++) { 1163 if (ureg->domain[i].tokens && 1164 ureg->domain[i].tokens != error_tokens) 1165 FREE(ureg->domain[i].tokens); 1166 } 1167 1168 FREE(ureg); 1169} 1170