Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/r300/compiler/radeon_dataflow_swizzles.c
4574 views
1
/*
2
* Copyright (C) 2009 Nicolai Haehnle.
3
* Copyright 2012 Advanced Micro Devices, Inc.
4
*
5
* All Rights Reserved.
6
*
7
* Permission is hereby granted, free of charge, to any person obtaining
8
* a copy of this software and associated documentation files (the
9
* "Software"), to deal in the Software without restriction, including
10
* without limitation the rights to use, copy, modify, merge, publish,
11
* distribute, sublicense, and/or sell copies of the Software, and to
12
* permit persons to whom the Software is furnished to do so, subject to
13
* the following conditions:
14
*
15
* The above copyright notice and this permission notice (including the
16
* next paragraph) shall be included in all copies or substantial
17
* portions of the Software.
18
*
19
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
*
27
* Authors:
28
* Nicolai Haehnle
29
* Tom Stellard <[email protected]>
30
*/
31
32
#include "radeon_dataflow.h"
33
34
#include "radeon_code.h"
35
#include "radeon_compiler.h"
36
#include "radeon_compiler_util.h"
37
#include "radeon_swizzle.h"
38
39
40
static void rewrite_source(struct radeon_compiler * c,
41
struct rc_instruction * inst, unsigned src)
42
{
43
struct rc_swizzle_split split;
44
unsigned int tempreg = rc_find_free_temporary(c);
45
unsigned int usemask;
46
47
usemask = 0;
48
for(unsigned int chan = 0; chan < 4; ++chan) {
49
if (GET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan) != RC_SWIZZLE_UNUSED)
50
usemask |= 1 << chan;
51
}
52
53
c->SwizzleCaps->Split(inst->U.I.SrcReg[src], usemask, &split);
54
55
for(unsigned int phase = 0; phase < split.NumPhases; ++phase) {
56
struct rc_instruction * mov = rc_insert_new_instruction(c, inst->Prev);
57
unsigned int phase_refmask;
58
unsigned int masked_negate;
59
60
mov->U.I.Opcode = RC_OPCODE_MOV;
61
mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
62
mov->U.I.DstReg.Index = tempreg;
63
mov->U.I.DstReg.WriteMask = split.Phase[phase];
64
mov->U.I.SrcReg[0] = inst->U.I.SrcReg[src];
65
mov->U.I.PreSub = inst->U.I.PreSub;
66
67
phase_refmask = 0;
68
for(unsigned int chan = 0; chan < 4; ++chan) {
69
if (!GET_BIT(split.Phase[phase], chan))
70
SET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan, RC_SWIZZLE_UNUSED);
71
else
72
phase_refmask |= 1 << GET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan);
73
}
74
75
phase_refmask &= RC_MASK_XYZW;
76
77
masked_negate = split.Phase[phase] & mov->U.I.SrcReg[0].Negate;
78
if (masked_negate == 0)
79
mov->U.I.SrcReg[0].Negate = 0;
80
else if (masked_negate == split.Phase[phase])
81
mov->U.I.SrcReg[0].Negate = RC_MASK_XYZW;
82
83
}
84
85
inst->U.I.SrcReg[src].File = RC_FILE_TEMPORARY;
86
inst->U.I.SrcReg[src].Index = tempreg;
87
inst->U.I.SrcReg[src].Swizzle = 0;
88
inst->U.I.SrcReg[src].Negate = RC_MASK_NONE;
89
inst->U.I.SrcReg[src].Abs = 0;
90
for(unsigned int chan = 0; chan < 4; ++chan) {
91
SET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan,
92
GET_BIT(usemask, chan) ? chan : RC_SWIZZLE_UNUSED);
93
}
94
}
95
96
/**
97
* This function will attempt to rewrite non-native swizzles that read from
98
* immediate registers by rearranging the immediates to allow the
99
* instruction to use native swizzles.
100
*/
101
static unsigned try_rewrite_constant(struct radeon_compiler *c,
102
struct rc_src_register *reg)
103
{
104
unsigned new_swizzle, chan, swz0, swz1, swz2, swz3, found_swizzle, swz;
105
unsigned all_inline = 0;
106
float imms[4] = {0.0f, 0.0f, 0.0f, 0.0f};
107
108
if (!rc_src_reg_is_immediate(c, reg->File, reg->Index)) {
109
/* The register does not contain immediates, but if all
110
* the swizzles are inline constants, we can still rewrite
111
* it. */
112
113
new_swizzle = RC_SWIZZLE_XYZW;
114
for (chan = 0 ; chan < 4; chan++) {
115
unsigned swz = GET_SWZ(reg->Swizzle, chan);
116
if (swz <= RC_SWIZZLE_W) {
117
return 0;
118
}
119
if (swz == RC_SWIZZLE_UNUSED) {
120
SET_SWZ(new_swizzle, chan, RC_SWIZZLE_UNUSED);
121
}
122
}
123
all_inline = 1;
124
} else {
125
new_swizzle = reg->Swizzle;
126
}
127
128
swz = RC_SWIZZLE_UNUSED;
129
found_swizzle = 1;
130
/* Check if all channels have the same swizzle. If they do we can skip
131
* the search for a native swizzle. We only need to check the first
132
* three channels, because any swizzle is legal in the fourth channel.
133
*/
134
for (chan = 0; chan < 3; chan++) {
135
unsigned chan_swz = GET_SWZ(reg->Swizzle, chan);
136
if (chan_swz == RC_SWIZZLE_UNUSED) {
137
continue;
138
}
139
if (swz == RC_SWIZZLE_UNUSED) {
140
swz = chan_swz;
141
} else if (swz != chan_swz) {
142
found_swizzle = 0;
143
break;
144
}
145
}
146
147
/* Find a legal swizzle */
148
149
/* This loop attempts to find a native swizzle where all the
150
* channels are different. */
151
while (!found_swizzle && !all_inline) {
152
swz0 = GET_SWZ(new_swizzle, 0);
153
swz1 = GET_SWZ(new_swizzle, 1);
154
swz2 = GET_SWZ(new_swizzle, 2);
155
156
/* Swizzle .W. is never legal. */
157
if (swz1 == RC_SWIZZLE_W ||
158
swz1 == RC_SWIZZLE_UNUSED ||
159
swz1 == RC_SWIZZLE_ZERO ||
160
swz1 == RC_SWIZZLE_HALF ||
161
swz1 == RC_SWIZZLE_ONE) {
162
/* We chose Z, because there are two non-repeating
163
* swizzle combinations of the form .Z. There are
164
* only one combination each for .X. and .Y. */
165
SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
166
continue;
167
}
168
169
if (swz2 == RC_SWIZZLE_UNUSED) {
170
/* We choose Y, because there are two non-repeating
171
* swizzle combinations of the form ..Y */
172
SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
173
continue;
174
}
175
176
switch (swz0) {
177
/* X.. */
178
case RC_SWIZZLE_X:
179
/* Legal swizzles that start with X: XYZ, XXX */
180
switch (swz1) {
181
/* XX. */
182
case RC_SWIZZLE_X:
183
/* The new swizzle will be:
184
* ZXY (XX. => ZX. => ZXY) */
185
SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);
186
break;
187
/* XY. */
188
case RC_SWIZZLE_Y:
189
/* The new swizzle is XYZ */
190
SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Z);
191
found_swizzle = 1;
192
break;
193
/* XZ. */
194
case RC_SWIZZLE_Z:
195
/* XZZ */
196
if (swz2 == RC_SWIZZLE_Z) {
197
/* The new swizzle is XYZ */
198
SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Y);
199
found_swizzle = 1;
200
} else { /* XZ[^Z] */
201
/* The new swizzle will be:
202
* YZX (XZ. => YZ. => YZX) */
203
SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Y);
204
}
205
break;
206
/* XW. Should have already been handled. */
207
case RC_SWIZZLE_W:
208
assert(0);
209
break;
210
}
211
break;
212
/* Y.. */
213
case RC_SWIZZLE_Y:
214
/* Legal swizzles that start with Y: YYY, YZX */
215
switch (swz1) {
216
/* YY. */
217
case RC_SWIZZLE_Y:
218
/* The new swizzle will be:
219
* XYZ (YY. => XY. => XYZ) */
220
SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
221
break;
222
/* YZ. */
223
case RC_SWIZZLE_Z:
224
/* The new swizzle is YZX */
225
SET_SWZ(new_swizzle, 2, RC_SWIZZLE_X);
226
found_swizzle = 1;
227
break;
228
/* YX. */
229
case RC_SWIZZLE_X:
230
/* YXX */
231
if (swz2 == RC_SWIZZLE_X) {
232
/*The new swizzle is YZX */
233
SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
234
found_swizzle = 1;
235
} else { /* YX[^X] */
236
/* The new swizzle will be:
237
* ZXY (YX. => ZX. -> ZXY) */
238
SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);
239
}
240
break;
241
/* YW. Should have already been handled. */
242
case RC_SWIZZLE_W:
243
assert(0);
244
break;
245
}
246
break;
247
/* Z.. */
248
case RC_SWIZZLE_Z:
249
/* Legal swizzles that start with Z: ZZZ, ZXY */
250
switch (swz1) {
251
/* ZZ. */
252
case RC_SWIZZLE_Z:
253
/* The new swizzle will be:
254
* WZY (ZZ. => WZ. => WZY) */
255
SET_SWZ(new_swizzle, 0, RC_SWIZZLE_W);
256
break;
257
/* ZX. */
258
case RC_SWIZZLE_X:
259
/* The new swizzle is ZXY */
260
SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
261
found_swizzle = 1;
262
break;
263
/* ZY. */
264
case RC_SWIZZLE_Y:
265
/* ZYY */
266
if (swz2 == RC_SWIZZLE_Y) {
267
/* The new swizzle is ZXY */
268
SET_SWZ(new_swizzle, 1, RC_SWIZZLE_X);
269
found_swizzle = 1;
270
} else { /* ZY[^Y] */
271
/* The new swizzle will be:
272
* XYZ (ZY. => XY. => XYZ) */
273
SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
274
}
275
break;
276
/* ZW. Should have already been handled. */
277
case RC_SWIZZLE_W:
278
assert(0);
279
break;
280
}
281
break;
282
283
/* W.. */
284
case RC_SWIZZLE_W:
285
/* Legal swizzles that start with X: WWW, WZY */
286
switch (swz1) {
287
/* WW. Should have already been handled. */
288
case RC_SWIZZLE_W:
289
assert(0);
290
break;
291
/* WZ. */
292
case RC_SWIZZLE_Z:
293
/* The new swizzle will be WZY */
294
SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
295
found_swizzle = 1;
296
break;
297
/* WX. */
298
case RC_SWIZZLE_X:
299
/* WY. */
300
case RC_SWIZZLE_Y:
301
/* W[XY]Y */
302
if (swz2 == RC_SWIZZLE_Y) {
303
/* The new swizzle will be WZY */
304
SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
305
found_swizzle = 1;
306
} else { /* W[XY][^Y] */
307
/* The new swizzle will be:
308
* ZXY (WX. => XX. => ZX. => ZXY) or
309
* XYZ (WY. => XY. => XYZ)
310
*/
311
SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
312
}
313
break;
314
}
315
break;
316
/* U.. 0.. 1.. H..*/
317
case RC_SWIZZLE_UNUSED:
318
case RC_SWIZZLE_ZERO:
319
case RC_SWIZZLE_ONE:
320
case RC_SWIZZLE_HALF:
321
SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
322
break;
323
}
324
}
325
326
/* Handle the swizzle in the w channel. */
327
swz3 = GET_SWZ(reg->Swizzle, 3);
328
329
/* We can skip this if the swizzle in channel w is an inline constant. */
330
if (swz3 <= RC_SWIZZLE_W) {
331
for (chan = 0; chan < 3; chan++) {
332
unsigned old_swz = GET_SWZ(reg->Swizzle, chan);
333
unsigned new_swz = GET_SWZ(new_swizzle, chan);
334
/* If the swizzle in the w channel is the same as the
335
* swizzle in any other channels, we need to rewrite it.
336
* For example:
337
* reg->Swizzle == XWZW
338
* new_swizzle == XYZX
339
* Since the swizzle in the y channel is being
340
* rewritten from W -> Y we need to change the swizzle
341
* in the w channel from W -> Y as well.
342
*/
343
if (old_swz == swz3) {
344
SET_SWZ(new_swizzle, 3,
345
GET_SWZ(new_swizzle, chan));
346
break;
347
}
348
349
/* The swizzle in channel w will be overwritten by one
350
* of the new swizzles. */
351
if (new_swz == swz3) {
352
/* Find an unused swizzle */
353
unsigned i;
354
unsigned used = 0;
355
for (i = 0; i < 3; i++) {
356
used |= 1 << GET_SWZ(new_swizzle, i);
357
}
358
for (i = 0; i < 4; i++) {
359
if (used & (1 << i)) {
360
continue;
361
}
362
SET_SWZ(new_swizzle, 3, i);
363
}
364
}
365
}
366
}
367
368
for (chan = 0; chan < 4; chan++) {
369
unsigned old_swz = GET_SWZ(reg->Swizzle, chan);
370
unsigned new_swz = GET_SWZ(new_swizzle, chan);
371
372
if (old_swz == RC_SWIZZLE_UNUSED) {
373
continue;
374
}
375
376
/* We don't need to change the swizzle in channel w if it is
377
* an inline constant. These are always legal in the w channel.
378
*
379
* Swizzles with a value > RC_SWIZZLE_W are inline constants.
380
*/
381
if (chan == 3 && old_swz > RC_SWIZZLE_W) {
382
continue;
383
}
384
385
assert(new_swz <= RC_SWIZZLE_W);
386
387
switch (old_swz) {
388
case RC_SWIZZLE_ZERO:
389
imms[new_swz] = 0.0f;
390
break;
391
case RC_SWIZZLE_HALF:
392
if (reg->Negate & (1 << chan)) {
393
imms[new_swz] = -0.5f;
394
} else {
395
imms[new_swz] = 0.5f;
396
}
397
break;
398
case RC_SWIZZLE_ONE:
399
if (reg->Negate & (1 << chan)) {
400
imms[new_swz] = -1.0f;
401
} else {
402
imms[new_swz] = 1.0f;
403
}
404
break;
405
default:
406
imms[new_swz] = rc_get_constant_value(c, reg->Index,
407
reg->Swizzle, reg->Negate, chan);
408
}
409
SET_SWZ(reg->Swizzle, chan, new_swz);
410
}
411
reg->Index = rc_constants_add_immediate_vec4(&c->Program.Constants,
412
imms);
413
/* We need to set the register file to CONSTANT in case we are
414
* converting a non-constant register with constant swizzles (e.g.
415
* ONE, ZERO, HALF).
416
*/
417
reg->File = RC_FILE_CONSTANT;
418
reg->Negate = 0;
419
return 1;
420
}
421
422
void rc_dataflow_swizzles(struct radeon_compiler * c, void *user)
423
{
424
struct rc_instruction * inst;
425
426
for(inst = c->Program.Instructions.Next;
427
inst != &c->Program.Instructions;
428
inst = inst->Next) {
429
const struct rc_opcode_info * opcode =
430
rc_get_opcode_info(inst->U.I.Opcode);
431
unsigned int src;
432
433
for(src = 0; src < opcode->NumSrcRegs; ++src) {
434
struct rc_src_register *reg = &inst->U.I.SrcReg[src];
435
if (c->SwizzleCaps->IsNative(inst->U.I.Opcode, *reg)) {
436
continue;
437
}
438
if (!c->is_r500 &&
439
c->Program.Constants.Count < R300_PFS_NUM_CONST_REGS &&
440
try_rewrite_constant(c, reg)) {
441
continue;
442
}
443
rewrite_source(c, inst, src);
444
}
445
}
446
if (c->Debug & RC_DBG_LOG)
447
rc_constants_print(&c->Program.Constants);
448
}
449
450