1 /* 2 * Copyright 2010 Tom Stellard <tstellar (at) gmail.com> 3 * 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a 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, sublicense, 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 16 * portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 */ 27 28 /** 29 * \file 30 */ 31 32 #include "radeon_compiler_util.h" 33 34 #include "radeon_compiler.h" 35 #include "radeon_dataflow.h" 36 /** 37 */ 38 unsigned int rc_swizzle_to_writemask(unsigned int swz) 39 { 40 unsigned int mask = 0; 41 unsigned int i; 42 43 for(i = 0; i < 4; i++) { 44 mask |= 1 << GET_SWZ(swz, i); 45 } 46 mask &= RC_MASK_XYZW; 47 48 return mask; 49 } 50 51 rc_swizzle get_swz(unsigned int swz, rc_swizzle idx) 52 { 53 if (idx & 0x4) 54 return idx; 55 return GET_SWZ(swz, idx); 56 } 57 58 /** 59 * The purpose of this function is to standardize the number channels used by 60 * swizzles. All swizzles regardless of what instruction they are a part of 61 * should have 4 channels initialized with values. 62 * @param channels The number of channels in initial_value that have a 63 * meaningful value. 64 * @return An initialized swizzle that has all of the unused channels set to 65 * RC_SWIZZLE_UNUSED. 66 */ 67 unsigned int rc_init_swizzle(unsigned int initial_value, unsigned int channels) 68 { 69 unsigned int i; 70 for (i = channels; i < 4; i++) { 71 SET_SWZ(initial_value, i, RC_SWIZZLE_UNUSED); 72 } 73 return initial_value; 74 } 75 76 unsigned int combine_swizzles4(unsigned int src, 77 rc_swizzle swz_x, rc_swizzle swz_y, rc_swizzle swz_z, rc_swizzle swz_w) 78 { 79 unsigned int ret = 0; 80 81 ret |= get_swz(src, swz_x); 82 ret |= get_swz(src, swz_y) << 3; 83 ret |= get_swz(src, swz_z) << 6; 84 ret |= get_swz(src, swz_w) << 9; 85 86 return ret; 87 } 88 89 unsigned int combine_swizzles(unsigned int src, unsigned int swz) 90 { 91 unsigned int ret = 0; 92 93 ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_X)); 94 ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Y)) << 3; 95 ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Z)) << 6; 96 ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_W)) << 9; 97 98 return ret; 99 } 100 101 /** 102 * @param mask Must be either RC_MASK_X, RC_MASK_Y, RC_MASK_Z, or RC_MASK_W 103 */ 104 rc_swizzle rc_mask_to_swizzle(unsigned int mask) 105 { 106 switch (mask) { 107 case RC_MASK_X: return RC_SWIZZLE_X; 108 case RC_MASK_Y: return RC_SWIZZLE_Y; 109 case RC_MASK_Z: return RC_SWIZZLE_Z; 110 case RC_MASK_W: return RC_SWIZZLE_W; 111 } 112 return RC_SWIZZLE_UNUSED; 113 } 114 115 /* Reorder mask bits according to swizzle. */ 116 unsigned swizzle_mask(unsigned swizzle, unsigned mask) 117 { 118 unsigned ret = 0; 119 for (unsigned chan = 0; chan < 4; ++chan) { 120 unsigned swz = GET_SWZ(swizzle, chan); 121 if (swz < 4) 122 ret |= GET_BIT(mask, swz) << chan; 123 } 124 return ret; 125 } 126 127 static unsigned int srcs_need_rewrite(const struct rc_opcode_info * info) 128 { 129 if (info->HasTexture) { 130 return 0; 131 } 132 switch (info->Opcode) { 133 case RC_OPCODE_DP2: 134 case RC_OPCODE_DP3: 135 case RC_OPCODE_DP4: 136 case RC_OPCODE_DDX: 137 case RC_OPCODE_DDY: 138 return 0; 139 default: 140 return 1; 141 } 142 } 143 144 /** 145 * @return A swizzle the results from converting old_swizzle using 146 * conversion_swizzle 147 */ 148 unsigned int rc_adjust_channels( 149 unsigned int old_swizzle, 150 unsigned int conversion_swizzle) 151 { 152 unsigned int i; 153 unsigned int new_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0); 154 for (i = 0; i < 4; i++) { 155 unsigned int new_chan = get_swz(conversion_swizzle, i); 156 if (new_chan == RC_SWIZZLE_UNUSED) { 157 continue; 158 } 159 SET_SWZ(new_swizzle, new_chan, GET_SWZ(old_swizzle, i)); 160 } 161 return new_swizzle; 162 } 163 164 static unsigned int rewrite_writemask( 165 unsigned int old_mask, 166 unsigned int conversion_swizzle) 167 { 168 unsigned int new_mask = 0; 169 unsigned int i; 170 171 for (i = 0; i < 4; i++) { 172 if (!GET_BIT(old_mask, i) 173 || GET_SWZ(conversion_swizzle, i) == RC_SWIZZLE_UNUSED) { 174 continue; 175 } 176 new_mask |= (1 << GET_SWZ(conversion_swizzle, i)); 177 } 178 179 return new_mask; 180 } 181 182 /** 183 * This function rewrites the writemask of sub and adjusts the swizzles 184 * of all its source registers based on the conversion_swizzle. 185 * conversion_swizzle represents a mapping of the old writemask to the 186 * new writemask. For a detailed description of how conversion swizzles 187 * work see rc_rewrite_swizzle(). 188 */ 189 void rc_pair_rewrite_writemask( 190 struct rc_pair_sub_instruction * sub, 191 unsigned int conversion_swizzle) 192 { 193 const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); 194 unsigned int i; 195 196 sub->WriteMask = rewrite_writemask(sub->WriteMask, conversion_swizzle); 197 198 if (!srcs_need_rewrite(info)) { 199 return ; 200 } 201 202 for (i = 0; i < info->NumSrcRegs; i++) { 203 sub->Arg[i].Swizzle = 204 rc_adjust_channels(sub->Arg[i].Swizzle, 205 conversion_swizzle); 206 } 207 } 208 209 static void normal_rewrite_writemask_cb( 210 void * userdata, 211 struct rc_instruction * inst, 212 struct rc_src_register * src) 213 { 214 unsigned int * conversion_swizzle = (unsigned int *)userdata; 215 src->Swizzle = rc_adjust_channels(src->Swizzle, *conversion_swizzle); 216 } 217 218 /** 219 * This function is the same as rc_pair_rewrite_writemask() except it 220 * operates on normal instructions. 221 */ 222 void rc_normal_rewrite_writemask( 223 struct rc_instruction * inst, 224 unsigned int conversion_swizzle) 225 { 226 struct rc_sub_instruction * sub = &inst->U.I; 227 const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); 228 sub->DstReg.WriteMask = 229 rewrite_writemask(sub->DstReg.WriteMask, conversion_swizzle); 230 231 if (info->HasTexture) { 232 unsigned int i; 233 assert(sub->TexSwizzle == RC_SWIZZLE_XYZW); 234 for (i = 0; i < 4; i++) { 235 unsigned int swz = GET_SWZ(conversion_swizzle, i); 236 if (swz > 3) 237 continue; 238 SET_SWZ(sub->TexSwizzle, swz, i); 239 } 240 } 241 242 if (!srcs_need_rewrite(info)) { 243 return; 244 } 245 246 rc_for_all_reads_src(inst, normal_rewrite_writemask_cb, 247 &conversion_swizzle); 248 } 249 250 /** 251 * This function replaces each value 'swz' in swizzle with the value of 252 * GET_SWZ(conversion_swizzle, swz). So, if you want to change all the X's 253 * in swizzle to Y, then conversion_swizzle should be Y___ (0xff9). If you want 254 * to change all the Y's in swizzle to X, then conversion_swizzle should be 255 * _X__ (0xfc7). If you want to change the Y's to X and the X's to Y, then 256 * conversion swizzle should be YX__ (0xfc1). 257 * @param swizzle The swizzle to change 258 * @param conversion_swizzle Describes the conversion to perform on the swizzle 259 * @return A converted swizzle 260 */ 261 unsigned int rc_rewrite_swizzle( 262 unsigned int swizzle, 263 unsigned int conversion_swizzle) 264 { 265 unsigned int chan; 266 unsigned int out_swizzle = swizzle; 267 268 for (chan = 0; chan < 4; chan++) { 269 unsigned int swz = GET_SWZ(swizzle, chan); 270 unsigned int new_swz; 271 if (swz > 3) { 272 SET_SWZ(out_swizzle, chan, swz); 273 } else { 274 new_swz = GET_SWZ(conversion_swizzle, swz); 275 if (new_swz != RC_SWIZZLE_UNUSED) { 276 SET_SWZ(out_swizzle, chan, new_swz); 277 } else { 278 SET_SWZ(out_swizzle, chan, swz); 279 } 280 } 281 } 282 return out_swizzle; 283 } 284 285 /** 286 * Left multiplication of a register with a swizzle 287 */ 288 struct rc_src_register lmul_swizzle(unsigned int swizzle, struct rc_src_register srcreg) 289 { 290 struct rc_src_register tmp = srcreg; 291 int i; 292 tmp.Swizzle = 0; 293 tmp.Negate = 0; 294 for(i = 0; i < 4; ++i) { 295 rc_swizzle swz = GET_SWZ(swizzle, i); 296 if (swz < 4) { 297 tmp.Swizzle |= GET_SWZ(srcreg.Swizzle, swz) << (i*3); 298 tmp.Negate |= GET_BIT(srcreg.Negate, swz) << i; 299 } else { 300 tmp.Swizzle |= swz << (i*3); 301 } 302 } 303 return tmp; 304 } 305 306 void reset_srcreg(struct rc_src_register* reg) 307 { 308 memset(reg, 0, sizeof(struct rc_src_register)); 309 reg->Swizzle = RC_SWIZZLE_XYZW; 310 } 311 312 unsigned int rc_src_reads_dst_mask( 313 rc_register_file src_file, 314 unsigned int src_idx, 315 unsigned int src_swz, 316 rc_register_file dst_file, 317 unsigned int dst_idx, 318 unsigned int dst_mask) 319 { 320 if (src_file != dst_file || src_idx != dst_idx) { 321 return RC_MASK_NONE; 322 } 323 return dst_mask & rc_swizzle_to_writemask(src_swz); 324 } 325 326 /** 327 * @return A bit mask specifying whether this swizzle will select from an RGB 328 * source, an Alpha source, or both. 329 */ 330 unsigned int rc_source_type_swz(unsigned int swizzle) 331 { 332 unsigned int chan; 333 unsigned int swz = RC_SWIZZLE_UNUSED; 334 unsigned int ret = RC_SOURCE_NONE; 335 336 for(chan = 0; chan < 4; chan++) { 337 swz = GET_SWZ(swizzle, chan); 338 if (swz == RC_SWIZZLE_W) { 339 ret |= RC_SOURCE_ALPHA; 340 } else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y 341 || swz == RC_SWIZZLE_Z) { 342 ret |= RC_SOURCE_RGB; 343 } 344 } 345 return ret; 346 } 347 348 unsigned int rc_source_type_mask(unsigned int mask) 349 { 350 unsigned int ret = RC_SOURCE_NONE; 351 352 if (mask & RC_MASK_XYZ) 353 ret |= RC_SOURCE_RGB; 354 355 if (mask & RC_MASK_W) 356 ret |= RC_SOURCE_ALPHA; 357 358 return ret; 359 } 360 361 struct src_select { 362 rc_register_file File; 363 int Index; 364 unsigned int SrcType; 365 }; 366 367 struct can_use_presub_data { 368 struct src_select Selects[5]; 369 unsigned int SelectCount; 370 const struct rc_src_register * ReplaceReg; 371 unsigned int ReplaceRemoved; 372 }; 373 374 static void can_use_presub_data_add_select( 375 struct can_use_presub_data * data, 376 rc_register_file file, 377 unsigned int index, 378 unsigned int src_type) 379 { 380 struct src_select * select; 381 382 select = &data->Selects[data->SelectCount++]; 383 select->File = file; 384 select->Index = index; 385 select->SrcType = src_type; 386 } 387 388 /** 389 * This callback function counts the number of sources in inst that are 390 * different from the sources in can_use_presub_data->RemoveSrcs. 391 */ 392 static void can_use_presub_read_cb( 393 void * userdata, 394 struct rc_instruction * inst, 395 struct rc_src_register * src) 396 { 397 struct can_use_presub_data * d = userdata; 398 399 if (!d->ReplaceRemoved && src == d->ReplaceReg) { 400 d->ReplaceRemoved = 1; 401 return; 402 } 403 404 if (src->File == RC_FILE_NONE) 405 return; 406 407 can_use_presub_data_add_select(d, src->File, src->Index, 408 rc_source_type_swz(src->Swizzle)); 409 } 410 411 unsigned int rc_inst_can_use_presub( 412 struct rc_instruction * inst, 413 rc_presubtract_op presub_op, 414 unsigned int presub_writemask, 415 const struct rc_src_register * replace_reg, 416 const struct rc_src_register * presub_src0, 417 const struct rc_src_register * presub_src1) 418 { 419 struct can_use_presub_data d; 420 unsigned int num_presub_srcs; 421 unsigned int i; 422 const struct rc_opcode_info * info = 423 rc_get_opcode_info(inst->U.I.Opcode); 424 int rgb_count = 0, alpha_count = 0; 425 unsigned int src_type0, src_type1; 426 427 if (presub_op == RC_PRESUB_NONE) { 428 return 1; 429 } 430 431 if (info->HasTexture) { 432 return 0; 433 } 434 435 /* We can't use more than one presubtract value in an 436 * instruction, unless the two prsubtract operations 437 * are the same and read from the same registers. 438 * XXX For now we will limit instructions to only one presubtract 439 * value.*/ 440 if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE) { 441 return 0; 442 } 443 444 memset(&d, 0, sizeof(d)); 445 d.ReplaceReg = replace_reg; 446 447 rc_for_all_reads_src(inst, can_use_presub_read_cb, &d); 448 449 num_presub_srcs = rc_presubtract_src_reg_count(presub_op); 450 451 src_type0 = rc_source_type_swz(presub_src0->Swizzle); 452 can_use_presub_data_add_select(&d, 453 presub_src0->File, 454 presub_src0->Index, 455 src_type0); 456 457 if (num_presub_srcs > 1) { 458 src_type1 = rc_source_type_swz(presub_src1->Swizzle); 459 can_use_presub_data_add_select(&d, 460 presub_src1->File, 461 presub_src1->Index, 462 src_type1); 463 464 /* Even if both of the presub sources read from the same 465 * register, we still need to use 2 different source selects 466 * for them, so we need to increment the count to compensate. 467 */ 468 if (presub_src0->File == presub_src1->File 469 && presub_src0->Index == presub_src1->Index) { 470 if (src_type0 & src_type1 & RC_SOURCE_RGB) { 471 rgb_count++; 472 } 473 if (src_type0 & src_type1 & RC_SOURCE_ALPHA) { 474 alpha_count++; 475 } 476 } 477 } 478 479 /* Count the number of source selects for Alpha and RGB. If we 480 * encounter two of the same source selects then we can ignore the 481 * first one. */ 482 for (i = 0; i < d.SelectCount; i++) { 483 unsigned int j; 484 unsigned int src_type = d.Selects[i].SrcType; 485 for (j = i + 1; j < d.SelectCount; j++) { 486 if (d.Selects[i].File == d.Selects[j].File 487 && d.Selects[i].Index == d.Selects[j].Index) { 488 src_type &= ~d.Selects[j].SrcType; 489 } 490 } 491 if (src_type & RC_SOURCE_RGB) { 492 rgb_count++; 493 } 494 495 if (src_type & RC_SOURCE_ALPHA) { 496 alpha_count++; 497 } 498 } 499 500 if (rgb_count > 3 || alpha_count > 3) { 501 return 0; 502 } 503 504 return 1; 505 } 506 507 struct max_data { 508 unsigned int Max; 509 unsigned int HasFileType; 510 rc_register_file File; 511 }; 512 513 static void max_callback( 514 void * userdata, 515 struct rc_instruction * inst, 516 rc_register_file file, 517 unsigned int index, 518 unsigned int mask) 519 { 520 struct max_data * d = (struct max_data*)userdata; 521 if (file == d->File && (!d->HasFileType || index > d->Max)) { 522 d->Max = index; 523 d->HasFileType = 1; 524 } 525 } 526 527 /** 528 * @return The maximum index of the specified register file used by the 529 * program. 530 */ 531 int rc_get_max_index( 532 struct radeon_compiler * c, 533 rc_register_file file) 534 { 535 struct max_data data; 536 struct rc_instruction * inst; 537 data.Max = 0; 538 data.HasFileType = 0; 539 data.File = file; 540 for (inst = c->Program.Instructions.Next; 541 inst != &c->Program.Instructions; 542 inst = inst->Next) { 543 rc_for_all_reads_mask(inst, max_callback, &data); 544 rc_for_all_writes_mask(inst, max_callback, &data); 545 } 546 if (!data.HasFileType) { 547 return -1; 548 } else { 549 return data.Max; 550 } 551 } 552 553 static unsigned int get_source_readmask( 554 struct rc_pair_sub_instruction * sub, 555 unsigned int source, 556 unsigned int src_type) 557 { 558 unsigned int i; 559 unsigned int readmask = 0; 560 const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); 561 562 for (i = 0; i < info->NumSrcRegs; i++) { 563 if (sub->Arg[i].Source != source 564 || src_type != rc_source_type_swz(sub->Arg[i].Swizzle)) { 565 continue; 566 } 567 readmask |= rc_swizzle_to_writemask(sub->Arg[i].Swizzle); 568 } 569 return readmask; 570 } 571 572 /** 573 * This function attempts to remove a source from a pair instructions. 574 * @param inst 575 * @param src_type RC_SOURCE_RGB, RC_SOURCE_ALPHA, or both bitwise or'd 576 * @param source The index of the source to remove 577 * @param new_readmask A mask representing the components that are read by 578 * the source that is intended to replace the one you are removing. If you 579 * want to remove a source only and not replace it, this parameter should be 580 * zero. 581 * @return 1 if the source was successfully removed, 0 if it was not 582 */ 583 unsigned int rc_pair_remove_src( 584 struct rc_instruction * inst, 585 unsigned int src_type, 586 unsigned int source, 587 unsigned int new_readmask) 588 { 589 unsigned int readmask = 0; 590 591 readmask |= get_source_readmask(&inst->U.P.RGB, source, src_type); 592 readmask |= get_source_readmask(&inst->U.P.Alpha, source, src_type); 593 594 if ((new_readmask & readmask) != readmask) 595 return 0; 596 597 if (src_type & RC_SOURCE_RGB) { 598 memset(&inst->U.P.RGB.Src[source], 0, 599 sizeof(struct rc_pair_instruction_source)); 600 } 601 602 if (src_type & RC_SOURCE_ALPHA) { 603 memset(&inst->U.P.Alpha.Src[source], 0, 604 sizeof(struct rc_pair_instruction_source)); 605 } 606 607 return 1; 608 } 609 610 /** 611 * @return RC_OPCODE_NOOP if inst is not a flow control instruction. 612 * @return The opcode of inst if it is a flow control instruction. 613 */ 614 rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst) 615 { 616 const struct rc_opcode_info * info; 617 if (inst->Type == RC_INSTRUCTION_NORMAL) { 618 info = rc_get_opcode_info(inst->U.I.Opcode); 619 } else { 620 info = rc_get_opcode_info(inst->U.P.RGB.Opcode); 621 /*A flow control instruction shouldn't have an alpha 622 * instruction.*/ 623 assert(!info->IsFlowControl || 624 inst->U.P.Alpha.Opcode == RC_OPCODE_NOP); 625 } 626 627 if (info->IsFlowControl) 628 return info->Opcode; 629 else 630 return RC_OPCODE_NOP; 631 632 } 633 634 /** 635 * @return The BGNLOOP instruction that starts the loop ended by endloop. 636 */ 637 struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop) 638 { 639 unsigned int endloop_count = 0; 640 struct rc_instruction * inst; 641 for (inst = endloop->Prev; inst != endloop; inst = inst->Prev) { 642 rc_opcode op = rc_get_flow_control_inst(inst); 643 if (op == RC_OPCODE_ENDLOOP) { 644 endloop_count++; 645 } else if (op == RC_OPCODE_BGNLOOP) { 646 if (endloop_count == 0) { 647 return inst; 648 } else { 649 endloop_count--; 650 } 651 } 652 } 653 return NULL; 654 } 655 656 /** 657 * @return The ENDLOOP instruction that ends the loop started by bgnloop. 658 */ 659 struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop) 660 { 661 unsigned int bgnloop_count = 0; 662 struct rc_instruction * inst; 663 for (inst = bgnloop->Next; inst!=bgnloop; inst = inst->Next) { 664 rc_opcode op = rc_get_flow_control_inst(inst); 665 if (op == RC_OPCODE_BGNLOOP) { 666 bgnloop_count++; 667 } else if (op == RC_OPCODE_ENDLOOP) { 668 if (bgnloop_count == 0) { 669 return inst; 670 } else { 671 bgnloop_count--; 672 } 673 } 674 } 675 return NULL; 676 } 677 678 /** 679 * @return A conversion swizzle for converting from old_mask->new_mask 680 */ 681 unsigned int rc_make_conversion_swizzle( 682 unsigned int old_mask, 683 unsigned int new_mask) 684 { 685 unsigned int conversion_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0); 686 unsigned int old_idx; 687 unsigned int new_idx = 0; 688 for (old_idx = 0; old_idx < 4; old_idx++) { 689 if (!GET_BIT(old_mask, old_idx)) 690 continue; 691 for ( ; new_idx < 4; new_idx++) { 692 if (GET_BIT(new_mask, new_idx)) { 693 SET_SWZ(conversion_swizzle, old_idx, new_idx); 694 new_idx++; 695 break; 696 } 697 } 698 } 699 return conversion_swizzle; 700 } 701 702 /** 703 * @return 1 if the register contains an immediate value, 0 otherwise. 704 */ 705 unsigned int rc_src_reg_is_immediate( 706 struct radeon_compiler * c, 707 unsigned int file, 708 unsigned int index) 709 { 710 return file == RC_FILE_CONSTANT && 711 c->Program.Constants.Constants[index].Type == RC_CONSTANT_IMMEDIATE; 712 } 713 714 /** 715 * @return The immediate value in the specified register. 716 */ 717 float rc_get_constant_value( 718 struct radeon_compiler * c, 719 unsigned int index, 720 unsigned int swizzle, 721 unsigned int negate, 722 unsigned int chan) 723 { 724 float base = 1.0f; 725 int swz = GET_SWZ(swizzle, chan); 726 if(swz >= 4 || index >= c->Program.Constants.Count ){ 727 rc_error(c, "get_constant_value: Can't find a value.\n"); 728 return 0.0f; 729 } 730 if(GET_BIT(negate, chan)){ 731 base = -1.0f; 732 } 733 return base * 734 c->Program.Constants.Constants[index].u.Immediate[swz]; 735 } 736 737 /** 738 * This function returns the component value (RC_SWIZZLE_*) of the first used 739 * channel in the swizzle. This is only useful for scalar instructions that are 740 * known to use only one channel of the swizzle. 741 */ 742 unsigned int rc_get_scalar_src_swz(unsigned int swizzle) 743 { 744 unsigned int swz, chan; 745 for (chan = 0; chan < 4; chan++) { 746 swz = GET_SWZ(swizzle, chan); 747 if (swz != RC_SWIZZLE_UNUSED) { 748 break; 749 } 750 } 751 assert(swz != RC_SWIZZLE_UNUSED); 752 return swz; 753 } 754