tgsi_ureg.c revision 8a7d1e7b7681a4f0be9cee9e62477317dcd09caf
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_dump.h" 33#include "util/u_memory.h" 34 35union tgsi_any_token { 36 struct tgsi_version version; 37 struct tgsi_header header; 38 struct tgsi_processor processor; 39 struct tgsi_token token; 40 struct tgsi_declaration decl; 41 struct tgsi_declaration_range decl_range; 42 struct tgsi_declaration_semantic decl_semantic; 43 struct tgsi_immediate imm; 44 union tgsi_immediate_data imm_data; 45 struct tgsi_instruction insn; 46 struct tgsi_instruction_ext_nv insn_ext_nv; 47 struct tgsi_instruction_ext_label insn_ext_label; 48 struct tgsi_instruction_ext_texture insn_ext_texture; 49 struct tgsi_instruction_ext_predicate insn_ext_predicate; 50 struct tgsi_src_register src; 51 struct tgsi_src_register_ext_swz src_ext_swz; 52 struct tgsi_src_register_ext_mod src_ext_mod; 53 struct tgsi_dimension dim; 54 struct tgsi_dst_register dst; 55 struct tgsi_dst_register_ext_concode dst_ext_code; 56 struct tgsi_dst_register_ext_modulate dst_ext_mod; 57 struct tgsi_dst_register_ext_predicate dst_ext_pred; 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_IMMEDIATE 32 72 73#define DOMAIN_DECL 0 74#define DOMAIN_INSN 1 75 76struct ureg_program 77{ 78 unsigned processor; 79 struct pipe_context *pipe; 80 81 struct { 82 unsigned semantic_name; 83 unsigned semantic_index; 84 unsigned interp; 85 } input[UREG_MAX_INPUT]; 86 unsigned nr_inputs; 87 88 struct { 89 unsigned semantic_name; 90 unsigned semantic_index; 91 } output[UREG_MAX_OUTPUT]; 92 unsigned nr_outputs; 93 94 struct { 95 float v[4]; 96 unsigned nr; 97 } immediate[UREG_MAX_OUTPUT]; 98 unsigned nr_immediates; 99 100 101 unsigned nr_constants; 102 unsigned nr_temps; 103 unsigned nr_samplers; 104 105 struct ureg_tokens domain[2]; 106}; 107 108static union tgsi_any_token error_tokens[32]; 109 110static void tokens_error( struct ureg_tokens *tokens ) 111{ 112 tokens->tokens = error_tokens; 113 tokens->size = Elements(error_tokens); 114 tokens->count = 0; 115} 116 117 118static void tokens_expand( struct ureg_tokens *tokens, 119 unsigned count ) 120{ 121 union tgsi_any_token *tmp; 122 123 if (tokens->tokens == error_tokens) 124 goto fail; 125 126 while (tokens->count + count > tokens->size) { 127 tokens->size = (1 << ++tokens->order); 128 } 129 130 tmp = MALLOC(tokens->size * sizeof(unsigned)); 131 if (tmp == NULL) { 132 FREE(tokens->tokens); 133 goto fail; 134 } 135 136 if (tokens->count) { 137 memcpy(tmp, tokens->tokens, tokens->count * sizeof tokens->tokens[0] ); 138 FREE(tokens->tokens); 139 } 140 141 tokens->tokens = tmp; 142 return; 143 144fail: 145 tokens_error(tokens); 146} 147 148static void set_bad( struct ureg_program *ureg ) 149{ 150 tokens_error(&ureg->domain[0]); 151} 152 153 154 155static union tgsi_any_token *get_tokens( struct ureg_program *ureg, 156 unsigned domain, 157 unsigned count ) 158{ 159 struct ureg_tokens *tokens = &ureg->domain[domain]; 160 union tgsi_any_token *result; 161 162 if (tokens->count + count > tokens->size) 163 tokens_expand(tokens, count); 164 165 result = &tokens->tokens[tokens->count]; 166 tokens->count += count; 167 return result; 168} 169 170 171static union tgsi_any_token *retrieve_token( struct ureg_program *ureg, 172 unsigned domain, 173 unsigned nr ) 174{ 175 if (ureg->domain[domain].tokens == error_tokens) 176 return &error_tokens[0]; 177 178 return &ureg->domain[domain].tokens[nr]; 179} 180 181 182 183static INLINE struct ureg_dst 184ureg_dst_register( unsigned file, 185 unsigned index ) 186{ 187 struct ureg_dst dst; 188 189 dst.File = file; 190 dst.WriteMask = TGSI_WRITEMASK_XYZW; 191 dst.Indirect = 0; 192 dst.Saturate = 0; 193 dst.Index = index; 194 dst.Pad1 = 0; 195 dst.Pad2 = 0; 196 197 return dst; 198} 199 200static INLINE struct ureg_src 201ureg_src_register( unsigned file, 202 unsigned index ) 203{ 204 struct ureg_src src; 205 206 src.File = file; 207 src.SwizzleX = TGSI_SWIZZLE_X; 208 src.SwizzleY = TGSI_SWIZZLE_Y; 209 src.SwizzleZ = TGSI_SWIZZLE_Z; 210 src.SwizzleW = TGSI_SWIZZLE_W; 211 src.Pad = 0; 212 src.Indirect = 0; 213 src.Absolute = 0; 214 src.Index = index; 215 src.Negate = 0; 216 217 return src; 218} 219 220 221 222 223static struct ureg_src 224ureg_DECL_input( struct ureg_program *ureg, 225 unsigned name, 226 unsigned index, 227 unsigned interp_mode ) 228{ 229 unsigned i; 230 231 for (i = 0; i < ureg->nr_inputs; i++) { 232 if (ureg->input[i].semantic_name == name && 233 ureg->input[i].semantic_index == index) 234 goto out; 235 } 236 237 if (ureg->nr_inputs < UREG_MAX_INPUT) { 238 ureg->input[i].semantic_name = name; 239 ureg->input[i].semantic_index = index; 240 ureg->input[i].interp = interp_mode; 241 ureg->nr_inputs++; 242 } 243 else { 244 set_bad( ureg ); 245 } 246 247out: 248 return ureg_src_register( TGSI_FILE_INPUT, i ); 249} 250 251 252 253struct ureg_src 254ureg_DECL_fs_input( struct ureg_program *ureg, 255 unsigned name, 256 unsigned index, 257 unsigned interp ) 258{ 259 return ureg_DECL_input( ureg, name, index, interp ); 260} 261 262 263struct ureg_src 264ureg_DECL_vs_input( struct ureg_program *ureg, 265 unsigned name, 266 unsigned index ) 267{ 268 return ureg_DECL_input( ureg, name, index, TGSI_INTERPOLATE_CONSTANT ); 269} 270 271 272struct ureg_dst 273ureg_DECL_output( struct ureg_program *ureg, 274 unsigned name, 275 unsigned index ) 276{ 277 unsigned i; 278 279 for (i = 0; i < ureg->nr_outputs; i++) { 280 if (ureg->output[i].semantic_name == name && 281 ureg->output[i].semantic_index == index) 282 goto out; 283 } 284 285 if (ureg->nr_outputs < UREG_MAX_OUTPUT) { 286 ureg->output[i].semantic_name = name; 287 ureg->output[i].semantic_index = index; 288 ureg->nr_outputs++; 289 } 290 else { 291 set_bad( ureg ); 292 } 293 294out: 295 return ureg_dst_register( TGSI_FILE_OUTPUT, i ); 296} 297 298 299/* Returns a new constant register. Keep track of which have been 300 * referred to so that we can emit decls later. 301 * 302 * There is nothing in this code to bind this constant to any tracked 303 * value or manage any constant_buffer contents -- that's the 304 * resposibility of the calling code. 305 */ 306struct ureg_src ureg_DECL_constant(struct ureg_program *ureg ) 307{ 308 return ureg_src_register( TGSI_FILE_TEMPORARY, ureg->nr_constants++ ); 309} 310 311 312/* Allocate a new temporary. No way to release temporaries in this code. 313 */ 314struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) 315{ 316 return ureg_dst_register( TGSI_FILE_TEMPORARY, ureg->nr_temps++ ); 317} 318 319 320/* Allocate a new sampler. 321 */ 322struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg ) 323{ 324 return ureg_src_register( TGSI_FILE_SAMPLER, ureg->nr_samplers++ ); 325} 326 327 328 329 330static int match_or_expand_immediate( const float *v, 331 unsigned nr, 332 float *v2, 333 unsigned *nr2, 334 unsigned *swizzle ) 335{ 336 unsigned i, j; 337 338 for (i = 0; i < nr; i++) { 339 boolean found = FALSE; 340 341 for (j = 0; j < *nr2 && !found; j++) { 342 if (v[i] == v2[j]) { 343 *swizzle |= j << (i * 2); 344 found = TRUE; 345 } 346 } 347 348 if (!found) { 349 if (*nr2 >= 4) 350 return FALSE; 351 352 v2[*nr2] = v[i]; 353 *swizzle |= *nr2 << (i * 2); 354 (*nr2)++; 355 } 356 } 357 358 return TRUE; 359} 360 361 362 363 364struct ureg_src ureg_DECL_immediate( struct ureg_program *ureg, 365 const float *v, 366 unsigned nr ) 367{ 368 unsigned i; 369 unsigned swizzle; 370 371 /* Could do a first pass where we examine all existing immediates 372 * without expanding. 373 */ 374 375 for (i = 0; i < ureg->nr_immediates; i++) { 376 if (match_or_expand_immediate( v, 377 nr, 378 ureg->immediate[i].v, 379 &ureg->immediate[i].nr, 380 &swizzle )) 381 goto out; 382 } 383 384 if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { 385 i = ureg->nr_immediates++; 386 if (match_or_expand_immediate( v, 387 nr, 388 ureg->immediate[i].v, 389 &ureg->immediate[i].nr, 390 &swizzle )) 391 goto out; 392 } 393 394 set_bad( ureg ); 395 396out: 397 return ureg_swizzle( ureg_src_register( TGSI_FILE_IMMEDIATE, i ), 398 (swizzle >> 0) & 0x3, 399 (swizzle >> 2) & 0x3, 400 (swizzle >> 4) & 0x3, 401 (swizzle >> 6) & 0x3); 402} 403 404 405void 406ureg_emit_src( struct ureg_program *ureg, 407 struct ureg_src src ) 408{ 409 unsigned size = (1 + 410 (src.Absolute ? 1 : 0) + 411 (src.Indirect ? 1 : 0)); 412 413 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 414 unsigned n = 0; 415 416 out[n].value = 0; 417 out[n].src.File = src.File; 418 out[n].src.SwizzleX = src.SwizzleX; 419 out[n].src.SwizzleY = src.SwizzleY; 420 out[n].src.SwizzleZ = src.SwizzleZ; 421 out[n].src.SwizzleW = src.SwizzleW; 422 out[n].src.Indirect = src.Indirect; 423 out[n].src.Index = src.Index; 424 n++; 425 426 if (src.Absolute) { 427 out[n].value = 0; 428 out[n].src_ext_mod.Absolute = 1; 429 n++; 430 } 431 432 if (src.Indirect) { 433 out[n].value = 0; 434 out[n].src.File = TGSI_FILE_ADDRESS; 435 out[n].src.SwizzleX = TGSI_SWIZZLE_X; 436 out[n].src.SwizzleY = TGSI_SWIZZLE_X; 437 out[n].src.SwizzleZ = TGSI_SWIZZLE_X; 438 out[n].src.SwizzleW = TGSI_SWIZZLE_X; 439 out[n].src.Indirect = 0; 440 out[n].src.Index = 0; 441 n++; 442 } 443 444 assert(n == size); 445} 446 447 448void 449ureg_emit_dst( struct ureg_program *ureg, 450 struct ureg_dst dst ) 451{ 452 unsigned size = (1 + 453 (dst.Indirect ? 1 : 0)); 454 455 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 456 unsigned n = 0; 457 458 out[n].value = 0; 459 out[n].dst.File = dst.File; 460 out[n].dst.WriteMask = dst.WriteMask; 461 out[n].dst.Indirect = dst.Indirect; 462 out[n].dst.Index = dst.Index; 463 n++; 464 465 if (dst.Indirect) { 466 out[n].value = 0; 467 out[n].src.File = TGSI_FILE_ADDRESS; 468 out[n].src.SwizzleX = TGSI_SWIZZLE_X; 469 out[n].src.SwizzleY = TGSI_SWIZZLE_X; 470 out[n].src.SwizzleZ = TGSI_SWIZZLE_X; 471 out[n].src.SwizzleW = TGSI_SWIZZLE_X; 472 out[n].src.Indirect = 0; 473 out[n].src.Index = 0; 474 n++; 475 } 476 477 assert(n == size); 478} 479 480 481 482unsigned 483ureg_emit_insn(struct ureg_program *ureg, 484 unsigned opcode, 485 boolean saturate, 486 unsigned num_dst, 487 unsigned num_src ) 488{ 489 union tgsi_any_token *out; 490 491 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 492 out[0].value = 0; 493 out[0].insn.Type = TGSI_TOKEN_TYPE_INSTRUCTION; 494 out[0].insn.NrTokens = 0; 495 out[0].insn.Opcode = opcode; 496 out[0].insn.Saturate = saturate; 497 out[0].insn.NrTokens = 0; 498 out[0].insn.NumDstRegs = num_dst; 499 out[0].insn.NumSrcRegs = num_src; 500 out[0].insn.Padding = 0; 501 out[0].insn.Extended = 0; 502 503 return ureg->domain[DOMAIN_INSN].count - 1; 504} 505 506 507void 508ureg_emit_label(struct ureg_program *ureg, 509 unsigned insn_token, 510 unsigned *label_token ) 511{ 512 union tgsi_any_token *out, *insn; 513 514 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 515 insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); 516 517 insn->insn.Extended = 1; 518 519 out[0].value = 0; 520 out[0].insn_ext_label.Type = TGSI_INSTRUCTION_EXT_TYPE_LABEL; 521} 522 523 524void 525ureg_emit_texture(struct ureg_program *ureg, 526 unsigned insn_token, 527 unsigned target ) 528{ 529 union tgsi_any_token *out, *insn; 530 531 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 532 insn = retrieve_token( ureg, DOMAIN_INSN, insn_token ); 533 534 insn->insn.Extended = 1; 535 536 out[0].value = 0; 537 out[0].insn_ext_texture.Type = TGSI_INSTRUCTION_EXT_TYPE_TEXTURE; 538 out[0].insn_ext_texture.Texture = target; 539} 540 541 542void 543ureg_fixup_insn_size(struct ureg_program *ureg, 544 unsigned insn ) 545{ 546 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); 547 548 out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; 549} 550 551 552 553 554 555static void emit_decl( struct ureg_program *ureg, 556 unsigned file, 557 unsigned index, 558 unsigned semantic_name, 559 unsigned semantic_index, 560 unsigned interp ) 561{ 562 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 563 564 out[0].value = 0; 565 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 566 out[0].decl.NrTokens = 3; 567 out[0].decl.File = file; 568 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 569 out[0].decl.Interpolate = interp; 570 out[0].decl.Semantic = 1; 571 572 out[1].value = 0; 573 out[1].decl_range.First = 574 out[1].decl_range.Last = index; 575 576 out[2].value = 0; 577 out[2].decl_semantic.SemanticName = semantic_name; 578 out[2].decl_semantic.SemanticIndex = semantic_index; 579 580} 581 582 583static void emit_decl_range( struct ureg_program *ureg, 584 unsigned file, 585 unsigned first, 586 unsigned count ) 587{ 588 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 589 590 out[0].value = 0; 591 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 592 out[0].decl.NrTokens = 2; 593 out[0].decl.File = file; 594 out[0].decl.UsageMask = 0xf; 595 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 596 out[0].decl.Semantic = 0; 597 598 out[1].value = 0; 599 out[1].decl_range.First = first; 600 out[1].decl_range.Last = first + count - 1; 601} 602 603static void emit_immediate( struct ureg_program *ureg, 604 const float *v ) 605{ 606 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); 607 608 out[0].value = 0; 609 out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; 610 out[0].imm.NrTokens = 5; 611 out[0].imm.DataType = TGSI_IMM_FLOAT32; 612 out[0].imm.Padding = 0; 613 out[0].imm.Extended = 0; 614 615 out[1].imm_data.Float = v[0]; 616 out[2].imm_data.Float = v[1]; 617 out[3].imm_data.Float = v[2]; 618 out[4].imm_data.Float = v[3]; 619} 620 621 622 623 624static void emit_decls( struct ureg_program *ureg ) 625{ 626 unsigned i; 627 628 for (i = 0; i < ureg->nr_inputs; i++) { 629 emit_decl( ureg, 630 TGSI_FILE_INPUT, 631 i, 632 ureg->input[i].semantic_name, 633 ureg->input[i].semantic_index, 634 ureg->input[i].interp ); 635 } 636 637 for (i = 0; i < ureg->nr_outputs; i++) { 638 emit_decl( ureg, 639 TGSI_FILE_OUTPUT, 640 i, 641 ureg->output[i].semantic_name, 642 ureg->output[i].semantic_index, 643 TGSI_INTERPOLATE_CONSTANT ); 644 } 645 646 if (ureg->nr_samplers) { 647 emit_decl_range( ureg, 648 TGSI_FILE_SAMPLER, 649 0, ureg->nr_samplers ); 650 } 651 652 if (ureg->nr_constants) { 653 emit_decl_range( ureg, 654 TGSI_FILE_CONSTANT, 655 0, ureg->nr_constants ); 656 } 657 658 if (ureg->nr_temps) { 659 emit_decl_range( ureg, 660 TGSI_FILE_TEMPORARY, 661 0, ureg->nr_temps ); 662 } 663 664 for (i = 0; i < ureg->nr_immediates; i++) { 665 emit_immediate( ureg, 666 ureg->immediate[i].v ); 667 } 668} 669 670/* Append the instruction tokens onto the declarations to build a 671 * contiguous stream suitable to send to the driver. 672 */ 673static void copy_instructions( struct ureg_program *ureg ) 674{ 675 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 676 union tgsi_any_token *out = get_tokens( ureg, 677 DOMAIN_DECL, 678 nr_tokens ); 679 680 memcpy(out, 681 ureg->domain[DOMAIN_INSN].tokens, 682 nr_tokens * sizeof out[0] ); 683} 684 685 686static void 687fixup_header_size(struct ureg_program *ureg, 688 unsigned insn ) 689{ 690 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 1 ); 691 692 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 3; 693} 694 695 696static void 697emit_header( struct ureg_program *ureg ) 698{ 699 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 700 701 out[0].version.MajorVersion = 1; 702 out[0].version.MinorVersion = 1; 703 out[0].version.Padding = 0; 704 705 out[1].header.HeaderSize = 2; 706 out[1].header.BodySize = 0; 707 708 out[2].processor.Processor = ureg->processor; 709 out[2].processor.Padding = 0; 710} 711 712 713void *ureg_create_shader( struct ureg_program *ureg ) 714{ 715 struct pipe_shader_state state; 716 unsigned insn; 717 718 emit_header( ureg ); 719 emit_decls( ureg ); 720 copy_instructions( ureg ); 721 fixup_header_size( ureg, insn ); 722 723 if (ureg->domain[0].tokens == error_tokens || 724 ureg->domain[1].tokens == error_tokens) { 725 debug_printf("%s: error in generated shader\n", __FUNCTION__); 726 assert(0); 727 return NULL; 728 } 729 730 state.tokens = (const struct tgsi_token *)ureg->domain[DOMAIN_DECL].tokens; 731 732 if (1) { 733 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 734 ureg->domain[DOMAIN_DECL].count); 735 tgsi_dump( state.tokens, 0 ); 736 } 737 738 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 739 return ureg->pipe->create_vs_state( ureg->pipe, &state ); 740 else 741 return ureg->pipe->create_fs_state( ureg->pipe, &state ); 742} 743 744 745 746 747struct ureg_program *ureg_create( struct pipe_context *pipe, 748 unsigned processor ) 749{ 750 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 751 if (ureg == NULL) 752 return NULL; 753 754 ureg->pipe = pipe; 755 ureg->processor = processor; 756 return ureg; 757} 758 759 760void ureg_destroy( struct ureg_program *ureg ) 761{ 762 unsigned i; 763 764 for (i = 0; i < Elements(ureg->domain); i++) { 765 if (ureg->domain[i].tokens && 766 ureg->domain[i].tokens != error_tokens) 767 FREE(ureg->domain[i].tokens); 768 } 769 770 FREE(ureg); 771} 772