• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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