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