• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
45 struct 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 
52 static 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 
66 static const int num_native_swizzles = ARRAY_SIZE(native_swizzles);
67 /* Only swizzles with srcp_stride != 0 can be used for presub, so
68  * just the first five from the list. */
69 static const int num_presub_swizzles = 5;
70 
71 /**
72  * Find a native RGB swizzle that matches the given swizzle.
73  * Returns 0 if none found.
74  */
lookup_native_swizzle(unsigned int swizzle)75 static const struct swizzle_data* lookup_native_swizzle(unsigned int swizzle)
76 {
77 	int i, comp;
78 
79 	for(i = 0; i < num_native_swizzles; ++i) {
80 		const struct swizzle_data* sd = &native_swizzles[i];
81 		for(comp = 0; comp < 3; ++comp) {
82 			unsigned int swz = GET_SWZ(swizzle, comp);
83 			if (swz == RC_SWIZZLE_UNUSED)
84 				continue;
85 			if (swz != GET_SWZ(sd->hash, comp))
86 				break;
87 		}
88 		if (comp == 3)
89 			return sd;
90 	}
91 
92 	return NULL;
93 }
94 
95 /**
96  * Determines if the given swizzle is valid for r300/r400.  In most situations
97  * it is better to use r300_swizzle_is_native() which can be accessed via
98  * struct radeon_compiler *c; c->SwizzleCaps->IsNative().
99  */
r300_swizzle_is_native_basic(unsigned int swizzle)100 int r300_swizzle_is_native_basic(unsigned int swizzle)
101 {
102 	if(lookup_native_swizzle(swizzle))
103 		return 1;
104 	else
105 		return 0;
106 }
107 
108 /**
109  * Check whether the given instruction supports the swizzle and negate
110  * combinations in the given source register.
111  */
r300_swizzle_is_native(rc_opcode opcode,struct rc_src_register reg)112 static int r300_swizzle_is_native(rc_opcode opcode, struct rc_src_register reg)
113 {
114 	const struct swizzle_data* sd;
115 	unsigned int relevant;
116 	int j;
117 
118 	if (opcode == RC_OPCODE_KIL ||
119 	    opcode == RC_OPCODE_TEX ||
120 	    opcode == RC_OPCODE_TXB ||
121 	    opcode == RC_OPCODE_TXP) {
122 		if (reg.Abs || reg.Negate)
123 			return 0;
124 
125 		for(j = 0; j < 4; ++j) {
126 			unsigned int swz = GET_SWZ(reg.Swizzle, j);
127 			if (swz == RC_SWIZZLE_UNUSED)
128 				continue;
129 			if (swz != j)
130 				return 0;
131 		}
132 
133 		return 1;
134 	}
135 
136 	relevant = 0;
137 
138 	for(j = 0; j < 3; ++j)
139 		if (GET_SWZ(reg.Swizzle, j) != RC_SWIZZLE_UNUSED)
140 			relevant |= 1 << j;
141 
142 	if ((reg.Negate & relevant) && ((reg.Negate & relevant) != relevant))
143 		return 0;
144 
145 	sd = lookup_native_swizzle(reg.Swizzle);
146 	if (!sd || (reg.File == RC_FILE_PRESUB && sd->srcp_stride == 0))
147 		return 0;
148 
149 	return 1;
150 }
151 
152 
r300_swizzle_split(struct rc_src_register src,unsigned int mask,struct rc_swizzle_split * split)153 static void r300_swizzle_split(
154 		struct rc_src_register src, unsigned int mask,
155 		struct rc_swizzle_split * split)
156 {
157 	split->NumPhases = 0;
158 
159 	while(mask) {
160 		unsigned int best_matchcount = 0;
161 		unsigned int best_matchmask = 0;
162 		int i, comp;
163 
164 		unsigned num_swizzles = src.File == RC_FILE_PRESUB ? num_presub_swizzles : num_native_swizzles;
165 
166 		for(i = 0; i < num_swizzles; ++i) {
167 			const struct swizzle_data *sd = &native_swizzles[i];
168 			unsigned int matchcount = 0;
169 			unsigned int matchmask = 0;
170 			for(comp = 0; comp < 3; ++comp) {
171 				unsigned int swz;
172 				if (!GET_BIT(mask, comp))
173 					continue;
174 				swz = GET_SWZ(src.Swizzle, comp);
175 				if (swz == RC_SWIZZLE_UNUSED)
176 					continue;
177 				if (swz == GET_SWZ(sd->hash, comp)) {
178 					/* check if the negate bit of current component
179 					 * is the same for already matched components */
180 					if (matchmask && (!!(src.Negate & matchmask) != !!(src.Negate & (1 << comp))))
181 						continue;
182 
183 					matchcount++;
184 					matchmask |= 1 << comp;
185 				}
186 			}
187 			if (matchcount > best_matchcount) {
188 				best_matchcount = matchcount;
189 				best_matchmask = matchmask;
190 				if (matchmask == (mask & RC_MASK_XYZ))
191 					break;
192 			}
193 		}
194 
195 		if (mask & RC_MASK_W)
196 			best_matchmask |= RC_MASK_W;
197 
198 		split->Phase[split->NumPhases++] = best_matchmask;
199 		mask &= ~best_matchmask;
200 	}
201 }
202 
203 const struct rc_swizzle_caps r300_swizzle_caps = {
204 	.IsNative = r300_swizzle_is_native,
205 	.Split = r300_swizzle_split
206 };
207 
208 
209 /**
210  * Translate an RGB (XYZ) swizzle into the hardware code for the given
211  * instruction source.
212  */
r300FPTranslateRGBSwizzle(unsigned int src,unsigned int swizzle)213 unsigned int r300FPTranslateRGBSwizzle(unsigned int src, unsigned int swizzle)
214 {
215 	const struct swizzle_data* sd = lookup_native_swizzle(swizzle);
216 
217 	if (!sd || (src == RC_PAIR_PRESUB_SRC && sd->srcp_stride == 0)) {
218 		fprintf(stderr, "Not a native swizzle: %08x\n", swizzle);
219 		return 0;
220 	}
221 
222 	if (src == RC_PAIR_PRESUB_SRC) {
223 		return sd->base + sd->srcp_stride;
224 	} else {
225 		return sd->base + src*sd->stride;
226 	}
227 }
228 
229 
230 /**
231  * Translate an Alpha (W) swizzle into the hardware code for the given
232  * instruction source.
233  */
r300FPTranslateAlphaSwizzle(unsigned int src,unsigned int swizzle)234 unsigned int r300FPTranslateAlphaSwizzle(unsigned int src, unsigned int swizzle)
235 {
236 	unsigned int swz = GET_SWZ(swizzle, 0);
237 	if (src == RC_PAIR_PRESUB_SRC) {
238 		return R300_ALU_ARGA_SRCP_X + swz;
239 	}
240 	if (swz < 3)
241 		return swz + 3*src;
242 
243 	switch(swz) {
244 	case RC_SWIZZLE_W: return R300_ALU_ARGA_SRC0A + src;
245 	case RC_SWIZZLE_ONE: return R300_ALU_ARGA_ONE;
246 	case RC_SWIZZLE_ZERO: return R300_ALU_ARGA_ZERO;
247 	case RC_SWIZZLE_HALF: return R300_ALU_ARGA_HALF;
248 	default: return R300_ALU_ARGA_ONE;
249 	}
250 }
251