tgsi_ureg.c revision d288698a76e2ad8408d303570578856a05ea96d0
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_debug.h" 37#include "util/u_memory.h" 38#include "util/u_math.h" 39 40union tgsi_any_token { 41 struct tgsi_header header; 42 struct tgsi_processor processor; 43 struct tgsi_token token; 44 struct tgsi_property prop; 45 struct tgsi_property_data prop_data; 46 struct tgsi_declaration decl; 47 struct tgsi_declaration_range decl_range; 48 struct tgsi_declaration_dimension decl_dim; 49 struct tgsi_declaration_semantic decl_semantic; 50 struct tgsi_immediate imm; 51 union tgsi_immediate_data imm_data; 52 struct tgsi_instruction insn; 53 struct tgsi_instruction_predicate insn_predicate; 54 struct tgsi_instruction_label insn_label; 55 struct tgsi_instruction_texture insn_texture; 56 struct tgsi_src_register src; 57 struct tgsi_dimension dim; 58 struct tgsi_dst_register dst; 59 unsigned value; 60}; 61 62 63struct ureg_tokens { 64 union tgsi_any_token *tokens; 65 unsigned size; 66 unsigned order; 67 unsigned count; 68}; 69 70#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS 71#define UREG_MAX_SYSTEM_VALUE PIPE_MAX_ATTRIBS 72#define UREG_MAX_OUTPUT PIPE_MAX_ATTRIBS 73#define UREG_MAX_CONSTANT_RANGE 32 74#define UREG_MAX_IMMEDIATE 32 75#define UREG_MAX_TEMP 256 76#define UREG_MAX_ADDR 2 77#define UREG_MAX_PRED 1 78 79struct const_decl { 80 struct { 81 unsigned first; 82 unsigned last; 83 } constant_range[UREG_MAX_CONSTANT_RANGE]; 84 unsigned nr_constant_ranges; 85}; 86 87#define DOMAIN_DECL 0 88#define DOMAIN_INSN 1 89 90struct ureg_program 91{ 92 unsigned processor; 93 struct pipe_context *pipe; 94 95 struct { 96 unsigned semantic_name; 97 unsigned semantic_index; 98 unsigned interp; 99 unsigned cylindrical_wrap; 100 } fs_input[UREG_MAX_INPUT]; 101 unsigned nr_fs_inputs; 102 103 unsigned vs_inputs[UREG_MAX_INPUT/32]; 104 105 struct { 106 unsigned index; 107 unsigned semantic_name; 108 unsigned semantic_index; 109 } gs_input[UREG_MAX_INPUT]; 110 unsigned nr_gs_inputs; 111 112 struct { 113 unsigned index; 114 unsigned semantic_name; 115 unsigned semantic_index; 116 } system_value[UREG_MAX_SYSTEM_VALUE]; 117 unsigned nr_system_values; 118 119 struct { 120 unsigned semantic_name; 121 unsigned semantic_index; 122 } output[UREG_MAX_OUTPUT]; 123 unsigned nr_outputs; 124 125 struct { 126 union { 127 float f[4]; 128 unsigned u[4]; 129 int i[4]; 130 } value; 131 unsigned nr; 132 unsigned type; 133 } immediate[UREG_MAX_IMMEDIATE]; 134 unsigned nr_immediates; 135 136 struct ureg_src sampler[PIPE_MAX_SAMPLERS]; 137 unsigned nr_samplers; 138 139 unsigned temps_active[UREG_MAX_TEMP / 32]; 140 unsigned nr_temps; 141 142 struct const_decl const_decls; 143 struct const_decl const_decls2D[PIPE_MAX_CONSTANT_BUFFERS]; 144 145 unsigned property_gs_input_prim; 146 unsigned property_gs_output_prim; 147 unsigned property_gs_max_vertices; 148 unsigned char property_fs_coord_origin; /* = TGSI_FS_COORD_ORIGIN_* */ 149 unsigned char property_fs_coord_pixel_center; /* = TGSI_FS_COORD_PIXEL_CENTER_* */ 150 151 unsigned nr_addrs; 152 unsigned nr_preds; 153 unsigned nr_instructions; 154 155 struct ureg_tokens domain[2]; 156}; 157 158static union tgsi_any_token error_tokens[32]; 159 160static void tokens_error( struct ureg_tokens *tokens ) 161{ 162 if (tokens->tokens && tokens->tokens != error_tokens) 163 FREE(tokens->tokens); 164 165 tokens->tokens = error_tokens; 166 tokens->size = Elements(error_tokens); 167 tokens->count = 0; 168} 169 170 171static void tokens_expand( struct ureg_tokens *tokens, 172 unsigned count ) 173{ 174 unsigned old_size = tokens->size * sizeof(unsigned); 175 176 if (tokens->tokens == error_tokens) { 177 return; 178 } 179 180 while (tokens->count + count > tokens->size) { 181 tokens->size = (1 << ++tokens->order); 182 } 183 184 tokens->tokens = REALLOC(tokens->tokens, 185 old_size, 186 tokens->size * sizeof(unsigned)); 187 if (tokens->tokens == NULL) { 188 tokens_error(tokens); 189 } 190} 191 192static void set_bad( struct ureg_program *ureg ) 193{ 194 tokens_error(&ureg->domain[0]); 195} 196 197 198 199static union tgsi_any_token *get_tokens( struct ureg_program *ureg, 200 unsigned domain, 201 unsigned count ) 202{ 203 struct ureg_tokens *tokens = &ureg->domain[domain]; 204 union tgsi_any_token *result; 205 206 if (tokens->count + count > tokens->size) 207 tokens_expand(tokens, count); 208 209 result = &tokens->tokens[tokens->count]; 210 tokens->count += count; 211 return result; 212} 213 214 215static union tgsi_any_token *retrieve_token( struct ureg_program *ureg, 216 unsigned domain, 217 unsigned nr ) 218{ 219 if (ureg->domain[domain].tokens == error_tokens) 220 return &error_tokens[0]; 221 222 return &ureg->domain[domain].tokens[nr]; 223} 224 225 226 227static INLINE struct ureg_dst 228ureg_dst_register( unsigned file, 229 unsigned index ) 230{ 231 struct ureg_dst dst; 232 233 dst.File = file; 234 dst.WriteMask = TGSI_WRITEMASK_XYZW; 235 dst.Indirect = 0; 236 dst.IndirectIndex = 0; 237 dst.IndirectSwizzle = 0; 238 dst.Saturate = 0; 239 dst.Predicate = 0; 240 dst.PredNegate = 0; 241 dst.PredSwizzleX = TGSI_SWIZZLE_X; 242 dst.PredSwizzleY = TGSI_SWIZZLE_Y; 243 dst.PredSwizzleZ = TGSI_SWIZZLE_Z; 244 dst.PredSwizzleW = TGSI_SWIZZLE_W; 245 dst.Index = index; 246 247 return dst; 248} 249 250 251void 252ureg_property_gs_input_prim(struct ureg_program *ureg, 253 unsigned input_prim) 254{ 255 ureg->property_gs_input_prim = input_prim; 256} 257 258void 259ureg_property_gs_output_prim(struct ureg_program *ureg, 260 unsigned output_prim) 261{ 262 ureg->property_gs_output_prim = output_prim; 263} 264 265void 266ureg_property_gs_max_vertices(struct ureg_program *ureg, 267 unsigned max_vertices) 268{ 269 ureg->property_gs_max_vertices = max_vertices; 270} 271 272void 273ureg_property_fs_coord_origin(struct ureg_program *ureg, 274 unsigned fs_coord_origin) 275{ 276 ureg->property_fs_coord_origin = fs_coord_origin; 277} 278 279void 280ureg_property_fs_coord_pixel_center(struct ureg_program *ureg, 281 unsigned fs_coord_pixel_center) 282{ 283 ureg->property_fs_coord_pixel_center = fs_coord_pixel_center; 284} 285 286 287 288struct ureg_src 289ureg_DECL_fs_input_cyl(struct ureg_program *ureg, 290 unsigned semantic_name, 291 unsigned semantic_index, 292 unsigned interp_mode, 293 unsigned cylindrical_wrap) 294{ 295 unsigned i; 296 297 for (i = 0; i < ureg->nr_fs_inputs; i++) { 298 if (ureg->fs_input[i].semantic_name == semantic_name && 299 ureg->fs_input[i].semantic_index == semantic_index) { 300 goto out; 301 } 302 } 303 304 if (ureg->nr_fs_inputs < UREG_MAX_INPUT) { 305 ureg->fs_input[i].semantic_name = semantic_name; 306 ureg->fs_input[i].semantic_index = semantic_index; 307 ureg->fs_input[i].interp = interp_mode; 308 ureg->fs_input[i].cylindrical_wrap = cylindrical_wrap; 309 ureg->nr_fs_inputs++; 310 } else { 311 set_bad(ureg); 312 } 313 314out: 315 return ureg_src_register(TGSI_FILE_INPUT, i); 316} 317 318 319struct ureg_src 320ureg_DECL_vs_input( struct ureg_program *ureg, 321 unsigned index ) 322{ 323 assert(ureg->processor == TGSI_PROCESSOR_VERTEX); 324 325 ureg->vs_inputs[index/32] |= 1 << (index % 32); 326 return ureg_src_register( TGSI_FILE_INPUT, index ); 327} 328 329 330struct ureg_src 331ureg_DECL_gs_input(struct ureg_program *ureg, 332 unsigned index, 333 unsigned semantic_name, 334 unsigned semantic_index) 335{ 336 if (ureg->nr_gs_inputs < UREG_MAX_INPUT) { 337 ureg->gs_input[ureg->nr_gs_inputs].index = index; 338 ureg->gs_input[ureg->nr_gs_inputs].semantic_name = semantic_name; 339 ureg->gs_input[ureg->nr_gs_inputs].semantic_index = semantic_index; 340 ureg->nr_gs_inputs++; 341 } else { 342 set_bad(ureg); 343 } 344 345 /* XXX: Add suport for true 2D input registers. */ 346 return ureg_src_register(TGSI_FILE_INPUT, index); 347} 348 349 350struct ureg_src 351ureg_DECL_system_value(struct ureg_program *ureg, 352 unsigned index, 353 unsigned semantic_name, 354 unsigned semantic_index) 355{ 356 if (ureg->nr_system_values < UREG_MAX_SYSTEM_VALUE) { 357 ureg->system_value[ureg->nr_system_values].index = index; 358 ureg->system_value[ureg->nr_system_values].semantic_name = semantic_name; 359 ureg->system_value[ureg->nr_system_values].semantic_index = semantic_index; 360 ureg->nr_system_values++; 361 } else { 362 set_bad(ureg); 363 } 364 365 return ureg_src_register(TGSI_FILE_SYSTEM_VALUE, index); 366} 367 368 369struct ureg_dst 370ureg_DECL_output( struct ureg_program *ureg, 371 unsigned name, 372 unsigned index ) 373{ 374 unsigned i; 375 376 for (i = 0; i < ureg->nr_outputs; i++) { 377 if (ureg->output[i].semantic_name == name && 378 ureg->output[i].semantic_index == index) 379 goto out; 380 } 381 382 if (ureg->nr_outputs < UREG_MAX_OUTPUT) { 383 ureg->output[i].semantic_name = name; 384 ureg->output[i].semantic_index = index; 385 ureg->nr_outputs++; 386 } 387 else { 388 set_bad( ureg ); 389 } 390 391out: 392 return ureg_dst_register( TGSI_FILE_OUTPUT, i ); 393} 394 395 396/* Returns a new constant register. Keep track of which have been 397 * referred to so that we can emit decls later. 398 * 399 * Constant operands declared with this function must be addressed 400 * with a two-dimensional index. 401 * 402 * There is nothing in this code to bind this constant to any tracked 403 * value or manage any constant_buffer contents -- that's the 404 * resposibility of the calling code. 405 */ 406void 407ureg_DECL_constant2D(struct ureg_program *ureg, 408 unsigned first, 409 unsigned last, 410 unsigned index2D) 411{ 412 struct const_decl *decl = &ureg->const_decls2D[index2D]; 413 414 assert(index2D < PIPE_MAX_CONSTANT_BUFFERS); 415 416 if (decl->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) { 417 uint i = decl->nr_constant_ranges++; 418 419 decl->constant_range[i].first = first; 420 decl->constant_range[i].last = last; 421 } 422} 423 424 425/* A one-dimensional, depricated version of ureg_DECL_constant2D(). 426 * 427 * Constant operands declared with this function must be addressed 428 * with a one-dimensional index. 429 */ 430struct ureg_src 431ureg_DECL_constant(struct ureg_program *ureg, 432 unsigned index) 433{ 434 struct const_decl *decl = &ureg->const_decls; 435 unsigned minconst = index, maxconst = index; 436 unsigned i; 437 438 /* Inside existing range? 439 */ 440 for (i = 0; i < decl->nr_constant_ranges; i++) { 441 if (decl->constant_range[i].first <= index && 442 decl->constant_range[i].last >= index) { 443 goto out; 444 } 445 } 446 447 /* Extend existing range? 448 */ 449 for (i = 0; i < decl->nr_constant_ranges; i++) { 450 if (decl->constant_range[i].last == index - 1) { 451 decl->constant_range[i].last = index; 452 goto out; 453 } 454 455 if (decl->constant_range[i].first == index + 1) { 456 decl->constant_range[i].first = index; 457 goto out; 458 } 459 460 minconst = MIN2(minconst, decl->constant_range[i].first); 461 maxconst = MAX2(maxconst, decl->constant_range[i].last); 462 } 463 464 /* Create new range? 465 */ 466 if (decl->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) { 467 i = decl->nr_constant_ranges++; 468 decl->constant_range[i].first = index; 469 decl->constant_range[i].last = index; 470 goto out; 471 } 472 473 /* Collapse all ranges down to one: 474 */ 475 i = 0; 476 decl->constant_range[0].first = minconst; 477 decl->constant_range[0].last = maxconst; 478 decl->nr_constant_ranges = 1; 479 480out: 481 assert(i < decl->nr_constant_ranges); 482 assert(decl->constant_range[i].first <= index); 483 assert(decl->constant_range[i].last >= index); 484 return ureg_src_register(TGSI_FILE_CONSTANT, index); 485} 486 487 488/* Allocate a new temporary. Temporaries greater than UREG_MAX_TEMP 489 * are legal, but will not be released. 490 */ 491struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) 492{ 493 unsigned i; 494 495 for (i = 0; i < UREG_MAX_TEMP; i += 32) { 496 int bit = ffs(~ureg->temps_active[i/32]); 497 if (bit != 0) { 498 i += bit - 1; 499 goto out; 500 } 501 } 502 503 /* No reusable temps, so allocate a new one: 504 */ 505 i = ureg->nr_temps++; 506 507out: 508 if (i < UREG_MAX_TEMP) 509 ureg->temps_active[i/32] |= 1 << (i % 32); 510 511 if (i >= ureg->nr_temps) 512 ureg->nr_temps = i + 1; 513 514 return ureg_dst_register( TGSI_FILE_TEMPORARY, i ); 515} 516 517 518void ureg_release_temporary( struct ureg_program *ureg, 519 struct ureg_dst tmp ) 520{ 521 if(tmp.File == TGSI_FILE_TEMPORARY) 522 if (tmp.Index < UREG_MAX_TEMP) 523 ureg->temps_active[tmp.Index/32] &= ~(1 << (tmp.Index % 32)); 524} 525 526 527/* Allocate a new address register. 528 */ 529struct ureg_dst ureg_DECL_address( struct ureg_program *ureg ) 530{ 531 if (ureg->nr_addrs < UREG_MAX_ADDR) 532 return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ ); 533 534 assert( 0 ); 535 return ureg_dst_register( TGSI_FILE_ADDRESS, 0 ); 536} 537 538/* Allocate a new predicate register. 539 */ 540struct ureg_dst 541ureg_DECL_predicate(struct ureg_program *ureg) 542{ 543 if (ureg->nr_preds < UREG_MAX_PRED) { 544 return ureg_dst_register(TGSI_FILE_PREDICATE, ureg->nr_preds++); 545 } 546 547 assert(0); 548 return ureg_dst_register(TGSI_FILE_PREDICATE, 0); 549} 550 551/* Allocate a new sampler. 552 */ 553struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, 554 unsigned nr ) 555{ 556 unsigned i; 557 558 for (i = 0; i < ureg->nr_samplers; i++) 559 if (ureg->sampler[i].Index == nr) 560 return ureg->sampler[i]; 561 562 if (i < PIPE_MAX_SAMPLERS) { 563 ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); 564 ureg->nr_samplers++; 565 return ureg->sampler[i]; 566 } 567 568 assert( 0 ); 569 return ureg->sampler[0]; 570} 571 572 573static int 574match_or_expand_immediate( const unsigned *v, 575 unsigned nr, 576 unsigned *v2, 577 unsigned *pnr2, 578 unsigned *swizzle ) 579{ 580 unsigned nr2 = *pnr2; 581 unsigned i, j; 582 583 *swizzle = 0; 584 585 for (i = 0; i < nr; i++) { 586 boolean found = FALSE; 587 588 for (j = 0; j < nr2 && !found; j++) { 589 if (v[i] == v2[j]) { 590 *swizzle |= j << (i * 2); 591 found = TRUE; 592 } 593 } 594 595 if (!found) { 596 if (nr2 >= 4) { 597 return FALSE; 598 } 599 600 v2[nr2] = v[i]; 601 *swizzle |= nr2 << (i * 2); 602 nr2++; 603 } 604 } 605 606 /* Actually expand immediate only when fully succeeded. 607 */ 608 *pnr2 = nr2; 609 return TRUE; 610} 611 612 613static struct ureg_src 614decl_immediate( struct ureg_program *ureg, 615 const unsigned *v, 616 unsigned nr, 617 unsigned type ) 618{ 619 unsigned i, j; 620 unsigned swizzle = 0; 621 622 /* Could do a first pass where we examine all existing immediates 623 * without expanding. 624 */ 625 626 for (i = 0; i < ureg->nr_immediates; i++) { 627 if (ureg->immediate[i].type != type) { 628 continue; 629 } 630 if (match_or_expand_immediate(v, 631 nr, 632 ureg->immediate[i].value.u, 633 &ureg->immediate[i].nr, 634 &swizzle)) { 635 goto out; 636 } 637 } 638 639 if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { 640 i = ureg->nr_immediates++; 641 ureg->immediate[i].type = type; 642 if (match_or_expand_immediate(v, 643 nr, 644 ureg->immediate[i].value.u, 645 &ureg->immediate[i].nr, 646 &swizzle)) { 647 goto out; 648 } 649 } 650 651 set_bad(ureg); 652 653out: 654 /* Make sure that all referenced elements are from this immediate. 655 * Has the effect of making size-one immediates into scalars. 656 */ 657 for (j = nr; j < 4; j++) { 658 swizzle |= (swizzle & 0x3) << (j * 2); 659 } 660 661 return ureg_swizzle(ureg_src_register(TGSI_FILE_IMMEDIATE, i), 662 (swizzle >> 0) & 0x3, 663 (swizzle >> 2) & 0x3, 664 (swizzle >> 4) & 0x3, 665 (swizzle >> 6) & 0x3); 666} 667 668 669struct ureg_src 670ureg_DECL_immediate( struct ureg_program *ureg, 671 const float *v, 672 unsigned nr ) 673{ 674 union { 675 float f[4]; 676 unsigned u[4]; 677 } fu; 678 unsigned int i; 679 680 for (i = 0; i < nr; i++) { 681 fu.f[i] = v[i]; 682 } 683 684 return decl_immediate(ureg, fu.u, nr, TGSI_IMM_FLOAT32); 685} 686 687 688struct ureg_src 689ureg_DECL_immediate_uint( struct ureg_program *ureg, 690 const unsigned *v, 691 unsigned nr ) 692{ 693 return decl_immediate(ureg, v, nr, TGSI_IMM_UINT32); 694} 695 696 697struct ureg_src 698ureg_DECL_immediate_block_uint( struct ureg_program *ureg, 699 const unsigned *v, 700 unsigned nr ) 701{ 702 uint index; 703 uint i; 704 705 if (ureg->nr_immediates + (nr + 3) / 4 > UREG_MAX_IMMEDIATE) { 706 set_bad(ureg); 707 return ureg_src_register(TGSI_FILE_IMMEDIATE, 0); 708 } 709 710 index = ureg->nr_immediates; 711 ureg->nr_immediates += (nr + 3) / 4; 712 713 for (i = index; i < ureg->nr_immediates; i++) { 714 ureg->immediate[i].type = TGSI_IMM_UINT32; 715 ureg->immediate[i].nr = nr > 4 ? 4 : nr; 716 memcpy(ureg->immediate[i].value.u, 717 &v[(i - index) * 4], 718 ureg->immediate[i].nr * sizeof(uint)); 719 nr -= 4; 720 } 721 722 return ureg_src_register(TGSI_FILE_IMMEDIATE, index); 723} 724 725 726struct ureg_src 727ureg_DECL_immediate_int( struct ureg_program *ureg, 728 const int *v, 729 unsigned nr ) 730{ 731 return decl_immediate(ureg, (const unsigned *)v, nr, TGSI_IMM_INT32); 732} 733 734 735void 736ureg_emit_src( struct ureg_program *ureg, 737 struct ureg_src src ) 738{ 739 unsigned size = 1 + (src.Indirect ? 1 : 0) + (src.Dimension ? 1 : 0); 740 741 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 742 unsigned n = 0; 743 744 assert(src.File != TGSI_FILE_NULL); 745 assert(src.File != TGSI_FILE_OUTPUT); 746 assert(src.File < TGSI_FILE_COUNT); 747 748 out[n].value = 0; 749 out[n].src.File = src.File; 750 out[n].src.SwizzleX = src.SwizzleX; 751 out[n].src.SwizzleY = src.SwizzleY; 752 out[n].src.SwizzleZ = src.SwizzleZ; 753 out[n].src.SwizzleW = src.SwizzleW; 754 out[n].src.Index = src.Index; 755 out[n].src.Negate = src.Negate; 756 out[0].src.Absolute = src.Absolute; 757 n++; 758 759 if (src.Indirect) { 760 out[0].src.Indirect = 1; 761 out[n].value = 0; 762 out[n].src.File = src.IndirectFile; 763 out[n].src.SwizzleX = src.IndirectSwizzle; 764 out[n].src.SwizzleY = src.IndirectSwizzle; 765 out[n].src.SwizzleZ = src.IndirectSwizzle; 766 out[n].src.SwizzleW = src.IndirectSwizzle; 767 out[n].src.Index = src.IndirectIndex; 768 n++; 769 } 770 771 if (src.Dimension) { 772 out[0].src.Dimension = 1; 773 out[n].dim.Indirect = 0; 774 out[n].dim.Dimension = 0; 775 out[n].dim.Padding = 0; 776 out[n].dim.Index = src.DimensionIndex; 777 n++; 778 } 779 780 assert(n == size); 781} 782 783 784void 785ureg_emit_dst( struct ureg_program *ureg, 786 struct ureg_dst dst ) 787{ 788 unsigned size = (1 + 789 (dst.Indirect ? 1 : 0)); 790 791 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 792 unsigned n = 0; 793 794 assert(dst.File != TGSI_FILE_NULL); 795 assert(dst.File != TGSI_FILE_CONSTANT); 796 assert(dst.File != TGSI_FILE_INPUT); 797 assert(dst.File != TGSI_FILE_SAMPLER); 798 assert(dst.File != TGSI_FILE_IMMEDIATE); 799 assert(dst.File < TGSI_FILE_COUNT); 800 801 out[n].value = 0; 802 out[n].dst.File = dst.File; 803 out[n].dst.WriteMask = dst.WriteMask; 804 out[n].dst.Indirect = dst.Indirect; 805 out[n].dst.Index = dst.Index; 806 n++; 807 808 if (dst.Indirect) { 809 out[n].value = 0; 810 out[n].src.File = TGSI_FILE_ADDRESS; 811 out[n].src.SwizzleX = dst.IndirectSwizzle; 812 out[n].src.SwizzleY = dst.IndirectSwizzle; 813 out[n].src.SwizzleZ = dst.IndirectSwizzle; 814 out[n].src.SwizzleW = dst.IndirectSwizzle; 815 out[n].src.Index = dst.IndirectIndex; 816 n++; 817 } 818 819 assert(n == size); 820} 821 822 823static void validate( unsigned opcode, 824 unsigned nr_dst, 825 unsigned nr_src ) 826{ 827#ifdef DEBUG 828 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); 829 assert(info); 830 if(info) { 831 assert(nr_dst == info->num_dst); 832 assert(nr_src == info->num_src); 833 } 834#endif 835} 836 837struct ureg_emit_insn_result 838ureg_emit_insn(struct ureg_program *ureg, 839 unsigned opcode, 840 boolean saturate, 841 boolean predicate, 842 boolean pred_negate, 843 unsigned pred_swizzle_x, 844 unsigned pred_swizzle_y, 845 unsigned pred_swizzle_z, 846 unsigned pred_swizzle_w, 847 unsigned num_dst, 848 unsigned num_src ) 849{ 850 union tgsi_any_token *out; 851 uint count = predicate ? 2 : 1; 852 struct ureg_emit_insn_result result; 853 854 validate( opcode, num_dst, num_src ); 855 856 out = get_tokens( ureg, DOMAIN_INSN, count ); 857 out[0].insn = tgsi_default_instruction(); 858 out[0].insn.Opcode = opcode; 859 out[0].insn.Saturate = saturate; 860 out[0].insn.NumDstRegs = num_dst; 861 out[0].insn.NumSrcRegs = num_src; 862 863 result.insn_token = ureg->domain[DOMAIN_INSN].count - count; 864 result.extended_token = result.insn_token; 865 866 if (predicate) { 867 out[0].insn.Predicate = 1; 868 out[1].insn_predicate = tgsi_default_instruction_predicate(); 869 out[1].insn_predicate.Negate = pred_negate; 870 out[1].insn_predicate.SwizzleX = pred_swizzle_x; 871 out[1].insn_predicate.SwizzleY = pred_swizzle_y; 872 out[1].insn_predicate.SwizzleZ = pred_swizzle_z; 873 out[1].insn_predicate.SwizzleW = pred_swizzle_w; 874 } 875 876 ureg->nr_instructions++; 877 878 return result; 879} 880 881 882void 883ureg_emit_label(struct ureg_program *ureg, 884 unsigned extended_token, 885 unsigned *label_token ) 886{ 887 union tgsi_any_token *out, *insn; 888 889 if(!label_token) 890 return; 891 892 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 893 out[0].value = 0; 894 895 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 896 insn->insn.Label = 1; 897 898 *label_token = ureg->domain[DOMAIN_INSN].count - 1; 899} 900 901/* Will return a number which can be used in a label to point to the 902 * next instruction to be emitted. 903 */ 904unsigned 905ureg_get_instruction_number( struct ureg_program *ureg ) 906{ 907 return ureg->nr_instructions; 908} 909 910/* Patch a given label (expressed as a token number) to point to a 911 * given instruction (expressed as an instruction number). 912 */ 913void 914ureg_fixup_label(struct ureg_program *ureg, 915 unsigned label_token, 916 unsigned instruction_number ) 917{ 918 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); 919 920 out->insn_label.Label = instruction_number; 921} 922 923 924void 925ureg_emit_texture(struct ureg_program *ureg, 926 unsigned extended_token, 927 unsigned target ) 928{ 929 union tgsi_any_token *out, *insn; 930 931 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 932 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 933 934 insn->insn.Texture = 1; 935 936 out[0].value = 0; 937 out[0].insn_texture.Texture = target; 938} 939 940 941void 942ureg_fixup_insn_size(struct ureg_program *ureg, 943 unsigned insn ) 944{ 945 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); 946 947 assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 948 out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; 949} 950 951 952void 953ureg_insn(struct ureg_program *ureg, 954 unsigned opcode, 955 const struct ureg_dst *dst, 956 unsigned nr_dst, 957 const struct ureg_src *src, 958 unsigned nr_src ) 959{ 960 struct ureg_emit_insn_result insn; 961 unsigned i; 962 boolean saturate; 963 boolean predicate; 964 boolean negate = FALSE; 965 unsigned swizzle[4] = { 0 }; 966 967 saturate = nr_dst ? dst[0].Saturate : FALSE; 968 predicate = nr_dst ? dst[0].Predicate : FALSE; 969 if (predicate) { 970 negate = dst[0].PredNegate; 971 swizzle[0] = dst[0].PredSwizzleX; 972 swizzle[1] = dst[0].PredSwizzleY; 973 swizzle[2] = dst[0].PredSwizzleZ; 974 swizzle[3] = dst[0].PredSwizzleW; 975 } 976 977 insn = ureg_emit_insn(ureg, 978 opcode, 979 saturate, 980 predicate, 981 negate, 982 swizzle[0], 983 swizzle[1], 984 swizzle[2], 985 swizzle[3], 986 nr_dst, 987 nr_src); 988 989 for (i = 0; i < nr_dst; i++) 990 ureg_emit_dst( ureg, dst[i] ); 991 992 for (i = 0; i < nr_src; i++) 993 ureg_emit_src( ureg, src[i] ); 994 995 ureg_fixup_insn_size( ureg, insn.insn_token ); 996} 997 998void 999ureg_tex_insn(struct ureg_program *ureg, 1000 unsigned opcode, 1001 const struct ureg_dst *dst, 1002 unsigned nr_dst, 1003 unsigned target, 1004 const struct ureg_src *src, 1005 unsigned nr_src ) 1006{ 1007 struct ureg_emit_insn_result insn; 1008 unsigned i; 1009 boolean saturate; 1010 boolean predicate; 1011 boolean negate = FALSE; 1012 unsigned swizzle[4] = { 0 }; 1013 1014 saturate = nr_dst ? dst[0].Saturate : FALSE; 1015 predicate = nr_dst ? dst[0].Predicate : FALSE; 1016 if (predicate) { 1017 negate = dst[0].PredNegate; 1018 swizzle[0] = dst[0].PredSwizzleX; 1019 swizzle[1] = dst[0].PredSwizzleY; 1020 swizzle[2] = dst[0].PredSwizzleZ; 1021 swizzle[3] = dst[0].PredSwizzleW; 1022 } 1023 1024 insn = ureg_emit_insn(ureg, 1025 opcode, 1026 saturate, 1027 predicate, 1028 negate, 1029 swizzle[0], 1030 swizzle[1], 1031 swizzle[2], 1032 swizzle[3], 1033 nr_dst, 1034 nr_src); 1035 1036 ureg_emit_texture( ureg, insn.extended_token, target ); 1037 1038 for (i = 0; i < nr_dst; i++) 1039 ureg_emit_dst( ureg, dst[i] ); 1040 1041 for (i = 0; i < nr_src; i++) 1042 ureg_emit_src( ureg, src[i] ); 1043 1044 ureg_fixup_insn_size( ureg, insn.insn_token ); 1045} 1046 1047 1048void 1049ureg_label_insn(struct ureg_program *ureg, 1050 unsigned opcode, 1051 const struct ureg_src *src, 1052 unsigned nr_src, 1053 unsigned *label_token ) 1054{ 1055 struct ureg_emit_insn_result insn; 1056 unsigned i; 1057 1058 insn = ureg_emit_insn(ureg, 1059 opcode, 1060 FALSE, 1061 FALSE, 1062 FALSE, 1063 TGSI_SWIZZLE_X, 1064 TGSI_SWIZZLE_Y, 1065 TGSI_SWIZZLE_Z, 1066 TGSI_SWIZZLE_W, 1067 0, 1068 nr_src); 1069 1070 ureg_emit_label( ureg, insn.extended_token, label_token ); 1071 1072 for (i = 0; i < nr_src; i++) 1073 ureg_emit_src( ureg, src[i] ); 1074 1075 ureg_fixup_insn_size( ureg, insn.insn_token ); 1076} 1077 1078 1079static void 1080emit_decl_semantic(struct ureg_program *ureg, 1081 unsigned file, 1082 unsigned index, 1083 unsigned semantic_name, 1084 unsigned semantic_index) 1085{ 1086 union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 3); 1087 1088 out[0].value = 0; 1089 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 1090 out[0].decl.NrTokens = 3; 1091 out[0].decl.File = file; 1092 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 1093 out[0].decl.Semantic = 1; 1094 1095 out[1].value = 0; 1096 out[1].decl_range.First = index; 1097 out[1].decl_range.Last = index; 1098 1099 out[2].value = 0; 1100 out[2].decl_semantic.Name = semantic_name; 1101 out[2].decl_semantic.Index = semantic_index; 1102} 1103 1104 1105static void 1106emit_decl_fs(struct ureg_program *ureg, 1107 unsigned file, 1108 unsigned index, 1109 unsigned semantic_name, 1110 unsigned semantic_index, 1111 unsigned interpolate, 1112 unsigned cylindrical_wrap) 1113{ 1114 union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 3); 1115 1116 out[0].value = 0; 1117 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 1118 out[0].decl.NrTokens = 3; 1119 out[0].decl.File = file; 1120 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 1121 out[0].decl.Interpolate = interpolate; 1122 out[0].decl.Semantic = 1; 1123 out[0].decl.CylindricalWrap = cylindrical_wrap; 1124 1125 out[1].value = 0; 1126 out[1].decl_range.First = index; 1127 out[1].decl_range.Last = index; 1128 1129 out[2].value = 0; 1130 out[2].decl_semantic.Name = semantic_name; 1131 out[2].decl_semantic.Index = semantic_index; 1132} 1133 1134 1135static void emit_decl_range( struct ureg_program *ureg, 1136 unsigned file, 1137 unsigned first, 1138 unsigned count ) 1139{ 1140 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 1141 1142 out[0].value = 0; 1143 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 1144 out[0].decl.NrTokens = 2; 1145 out[0].decl.File = file; 1146 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; 1147 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 1148 out[0].decl.Semantic = 0; 1149 1150 out[1].value = 0; 1151 out[1].decl_range.First = first; 1152 out[1].decl_range.Last = first + count - 1; 1153} 1154 1155static void 1156emit_decl_range2D(struct ureg_program *ureg, 1157 unsigned file, 1158 unsigned first, 1159 unsigned last, 1160 unsigned index2D) 1161{ 1162 union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 3); 1163 1164 out[0].value = 0; 1165 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 1166 out[0].decl.NrTokens = 3; 1167 out[0].decl.File = file; 1168 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; 1169 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 1170 out[0].decl.Dimension = 1; 1171 1172 out[1].value = 0; 1173 out[1].decl_range.First = first; 1174 out[1].decl_range.Last = last; 1175 1176 out[2].value = 0; 1177 out[2].decl_dim.Index2D = index2D; 1178} 1179 1180static void 1181emit_immediate( struct ureg_program *ureg, 1182 const unsigned *v, 1183 unsigned type ) 1184{ 1185 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); 1186 1187 out[0].value = 0; 1188 out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; 1189 out[0].imm.NrTokens = 5; 1190 out[0].imm.DataType = type; 1191 out[0].imm.Padding = 0; 1192 1193 out[1].imm_data.Uint = v[0]; 1194 out[2].imm_data.Uint = v[1]; 1195 out[3].imm_data.Uint = v[2]; 1196 out[4].imm_data.Uint = v[3]; 1197} 1198 1199static void 1200emit_property(struct ureg_program *ureg, 1201 unsigned name, 1202 unsigned data) 1203{ 1204 union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 2); 1205 1206 out[0].value = 0; 1207 out[0].prop.Type = TGSI_TOKEN_TYPE_PROPERTY; 1208 out[0].prop.NrTokens = 2; 1209 out[0].prop.PropertyName = name; 1210 1211 out[1].prop_data.Data = data; 1212} 1213 1214 1215static void emit_decls( struct ureg_program *ureg ) 1216{ 1217 unsigned i; 1218 1219 if (ureg->property_gs_input_prim != ~0) { 1220 assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); 1221 1222 emit_property(ureg, 1223 TGSI_PROPERTY_GS_INPUT_PRIM, 1224 ureg->property_gs_input_prim); 1225 } 1226 1227 if (ureg->property_gs_output_prim != ~0) { 1228 assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); 1229 1230 emit_property(ureg, 1231 TGSI_PROPERTY_GS_OUTPUT_PRIM, 1232 ureg->property_gs_output_prim); 1233 } 1234 1235 if (ureg->property_gs_max_vertices != ~0) { 1236 assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); 1237 1238 emit_property(ureg, 1239 TGSI_PROPERTY_GS_MAX_VERTICES, 1240 ureg->property_gs_max_vertices); 1241 } 1242 1243 if (ureg->property_fs_coord_origin) { 1244 assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT); 1245 1246 emit_property(ureg, 1247 TGSI_PROPERTY_FS_COORD_ORIGIN, 1248 ureg->property_fs_coord_origin); 1249 } 1250 1251 if (ureg->property_fs_coord_pixel_center) { 1252 assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT); 1253 1254 emit_property(ureg, 1255 TGSI_PROPERTY_FS_COORD_PIXEL_CENTER, 1256 ureg->property_fs_coord_pixel_center); 1257 } 1258 1259 if (ureg->processor == TGSI_PROCESSOR_VERTEX) { 1260 for (i = 0; i < UREG_MAX_INPUT; i++) { 1261 if (ureg->vs_inputs[i/32] & (1 << (i%32))) { 1262 emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); 1263 } 1264 } 1265 } else if (ureg->processor == TGSI_PROCESSOR_FRAGMENT) { 1266 for (i = 0; i < ureg->nr_fs_inputs; i++) { 1267 emit_decl_fs(ureg, 1268 TGSI_FILE_INPUT, 1269 i, 1270 ureg->fs_input[i].semantic_name, 1271 ureg->fs_input[i].semantic_index, 1272 ureg->fs_input[i].interp, 1273 ureg->fs_input[i].cylindrical_wrap); 1274 } 1275 } else { 1276 for (i = 0; i < ureg->nr_gs_inputs; i++) { 1277 emit_decl_semantic(ureg, 1278 TGSI_FILE_INPUT, 1279 ureg->gs_input[i].index, 1280 ureg->gs_input[i].semantic_name, 1281 ureg->gs_input[i].semantic_index); 1282 } 1283 } 1284 1285 for (i = 0; i < ureg->nr_system_values; i++) { 1286 emit_decl_semantic(ureg, 1287 TGSI_FILE_SYSTEM_VALUE, 1288 ureg->system_value[i].index, 1289 ureg->system_value[i].semantic_name, 1290 ureg->system_value[i].semantic_index); 1291 } 1292 1293 for (i = 0; i < ureg->nr_outputs; i++) { 1294 emit_decl_semantic(ureg, 1295 TGSI_FILE_OUTPUT, 1296 i, 1297 ureg->output[i].semantic_name, 1298 ureg->output[i].semantic_index); 1299 } 1300 1301 for (i = 0; i < ureg->nr_samplers; i++) { 1302 emit_decl_range( ureg, 1303 TGSI_FILE_SAMPLER, 1304 ureg->sampler[i].Index, 1 ); 1305 } 1306 1307 if (ureg->const_decls.nr_constant_ranges) { 1308 for (i = 0; i < ureg->const_decls.nr_constant_ranges; i++) { 1309 emit_decl_range(ureg, 1310 TGSI_FILE_CONSTANT, 1311 ureg->const_decls.constant_range[i].first, 1312 ureg->const_decls.constant_range[i].last - ureg->const_decls.constant_range[i].first + 1); 1313 } 1314 } 1315 1316 for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { 1317 struct const_decl *decl = &ureg->const_decls2D[i]; 1318 1319 if (decl->nr_constant_ranges) { 1320 uint j; 1321 1322 for (j = 0; j < decl->nr_constant_ranges; j++) { 1323 emit_decl_range2D(ureg, 1324 TGSI_FILE_CONSTANT, 1325 decl->constant_range[j].first, 1326 decl->constant_range[j].last, 1327 i); 1328 } 1329 } 1330 } 1331 1332 if (ureg->nr_temps) { 1333 emit_decl_range( ureg, 1334 TGSI_FILE_TEMPORARY, 1335 0, ureg->nr_temps ); 1336 } 1337 1338 if (ureg->nr_addrs) { 1339 emit_decl_range( ureg, 1340 TGSI_FILE_ADDRESS, 1341 0, ureg->nr_addrs ); 1342 } 1343 1344 if (ureg->nr_preds) { 1345 emit_decl_range(ureg, 1346 TGSI_FILE_PREDICATE, 1347 0, 1348 ureg->nr_preds); 1349 } 1350 1351 for (i = 0; i < ureg->nr_immediates; i++) { 1352 emit_immediate( ureg, 1353 ureg->immediate[i].value.u, 1354 ureg->immediate[i].type ); 1355 } 1356} 1357 1358/* Append the instruction tokens onto the declarations to build a 1359 * contiguous stream suitable to send to the driver. 1360 */ 1361static void copy_instructions( struct ureg_program *ureg ) 1362{ 1363 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 1364 union tgsi_any_token *out = get_tokens( ureg, 1365 DOMAIN_DECL, 1366 nr_tokens ); 1367 1368 memcpy(out, 1369 ureg->domain[DOMAIN_INSN].tokens, 1370 nr_tokens * sizeof out[0] ); 1371} 1372 1373 1374static void 1375fixup_header_size(struct ureg_program *ureg) 1376{ 1377 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 0 ); 1378 1379 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 2; 1380} 1381 1382 1383static void 1384emit_header( struct ureg_program *ureg ) 1385{ 1386 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 1387 1388 out[0].header.HeaderSize = 2; 1389 out[0].header.BodySize = 0; 1390 1391 out[1].processor.Processor = ureg->processor; 1392 out[1].processor.Padding = 0; 1393} 1394 1395 1396const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) 1397{ 1398 const struct tgsi_token *tokens; 1399 1400 emit_header( ureg ); 1401 emit_decls( ureg ); 1402 copy_instructions( ureg ); 1403 fixup_header_size( ureg ); 1404 1405 if (ureg->domain[0].tokens == error_tokens || 1406 ureg->domain[1].tokens == error_tokens) { 1407 debug_printf("%s: error in generated shader\n", __FUNCTION__); 1408 assert(0); 1409 return NULL; 1410 } 1411 1412 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1413 1414 if (0) { 1415 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 1416 ureg->domain[DOMAIN_DECL].count); 1417 tgsi_dump( tokens, 0 ); 1418 } 1419 1420#if DEBUG 1421 if (tokens && !tgsi_sanity_check(tokens)) { 1422 debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); 1423 tgsi_dump(tokens, 0); 1424 assert(0); 1425 } 1426#endif 1427 1428 1429 return tokens; 1430} 1431 1432 1433void *ureg_create_shader( struct ureg_program *ureg, 1434 struct pipe_context *pipe ) 1435{ 1436 struct pipe_shader_state state; 1437 1438 state.tokens = ureg_finalize(ureg); 1439 if(!state.tokens) 1440 return NULL; 1441 1442 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 1443 return pipe->create_vs_state( pipe, &state ); 1444 else 1445 return pipe->create_fs_state( pipe, &state ); 1446} 1447 1448 1449const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg, 1450 unsigned *nr_tokens ) 1451{ 1452 const struct tgsi_token *tokens; 1453 1454 ureg_finalize(ureg); 1455 1456 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1457 1458 if (nr_tokens) 1459 *nr_tokens = ureg->domain[DOMAIN_DECL].size; 1460 1461 ureg->domain[DOMAIN_DECL].tokens = 0; 1462 ureg->domain[DOMAIN_DECL].size = 0; 1463 ureg->domain[DOMAIN_DECL].order = 0; 1464 ureg->domain[DOMAIN_DECL].count = 0; 1465 1466 return tokens; 1467} 1468 1469 1470struct ureg_program *ureg_create( unsigned processor ) 1471{ 1472 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 1473 if (ureg == NULL) 1474 return NULL; 1475 1476 ureg->processor = processor; 1477 ureg->property_gs_input_prim = ~0; 1478 ureg->property_gs_output_prim = ~0; 1479 ureg->property_gs_max_vertices = ~0; 1480 return ureg; 1481} 1482 1483 1484void ureg_destroy( struct ureg_program *ureg ) 1485{ 1486 unsigned i; 1487 1488 for (i = 0; i < Elements(ureg->domain); i++) { 1489 if (ureg->domain[i].tokens && 1490 ureg->domain[i].tokens != error_tokens) 1491 FREE(ureg->domain[i].tokens); 1492 } 1493 1494 FREE(ureg); 1495} 1496