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