1/* 2 * Copyright (C) 2008 Nicolai Haehnle. 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 * Utilities to deal with the somewhat odd restriction on R300 fragment 31 * program swizzles. 32 */ 33 34#include "r300_fragprog_swizzle.h" 35 36#include <stdio.h> 37 38#include "util/macros.h" 39 40#include "r300_reg.h" 41#include "radeon_compiler.h" 42 43#define MAKE_SWZ3(x, y, z) (RC_MAKE_SWIZZLE(RC_SWIZZLE_##x, RC_SWIZZLE_##y, RC_SWIZZLE_##z, RC_SWIZZLE_ZERO)) 44 45struct swizzle_data { 46 unsigned int hash; /**< swizzle value this matches */ 47 unsigned int base; /**< base value for hw swizzle */ 48 unsigned int stride; /**< difference in base between arg0/1/2 */ 49 unsigned int srcp_stride; /**< difference in base between arg0/scrp */ 50}; 51 52static const struct swizzle_data native_swizzles[] = { 53 {MAKE_SWZ3(X, Y, Z), R300_ALU_ARGC_SRC0C_XYZ, 4, 15}, 54 {MAKE_SWZ3(X, X, X), R300_ALU_ARGC_SRC0C_XXX, 4, 15}, 55 {MAKE_SWZ3(Y, Y, Y), R300_ALU_ARGC_SRC0C_YYY, 4, 15}, 56 {MAKE_SWZ3(Z, Z, Z), R300_ALU_ARGC_SRC0C_ZZZ, 4, 15}, 57 {MAKE_SWZ3(W, W, W), R300_ALU_ARGC_SRC0A, 1, 7}, 58 {MAKE_SWZ3(Y, Z, X), R300_ALU_ARGC_SRC0C_YZX, 1, 0}, 59 {MAKE_SWZ3(Z, X, Y), R300_ALU_ARGC_SRC0C_ZXY, 1, 0}, 60 {MAKE_SWZ3(W, Z, Y), R300_ALU_ARGC_SRC0CA_WZY, 1, 0}, 61 {MAKE_SWZ3(ONE, ONE, ONE), R300_ALU_ARGC_ONE, 0, 0}, 62 {MAKE_SWZ3(ZERO, ZERO, ZERO), R300_ALU_ARGC_ZERO, 0, 0}, 63 {MAKE_SWZ3(HALF, HALF, HALF), R300_ALU_ARGC_HALF, 0, 0} 64}; 65 66static const int num_native_swizzles = ARRAY_SIZE(native_swizzles); 67 68/** 69 * Find a native RGB swizzle that matches the given swizzle. 70 * Returns 0 if none found. 71 */ 72static const struct swizzle_data* lookup_native_swizzle(unsigned int swizzle) 73{ 74 int i, comp; 75 76 for(i = 0; i < num_native_swizzles; ++i) { 77 const struct swizzle_data* sd = &native_swizzles[i]; 78 for(comp = 0; comp < 3; ++comp) { 79 unsigned int swz = GET_SWZ(swizzle, comp); 80 if (swz == RC_SWIZZLE_UNUSED) 81 continue; 82 if (swz != GET_SWZ(sd->hash, comp)) 83 break; 84 } 85 if (comp == 3) 86 return sd; 87 } 88 89 return 0; 90} 91 92/** 93 * Determines if the given swizzle is valid for r300/r400. In most situations 94 * it is better to use r300_swizzle_is_native() which can be accesed via 95 * struct radeon_compiler *c; c->SwizzleCaps->IsNative(). 96 */ 97int r300_swizzle_is_native_basic(unsigned int swizzle) 98{ 99 if(lookup_native_swizzle(swizzle)) 100 return 1; 101 else 102 return 0; 103} 104 105/** 106 * Check whether the given instruction supports the swizzle and negate 107 * combinations in the given source register. 108 */ 109static int r300_swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) 110{ 111 const struct swizzle_data* sd; 112 unsigned int relevant; 113 int j; 114 115 if (opcode == RC_OPCODE_KIL || 116 opcode == RC_OPCODE_TEX || 117 opcode == RC_OPCODE_TXB || 118 opcode == RC_OPCODE_TXP) { 119 if (reg.Abs || reg.Negate) 120 return 0; 121 122 for(j = 0; j < 4; ++j) { 123 unsigned int swz = GET_SWZ(reg.Swizzle, j); 124 if (swz == RC_SWIZZLE_UNUSED) 125 continue; 126 if (swz != j) 127 return 0; 128 } 129 130 return 1; 131 } 132 133 relevant = 0; 134 135 for(j = 0; j < 3; ++j) 136 if (GET_SWZ(reg.Swizzle, j) != RC_SWIZZLE_UNUSED) 137 relevant |= 1 << j; 138 139 if ((reg.Negate & relevant) && ((reg.Negate & relevant) != relevant)) 140 return 0; 141 142 sd = lookup_native_swizzle(reg.Swizzle); 143 if (!sd || (reg.File == RC_FILE_PRESUB && sd->srcp_stride == 0)) 144 return 0; 145 146 return 1; 147} 148 149 150static void r300_swizzle_split( 151 struct rc_src_register src, unsigned int mask, 152 struct rc_swizzle_split * split) 153{ 154 split->NumPhases = 0; 155 156 while(mask) { 157 unsigned int best_matchcount = 0; 158 unsigned int best_matchmask = 0; 159 int i, comp; 160 161 for(i = 0; i < num_native_swizzles; ++i) { 162 const struct swizzle_data *sd = &native_swizzles[i]; 163 unsigned int matchcount = 0; 164 unsigned int matchmask = 0; 165 for(comp = 0; comp < 3; ++comp) { 166 unsigned int swz; 167 if (!GET_BIT(mask, comp)) 168 continue; 169 swz = GET_SWZ(src.Swizzle, comp); 170 if (swz == RC_SWIZZLE_UNUSED) 171 continue; 172 if (swz == GET_SWZ(sd->hash, comp)) { 173 /* check if the negate bit of current component 174 * is the same for already matched components */ 175 if (matchmask && (!!(src.Negate & matchmask) != !!(src.Negate & (1 << comp)))) 176 continue; 177 178 matchcount++; 179 matchmask |= 1 << comp; 180 } 181 } 182 if (matchcount > best_matchcount) { 183 best_matchcount = matchcount; 184 best_matchmask = matchmask; 185 if (matchmask == (mask & RC_MASK_XYZ)) 186 break; 187 } 188 } 189 190 if (mask & RC_MASK_W) 191 best_matchmask |= RC_MASK_W; 192 193 split->Phase[split->NumPhases++] = best_matchmask; 194 mask &= ~best_matchmask; 195 } 196} 197 198struct rc_swizzle_caps r300_swizzle_caps = { 199 .IsNative = r300_swizzle_is_native, 200 .Split = r300_swizzle_split 201}; 202 203 204/** 205 * Translate an RGB (XYZ) swizzle into the hardware code for the given 206 * instruction source. 207 */ 208unsigned int r300FPTranslateRGBSwizzle(unsigned int src, unsigned int swizzle) 209{ 210 const struct swizzle_data* sd = lookup_native_swizzle(swizzle); 211 212 if (!sd || (src == RC_PAIR_PRESUB_SRC && sd->srcp_stride == 0)) { 213 fprintf(stderr, "Not a native swizzle: %08x\n", swizzle); 214 return 0; 215 } 216 217 if (src == RC_PAIR_PRESUB_SRC) { 218 return sd->base + sd->srcp_stride; 219 } else { 220 return sd->base + src*sd->stride; 221 } 222} 223 224 225/** 226 * Translate an Alpha (W) swizzle into the hardware code for the given 227 * instruction source. 228 */ 229unsigned int r300FPTranslateAlphaSwizzle(unsigned int src, unsigned int swizzle) 230{ 231 unsigned int swz = GET_SWZ(swizzle, 0); 232 if (src == RC_PAIR_PRESUB_SRC) { 233 return R300_ALU_ARGA_SRCP_X + swz; 234 } 235 if (swz < 3) 236 return swz + 3*src; 237 238 switch(swz) { 239 case RC_SWIZZLE_W: return R300_ALU_ARGA_SRC0A + src; 240 case RC_SWIZZLE_ONE: return R300_ALU_ARGA_ONE; 241 case RC_SWIZZLE_ZERO: return R300_ALU_ARGA_ZERO; 242 case RC_SWIZZLE_HALF: return R300_ALU_ARGA_HALF; 243 default: return R300_ALU_ARGA_ONE; 244 } 245} 246