tgsi_ureg.c revision ae4704eabc237e13c9b06df9c44f31c9baca6208
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_swz src_ext_swz; 55 struct tgsi_src_register_ext_mod src_ext_mod; 56 struct tgsi_dimension dim; 57 struct tgsi_dst_register dst; 58 struct tgsi_dst_register_ext_concode dst_ext_code; 59 struct tgsi_dst_register_ext_modulate dst_ext_mod; 60 struct tgsi_dst_register_ext_predicate dst_ext_pred; 61 unsigned value; 62}; 63 64 65struct ureg_tokens { 66 union tgsi_any_token *tokens; 67 unsigned size; 68 unsigned order; 69 unsigned count; 70}; 71 72#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS 73#define UREG_MAX_OUTPUT PIPE_MAX_ATTRIBS 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 unsigned nr_addrs; 114 115 unsigned nr_constants; 116 unsigned nr_instructions; 117 118 struct ureg_tokens domain[2]; 119}; 120 121static union tgsi_any_token error_tokens[32]; 122 123static void tokens_error( struct ureg_tokens *tokens ) 124{ 125 if (tokens->tokens && tokens->tokens != error_tokens) 126 FREE(tokens->tokens); 127 128 tokens->tokens = error_tokens; 129 tokens->size = Elements(error_tokens); 130 tokens->count = 0; 131} 132 133 134static void tokens_expand( struct ureg_tokens *tokens, 135 unsigned count ) 136{ 137 unsigned old_size = tokens->size * sizeof(unsigned); 138 139 if (tokens->tokens == error_tokens) 140 goto fail; 141 142 while (tokens->count + count > tokens->size) { 143 tokens->size = (1 << ++tokens->order); 144 } 145 146 tokens->tokens = REALLOC(tokens->tokens, 147 old_size, 148 tokens->size * sizeof(unsigned)); 149 if (tokens->tokens == NULL) 150 goto fail; 151 152 return; 153 154fail: 155 tokens_error(tokens); 156} 157 158static void set_bad( struct ureg_program *ureg ) 159{ 160 tokens_error(&ureg->domain[0]); 161} 162 163 164 165static union tgsi_any_token *get_tokens( struct ureg_program *ureg, 166 unsigned domain, 167 unsigned count ) 168{ 169 struct ureg_tokens *tokens = &ureg->domain[domain]; 170 union tgsi_any_token *result; 171 172 if (tokens->count + count > tokens->size) 173 tokens_expand(tokens, count); 174 175 result = &tokens->tokens[tokens->count]; 176 tokens->count += count; 177 return result; 178} 179 180 181static union tgsi_any_token *retrieve_token( struct ureg_program *ureg, 182 unsigned domain, 183 unsigned nr ) 184{ 185 if (ureg->domain[domain].tokens == error_tokens) 186 return &error_tokens[0]; 187 188 return &ureg->domain[domain].tokens[nr]; 189} 190 191 192 193static INLINE struct ureg_dst 194ureg_dst_register( unsigned file, 195 unsigned index ) 196{ 197 struct ureg_dst dst; 198 199 dst.File = file; 200 dst.WriteMask = TGSI_WRITEMASK_XYZW; 201 dst.Indirect = 0; 202 dst.IndirectIndex = 0; 203 dst.IndirectSwizzle = 0; 204 dst.Saturate = 0; 205 dst.Index = index; 206 dst.Pad1 = 0; 207 dst.Pad2 = 0; 208 209 return dst; 210} 211 212static INLINE struct ureg_src 213ureg_src_register( unsigned file, 214 unsigned index ) 215{ 216 struct ureg_src src; 217 218 src.File = file; 219 src.SwizzleX = TGSI_SWIZZLE_X; 220 src.SwizzleY = TGSI_SWIZZLE_Y; 221 src.SwizzleZ = TGSI_SWIZZLE_Z; 222 src.SwizzleW = TGSI_SWIZZLE_W; 223 src.Pad = 0; 224 src.Indirect = 0; 225 src.IndirectIndex = 0; 226 src.IndirectSwizzle = 0; 227 src.Absolute = 0; 228 src.Index = index; 229 src.Negate = 0; 230 231 return src; 232} 233 234 235 236 237struct ureg_src 238ureg_DECL_fs_input( struct ureg_program *ureg, 239 unsigned name, 240 unsigned index, 241 unsigned interp_mode ) 242{ 243 unsigned i; 244 245 for (i = 0; i < ureg->nr_fs_inputs; i++) { 246 if (ureg->fs_input[i].semantic_name == name && 247 ureg->fs_input[i].semantic_index == index) 248 goto out; 249 } 250 251 if (ureg->nr_fs_inputs < UREG_MAX_INPUT) { 252 ureg->fs_input[i].semantic_name = name; 253 ureg->fs_input[i].semantic_index = index; 254 ureg->fs_input[i].interp = interp_mode; 255 ureg->nr_fs_inputs++; 256 } 257 else { 258 set_bad( ureg ); 259 } 260 261out: 262 return ureg_src_register( TGSI_FILE_INPUT, i ); 263} 264 265 266struct ureg_src 267ureg_DECL_vs_input( struct ureg_program *ureg, 268 unsigned index ) 269{ 270 assert(ureg->processor == TGSI_PROCESSOR_VERTEX); 271 272 ureg->vs_inputs[index/32] |= 1 << (index % 32); 273 return ureg_src_register( TGSI_FILE_INPUT, index ); 274} 275 276 277struct ureg_dst 278ureg_DECL_output( struct ureg_program *ureg, 279 unsigned name, 280 unsigned index ) 281{ 282 unsigned i; 283 284 for (i = 0; i < ureg->nr_outputs; i++) { 285 if (ureg->output[i].semantic_name == name && 286 ureg->output[i].semantic_index == index) 287 goto out; 288 } 289 290 if (ureg->nr_outputs < UREG_MAX_OUTPUT) { 291 ureg->output[i].semantic_name = name; 292 ureg->output[i].semantic_index = index; 293 ureg->nr_outputs++; 294 } 295 else { 296 set_bad( ureg ); 297 } 298 299out: 300 return ureg_dst_register( TGSI_FILE_OUTPUT, i ); 301} 302 303 304/* Returns a new constant register. Keep track of which have been 305 * referred to so that we can emit decls later. 306 * 307 * There is nothing in this code to bind this constant to any tracked 308 * value or manage any constant_buffer contents -- that's the 309 * resposibility of the calling code. 310 */ 311struct ureg_src ureg_DECL_constant(struct ureg_program *ureg, 312 unsigned index ) 313{ 314 315 316 return ureg_src_register( TGSI_FILE_CONSTANT, ureg->nr_constants++ ); 317} 318 319 320/* Allocate a new temporary. Temporaries greater than UREG_MAX_TEMP 321 * are legal, but will not be released. 322 */ 323struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) 324{ 325 unsigned i; 326 327 for (i = 0; i < UREG_MAX_TEMP; i += 32) { 328 int bit = ffs(~ureg->temps_active[i/32]); 329 if (bit != 0) { 330 i += bit - 1; 331 goto out; 332 } 333 } 334 335 /* No reusable temps, so allocate a new one: 336 */ 337 i = ureg->nr_temps++; 338 339out: 340 if (i < UREG_MAX_TEMP) 341 ureg->temps_active[i/32] |= 1 << (i % 32); 342 343 if (i >= ureg->nr_temps) 344 ureg->nr_temps = i + 1; 345 346 return ureg_dst_register( TGSI_FILE_TEMPORARY, i ); 347} 348 349 350void ureg_release_temporary( struct ureg_program *ureg, 351 struct ureg_dst tmp ) 352{ 353 if(tmp.File == TGSI_FILE_TEMPORARY) 354 if (tmp.Index < UREG_MAX_TEMP) 355 ureg->temps_active[tmp.Index/32] &= ~(1 << (tmp.Index % 32)); 356} 357 358 359/* Allocate a new address register. 360 */ 361struct ureg_dst ureg_DECL_address( struct ureg_program *ureg ) 362{ 363 if (ureg->nr_addrs < UREG_MAX_ADDR) 364 return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ ); 365 366 assert( 0 ); 367 return ureg_dst_register( TGSI_FILE_ADDRESS, 0 ); 368} 369 370/* Allocate a new sampler. 371 */ 372struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, 373 unsigned nr ) 374{ 375 unsigned i; 376 377 for (i = 0; i < ureg->nr_samplers; i++) 378 if (ureg->sampler[i].Index == nr) 379 return ureg->sampler[i]; 380 381 if (i < PIPE_MAX_SAMPLERS) { 382 ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); 383 ureg->nr_samplers++; 384 return ureg->sampler[i]; 385 } 386 387 assert( 0 ); 388 return ureg->sampler[0]; 389} 390 391 392 393 394static int match_or_expand_immediate( const float *v, 395 unsigned nr, 396 float *v2, 397 unsigned *nr2, 398 unsigned *swizzle ) 399{ 400 unsigned i, j; 401 402 *swizzle = 0; 403 404 for (i = 0; i < nr; i++) { 405 boolean found = FALSE; 406 407 for (j = 0; j < *nr2 && !found; j++) { 408 if (v[i] == v2[j]) { 409 *swizzle |= j << (i * 2); 410 found = TRUE; 411 } 412 } 413 414 if (!found) { 415 if (*nr2 >= 4) 416 return FALSE; 417 418 v2[*nr2] = v[i]; 419 *swizzle |= *nr2 << (i * 2); 420 (*nr2)++; 421 } 422 } 423 424 return TRUE; 425} 426 427 428 429 430struct ureg_src ureg_DECL_immediate( struct ureg_program *ureg, 431 const float *v, 432 unsigned nr ) 433{ 434 unsigned i, j; 435 unsigned swizzle; 436 437 /* Could do a first pass where we examine all existing immediates 438 * without expanding. 439 */ 440 441 for (i = 0; i < ureg->nr_immediates; i++) { 442 if (match_or_expand_immediate( v, 443 nr, 444 ureg->immediate[i].v, 445 &ureg->immediate[i].nr, 446 &swizzle )) 447 goto out; 448 } 449 450 if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { 451 i = ureg->nr_immediates++; 452 if (match_or_expand_immediate( v, 453 nr, 454 ureg->immediate[i].v, 455 &ureg->immediate[i].nr, 456 &swizzle )) 457 goto out; 458 } 459 460 set_bad( ureg ); 461 462out: 463 /* Make sure that all referenced elements are from this immediate. 464 * Has the effect of making size-one immediates into scalars. 465 */ 466 for (j = nr; j < 4; j++) 467 swizzle |= (swizzle & 0x3) << (j * 2); 468 469 return ureg_swizzle( ureg_src_register( TGSI_FILE_IMMEDIATE, i ), 470 (swizzle >> 0) & 0x3, 471 (swizzle >> 2) & 0x3, 472 (swizzle >> 4) & 0x3, 473 (swizzle >> 6) & 0x3); 474} 475 476 477void 478ureg_emit_src( struct ureg_program *ureg, 479 struct ureg_src src ) 480{ 481 unsigned size = (1 + 482 (src.Absolute ? 1 : 0) + 483 (src.Indirect ? 1 : 0)); 484 485 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 486 unsigned n = 0; 487 488 assert(src.File != TGSI_FILE_NULL); 489 assert(src.File != TGSI_FILE_OUTPUT); 490 assert(src.File < TGSI_FILE_COUNT); 491 492 out[n].value = 0; 493 out[n].src.File = src.File; 494 out[n].src.SwizzleX = src.SwizzleX; 495 out[n].src.SwizzleY = src.SwizzleY; 496 out[n].src.SwizzleZ = src.SwizzleZ; 497 out[n].src.SwizzleW = src.SwizzleW; 498 out[n].src.Index = src.Index; 499 out[n].src.Negate = src.Negate; 500 n++; 501 502 if (src.Absolute) { 503 out[0].src.Extended = 1; 504 out[0].src.Negate = 0; 505 out[n].value = 0; 506 out[n].src_ext_mod.Type = TGSI_SRC_REGISTER_EXT_TYPE_MOD; 507 out[n].src_ext_mod.Absolute = 1; 508 out[n].src_ext_mod.Negate = src.Negate; 509 n++; 510 } 511 512 if (src.Indirect) { 513 out[0].src.Indirect = 1; 514 out[n].value = 0; 515 out[n].src.File = TGSI_FILE_ADDRESS; 516 out[n].src.SwizzleX = src.IndirectSwizzle; 517 out[n].src.SwizzleY = src.IndirectSwizzle; 518 out[n].src.SwizzleZ = src.IndirectSwizzle; 519 out[n].src.SwizzleW = src.IndirectSwizzle; 520 out[n].src.Index = src.IndirectIndex; 521 n++; 522 } 523 524 assert(n == size); 525} 526 527 528void 529ureg_emit_dst( struct ureg_program *ureg, 530 struct ureg_dst dst ) 531{ 532 unsigned size = (1 + 533 (dst.Indirect ? 1 : 0)); 534 535 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 536 unsigned n = 0; 537 538 assert(dst.File != TGSI_FILE_NULL); 539 assert(dst.File != TGSI_FILE_CONSTANT); 540 assert(dst.File != TGSI_FILE_INPUT); 541 assert(dst.File != TGSI_FILE_SAMPLER); 542 assert(dst.File != TGSI_FILE_IMMEDIATE); 543 assert(dst.File < TGSI_FILE_COUNT); 544 545 out[n].value = 0; 546 out[n].dst.File = dst.File; 547 out[n].dst.WriteMask = dst.WriteMask; 548 out[n].dst.Indirect = dst.Indirect; 549 out[n].dst.Index = dst.Index; 550 n++; 551 552 if (dst.Indirect) { 553 out[n].value = 0; 554 out[n].src.File = TGSI_FILE_ADDRESS; 555 out[n].src.SwizzleX = dst.IndirectSwizzle; 556 out[n].src.SwizzleY = dst.IndirectSwizzle; 557 out[n].src.SwizzleZ = dst.IndirectSwizzle; 558 out[n].src.SwizzleW = dst.IndirectSwizzle; 559 out[n].src.Index = dst.IndirectIndex; 560 n++; 561 } 562 563 assert(n == size); 564} 565 566 567 568unsigned 569ureg_emit_insn(struct ureg_program *ureg, 570 unsigned opcode, 571 boolean saturate, 572 unsigned num_dst, 573 unsigned num_src ) 574{ 575 union tgsi_any_token *out; 576 577 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 578 out[0].value = 0; 579 out[0].insn.Type = TGSI_TOKEN_TYPE_INSTRUCTION; 580 out[0].insn.NrTokens = 0; 581 out[0].insn.Opcode = opcode; 582 out[0].insn.Saturate = saturate; 583 out[0].insn.NumDstRegs = num_dst; 584 out[0].insn.NumSrcRegs = num_src; 585 out[0].insn.Padding = 0; 586 out[0].insn.Extended = 0; 587 588 ureg->nr_instructions++; 589 590 return ureg->domain[DOMAIN_INSN].count - 1; 591} 592 593 594void 595ureg_emit_label(struct ureg_program *ureg, 596 unsigned insn_token, 597 unsigned *label_token ) 598{ 599 union tgsi_any_token *out, *insn; 600 601 if(!label_token) 602 return; 603 604 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 605 insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); 606 607 insn->insn.Extended = 1; 608 609 out[0].value = 0; 610 out[0].insn_ext_label.Type = TGSI_INSTRUCTION_EXT_TYPE_LABEL; 611 612 *label_token = ureg->domain[DOMAIN_INSN].count - 1; 613} 614 615/* Will return a number which can be used in a label to point to the 616 * next instruction to be emitted. 617 */ 618unsigned 619ureg_get_instruction_number( struct ureg_program *ureg ) 620{ 621 return ureg->nr_instructions; 622} 623 624/* Patch a given label (expressed as a token number) to point to a 625 * given instruction (expressed as an instruction number). 626 */ 627void 628ureg_fixup_label(struct ureg_program *ureg, 629 unsigned label_token, 630 unsigned instruction_number ) 631{ 632 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); 633 634 assert(out->insn_ext_label.Type == TGSI_INSTRUCTION_EXT_TYPE_LABEL); 635 out->insn_ext_label.Label = instruction_number; 636} 637 638 639void 640ureg_emit_texture(struct ureg_program *ureg, 641 unsigned insn_token, 642 unsigned target ) 643{ 644 union tgsi_any_token *out, *insn; 645 646 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 647 insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); 648 649 insn->insn.Extended = 1; 650 651 out[0].value = 0; 652 out[0].insn_ext_texture.Type = TGSI_INSTRUCTION_EXT_TYPE_TEXTURE; 653 out[0].insn_ext_texture.Texture = target; 654} 655 656 657void 658ureg_fixup_insn_size(struct ureg_program *ureg, 659 unsigned insn ) 660{ 661 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); 662 663 assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 664 out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; 665} 666 667 668void 669ureg_insn(struct ureg_program *ureg, 670 unsigned opcode, 671 const struct ureg_dst *dst, 672 unsigned nr_dst, 673 const struct ureg_src *src, 674 unsigned nr_src ) 675{ 676 unsigned insn, i; 677 boolean saturate; 678 679#ifdef DEBUG 680 { 681 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); 682 assert(info); 683 if(info) { 684 assert(nr_dst == info->num_dst); 685 assert(nr_src == info->num_src); 686 } 687 } 688#endif 689 690 saturate = nr_dst ? dst[0].Saturate : FALSE; 691 692 insn = ureg_emit_insn( ureg, opcode, saturate, nr_dst, nr_src ); 693 694 for (i = 0; i < nr_dst; i++) 695 ureg_emit_dst( ureg, dst[i] ); 696 697 for (i = 0; i < nr_src; i++) 698 ureg_emit_src( ureg, src[i] ); 699 700 ureg_fixup_insn_size( ureg, insn ); 701} 702 703 704 705static void emit_decl( struct ureg_program *ureg, 706 unsigned file, 707 unsigned index, 708 unsigned semantic_name, 709 unsigned semantic_index, 710 unsigned interp ) 711{ 712 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 713 714 out[0].value = 0; 715 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 716 out[0].decl.NrTokens = 3; 717 out[0].decl.File = file; 718 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 719 out[0].decl.Interpolate = interp; 720 out[0].decl.Semantic = 1; 721 722 out[1].value = 0; 723 out[1].decl_range.First = 724 out[1].decl_range.Last = index; 725 726 out[2].value = 0; 727 out[2].decl_semantic.SemanticName = semantic_name; 728 out[2].decl_semantic.SemanticIndex = semantic_index; 729 730} 731 732 733static void emit_decl_range( struct ureg_program *ureg, 734 unsigned file, 735 unsigned first, 736 unsigned count ) 737{ 738 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 739 740 out[0].value = 0; 741 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 742 out[0].decl.NrTokens = 2; 743 out[0].decl.File = file; 744 out[0].decl.UsageMask = 0xf; 745 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 746 out[0].decl.Semantic = 0; 747 748 out[1].value = 0; 749 out[1].decl_range.First = first; 750 out[1].decl_range.Last = first + count - 1; 751} 752 753static void emit_immediate( struct ureg_program *ureg, 754 const float *v ) 755{ 756 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); 757 758 out[0].value = 0; 759 out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; 760 out[0].imm.NrTokens = 5; 761 out[0].imm.DataType = TGSI_IMM_FLOAT32; 762 out[0].imm.Padding = 0; 763 out[0].imm.Extended = 0; 764 765 out[1].imm_data.Float = v[0]; 766 out[2].imm_data.Float = v[1]; 767 out[3].imm_data.Float = v[2]; 768 out[4].imm_data.Float = v[3]; 769} 770 771 772 773 774static void emit_decls( struct ureg_program *ureg ) 775{ 776 unsigned i; 777 778 if (ureg->processor == TGSI_PROCESSOR_VERTEX) { 779 for (i = 0; i < UREG_MAX_INPUT; i++) { 780 if (ureg->vs_inputs[i/32] & (1 << (i%32))) { 781 emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); 782 } 783 } 784 } 785 else { 786 for (i = 0; i < ureg->nr_fs_inputs; i++) { 787 emit_decl( ureg, 788 TGSI_FILE_INPUT, 789 i, 790 ureg->fs_input[i].semantic_name, 791 ureg->fs_input[i].semantic_index, 792 ureg->fs_input[i].interp ); 793 } 794 } 795 796 for (i = 0; i < ureg->nr_outputs; i++) { 797 emit_decl( ureg, 798 TGSI_FILE_OUTPUT, 799 i, 800 ureg->output[i].semantic_name, 801 ureg->output[i].semantic_index, 802 TGSI_INTERPOLATE_CONSTANT ); 803 } 804 805 for (i = 0; i < ureg->nr_samplers; i++) { 806 emit_decl_range( ureg, 807 TGSI_FILE_SAMPLER, 808 ureg->sampler[i].Index, 1 ); 809 } 810 811 if (ureg->nr_constants) { 812 emit_decl_range( ureg, 813 TGSI_FILE_CONSTANT, 814 0, ureg->nr_constants ); 815 } 816 817 if (ureg->nr_temps) { 818 emit_decl_range( ureg, 819 TGSI_FILE_TEMPORARY, 820 0, ureg->nr_temps ); 821 } 822 823 if (ureg->nr_addrs) { 824 emit_decl_range( ureg, 825 TGSI_FILE_ADDRESS, 826 0, ureg->nr_addrs ); 827 } 828 829 for (i = 0; i < ureg->nr_immediates; i++) { 830 emit_immediate( ureg, 831 ureg->immediate[i].v ); 832 } 833} 834 835/* Append the instruction tokens onto the declarations to build a 836 * contiguous stream suitable to send to the driver. 837 */ 838static void copy_instructions( struct ureg_program *ureg ) 839{ 840 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 841 union tgsi_any_token *out = get_tokens( ureg, 842 DOMAIN_DECL, 843 nr_tokens ); 844 845 memcpy(out, 846 ureg->domain[DOMAIN_INSN].tokens, 847 nr_tokens * sizeof out[0] ); 848} 849 850 851static void 852fixup_header_size(struct ureg_program *ureg) 853{ 854 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 1 ); 855 856 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3; 857} 858 859 860static void 861emit_header( struct ureg_program *ureg ) 862{ 863 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 864 865 out[0].version.MajorVersion = 1; 866 out[0].version.MinorVersion = 1; 867 out[0].version.Padding = 0; 868 869 out[1].header.HeaderSize = 2; 870 out[1].header.BodySize = 0; 871 872 out[2].processor.Processor = ureg->processor; 873 out[2].processor.Padding = 0; 874} 875 876 877const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) 878{ 879 const struct tgsi_token *tokens; 880 881 emit_header( ureg ); 882 emit_decls( ureg ); 883 copy_instructions( ureg ); 884 fixup_header_size( ureg ); 885 886 if (ureg->domain[0].tokens == error_tokens || 887 ureg->domain[1].tokens == error_tokens) { 888 debug_printf("%s: error in generated shader\n", __FUNCTION__); 889 assert(0); 890 return NULL; 891 } 892 893 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 894 895 if (0) { 896 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 897 ureg->domain[DOMAIN_DECL].count); 898 tgsi_dump( tokens, 0 ); 899 } 900 901#if DEBUG 902 if (tokens && !tgsi_sanity_check(tokens)) { 903 debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); 904 tgsi_dump(tokens, 0); 905 assert(0); 906 } 907#endif 908 909 910 return tokens; 911} 912 913 914void *ureg_create_shader( struct ureg_program *ureg, 915 struct pipe_context *pipe ) 916{ 917 struct pipe_shader_state state; 918 919 state.tokens = ureg_finalize(ureg); 920 if(!state.tokens) 921 return NULL; 922 923 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 924 return pipe->create_vs_state( pipe, &state ); 925 else 926 return pipe->create_fs_state( pipe, &state ); 927} 928 929 930 931 932struct ureg_program *ureg_create( unsigned processor ) 933{ 934 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 935 if (ureg == NULL) 936 return NULL; 937 938 ureg->processor = processor; 939 return ureg; 940} 941 942 943void ureg_destroy( struct ureg_program *ureg ) 944{ 945 unsigned i; 946 947 for (i = 0; i < Elements(ureg->domain); i++) { 948 if (ureg->domain[i].tokens && 949 ureg->domain[i].tokens != error_tokens) 950 FREE(ureg->domain[i].tokens); 951 } 952 953 FREE(ureg); 954} 955