tgsi_ureg.c revision 6d8dbd3d1ec888300fb0e9ac3cf61808ba8ecc2b
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{ 313 return ureg_src_register( TGSI_FILE_CONSTANT, ureg->nr_constants++ ); 314} 315 316 317/* Allocate a new temporary. Temporaries greater than UREG_MAX_TEMP 318 * are legal, but will not be released. 319 */ 320struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) 321{ 322 unsigned i; 323 324 for (i = 0; i < UREG_MAX_TEMP; i += 32) { 325 int bit = ffs(~ureg->temps_active[i/32]); 326 if (bit != 0) { 327 i += bit - 1; 328 goto out; 329 } 330 } 331 332 /* No reusable temps, so allocate a new one: 333 */ 334 i = ureg->nr_temps++; 335 336out: 337 if (i < UREG_MAX_TEMP) 338 ureg->temps_active[i/32] |= 1 << (i % 32); 339 340 if (i >= ureg->nr_temps) 341 ureg->nr_temps = i + 1; 342 343 return ureg_dst_register( TGSI_FILE_TEMPORARY, i ); 344} 345 346 347void ureg_release_temporary( struct ureg_program *ureg, 348 struct ureg_dst tmp ) 349{ 350 if(tmp.File == TGSI_FILE_TEMPORARY) 351 if (tmp.Index < UREG_MAX_TEMP) 352 ureg->temps_active[tmp.Index/32] &= ~(1 << (tmp.Index % 32)); 353} 354 355 356/* Allocate a new address register. 357 */ 358struct ureg_dst ureg_DECL_address( struct ureg_program *ureg ) 359{ 360 if (ureg->nr_addrs < UREG_MAX_ADDR) 361 return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ ); 362 363 assert( 0 ); 364 return ureg_dst_register( TGSI_FILE_ADDRESS, 0 ); 365} 366 367/* Allocate a new sampler. 368 */ 369struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, 370 unsigned nr ) 371{ 372 unsigned i; 373 374 for (i = 0; i < ureg->nr_samplers; i++) 375 if (ureg->sampler[i].Index == nr) 376 return ureg->sampler[i]; 377 378 if (i < PIPE_MAX_SAMPLERS) { 379 ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); 380 ureg->nr_samplers++; 381 return ureg->sampler[i]; 382 } 383 384 assert( 0 ); 385 return ureg->sampler[0]; 386} 387 388 389 390 391static int match_or_expand_immediate( const float *v, 392 unsigned nr, 393 float *v2, 394 unsigned *nr2, 395 unsigned *swizzle ) 396{ 397 unsigned i, j; 398 399 *swizzle = 0; 400 401 for (i = 0; i < nr; i++) { 402 boolean found = FALSE; 403 404 for (j = 0; j < *nr2 && !found; j++) { 405 if (v[i] == v2[j]) { 406 *swizzle |= j << (i * 2); 407 found = TRUE; 408 } 409 } 410 411 if (!found) { 412 if (*nr2 >= 4) 413 return FALSE; 414 415 v2[*nr2] = v[i]; 416 *swizzle |= *nr2 << (i * 2); 417 (*nr2)++; 418 } 419 } 420 421 return TRUE; 422} 423 424 425 426 427struct ureg_src ureg_DECL_immediate( struct ureg_program *ureg, 428 const float *v, 429 unsigned nr ) 430{ 431 unsigned i, j; 432 unsigned swizzle; 433 434 /* Could do a first pass where we examine all existing immediates 435 * without expanding. 436 */ 437 438 for (i = 0; i < ureg->nr_immediates; i++) { 439 if (match_or_expand_immediate( v, 440 nr, 441 ureg->immediate[i].v, 442 &ureg->immediate[i].nr, 443 &swizzle )) 444 goto out; 445 } 446 447 if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { 448 i = ureg->nr_immediates++; 449 if (match_or_expand_immediate( v, 450 nr, 451 ureg->immediate[i].v, 452 &ureg->immediate[i].nr, 453 &swizzle )) 454 goto out; 455 } 456 457 set_bad( ureg ); 458 459out: 460 /* Make sure that all referenced elements are from this immediate. 461 * Has the effect of making size-one immediates into scalars. 462 */ 463 for (j = nr; j < 4; j++) 464 swizzle |= (swizzle & 0x3) << (j * 2); 465 466 return ureg_swizzle( ureg_src_register( TGSI_FILE_IMMEDIATE, i ), 467 (swizzle >> 0) & 0x3, 468 (swizzle >> 2) & 0x3, 469 (swizzle >> 4) & 0x3, 470 (swizzle >> 6) & 0x3); 471} 472 473 474void 475ureg_emit_src( struct ureg_program *ureg, 476 struct ureg_src src ) 477{ 478 unsigned size = (1 + 479 (src.Absolute ? 1 : 0) + 480 (src.Indirect ? 1 : 0)); 481 482 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 483 unsigned n = 0; 484 485 assert(src.File != TGSI_FILE_NULL); 486 assert(src.File != TGSI_FILE_OUTPUT); 487 assert(src.File < TGSI_FILE_COUNT); 488 489 out[n].value = 0; 490 out[n].src.File = src.File; 491 out[n].src.SwizzleX = src.SwizzleX; 492 out[n].src.SwizzleY = src.SwizzleY; 493 out[n].src.SwizzleZ = src.SwizzleZ; 494 out[n].src.SwizzleW = src.SwizzleW; 495 out[n].src.Index = src.Index; 496 out[n].src.Negate = src.Negate; 497 n++; 498 499 if (src.Absolute) { 500 out[0].src.Extended = 1; 501 out[0].src.Negate = 0; 502 out[n].value = 0; 503 out[n].src_ext_mod.Type = TGSI_SRC_REGISTER_EXT_TYPE_MOD; 504 out[n].src_ext_mod.Absolute = 1; 505 out[n].src_ext_mod.Negate = src.Negate; 506 n++; 507 } 508 509 if (src.Indirect) { 510 out[0].src.Indirect = 1; 511 out[n].value = 0; 512 out[n].src.File = TGSI_FILE_ADDRESS; 513 out[n].src.SwizzleX = src.IndirectSwizzle; 514 out[n].src.SwizzleY = src.IndirectSwizzle; 515 out[n].src.SwizzleZ = src.IndirectSwizzle; 516 out[n].src.SwizzleW = src.IndirectSwizzle; 517 out[n].src.Index = src.IndirectIndex; 518 n++; 519 } 520 521 assert(n == size); 522} 523 524 525void 526ureg_emit_dst( struct ureg_program *ureg, 527 struct ureg_dst dst ) 528{ 529 unsigned size = (1 + 530 (dst.Indirect ? 1 : 0)); 531 532 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 533 unsigned n = 0; 534 535 assert(dst.File != TGSI_FILE_NULL); 536 assert(dst.File != TGSI_FILE_CONSTANT); 537 assert(dst.File != TGSI_FILE_INPUT); 538 assert(dst.File != TGSI_FILE_SAMPLER); 539 assert(dst.File != TGSI_FILE_IMMEDIATE); 540 assert(dst.File < TGSI_FILE_COUNT); 541 542 out[n].value = 0; 543 out[n].dst.File = dst.File; 544 out[n].dst.WriteMask = dst.WriteMask; 545 out[n].dst.Indirect = dst.Indirect; 546 out[n].dst.Index = dst.Index; 547 n++; 548 549 if (dst.Indirect) { 550 out[n].value = 0; 551 out[n].src.File = TGSI_FILE_ADDRESS; 552 out[n].src.SwizzleX = dst.IndirectSwizzle; 553 out[n].src.SwizzleY = dst.IndirectSwizzle; 554 out[n].src.SwizzleZ = dst.IndirectSwizzle; 555 out[n].src.SwizzleW = dst.IndirectSwizzle; 556 out[n].src.Index = dst.IndirectIndex; 557 n++; 558 } 559 560 assert(n == size); 561} 562 563 564 565unsigned 566ureg_emit_insn(struct ureg_program *ureg, 567 unsigned opcode, 568 boolean saturate, 569 unsigned num_dst, 570 unsigned num_src ) 571{ 572 union tgsi_any_token *out; 573 574 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 575 out[0].value = 0; 576 out[0].insn.Type = TGSI_TOKEN_TYPE_INSTRUCTION; 577 out[0].insn.NrTokens = 0; 578 out[0].insn.Opcode = opcode; 579 out[0].insn.Saturate = saturate; 580 out[0].insn.NumDstRegs = num_dst; 581 out[0].insn.NumSrcRegs = num_src; 582 out[0].insn.Padding = 0; 583 out[0].insn.Extended = 0; 584 585 ureg->nr_instructions++; 586 587 return ureg->domain[DOMAIN_INSN].count - 1; 588} 589 590 591void 592ureg_emit_label(struct ureg_program *ureg, 593 unsigned insn_token, 594 unsigned *label_token ) 595{ 596 union tgsi_any_token *out, *insn; 597 598 if(!label_token) 599 return; 600 601 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 602 insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); 603 604 insn->insn.Extended = 1; 605 606 out[0].value = 0; 607 out[0].insn_ext_label.Type = TGSI_INSTRUCTION_EXT_TYPE_LABEL; 608 609 *label_token = ureg->domain[DOMAIN_INSN].count - 1; 610} 611 612/* Will return a number which can be used in a label to point to the 613 * next instruction to be emitted. 614 */ 615unsigned 616ureg_get_instruction_number( struct ureg_program *ureg ) 617{ 618 return ureg->nr_instructions; 619} 620 621/* Patch a given label (expressed as a token number) to point to a 622 * given instruction (expressed as an instruction number). 623 */ 624void 625ureg_fixup_label(struct ureg_program *ureg, 626 unsigned label_token, 627 unsigned instruction_number ) 628{ 629 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); 630 631 assert(out->insn_ext_label.Type == TGSI_INSTRUCTION_EXT_TYPE_LABEL); 632 out->insn_ext_label.Label = instruction_number; 633} 634 635 636void 637ureg_emit_texture(struct ureg_program *ureg, 638 unsigned insn_token, 639 unsigned target ) 640{ 641 union tgsi_any_token *out, *insn; 642 643 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 644 insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); 645 646 insn->insn.Extended = 1; 647 648 out[0].value = 0; 649 out[0].insn_ext_texture.Type = TGSI_INSTRUCTION_EXT_TYPE_TEXTURE; 650 out[0].insn_ext_texture.Texture = target; 651} 652 653 654void 655ureg_fixup_insn_size(struct ureg_program *ureg, 656 unsigned insn ) 657{ 658 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); 659 660 assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 661 out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; 662} 663 664 665void 666ureg_insn(struct ureg_program *ureg, 667 unsigned opcode, 668 const struct ureg_dst *dst, 669 unsigned nr_dst, 670 const struct ureg_src *src, 671 unsigned nr_src ) 672{ 673 unsigned insn, i; 674 boolean saturate; 675 676#ifdef DEBUG 677 { 678 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); 679 assert(info); 680 if(info) { 681 assert(nr_dst == info->num_dst); 682 assert(nr_src == info->num_src); 683 } 684 } 685#endif 686 687 saturate = nr_dst ? dst[0].Saturate : FALSE; 688 689 insn = ureg_emit_insn( ureg, opcode, saturate, nr_dst, nr_src ); 690 691 for (i = 0; i < nr_dst; i++) 692 ureg_emit_dst( ureg, dst[i] ); 693 694 for (i = 0; i < nr_src; i++) 695 ureg_emit_src( ureg, src[i] ); 696 697 ureg_fixup_insn_size( ureg, insn ); 698} 699 700 701 702static void emit_decl( struct ureg_program *ureg, 703 unsigned file, 704 unsigned index, 705 unsigned semantic_name, 706 unsigned semantic_index, 707 unsigned interp ) 708{ 709 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 710 711 out[0].value = 0; 712 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 713 out[0].decl.NrTokens = 3; 714 out[0].decl.File = file; 715 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 716 out[0].decl.Interpolate = interp; 717 out[0].decl.Semantic = 1; 718 719 out[1].value = 0; 720 out[1].decl_range.First = 721 out[1].decl_range.Last = index; 722 723 out[2].value = 0; 724 out[2].decl_semantic.SemanticName = semantic_name; 725 out[2].decl_semantic.SemanticIndex = semantic_index; 726 727} 728 729 730static void emit_decl_range( struct ureg_program *ureg, 731 unsigned file, 732 unsigned first, 733 unsigned count ) 734{ 735 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 736 737 out[0].value = 0; 738 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 739 out[0].decl.NrTokens = 2; 740 out[0].decl.File = file; 741 out[0].decl.UsageMask = 0xf; 742 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 743 out[0].decl.Semantic = 0; 744 745 out[1].value = 0; 746 out[1].decl_range.First = first; 747 out[1].decl_range.Last = first + count - 1; 748} 749 750static void emit_immediate( struct ureg_program *ureg, 751 const float *v ) 752{ 753 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); 754 755 out[0].value = 0; 756 out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; 757 out[0].imm.NrTokens = 5; 758 out[0].imm.DataType = TGSI_IMM_FLOAT32; 759 out[0].imm.Padding = 0; 760 out[0].imm.Extended = 0; 761 762 out[1].imm_data.Float = v[0]; 763 out[2].imm_data.Float = v[1]; 764 out[3].imm_data.Float = v[2]; 765 out[4].imm_data.Float = v[3]; 766} 767 768 769 770 771static void emit_decls( struct ureg_program *ureg ) 772{ 773 unsigned i; 774 775 if (ureg->processor == TGSI_PROCESSOR_VERTEX) { 776 for (i = 0; i < UREG_MAX_INPUT; i++) { 777 if (ureg->vs_inputs[i/32] & (1 << (i%32))) { 778 emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); 779 } 780 } 781 } 782 else { 783 for (i = 0; i < ureg->nr_fs_inputs; i++) { 784 emit_decl( ureg, 785 TGSI_FILE_INPUT, 786 i, 787 ureg->fs_input[i].semantic_name, 788 ureg->fs_input[i].semantic_index, 789 ureg->fs_input[i].interp ); 790 } 791 } 792 793 for (i = 0; i < ureg->nr_outputs; i++) { 794 emit_decl( ureg, 795 TGSI_FILE_OUTPUT, 796 i, 797 ureg->output[i].semantic_name, 798 ureg->output[i].semantic_index, 799 TGSI_INTERPOLATE_CONSTANT ); 800 } 801 802 for (i = 0; i < ureg->nr_samplers; i++) { 803 emit_decl_range( ureg, 804 TGSI_FILE_SAMPLER, 805 ureg->sampler[i].Index, 1 ); 806 } 807 808 if (ureg->nr_constants) { 809 emit_decl_range( ureg, 810 TGSI_FILE_CONSTANT, 811 0, ureg->nr_constants ); 812 } 813 814 if (ureg->nr_temps) { 815 emit_decl_range( ureg, 816 TGSI_FILE_TEMPORARY, 817 0, ureg->nr_temps ); 818 } 819 820 if (ureg->nr_addrs) { 821 emit_decl_range( ureg, 822 TGSI_FILE_ADDRESS, 823 0, ureg->nr_addrs ); 824 } 825 826 for (i = 0; i < ureg->nr_immediates; i++) { 827 emit_immediate( ureg, 828 ureg->immediate[i].v ); 829 } 830} 831 832/* Append the instruction tokens onto the declarations to build a 833 * contiguous stream suitable to send to the driver. 834 */ 835static void copy_instructions( struct ureg_program *ureg ) 836{ 837 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 838 union tgsi_any_token *out = get_tokens( ureg, 839 DOMAIN_DECL, 840 nr_tokens ); 841 842 memcpy(out, 843 ureg->domain[DOMAIN_INSN].tokens, 844 nr_tokens * sizeof out[0] ); 845} 846 847 848static void 849fixup_header_size(struct ureg_program *ureg) 850{ 851 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 1 ); 852 853 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3; 854} 855 856 857static void 858emit_header( struct ureg_program *ureg ) 859{ 860 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 861 862 out[0].version.MajorVersion = 1; 863 out[0].version.MinorVersion = 1; 864 out[0].version.Padding = 0; 865 866 out[1].header.HeaderSize = 2; 867 out[1].header.BodySize = 0; 868 869 out[2].processor.Processor = ureg->processor; 870 out[2].processor.Padding = 0; 871} 872 873 874const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) 875{ 876 const struct tgsi_token *tokens; 877 878 emit_header( ureg ); 879 emit_decls( ureg ); 880 copy_instructions( ureg ); 881 fixup_header_size( ureg ); 882 883 if (ureg->domain[0].tokens == error_tokens || 884 ureg->domain[1].tokens == error_tokens) { 885 debug_printf("%s: error in generated shader\n", __FUNCTION__); 886 assert(0); 887 return NULL; 888 } 889 890 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 891 892 if (0) { 893 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 894 ureg->domain[DOMAIN_DECL].count); 895 tgsi_dump( tokens, 0 ); 896 } 897 898#if DEBUG 899 if (tokens && !tgsi_sanity_check(tokens)) { 900 debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); 901 tgsi_dump(tokens, 0); 902 assert(0); 903 } 904#endif 905 906 907 return tokens; 908} 909 910 911void *ureg_create_shader( struct ureg_program *ureg, 912 struct pipe_context *pipe ) 913{ 914 struct pipe_shader_state state; 915 916 state.tokens = ureg_finalize(ureg); 917 if(!state.tokens) 918 return NULL; 919 920 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 921 return pipe->create_vs_state( pipe, &state ); 922 else 923 return pipe->create_fs_state( pipe, &state ); 924} 925 926 927 928 929struct ureg_program *ureg_create( unsigned processor ) 930{ 931 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 932 if (ureg == NULL) 933 return NULL; 934 935 ureg->processor = processor; 936 return ureg; 937} 938 939 940void ureg_destroy( struct ureg_program *ureg ) 941{ 942 unsigned i; 943 944 for (i = 0; i < Elements(ureg->domain); i++) { 945 if (ureg->domain[i].tokens && 946 ureg->domain[i].tokens != error_tokens) 947 FREE(ureg->domain[i].tokens); 948 } 949 950 FREE(ureg); 951} 952