Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nv30/nvfx_vertprog.c
4574 views
1
#include <strings.h>
2
#include "pipe/p_context.h"
3
#include "pipe/p_defines.h"
4
#include "pipe/p_state.h"
5
#include "util/compiler.h"
6
#include "util/u_dynarray.h"
7
#include "util/u_debug.h"
8
#include "util/u_memory.h"
9
10
#include "pipe/p_shader_tokens.h"
11
#include "tgsi/tgsi_parse.h"
12
#include "tgsi/tgsi_dump.h"
13
#include "tgsi/tgsi_util.h"
14
#include "tgsi/tgsi_ureg.h"
15
16
#include "draw/draw_context.h"
17
18
#include "nv_object.xml.h"
19
#include "nouveau_debug.h"
20
#include "nv30/nv30-40_3d.xml.h"
21
#include "nv30/nv30_state.h"
22
23
/* TODO (at least...):
24
* 1. Indexed consts + ARL
25
* 3. NV_vp11, NV_vp2, NV_vp3 features
26
* - extra arith opcodes
27
* - branching
28
* - texture sampling
29
* - indexed attribs
30
* - indexed results
31
* 4. bugs
32
*/
33
34
#include "nv30/nv30_vertprog.h"
35
#include "nv30/nv40_vertprog.h"
36
37
struct nvfx_loop_entry {
38
unsigned brk_target;
39
unsigned cont_target;
40
};
41
42
struct nvfx_vpc {
43
struct pipe_shader_state pipe;
44
struct nv30_vertprog *vp;
45
struct tgsi_shader_info* info;
46
47
struct nv30_vertprog_exec *vpi;
48
49
unsigned r_temps;
50
unsigned r_temps_discard;
51
struct nvfx_reg r_result[PIPE_MAX_SHADER_OUTPUTS];
52
struct nvfx_reg *r_address;
53
struct nvfx_reg *r_temp;
54
struct nvfx_reg *r_const;
55
struct nvfx_reg r_0_1;
56
57
struct nvfx_reg *imm;
58
unsigned nr_imm;
59
60
int hpos_idx;
61
int cvtx_idx;
62
63
unsigned is_nv4x;
64
65
struct util_dynarray label_relocs;
66
struct util_dynarray loop_stack;
67
};
68
69
static struct nvfx_reg
70
temp(struct nvfx_vpc *vpc)
71
{
72
int idx = ffs(~vpc->r_temps) - 1;
73
74
if (idx < 0 || (!vpc->is_nv4x && idx >= 16)) {
75
NOUVEAU_ERR("out of temps!!\n");
76
return nvfx_reg(NVFXSR_TEMP, 0);
77
}
78
79
vpc->r_temps |= (1 << idx);
80
vpc->r_temps_discard |= (1 << idx);
81
return nvfx_reg(NVFXSR_TEMP, idx);
82
}
83
84
static inline void
85
release_temps(struct nvfx_vpc *vpc)
86
{
87
vpc->r_temps &= ~vpc->r_temps_discard;
88
vpc->r_temps_discard = 0;
89
}
90
91
static struct nvfx_reg
92
constant(struct nvfx_vpc *vpc, int pipe, float x, float y, float z, float w)
93
{
94
struct nv30_vertprog *vp = vpc->vp;
95
struct nv30_vertprog_data *vpd;
96
int idx;
97
98
if (pipe >= 0) {
99
for (idx = 0; idx < vp->nr_consts; idx++) {
100
if (vp->consts[idx].index == pipe)
101
return nvfx_reg(NVFXSR_CONST, idx);
102
}
103
}
104
105
idx = vp->nr_consts++;
106
vp->consts = realloc(vp->consts, sizeof(*vpd) * vp->nr_consts);
107
vpd = &vp->consts[idx];
108
109
vpd->index = pipe;
110
vpd->value[0] = x;
111
vpd->value[1] = y;
112
vpd->value[2] = z;
113
vpd->value[3] = w;
114
return nvfx_reg(NVFXSR_CONST, idx);
115
}
116
117
#define arith(s,t,o,d,m,s0,s1,s2) \
118
nvfx_insn((s), (NVFX_VP_INST_SLOT_##t << 7) | NVFX_VP_INST_##t##_OP_##o, -1, (d), (m), (s0), (s1), (s2))
119
120
static void
121
emit_src(struct nvfx_vpc *vpc, uint32_t *hw,
122
int pos, struct nvfx_src src)
123
{
124
struct nv30_vertprog *vp = vpc->vp;
125
uint32_t sr = 0;
126
struct nvfx_relocation reloc;
127
128
switch (src.reg.type) {
129
case NVFXSR_TEMP:
130
sr |= (NVFX_VP(SRC_REG_TYPE_TEMP) << NVFX_VP(SRC_REG_TYPE_SHIFT));
131
sr |= (src.reg.index << NVFX_VP(SRC_TEMP_SRC_SHIFT));
132
break;
133
case NVFXSR_INPUT:
134
sr |= (NVFX_VP(SRC_REG_TYPE_INPUT) <<
135
NVFX_VP(SRC_REG_TYPE_SHIFT));
136
vp->ir |= (1 << src.reg.index);
137
hw[1] |= (src.reg.index << NVFX_VP(INST_INPUT_SRC_SHIFT));
138
break;
139
case NVFXSR_CONST:
140
sr |= (NVFX_VP(SRC_REG_TYPE_CONST) <<
141
NVFX_VP(SRC_REG_TYPE_SHIFT));
142
if (src.reg.index < 256 && src.reg.index >= -256) {
143
reloc.location = vp->nr_insns - 1;
144
reloc.target = src.reg.index;
145
util_dynarray_append(&vp->const_relocs, struct nvfx_relocation, reloc);
146
} else {
147
hw[1] |= (src.reg.index << NVFX_VP(INST_CONST_SRC_SHIFT)) &
148
NVFX_VP(INST_CONST_SRC_MASK);
149
}
150
break;
151
case NVFXSR_NONE:
152
sr |= (NVFX_VP(SRC_REG_TYPE_INPUT) <<
153
NVFX_VP(SRC_REG_TYPE_SHIFT));
154
break;
155
default:
156
assert(0);
157
}
158
159
if (src.negate)
160
sr |= NVFX_VP(SRC_NEGATE);
161
162
if (src.abs)
163
hw[0] |= (1 << (21 + pos));
164
165
sr |= ((src.swz[0] << NVFX_VP(SRC_SWZ_X_SHIFT)) |
166
(src.swz[1] << NVFX_VP(SRC_SWZ_Y_SHIFT)) |
167
(src.swz[2] << NVFX_VP(SRC_SWZ_Z_SHIFT)) |
168
(src.swz[3] << NVFX_VP(SRC_SWZ_W_SHIFT)));
169
170
if(src.indirect) {
171
if(src.reg.type == NVFXSR_CONST)
172
hw[3] |= NVFX_VP(INST_INDEX_CONST);
173
else if(src.reg.type == NVFXSR_INPUT)
174
hw[0] |= NVFX_VP(INST_INDEX_INPUT);
175
else
176
assert(0);
177
178
if(src.indirect_reg)
179
hw[0] |= NVFX_VP(INST_ADDR_REG_SELECT_1);
180
hw[0] |= src.indirect_swz << NVFX_VP(INST_ADDR_SWZ_SHIFT);
181
}
182
183
switch (pos) {
184
case 0:
185
hw[1] |= ((sr & NVFX_VP(SRC0_HIGH_MASK)) >>
186
NVFX_VP(SRC0_HIGH_SHIFT)) << NVFX_VP(INST_SRC0H_SHIFT);
187
hw[2] |= (sr & NVFX_VP(SRC0_LOW_MASK)) <<
188
NVFX_VP(INST_SRC0L_SHIFT);
189
break;
190
case 1:
191
hw[2] |= sr << NVFX_VP(INST_SRC1_SHIFT);
192
break;
193
case 2:
194
hw[2] |= ((sr & NVFX_VP(SRC2_HIGH_MASK)) >>
195
NVFX_VP(SRC2_HIGH_SHIFT)) << NVFX_VP(INST_SRC2H_SHIFT);
196
hw[3] |= (sr & NVFX_VP(SRC2_LOW_MASK)) <<
197
NVFX_VP(INST_SRC2L_SHIFT);
198
break;
199
default:
200
assert(0);
201
}
202
}
203
204
static void
205
emit_dst(struct nvfx_vpc *vpc, uint32_t *hw,
206
int slot, struct nvfx_reg dst)
207
{
208
struct nv30_vertprog *vp = vpc->vp;
209
210
switch (dst.type) {
211
case NVFXSR_NONE:
212
if(!vpc->is_nv4x)
213
hw[0] |= NV30_VP_INST_DEST_TEMP_ID_MASK;
214
else {
215
hw[3] |= NV40_VP_INST_DEST_MASK;
216
if (slot == 0)
217
hw[0] |= NV40_VP_INST_VEC_DEST_TEMP_MASK;
218
else
219
hw[3] |= NV40_VP_INST_SCA_DEST_TEMP_MASK;
220
}
221
break;
222
case NVFXSR_TEMP:
223
if(!vpc->is_nv4x)
224
hw[0] |= (dst.index << NV30_VP_INST_DEST_TEMP_ID_SHIFT);
225
else {
226
hw[3] |= NV40_VP_INST_DEST_MASK;
227
if (slot == 0)
228
hw[0] |= (dst.index << NV40_VP_INST_VEC_DEST_TEMP_SHIFT);
229
else
230
hw[3] |= (dst.index << NV40_VP_INST_SCA_DEST_TEMP_SHIFT);
231
}
232
break;
233
case NVFXSR_OUTPUT:
234
/* TODO: this may be wrong because on nv30 COL0 and BFC0 are swapped */
235
if(vpc->is_nv4x) {
236
switch (dst.index) {
237
case NV30_VP_INST_DEST_CLP(0):
238
dst.index = NVFX_VP(INST_DEST_FOGC);
239
vp->or |= (1 << 6);
240
break;
241
case NV30_VP_INST_DEST_CLP(1):
242
dst.index = NVFX_VP(INST_DEST_FOGC);
243
vp->or |= (1 << 7);
244
break;
245
case NV30_VP_INST_DEST_CLP(2):
246
dst.index = NVFX_VP(INST_DEST_FOGC);
247
vp->or |= (1 << 8);
248
break;
249
case NV30_VP_INST_DEST_CLP(3):
250
dst.index = NVFX_VP(INST_DEST_PSZ);
251
vp->or |= (1 << 9);
252
break;
253
case NV30_VP_INST_DEST_CLP(4):
254
dst.index = NVFX_VP(INST_DEST_PSZ);
255
vp->or |= (1 << 10);
256
break;
257
case NV30_VP_INST_DEST_CLP(5):
258
dst.index = NVFX_VP(INST_DEST_PSZ);
259
vp->or |= (1 << 11);
260
break;
261
case NV40_VP_INST_DEST_COL0: vp->or |= (1 << 0); break;
262
case NV40_VP_INST_DEST_COL1: vp->or |= (1 << 1); break;
263
case NV40_VP_INST_DEST_BFC0: vp->or |= (1 << 2); break;
264
case NV40_VP_INST_DEST_BFC1: vp->or |= (1 << 3); break;
265
case NV40_VP_INST_DEST_FOGC: vp->or |= (1 << 4); break;
266
case NV40_VP_INST_DEST_PSZ : vp->or |= (1 << 5); break;
267
}
268
}
269
270
if(!vpc->is_nv4x) {
271
hw[3] |= (dst.index << NV30_VP_INST_DEST_SHIFT);
272
hw[0] |= NV30_VP_INST_VEC_DEST_TEMP_MASK;
273
274
/*XXX: no way this is entirely correct, someone needs to
275
* figure out what exactly it is.
276
*/
277
hw[3] |= 0x800;
278
} else {
279
hw[3] |= (dst.index << NV40_VP_INST_DEST_SHIFT);
280
if (slot == 0) {
281
hw[0] |= NV40_VP_INST_VEC_RESULT;
282
hw[0] |= NV40_VP_INST_VEC_DEST_TEMP_MASK;
283
} else {
284
hw[3] |= NV40_VP_INST_SCA_RESULT;
285
hw[3] |= NV40_VP_INST_SCA_DEST_TEMP_MASK;
286
}
287
}
288
break;
289
default:
290
assert(0);
291
}
292
}
293
294
static void
295
nvfx_vp_emit(struct nvfx_vpc *vpc, struct nvfx_insn insn)
296
{
297
struct nv30_vertprog *vp = vpc->vp;
298
unsigned slot = insn.op >> 7;
299
unsigned op = insn.op & 0x7f;
300
uint32_t *hw;
301
302
vp->insns = realloc(vp->insns, ++vp->nr_insns * sizeof(*vpc->vpi));
303
vpc->vpi = &vp->insns[vp->nr_insns - 1];
304
memset(vpc->vpi, 0, sizeof(*vpc->vpi));
305
306
hw = vpc->vpi->data;
307
308
if (insn.cc_test != NVFX_COND_TR)
309
hw[0] |= NVFX_VP(INST_COND_TEST_ENABLE);
310
hw[0] |= (insn.cc_test << NVFX_VP(INST_COND_SHIFT));
311
hw[0] |= ((insn.cc_swz[0] << NVFX_VP(INST_COND_SWZ_X_SHIFT)) |
312
(insn.cc_swz[1] << NVFX_VP(INST_COND_SWZ_Y_SHIFT)) |
313
(insn.cc_swz[2] << NVFX_VP(INST_COND_SWZ_Z_SHIFT)) |
314
(insn.cc_swz[3] << NVFX_VP(INST_COND_SWZ_W_SHIFT)));
315
if(insn.cc_update)
316
hw[0] |= NVFX_VP(INST_COND_UPDATE_ENABLE);
317
318
if(insn.sat) {
319
assert(vpc->is_nv4x);
320
if(vpc->is_nv4x)
321
hw[0] |= NV40_VP_INST_SATURATE;
322
}
323
324
if(!vpc->is_nv4x) {
325
if(slot == 0)
326
hw[1] |= (op << NV30_VP_INST_VEC_OPCODE_SHIFT);
327
else {
328
hw[0] |= ((op >> 4) << NV30_VP_INST_SCA_OPCODEH_SHIFT);
329
hw[1] |= ((op & 0xf) << NV30_VP_INST_SCA_OPCODEL_SHIFT);
330
}
331
// hw[3] |= NVFX_VP(INST_SCA_DEST_TEMP_MASK);
332
// hw[3] |= (mask << NVFX_VP(INST_VEC_WRITEMASK_SHIFT));
333
334
if (insn.dst.type == NVFXSR_OUTPUT) {
335
if (slot)
336
hw[3] |= (insn.mask << NV30_VP_INST_SDEST_WRITEMASK_SHIFT);
337
else
338
hw[3] |= (insn.mask << NV30_VP_INST_VDEST_WRITEMASK_SHIFT);
339
} else {
340
if (slot)
341
hw[3] |= (insn.mask << NV30_VP_INST_STEMP_WRITEMASK_SHIFT);
342
else
343
hw[3] |= (insn.mask << NV30_VP_INST_VTEMP_WRITEMASK_SHIFT);
344
}
345
} else {
346
if (slot == 0) {
347
hw[1] |= (op << NV40_VP_INST_VEC_OPCODE_SHIFT);
348
hw[3] |= NV40_VP_INST_SCA_DEST_TEMP_MASK;
349
hw[3] |= (insn.mask << NV40_VP_INST_VEC_WRITEMASK_SHIFT);
350
} else {
351
hw[1] |= (op << NV40_VP_INST_SCA_OPCODE_SHIFT);
352
hw[0] |= NV40_VP_INST_VEC_DEST_TEMP_MASK ;
353
hw[3] |= (insn.mask << NV40_VP_INST_SCA_WRITEMASK_SHIFT);
354
}
355
}
356
357
emit_dst(vpc, hw, slot, insn.dst);
358
emit_src(vpc, hw, 0, insn.src[0]);
359
emit_src(vpc, hw, 1, insn.src[1]);
360
emit_src(vpc, hw, 2, insn.src[2]);
361
362
// if(insn.src[0].indirect || op == NVFX_VP_INST_VEC_OP_ARL)
363
// hw[3] |= NV40_VP_INST_SCA_RESULT;
364
}
365
366
static inline struct nvfx_src
367
tgsi_src(struct nvfx_vpc *vpc, const struct tgsi_full_src_register *fsrc) {
368
struct nvfx_src src;
369
370
switch (fsrc->Register.File) {
371
case TGSI_FILE_INPUT:
372
src.reg = nvfx_reg(NVFXSR_INPUT, fsrc->Register.Index);
373
break;
374
case TGSI_FILE_CONSTANT:
375
if(fsrc->Register.Indirect) {
376
src.reg = vpc->r_const[0];
377
src.reg.index = fsrc->Register.Index;
378
} else {
379
src.reg = vpc->r_const[fsrc->Register.Index];
380
}
381
break;
382
case TGSI_FILE_IMMEDIATE:
383
src.reg = vpc->imm[fsrc->Register.Index];
384
break;
385
case TGSI_FILE_TEMPORARY:
386
src.reg = vpc->r_temp[fsrc->Register.Index];
387
break;
388
default:
389
NOUVEAU_ERR("bad src file\n");
390
src.reg.index = 0;
391
src.reg.type = -1;
392
break;
393
}
394
395
src.abs = fsrc->Register.Absolute;
396
src.negate = fsrc->Register.Negate;
397
src.swz[0] = fsrc->Register.SwizzleX;
398
src.swz[1] = fsrc->Register.SwizzleY;
399
src.swz[2] = fsrc->Register.SwizzleZ;
400
src.swz[3] = fsrc->Register.SwizzleW;
401
src.indirect = 0;
402
src.indirect_reg = 0;
403
src.indirect_swz = 0;
404
405
if(fsrc->Register.Indirect) {
406
if(fsrc->Indirect.File == TGSI_FILE_ADDRESS &&
407
(fsrc->Register.File == TGSI_FILE_CONSTANT ||
408
fsrc->Register.File == TGSI_FILE_INPUT)) {
409
src.indirect = 1;
410
src.indirect_reg = fsrc->Indirect.Index;
411
src.indirect_swz = fsrc->Indirect.Swizzle;
412
} else {
413
src.reg.index = 0;
414
src.reg.type = -1;
415
}
416
}
417
418
return src;
419
}
420
421
static inline struct nvfx_reg
422
tgsi_dst(struct nvfx_vpc *vpc, const struct tgsi_full_dst_register *fdst) {
423
struct nvfx_reg dst;
424
425
switch (fdst->Register.File) {
426
case TGSI_FILE_NULL:
427
dst = nvfx_reg(NVFXSR_NONE, 0);
428
break;
429
case TGSI_FILE_OUTPUT:
430
dst = vpc->r_result[fdst->Register.Index];
431
break;
432
case TGSI_FILE_TEMPORARY:
433
dst = vpc->r_temp[fdst->Register.Index];
434
break;
435
case TGSI_FILE_ADDRESS:
436
dst = vpc->r_address[fdst->Register.Index];
437
break;
438
default:
439
NOUVEAU_ERR("bad dst file %i\n", fdst->Register.File);
440
dst.index = 0;
441
dst.type = 0;
442
break;
443
}
444
445
return dst;
446
}
447
448
static inline int
449
tgsi_mask(uint tgsi)
450
{
451
int mask = 0;
452
453
if (tgsi & TGSI_WRITEMASK_X) mask |= NVFX_VP_MASK_X;
454
if (tgsi & TGSI_WRITEMASK_Y) mask |= NVFX_VP_MASK_Y;
455
if (tgsi & TGSI_WRITEMASK_Z) mask |= NVFX_VP_MASK_Z;
456
if (tgsi & TGSI_WRITEMASK_W) mask |= NVFX_VP_MASK_W;
457
return mask;
458
}
459
460
static bool
461
nvfx_vertprog_parse_instruction(struct nvfx_vpc *vpc,
462
unsigned idx, const struct tgsi_full_instruction *finst)
463
{
464
struct nvfx_src src[3], tmp;
465
struct nvfx_reg dst;
466
struct nvfx_reg final_dst;
467
struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE, 0));
468
struct nvfx_insn insn;
469
struct nvfx_relocation reloc;
470
struct nvfx_loop_entry loop;
471
bool sat = false;
472
int mask;
473
int ai = -1, ci = -1, ii = -1;
474
int i;
475
unsigned sub_depth = 0;
476
477
for (i = 0; i < finst->Instruction.NumSrcRegs; i++) {
478
const struct tgsi_full_src_register *fsrc;
479
480
fsrc = &finst->Src[i];
481
if (fsrc->Register.File == TGSI_FILE_TEMPORARY) {
482
src[i] = tgsi_src(vpc, fsrc);
483
}
484
}
485
486
for (i = 0; i < finst->Instruction.NumSrcRegs; i++) {
487
const struct tgsi_full_src_register *fsrc;
488
489
fsrc = &finst->Src[i];
490
491
switch (fsrc->Register.File) {
492
case TGSI_FILE_INPUT:
493
if (ai == -1 || ai == fsrc->Register.Index) {
494
ai = fsrc->Register.Index;
495
src[i] = tgsi_src(vpc, fsrc);
496
} else {
497
src[i] = nvfx_src(temp(vpc));
498
nvfx_vp_emit(vpc, arith(0, VEC, MOV, src[i].reg, NVFX_VP_MASK_ALL,
499
tgsi_src(vpc, fsrc), none, none));
500
}
501
break;
502
case TGSI_FILE_CONSTANT:
503
if ((ci == -1 && ii == -1) ||
504
ci == fsrc->Register.Index) {
505
ci = fsrc->Register.Index;
506
src[i] = tgsi_src(vpc, fsrc);
507
} else {
508
src[i] = nvfx_src(temp(vpc));
509
nvfx_vp_emit(vpc, arith(0, VEC, MOV, src[i].reg, NVFX_VP_MASK_ALL,
510
tgsi_src(vpc, fsrc), none, none));
511
}
512
break;
513
case TGSI_FILE_IMMEDIATE:
514
if ((ci == -1 && ii == -1) ||
515
ii == fsrc->Register.Index) {
516
ii = fsrc->Register.Index;
517
src[i] = tgsi_src(vpc, fsrc);
518
} else {
519
src[i] = nvfx_src(temp(vpc));
520
nvfx_vp_emit(vpc, arith(0, VEC, MOV, src[i].reg, NVFX_VP_MASK_ALL,
521
tgsi_src(vpc, fsrc), none, none));
522
}
523
break;
524
case TGSI_FILE_TEMPORARY:
525
/* handled above */
526
break;
527
default:
528
NOUVEAU_ERR("bad src file\n");
529
return false;
530
}
531
}
532
533
for (i = 0; i < finst->Instruction.NumSrcRegs; i++) {
534
if(src[i].reg.type < 0)
535
return false;
536
}
537
538
if(finst->Dst[0].Register.File == TGSI_FILE_ADDRESS &&
539
finst->Instruction.Opcode != TGSI_OPCODE_ARL)
540
return false;
541
542
final_dst = dst = tgsi_dst(vpc, &finst->Dst[0]);
543
mask = tgsi_mask(finst->Dst[0].Register.WriteMask);
544
if(finst->Instruction.Saturate) {
545
assert(finst->Instruction.Opcode != TGSI_OPCODE_ARL);
546
if (vpc->is_nv4x)
547
sat = true;
548
else
549
if(dst.type != NVFXSR_TEMP)
550
dst = temp(vpc);
551
}
552
553
switch (finst->Instruction.Opcode) {
554
case TGSI_OPCODE_ADD:
555
nvfx_vp_emit(vpc, arith(sat, VEC, ADD, dst, mask, src[0], none, src[1]));
556
break;
557
case TGSI_OPCODE_ARL:
558
nvfx_vp_emit(vpc, arith(0, VEC, ARL, dst, mask, src[0], none, none));
559
break;
560
case TGSI_OPCODE_CEIL:
561
tmp = nvfx_src(temp(vpc));
562
nvfx_vp_emit(vpc, arith(0, VEC, FLR, tmp.reg, mask, neg(src[0]), none, none));
563
nvfx_vp_emit(vpc, arith(sat, VEC, MOV, dst, mask, neg(tmp), none, none));
564
break;
565
case TGSI_OPCODE_CMP:
566
insn = arith(0, VEC, MOV, none.reg, mask, src[0], none, none);
567
insn.cc_update = 1;
568
nvfx_vp_emit(vpc, insn);
569
570
insn = arith(sat, VEC, MOV, dst, mask, src[2], none, none);
571
insn.cc_test = NVFX_COND_GE;
572
nvfx_vp_emit(vpc, insn);
573
574
insn = arith(sat, VEC, MOV, dst, mask, src[1], none, none);
575
insn.cc_test = NVFX_COND_LT;
576
nvfx_vp_emit(vpc, insn);
577
break;
578
case TGSI_OPCODE_COS:
579
nvfx_vp_emit(vpc, arith(sat, SCA, COS, dst, mask, none, none, src[0]));
580
break;
581
case TGSI_OPCODE_DP2:
582
tmp = nvfx_src(temp(vpc));
583
nvfx_vp_emit(vpc, arith(0, VEC, MUL, tmp.reg, NVFX_VP_MASK_X | NVFX_VP_MASK_Y, src[0], src[1], none));
584
nvfx_vp_emit(vpc, arith(sat, VEC, ADD, dst, mask, swz(tmp, X, X, X, X), none, swz(tmp, Y, Y, Y, Y)));
585
break;
586
case TGSI_OPCODE_DP3:
587
nvfx_vp_emit(vpc, arith(sat, VEC, DP3, dst, mask, src[0], src[1], none));
588
break;
589
case TGSI_OPCODE_DP4:
590
nvfx_vp_emit(vpc, arith(sat, VEC, DP4, dst, mask, src[0], src[1], none));
591
break;
592
case TGSI_OPCODE_DST:
593
nvfx_vp_emit(vpc, arith(sat, VEC, DST, dst, mask, src[0], src[1], none));
594
break;
595
case TGSI_OPCODE_EX2:
596
nvfx_vp_emit(vpc, arith(sat, SCA, EX2, dst, mask, none, none, src[0]));
597
break;
598
case TGSI_OPCODE_EXP:
599
nvfx_vp_emit(vpc, arith(sat, SCA, EXP, dst, mask, none, none, src[0]));
600
break;
601
case TGSI_OPCODE_FLR:
602
nvfx_vp_emit(vpc, arith(sat, VEC, FLR, dst, mask, src[0], none, none));
603
break;
604
case TGSI_OPCODE_FRC:
605
nvfx_vp_emit(vpc, arith(sat, VEC, FRC, dst, mask, src[0], none, none));
606
break;
607
case TGSI_OPCODE_LG2:
608
nvfx_vp_emit(vpc, arith(sat, SCA, LG2, dst, mask, none, none, src[0]));
609
break;
610
case TGSI_OPCODE_LIT:
611
nvfx_vp_emit(vpc, arith(sat, SCA, LIT, dst, mask, none, none, src[0]));
612
break;
613
case TGSI_OPCODE_LOG:
614
nvfx_vp_emit(vpc, arith(sat, SCA, LOG, dst, mask, none, none, src[0]));
615
break;
616
case TGSI_OPCODE_LRP:
617
tmp = nvfx_src(temp(vpc));
618
nvfx_vp_emit(vpc, arith(0, VEC, MAD, tmp.reg, mask, neg(src[0]), src[2], src[2]));
619
nvfx_vp_emit(vpc, arith(sat, VEC, MAD, dst, mask, src[0], src[1], tmp));
620
break;
621
case TGSI_OPCODE_MAD:
622
nvfx_vp_emit(vpc, arith(sat, VEC, MAD, dst, mask, src[0], src[1], src[2]));
623
break;
624
case TGSI_OPCODE_MAX:
625
nvfx_vp_emit(vpc, arith(sat, VEC, MAX, dst, mask, src[0], src[1], none));
626
break;
627
case TGSI_OPCODE_MIN:
628
nvfx_vp_emit(vpc, arith(sat, VEC, MIN, dst, mask, src[0], src[1], none));
629
break;
630
case TGSI_OPCODE_MOV:
631
nvfx_vp_emit(vpc, arith(sat, VEC, MOV, dst, mask, src[0], none, none));
632
break;
633
case TGSI_OPCODE_MUL:
634
nvfx_vp_emit(vpc, arith(sat, VEC, MUL, dst, mask, src[0], src[1], none));
635
break;
636
case TGSI_OPCODE_NOP:
637
break;
638
case TGSI_OPCODE_POW:
639
tmp = nvfx_src(temp(vpc));
640
nvfx_vp_emit(vpc, arith(0, SCA, LG2, tmp.reg, NVFX_VP_MASK_X, none, none, swz(src[0], X, X, X, X)));
641
nvfx_vp_emit(vpc, arith(0, VEC, MUL, tmp.reg, NVFX_VP_MASK_X, swz(tmp, X, X, X, X), swz(src[1], X, X, X, X), none));
642
nvfx_vp_emit(vpc, arith(sat, SCA, EX2, dst, mask, none, none, swz(tmp, X, X, X, X)));
643
break;
644
case TGSI_OPCODE_RCP:
645
nvfx_vp_emit(vpc, arith(sat, SCA, RCP, dst, mask, none, none, src[0]));
646
break;
647
case TGSI_OPCODE_RSQ:
648
nvfx_vp_emit(vpc, arith(sat, SCA, RSQ, dst, mask, none, none, abs(src[0])));
649
break;
650
case TGSI_OPCODE_SEQ:
651
nvfx_vp_emit(vpc, arith(sat, VEC, SEQ, dst, mask, src[0], src[1], none));
652
break;
653
case TGSI_OPCODE_SGE:
654
nvfx_vp_emit(vpc, arith(sat, VEC, SGE, dst, mask, src[0], src[1], none));
655
break;
656
case TGSI_OPCODE_SGT:
657
nvfx_vp_emit(vpc, arith(sat, VEC, SGT, dst, mask, src[0], src[1], none));
658
break;
659
case TGSI_OPCODE_SIN:
660
nvfx_vp_emit(vpc, arith(sat, SCA, SIN, dst, mask, none, none, src[0]));
661
break;
662
case TGSI_OPCODE_SLE:
663
nvfx_vp_emit(vpc, arith(sat, VEC, SLE, dst, mask, src[0], src[1], none));
664
break;
665
case TGSI_OPCODE_SLT:
666
nvfx_vp_emit(vpc, arith(sat, VEC, SLT, dst, mask, src[0], src[1], none));
667
break;
668
case TGSI_OPCODE_SNE:
669
nvfx_vp_emit(vpc, arith(sat, VEC, SNE, dst, mask, src[0], src[1], none));
670
break;
671
case TGSI_OPCODE_SSG:
672
nvfx_vp_emit(vpc, arith(sat, VEC, SSG, dst, mask, src[0], none, none));
673
break;
674
case TGSI_OPCODE_TRUNC:
675
tmp = nvfx_src(temp(vpc));
676
insn = arith(0, VEC, MOV, none.reg, mask, src[0], none, none);
677
insn.cc_update = 1;
678
nvfx_vp_emit(vpc, insn);
679
680
nvfx_vp_emit(vpc, arith(0, VEC, FLR, tmp.reg, mask, abs(src[0]), none, none));
681
nvfx_vp_emit(vpc, arith(sat, VEC, MOV, dst, mask, tmp, none, none));
682
683
insn = arith(sat, VEC, MOV, dst, mask, neg(tmp), none, none);
684
insn.cc_test = NVFX_COND_LT;
685
nvfx_vp_emit(vpc, insn);
686
break;
687
case TGSI_OPCODE_IF:
688
insn = arith(0, VEC, MOV, none.reg, NVFX_VP_MASK_X, src[0], none, none);
689
insn.cc_update = 1;
690
nvfx_vp_emit(vpc, insn);
691
692
reloc.location = vpc->vp->nr_insns;
693
reloc.target = finst->Label.Label + 1;
694
util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc);
695
696
insn = arith(0, SCA, BRA, none.reg, 0, none, none, none);
697
insn.cc_test = NVFX_COND_EQ;
698
insn.cc_swz[0] = insn.cc_swz[1] = insn.cc_swz[2] = insn.cc_swz[3] = 0;
699
nvfx_vp_emit(vpc, insn);
700
break;
701
case TGSI_OPCODE_ELSE:
702
case TGSI_OPCODE_CAL:
703
reloc.location = vpc->vp->nr_insns;
704
reloc.target = finst->Label.Label;
705
util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc);
706
707
if(finst->Instruction.Opcode == TGSI_OPCODE_CAL)
708
insn = arith(0, SCA, CAL, none.reg, 0, none, none, none);
709
else
710
insn = arith(0, SCA, BRA, none.reg, 0, none, none, none);
711
nvfx_vp_emit(vpc, insn);
712
break;
713
case TGSI_OPCODE_RET:
714
if(sub_depth || !vpc->vp->enabled_ucps) {
715
tmp = none;
716
tmp.swz[0] = tmp.swz[1] = tmp.swz[2] = tmp.swz[3] = 0;
717
nvfx_vp_emit(vpc, arith(0, SCA, RET, none.reg, 0, none, none, tmp));
718
} else {
719
reloc.location = vpc->vp->nr_insns;
720
reloc.target = vpc->info->num_instructions;
721
util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc);
722
nvfx_vp_emit(vpc, arith(0, SCA, BRA, none.reg, 0, none, none, none));
723
}
724
break;
725
case TGSI_OPCODE_BGNSUB:
726
++sub_depth;
727
break;
728
case TGSI_OPCODE_ENDSUB:
729
--sub_depth;
730
break;
731
case TGSI_OPCODE_ENDIF:
732
/* nothing to do here */
733
break;
734
case TGSI_OPCODE_BGNLOOP:
735
loop.cont_target = idx;
736
loop.brk_target = finst->Label.Label + 1;
737
util_dynarray_append(&vpc->loop_stack, struct nvfx_loop_entry, loop);
738
break;
739
case TGSI_OPCODE_ENDLOOP:
740
loop = util_dynarray_pop(&vpc->loop_stack, struct nvfx_loop_entry);
741
742
reloc.location = vpc->vp->nr_insns;
743
reloc.target = loop.cont_target;
744
util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc);
745
746
nvfx_vp_emit(vpc, arith(0, SCA, BRA, none.reg, 0, none, none, none));
747
break;
748
case TGSI_OPCODE_CONT:
749
loop = util_dynarray_top(&vpc->loop_stack, struct nvfx_loop_entry);
750
751
reloc.location = vpc->vp->nr_insns;
752
reloc.target = loop.cont_target;
753
util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc);
754
755
nvfx_vp_emit(vpc, arith(0, SCA, BRA, none.reg, 0, none, none, none));
756
break;
757
case TGSI_OPCODE_BRK:
758
loop = util_dynarray_top(&vpc->loop_stack, struct nvfx_loop_entry);
759
760
reloc.location = vpc->vp->nr_insns;
761
reloc.target = loop.brk_target;
762
util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc);
763
764
nvfx_vp_emit(vpc, arith(0, SCA, BRA, none.reg, 0, none, none, none));
765
break;
766
case TGSI_OPCODE_END:
767
assert(!sub_depth);
768
if(vpc->vp->enabled_ucps) {
769
if(idx != (vpc->info->num_instructions - 1)) {
770
reloc.location = vpc->vp->nr_insns;
771
reloc.target = vpc->info->num_instructions;
772
util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc);
773
nvfx_vp_emit(vpc, arith(0, SCA, BRA, none.reg, 0, none, none, none));
774
}
775
} else {
776
if(vpc->vp->nr_insns)
777
vpc->vp->insns[vpc->vp->nr_insns - 1].data[3] |= NVFX_VP_INST_LAST;
778
nvfx_vp_emit(vpc, arith(0, VEC, NOP, none.reg, 0, none, none, none));
779
vpc->vp->insns[vpc->vp->nr_insns - 1].data[3] |= NVFX_VP_INST_LAST;
780
}
781
break;
782
default:
783
NOUVEAU_ERR("invalid opcode %d\n", finst->Instruction.Opcode);
784
return false;
785
}
786
787
if(finst->Instruction.Saturate && !vpc->is_nv4x) {
788
if (!vpc->r_0_1.type)
789
vpc->r_0_1 = constant(vpc, -1, 0, 1, 0, 0);
790
nvfx_vp_emit(vpc, arith(0, VEC, MAX, dst, mask, nvfx_src(dst), swz(nvfx_src(vpc->r_0_1), X, X, X, X), none));
791
nvfx_vp_emit(vpc, arith(0, VEC, MIN, final_dst, mask, nvfx_src(dst), swz(nvfx_src(vpc->r_0_1), Y, Y, Y, Y), none));
792
}
793
794
release_temps(vpc);
795
return true;
796
}
797
798
static bool
799
nvfx_vertprog_parse_decl_output(struct nvfx_vpc *vpc,
800
const struct tgsi_full_declaration *fdec)
801
{
802
unsigned num_texcoords = vpc->is_nv4x ? 10 : 8;
803
unsigned idx = fdec->Range.First;
804
unsigned semantic_index = fdec->Semantic.Index;
805
int hw = 0, i;
806
807
switch (fdec->Semantic.Name) {
808
case TGSI_SEMANTIC_POSITION:
809
hw = NVFX_VP(INST_DEST_POS);
810
vpc->hpos_idx = idx;
811
break;
812
case TGSI_SEMANTIC_CLIPVERTEX:
813
vpc->r_result[idx] = temp(vpc);
814
vpc->r_temps_discard = 0;
815
vpc->cvtx_idx = idx;
816
return true;
817
case TGSI_SEMANTIC_COLOR:
818
if (fdec->Semantic.Index == 0) {
819
hw = NVFX_VP(INST_DEST_COL0);
820
} else
821
if (fdec->Semantic.Index == 1) {
822
hw = NVFX_VP(INST_DEST_COL1);
823
} else {
824
NOUVEAU_ERR("bad colour semantic index\n");
825
return false;
826
}
827
break;
828
case TGSI_SEMANTIC_BCOLOR:
829
if (fdec->Semantic.Index == 0) {
830
hw = NVFX_VP(INST_DEST_BFC0);
831
} else
832
if (fdec->Semantic.Index == 1) {
833
hw = NVFX_VP(INST_DEST_BFC1);
834
} else {
835
NOUVEAU_ERR("bad bcolour semantic index\n");
836
return false;
837
}
838
break;
839
case TGSI_SEMANTIC_FOG:
840
hw = NVFX_VP(INST_DEST_FOGC);
841
break;
842
case TGSI_SEMANTIC_PSIZE:
843
hw = NVFX_VP(INST_DEST_PSZ);
844
break;
845
case TGSI_SEMANTIC_GENERIC:
846
/* this is really an identifier for VP/FP linkage */
847
semantic_index += 8;
848
FALLTHROUGH;
849
case TGSI_SEMANTIC_TEXCOORD:
850
for (i = 0; i < num_texcoords; i++) {
851
if (vpc->vp->texcoord[i] == semantic_index) {
852
hw = NVFX_VP(INST_DEST_TC(i));
853
break;
854
}
855
}
856
857
if (i == num_texcoords) {
858
vpc->r_result[idx] = nvfx_reg(NVFXSR_NONE, 0);
859
return true;
860
}
861
break;
862
case TGSI_SEMANTIC_EDGEFLAG:
863
vpc->r_result[idx] = nvfx_reg(NVFXSR_NONE, 0);
864
return true;
865
default:
866
NOUVEAU_ERR("bad output semantic\n");
867
return false;
868
}
869
870
vpc->r_result[idx] = nvfx_reg(NVFXSR_OUTPUT, hw);
871
return true;
872
}
873
874
static bool
875
nvfx_vertprog_prepare(struct nvfx_vpc *vpc)
876
{
877
struct tgsi_parse_context p;
878
int high_const = -1, high_temp = -1, high_addr = -1, nr_imm = 0, i;
879
880
tgsi_parse_init(&p, vpc->pipe.tokens);
881
while (!tgsi_parse_end_of_tokens(&p)) {
882
const union tgsi_full_token *tok = &p.FullToken;
883
884
tgsi_parse_token(&p);
885
switch(tok->Token.Type) {
886
case TGSI_TOKEN_TYPE_IMMEDIATE:
887
nr_imm++;
888
break;
889
case TGSI_TOKEN_TYPE_DECLARATION:
890
{
891
const struct tgsi_full_declaration *fdec;
892
893
fdec = &p.FullToken.FullDeclaration;
894
switch (fdec->Declaration.File) {
895
case TGSI_FILE_TEMPORARY:
896
if (fdec->Range.Last > high_temp) {
897
high_temp =
898
fdec->Range.Last;
899
}
900
break;
901
case TGSI_FILE_ADDRESS:
902
if (fdec->Range.Last > high_addr) {
903
high_addr =
904
fdec->Range.Last;
905
}
906
break;
907
case TGSI_FILE_CONSTANT:
908
if (fdec->Range.Last > high_const) {
909
high_const =
910
fdec->Range.Last;
911
}
912
break;
913
case TGSI_FILE_OUTPUT:
914
if (!nvfx_vertprog_parse_decl_output(vpc, fdec))
915
return false;
916
break;
917
default:
918
break;
919
}
920
}
921
break;
922
default:
923
break;
924
}
925
}
926
tgsi_parse_free(&p);
927
928
if (nr_imm) {
929
vpc->imm = CALLOC(nr_imm, sizeof(struct nvfx_reg));
930
assert(vpc->imm);
931
}
932
933
if (++high_temp) {
934
vpc->r_temp = CALLOC(high_temp, sizeof(struct nvfx_reg));
935
for (i = 0; i < high_temp; i++)
936
vpc->r_temp[i] = temp(vpc);
937
}
938
939
if (++high_addr) {
940
vpc->r_address = CALLOC(high_addr, sizeof(struct nvfx_reg));
941
for (i = 0; i < high_addr; i++)
942
vpc->r_address[i] = nvfx_reg(NVFXSR_TEMP, i);
943
}
944
945
if(++high_const) {
946
vpc->r_const = CALLOC(high_const, sizeof(struct nvfx_reg));
947
for (i = 0; i < high_const; i++)
948
vpc->r_const[i] = constant(vpc, i, 0, 0, 0, 0);
949
}
950
951
vpc->r_temps_discard = 0;
952
return true;
953
}
954
955
DEBUG_GET_ONCE_BOOL_OPTION(nvfx_dump_vp, "NVFX_DUMP_VP", false)
956
957
bool
958
_nvfx_vertprog_translate(uint16_t oclass, struct nv30_vertprog *vp)
959
{
960
struct tgsi_parse_context parse;
961
struct nvfx_vpc *vpc = NULL;
962
struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE, 0));
963
struct util_dynarray insns;
964
int i, ucps;
965
966
vp->translated = false;
967
vp->nr_insns = 0;
968
vp->nr_consts = 0;
969
970
vpc = CALLOC_STRUCT(nvfx_vpc);
971
if (!vpc)
972
return false;
973
vpc->is_nv4x = (oclass >= NV40_3D_CLASS) ? ~0 : 0;
974
vpc->vp = vp;
975
vpc->pipe = vp->pipe;
976
vpc->info = &vp->info;
977
vpc->cvtx_idx = -1;
978
979
if (!nvfx_vertprog_prepare(vpc)) {
980
FREE(vpc);
981
return false;
982
}
983
984
/* Redirect post-transform vertex position to a temp if user clip
985
* planes are enabled. We need to append code to the vtxprog
986
* to handle clip planes later.
987
*/
988
if (vp->enabled_ucps && vpc->cvtx_idx < 0) {
989
vpc->r_result[vpc->hpos_idx] = temp(vpc);
990
vpc->r_temps_discard = 0;
991
vpc->cvtx_idx = vpc->hpos_idx;
992
}
993
994
util_dynarray_init(&insns, NULL);
995
996
tgsi_parse_init(&parse, vp->pipe.tokens);
997
while (!tgsi_parse_end_of_tokens(&parse)) {
998
tgsi_parse_token(&parse);
999
1000
switch (parse.FullToken.Token.Type) {
1001
case TGSI_TOKEN_TYPE_IMMEDIATE:
1002
{
1003
const struct tgsi_full_immediate *imm;
1004
1005
imm = &parse.FullToken.FullImmediate;
1006
assert(imm->Immediate.DataType == TGSI_IMM_FLOAT32);
1007
assert(imm->Immediate.NrTokens == 4 + 1);
1008
vpc->imm[vpc->nr_imm++] =
1009
constant(vpc, -1,
1010
imm->u[0].Float,
1011
imm->u[1].Float,
1012
imm->u[2].Float,
1013
imm->u[3].Float);
1014
}
1015
break;
1016
case TGSI_TOKEN_TYPE_INSTRUCTION:
1017
{
1018
const struct tgsi_full_instruction *finst;
1019
unsigned idx = insns.size >> 2;
1020
util_dynarray_append(&insns, unsigned, vp->nr_insns);
1021
finst = &parse.FullToken.FullInstruction;
1022
if (!nvfx_vertprog_parse_instruction(vpc, idx, finst))
1023
goto out;
1024
}
1025
break;
1026
default:
1027
break;
1028
}
1029
}
1030
1031
util_dynarray_append(&insns, unsigned, vp->nr_insns);
1032
1033
for(unsigned i = 0; i < vpc->label_relocs.size; i += sizeof(struct nvfx_relocation))
1034
{
1035
struct nvfx_relocation* label_reloc = (struct nvfx_relocation*)((char*)vpc->label_relocs.data + i);
1036
struct nvfx_relocation hw_reloc;
1037
1038
hw_reloc.location = label_reloc->location;
1039
hw_reloc.target = ((unsigned*)insns.data)[label_reloc->target];
1040
1041
//debug_printf("hw %u -> tgsi %u = hw %u\n", hw_reloc.location, label_reloc->target, hw_reloc.target);
1042
1043
util_dynarray_append(&vp->branch_relocs, struct nvfx_relocation, hw_reloc);
1044
}
1045
util_dynarray_fini(&insns);
1046
util_dynarray_trim(&vp->branch_relocs);
1047
1048
/* XXX: what if we add a RET before?! make sure we jump here...*/
1049
1050
/* Write out HPOS if it was redirected to a temp earlier */
1051
if (vpc->r_result[vpc->hpos_idx].type != NVFXSR_OUTPUT) {
1052
struct nvfx_reg hpos = nvfx_reg(NVFXSR_OUTPUT,
1053
NVFX_VP(INST_DEST_POS));
1054
struct nvfx_src htmp = nvfx_src(vpc->r_result[vpc->hpos_idx]);
1055
1056
nvfx_vp_emit(vpc, arith(0, VEC, MOV, hpos, NVFX_VP_MASK_ALL, htmp, none, none));
1057
}
1058
1059
/* Insert code to handle user clip planes */
1060
ucps = vp->enabled_ucps;
1061
while (ucps) {
1062
int i = ffs(ucps) - 1; ucps &= ~(1 << i);
1063
struct nvfx_reg cdst = nvfx_reg(NVFXSR_OUTPUT, NV30_VP_INST_DEST_CLP(i));
1064
struct nvfx_src ceqn = nvfx_src(nvfx_reg(NVFXSR_CONST, 512 + i));
1065
struct nvfx_src htmp = nvfx_src(vpc->r_result[vpc->cvtx_idx]);
1066
unsigned mask;
1067
1068
if(vpc->is_nv4x)
1069
{
1070
switch (i) {
1071
case 0: case 3: mask = NVFX_VP_MASK_Y; break;
1072
case 1: case 4: mask = NVFX_VP_MASK_Z; break;
1073
case 2: case 5: mask = NVFX_VP_MASK_W; break;
1074
default:
1075
NOUVEAU_ERR("invalid clip dist #%d\n", i);
1076
goto out;
1077
}
1078
}
1079
else
1080
mask = NVFX_VP_MASK_X;
1081
1082
nvfx_vp_emit(vpc, arith(0, VEC, DP4, cdst, mask, htmp, ceqn, none));
1083
}
1084
1085
if (vpc->vp->nr_insns)
1086
vpc->vp->insns[vpc->vp->nr_insns - 1].data[3] |= NVFX_VP_INST_LAST;
1087
1088
if(debug_get_option_nvfx_dump_vp())
1089
{
1090
debug_printf("\n");
1091
tgsi_dump(vpc->pipe.tokens, 0);
1092
1093
debug_printf("\n%s vertex program:\n", vpc->is_nv4x ? "nv4x" : "nv3x");
1094
for (i = 0; i < vp->nr_insns; i++)
1095
debug_printf("%3u: %08x %08x %08x %08x\n", i, vp->insns[i].data[0], vp->insns[i].data[1], vp->insns[i].data[2], vp->insns[i].data[3]);
1096
debug_printf("\n");
1097
}
1098
1099
vp->translated = true;
1100
1101
out:
1102
tgsi_parse_free(&parse);
1103
if (vpc) {
1104
util_dynarray_fini(&vpc->label_relocs);
1105
util_dynarray_fini(&vpc->loop_stack);
1106
FREE(vpc->r_temp);
1107
FREE(vpc->r_address);
1108
FREE(vpc->r_const);
1109
FREE(vpc->imm);
1110
FREE(vpc);
1111
}
1112
1113
return vp->translated;
1114
}
1115
1116