nv50_program.c revision 55b2fe1047b37d0d86641a252e1c745111030393
1030249dd247444687663c4969ff078dc0a4b24acekm#include "pipe/p_context.h"
2030249dd247444687663c4969ff078dc0a4b24acekm#include "pipe/p_defines.h"
3030249dd247444687663c4969ff078dc0a4b24acekm#include "pipe/p_state.h"
4030249dd247444687663c4969ff078dc0a4b24acekm#include "pipe/p_inlines.h"
5030249dd247444687663c4969ff078dc0a4b24acekm
6030249dd247444687663c4969ff078dc0a4b24acekm#include "pipe/p_shader_tokens.h"
7030249dd247444687663c4969ff078dc0a4b24acekm#include "tgsi/util/tgsi_parse.h"
8030249dd247444687663c4969ff078dc0a4b24acekm#include "tgsi/util/tgsi_util.h"
9030249dd247444687663c4969ff078dc0a4b24acekm
10030249dd247444687663c4969ff078dc0a4b24acekm#include "nv50_context.h"
11db4fecfb01ac51e936e4b7496a4929e713080f07ekm#include "nv50_state.h"
12db4fecfb01ac51e936e4b7496a4929e713080f07ekm
13db4fecfb01ac51e936e4b7496a4929e713080f07ekm#define NV50_SU_MAX_TEMP 64
14db4fecfb01ac51e936e4b7496a4929e713080f07ekm#define TX_FRAGPROG 0
15030249dd247444687663c4969ff078dc0a4b24acekm
16030249dd247444687663c4969ff078dc0a4b24acekmstruct nv50_reg {
17030249dd247444687663c4969ff078dc0a4b24acekm	enum {
18030249dd247444687663c4969ff078dc0a4b24acekm		P_TEMP,
1935b72fbceb09031cbd6039e0dbbd44ed24296509ekm		P_ATTR,
20030249dd247444687663c4969ff078dc0a4b24acekm		P_RESULT,
21db4fecfb01ac51e936e4b7496a4929e713080f07ekm		P_CONST,
22030249dd247444687663c4969ff078dc0a4b24acekm		P_IMMD
2360d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	} type;
24030249dd247444687663c4969ff078dc0a4b24acekm	int index;
25030249dd247444687663c4969ff078dc0a4b24acekm
26030249dd247444687663c4969ff078dc0a4b24acekm	int hw;
27030249dd247444687663c4969ff078dc0a4b24acekm	int neg;
28030249dd247444687663c4969ff078dc0a4b24acekm};
29030249dd247444687663c4969ff078dc0a4b24acekm
30030249dd247444687663c4969ff078dc0a4b24acekmstruct nv50_pc {
31db4fecfb01ac51e936e4b7496a4929e713080f07ekm	struct nv50_program *p;
32030249dd247444687663c4969ff078dc0a4b24acekm
33030249dd247444687663c4969ff078dc0a4b24acekm	/* hw resources */
3460d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	struct nv50_reg *r_temp[NV50_SU_MAX_TEMP];
3560d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson
3660d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	/* tgsi resources */
3760d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	struct nv50_reg *temp;
3860d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	int temp_nr;
3960d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	struct nv50_reg *attr;
4060d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	int attr_nr;
4160d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	struct nv50_reg *result;
4260d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	int result_nr;
4360d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	struct nv50_reg *param;
4460d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	int param_nr;
4560d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	struct nv50_reg *immd;
4660d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	float *immd_buf;
4760d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	int immd_nr;
4860d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson};
4960d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson
506955870806624479723addfae6dcf5d13968796cPeter Kastingstatic void
516955870806624479723addfae6dcf5d13968796cPeter Kastingalloc_reg(struct nv50_pc *pc, struct nv50_reg *reg)
5260d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson{
5360d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	int i;
54dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting
5560d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	if (reg->type != P_TEMP || reg->hw >= 0)
5660d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson		return;
5760d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson
5860d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson	for (i = 0; i < NV50_SU_MAX_TEMP; i++) {
5960d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson		if (!(pc->r_temp[i])) {
6060d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson			pc->r_temp[i] = reg;
6160d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson			reg->hw = i;
62030249dd247444687663c4969ff078dc0a4b24acekm			if (pc->p->cfg.vp.high_temp < (i + 1))
63db4fecfb01ac51e936e4b7496a4929e713080f07ekm				pc->p->cfg.vp.high_temp = i + 1;
6460d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson			return;
6560d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson		}
666955870806624479723addfae6dcf5d13968796cPeter Kasting	}
67b7553dfdbb1ca7779eb0d80b5f509523c9b00086ekm
68db4fecfb01ac51e936e4b7496a4929e713080f07ekm	assert(0);
6960d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson}
7060d9b332a5391045439bfb6a3a5447973e3d5603ekmeyerson
716955870806624479723addfae6dcf5d13968796cPeter Kastingstatic struct nv50_reg *
7260d9b332a5391045439bfb6a3a5447973e3d5603ekmeyersonalloc_temp(struct nv50_pc *pc, struct nv50_reg *dst)
73db4fecfb01ac51e936e4b7496a4929e713080f07ekm{
74030249dd247444687663c4969ff078dc0a4b24acekm	struct nv50_reg *r;
75030249dd247444687663c4969ff078dc0a4b24acekm	int i;
76db4fecfb01ac51e936e4b7496a4929e713080f07ekm
77db4fecfb01ac51e936e4b7496a4929e713080f07ekm	if (dst && dst->type == P_TEMP && dst->hw == -1)
78030249dd247444687663c4969ff078dc0a4b24acekm		return dst;
79030249dd247444687663c4969ff078dc0a4b24acekm
80db4fecfb01ac51e936e4b7496a4929e713080f07ekm	for (i = 0; i < NV50_SU_MAX_TEMP; i++) {
81030249dd247444687663c4969ff078dc0a4b24acekm		if (!pc->r_temp[i]) {
82030249dd247444687663c4969ff078dc0a4b24acekm			r = CALLOC_STRUCT(nv50_reg);
83030249dd247444687663c4969ff078dc0a4b24acekm			r->type = P_TEMP;
84db4fecfb01ac51e936e4b7496a4929e713080f07ekm			r->index = -1;
85db4fecfb01ac51e936e4b7496a4929e713080f07ekm			r->hw = i;
86db4fecfb01ac51e936e4b7496a4929e713080f07ekm			pc->r_temp[i] = r;
87b297c5a01f88219da26cffe433804963d1b70f0fpkasting			return r;
886955870806624479723addfae6dcf5d13968796cPeter Kasting		}
89dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting	}
906955870806624479723addfae6dcf5d13968796cPeter Kasting
91b297c5a01f88219da26cffe433804963d1b70f0fpkasting	assert(0);
92030249dd247444687663c4969ff078dc0a4b24acekm	return NULL;
93030249dd247444687663c4969ff078dc0a4b24acekm}
94030249dd247444687663c4969ff078dc0a4b24acekm
95030249dd247444687663c4969ff078dc0a4b24acekmstatic void
96030249dd247444687663c4969ff078dc0a4b24acekmfree_temp(struct nv50_pc *pc, struct nv50_reg *r)
97030249dd247444687663c4969ff078dc0a4b24acekm{
9835b72fbceb09031cbd6039e0dbbd44ed24296509ekm	if (r->index == -1) {
9935b72fbceb09031cbd6039e0dbbd44ed24296509ekm		FREE(pc->r_temp[r->hw]);
100030249dd247444687663c4969ff078dc0a4b24acekm		pc->r_temp[r->hw] = NULL;
101db4fecfb01ac51e936e4b7496a4929e713080f07ekm	}
102db4fecfb01ac51e936e4b7496a4929e713080f07ekm}
103db4fecfb01ac51e936e4b7496a4929e713080f07ekm
104030249dd247444687663c4969ff078dc0a4b24acekmstatic struct nv50_reg *
105db4fecfb01ac51e936e4b7496a4929e713080f07ekmtgsi_dst(struct nv50_pc *pc, int c, const struct tgsi_full_dst_register *dst)
106db4fecfb01ac51e936e4b7496a4929e713080f07ekm{
107db4fecfb01ac51e936e4b7496a4929e713080f07ekm	switch (dst->DstRegister.File) {
108030249dd247444687663c4969ff078dc0a4b24acekm	case TGSI_FILE_TEMPORARY:
109030249dd247444687663c4969ff078dc0a4b24acekm		return &pc->temp[dst->DstRegister.Index * 4 + c];
110db4fecfb01ac51e936e4b7496a4929e713080f07ekm	case TGSI_FILE_OUTPUT:
111db4fecfb01ac51e936e4b7496a4929e713080f07ekm		return &pc->result[dst->DstRegister.Index * 4 + c];
112030249dd247444687663c4969ff078dc0a4b24acekm	case TGSI_FILE_NULL:
113db4fecfb01ac51e936e4b7496a4929e713080f07ekm		return NULL;
11435b72fbceb09031cbd6039e0dbbd44ed24296509ekm	default:
11535b72fbceb09031cbd6039e0dbbd44ed24296509ekm		break;
11635b72fbceb09031cbd6039e0dbbd44ed24296509ekm	}
11735b72fbceb09031cbd6039e0dbbd44ed24296509ekm
11835b72fbceb09031cbd6039e0dbbd44ed24296509ekm	return NULL;
11935b72fbceb09031cbd6039e0dbbd44ed24296509ekm}
120db4fecfb01ac51e936e4b7496a4929e713080f07ekm
121030249dd247444687663c4969ff078dc0a4b24acekmstatic struct nv50_reg *
122030249dd247444687663c4969ff078dc0a4b24acekmtgsi_src(struct nv50_pc *pc, int c, const struct tgsi_full_src_register *src)
123030249dd247444687663c4969ff078dc0a4b24acekm{
124db4fecfb01ac51e936e4b7496a4929e713080f07ekm	/* Handle swizzling */
125dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting	switch (c) {
126db4fecfb01ac51e936e4b7496a4929e713080f07ekm	case 0: c = src->SrcRegister.SwizzleX; break;
127db4fecfb01ac51e936e4b7496a4929e713080f07ekm	case 1: c = src->SrcRegister.SwizzleY; break;
128030249dd247444687663c4969ff078dc0a4b24acekm	case 2: c = src->SrcRegister.SwizzleZ; break;
129db4fecfb01ac51e936e4b7496a4929e713080f07ekm	case 3: c = src->SrcRegister.SwizzleW; break;
130db4fecfb01ac51e936e4b7496a4929e713080f07ekm	default:
131db4fecfb01ac51e936e4b7496a4929e713080f07ekm		assert(0);
132dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting	}
133db4fecfb01ac51e936e4b7496a4929e713080f07ekm
134db4fecfb01ac51e936e4b7496a4929e713080f07ekm	switch (src->SrcRegister.File) {
135db4fecfb01ac51e936e4b7496a4929e713080f07ekm	case TGSI_FILE_INPUT:
136030249dd247444687663c4969ff078dc0a4b24acekm		return &pc->attr[src->SrcRegister.Index * 4 + c];
137db4fecfb01ac51e936e4b7496a4929e713080f07ekm	case TGSI_FILE_TEMPORARY:
138db4fecfb01ac51e936e4b7496a4929e713080f07ekm		return &pc->temp[src->SrcRegister.Index * 4 + c];
139dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting	case TGSI_FILE_CONSTANT:
140030249dd247444687663c4969ff078dc0a4b24acekm		return &pc->param[src->SrcRegister.Index * 4 + c];
141dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting	case TGSI_FILE_IMMEDIATE:
142dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting		return &pc->immd[src->SrcRegister.Index * 4 + c];
143dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting	default:
144dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting		break;
145030249dd247444687663c4969ff078dc0a4b24acekm	}
146030249dd247444687663c4969ff078dc0a4b24acekm
1476955870806624479723addfae6dcf5d13968796cPeter Kasting	return NULL;
1486955870806624479723addfae6dcf5d13968796cPeter Kasting}
149dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting
15060d9b332a5391045439bfb6a3a5447973e3d5603ekmeyersonstatic void
151dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kastingemit(struct nv50_pc *pc, unsigned *inst)
152dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting{
153030249dd247444687663c4969ff078dc0a4b24acekm	struct nv50_program *p = pc->p;
154030249dd247444687663c4969ff078dc0a4b24acekm
155030249dd247444687663c4969ff078dc0a4b24acekm       if (inst[0] & 1) {
156db4fecfb01ac51e936e4b7496a4929e713080f07ekm               p->insns_nr += 2;
157db4fecfb01ac51e936e4b7496a4929e713080f07ekm               p->insns = realloc(p->insns, sizeof(unsigned) * p->insns_nr);
15835b72fbceb09031cbd6039e0dbbd44ed24296509ekm               memcpy(p->insns + (p->insns_nr - 2), inst, sizeof(unsigned)*2);
159db4fecfb01ac51e936e4b7496a4929e713080f07ekm       } else {
160dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting               p->insns_nr += 1;
161db4fecfb01ac51e936e4b7496a4929e713080f07ekm               p->insns = realloc(p->insns, sizeof(unsigned) * p->insns_nr);
162db4fecfb01ac51e936e4b7496a4929e713080f07ekm               memcpy(p->insns + (p->insns_nr - 1), inst, sizeof(unsigned));
163db4fecfb01ac51e936e4b7496a4929e713080f07ekm       }
164030249dd247444687663c4969ff078dc0a4b24acekm}
165030249dd247444687663c4969ff078dc0a4b24acekm
16660d9b332a5391045439bfb6a3a5447973e3d5603ekmeyersonstatic INLINE void set_long(struct nv50_pc *, unsigned *);
167030249dd247444687663c4969ff078dc0a4b24acekm
16860d9b332a5391045439bfb6a3a5447973e3d5603ekmeyersonstatic boolean
16960d9b332a5391045439bfb6a3a5447973e3d5603ekmeyersonis_long(unsigned *inst)
170db4fecfb01ac51e936e4b7496a4929e713080f07ekm{
171db4fecfb01ac51e936e4b7496a4929e713080f07ekm	if (inst[0] & 1)
172030249dd247444687663c4969ff078dc0a4b24acekm		return TRUE;
173030249dd247444687663c4969ff078dc0a4b24acekm	return FALSE;
174db4fecfb01ac51e936e4b7496a4929e713080f07ekm}
175db4fecfb01ac51e936e4b7496a4929e713080f07ekm
176030249dd247444687663c4969ff078dc0a4b24acekmstatic boolean
177030249dd247444687663c4969ff078dc0a4b24acekmis_immd(unsigned *inst)
178030249dd247444687663c4969ff078dc0a4b24acekm{
179030249dd247444687663c4969ff078dc0a4b24acekm	if (is_long(inst) && (inst[1] & 3) == 3)
180030249dd247444687663c4969ff078dc0a4b24acekm		return TRUE;
181030249dd247444687663c4969ff078dc0a4b24acekm	return FALSE;
182030249dd247444687663c4969ff078dc0a4b24acekm}
183
184static INLINE void
185set_pred(struct nv50_pc *pc, unsigned pred, unsigned idx, unsigned *inst)
186{
187	set_long(pc, inst);
188	inst[1] &= ~((0x1f << 7) | (0x3 << 12));
189	inst[1] |= (pred << 7) | (idx << 12);
190}
191
192static INLINE void
193set_pred_wr(struct nv50_pc *pc, unsigned on, unsigned idx, unsigned *inst)
194{
195	set_long(pc, inst);
196	inst[1] &= ~((0x3 << 4) | (1 << 6));
197	inst[1] |= (idx << 4) | (on << 6);
198}
199
200static INLINE void
201set_long(struct nv50_pc *pc, unsigned *inst)
202{
203	if (is_long(inst))
204		return;
205
206	inst[0] |= 1;
207	set_pred(pc, 0xf, 0, inst);
208	set_pred_wr(pc, 0, 0, inst);
209}
210
211static INLINE void
212set_dst(struct nv50_pc *pc, struct nv50_reg *dst, unsigned *inst)
213{
214	if (dst->type == P_RESULT) {
215		set_long(pc, inst);
216		inst[1] |= 0x00000008;
217	}
218
219	alloc_reg(pc, dst);
220	inst[0] |= (dst->hw << 2);
221}
222
223static INLINE void
224set_immd(struct nv50_pc *pc, struct nv50_reg *imm, unsigned *inst)
225{
226	unsigned val = fui(pc->immd_buf[imm->hw]); /* XXX */
227
228	set_long(pc, inst);
229	/*XXX: can't be predicated - bits overlap.. catch cases where both
230	 *     are required and avoid them. */
231	set_pred(pc, 0, 0, inst);
232	set_pred_wr(pc, 0, 0, inst);
233
234	inst[1] |= 0x00000002 | 0x00000001;
235	inst[0] |= (val & 0x3f) << 16;
236	inst[1] |= (val >> 6) << 2;
237}
238
239static void
240emit_mov(struct nv50_pc *pc, struct nv50_reg *dst, struct nv50_reg *src)
241{
242	unsigned inst[2] = { 0, 0 };
243	int i;
244
245	inst[0] |= 0x10000000;
246
247	set_dst(pc, dst, inst);
248
249	if (dst->type != P_RESULT && src->type == P_IMMD) {
250		set_immd(pc, src, inst);
251		/*XXX: 32-bit, but steals part of "half" reg space - need to
252		 *     catch and handle this case if/when we do half-regs
253		 */
254		inst[0] |= 0x00008000;
255	} else
256	if (src->type == P_IMMD || src->type == P_CONST) {
257		set_long(pc, inst);
258		if (src->type == P_IMMD)
259			inst[1] |= (NV50_CB_PMISC << 22);
260		else
261			inst[1] |= (NV50_CB_PVP << 22);
262		inst[0] |= (src->hw << 9);
263		inst[1] |= 0x20000000; /* src0 const? */
264	} else {
265		if (src->type == P_ATTR) {
266			set_long(pc, inst);
267			inst[1] |= 0x00200000;
268		}
269
270		alloc_reg(pc, src);
271		inst[0] |= (src->hw << 9);
272	}
273
274	/* We really should support "half" instructions here at some point,
275	 * but I don't feel confident enough about them yet.
276	 */
277	set_long(pc, inst);
278	if (is_long(inst) && !is_immd(inst)) {
279		inst[1] |= 0x04000000; /* 32-bit */
280		inst[1] |= 0x0003c000; /* "subsubop" 0xf == mov */
281	}
282
283	emit(pc, inst);
284}
285
286static boolean
287nv50_program_tx_insn(struct nv50_pc *pc, const union tgsi_full_token *tok)
288{
289	const struct tgsi_full_instruction *inst = &tok->FullInstruction;
290	struct nv50_reg *dst[4], *src[3][4];
291	unsigned mask;
292	int i, c;
293
294	NOUVEAU_ERR("insn %p\n", tok);
295
296	mask = inst->FullDstRegisters[0].DstRegister.WriteMask;
297
298	for (c = 0; c < 4; c++) {
299		if (mask & (1 << c))
300			dst[c] = tgsi_dst(pc, c, &inst->FullDstRegisters[0]);
301		else
302			dst[c] = NULL;
303	}
304
305	for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
306		for (c = 0; c < 4; c++)
307			src[i][c] = tgsi_src(pc, c, &inst->FullSrcRegisters[i]);
308	}
309
310	switch (inst->Instruction.Opcode) {
311	case TGSI_OPCODE_MOV:
312		for (c = 0; c < 4; c++)
313			emit_mov(pc, dst[c], src[0][c]);
314		break;
315	case TGSI_OPCODE_END:
316		break;
317	default:
318		NOUVEAU_ERR("invalid opcode %d\n", inst->Instruction.Opcode);
319		return FALSE;
320	}
321
322	return TRUE;
323}
324
325static boolean
326nv50_program_tx_prep(struct nv50_pc *pc)
327{
328	struct tgsi_parse_context p;
329	boolean ret = FALSE;
330	unsigned i, c;
331
332	tgsi_parse_init(&p, pc->p->pipe.tokens);
333	while (!tgsi_parse_end_of_tokens(&p)) {
334		const union tgsi_full_token *tok = &p.FullToken;
335
336		tgsi_parse_token(&p);
337		switch (tok->Token.Type) {
338		case TGSI_TOKEN_TYPE_IMMEDIATE:
339		{
340			const struct tgsi_full_immediate *imm =
341				&p.FullToken.FullImmediate;
342
343			pc->immd_nr++;
344			pc->immd_buf = realloc(pc->immd_buf, 4 * pc->immd_nr *
345							     sizeof(float));
346			pc->immd_buf[4 * (pc->immd_nr - 1) + 0] =
347				imm->u.ImmediateFloat32[0].Float;
348			pc->immd_buf[4 * (pc->immd_nr - 1) + 1] =
349				imm->u.ImmediateFloat32[1].Float;
350			pc->immd_buf[4 * (pc->immd_nr - 1) + 2] =
351				imm->u.ImmediateFloat32[2].Float;
352			pc->immd_buf[4 * (pc->immd_nr - 1) + 3] =
353				imm->u.ImmediateFloat32[3].Float;
354		}
355			break;
356		case TGSI_TOKEN_TYPE_DECLARATION:
357		{
358			const struct tgsi_full_declaration *d;
359			unsigned last;
360
361			d = &p.FullToken.FullDeclaration;
362			last = d->u.DeclarationRange.Last;
363
364			switch (d->Declaration.File) {
365			case TGSI_FILE_TEMPORARY:
366				if (pc->temp_nr < (last + 1))
367					pc->temp_nr = last + 1;
368				break;
369			case TGSI_FILE_OUTPUT:
370				if (pc->result_nr < (last + 1))
371					pc->result_nr = last + 1;
372				break;
373			case TGSI_FILE_INPUT:
374				if (pc->attr_nr < (last + 1))
375					pc->attr_nr = last + 1;
376				break;
377			case TGSI_FILE_CONSTANT:
378				if (pc->param_nr < (last + 1))
379					pc->param_nr = last + 1;
380				break;
381			default:
382				NOUVEAU_ERR("bad decl file %d\n",
383					    d->Declaration.File);
384				goto out_err;
385			}
386		}
387			break;
388		case TGSI_TOKEN_TYPE_INSTRUCTION:
389			break;
390		default:
391			break;
392		}
393	}
394
395	NOUVEAU_ERR("%d temps\n", pc->temp_nr);
396	if (pc->temp_nr) {
397		pc->temp = calloc(pc->temp_nr * 4, sizeof(struct nv50_reg));
398		if (!pc->temp)
399			goto out_err;
400
401		for (i = 0; i < pc->temp_nr; i++) {
402			for (c = 0; c < 4; c++) {
403				pc->temp[i*4+c].type = P_TEMP;
404				pc->temp[i*4+c].hw = -1;
405				pc->temp[i*4+c].index = i;
406			}
407		}
408	}
409
410	NOUVEAU_ERR("%d attrib regs\n", pc->attr_nr);
411	if (pc->attr_nr) {
412		int aid = 0;
413
414		pc->attr = calloc(pc->attr_nr * 4, sizeof(struct nv50_reg));
415		if (!pc->attr)
416			goto out_err;
417
418		for (i = 0; i < pc->attr_nr; i++) {
419			for (c = 0; c < 4; c++) {
420				pc->p->cfg.vp.attr[aid/32] |= (1 << (aid % 32));
421				pc->attr[i*4+c].type = P_ATTR;
422				pc->attr[i*4+c].hw = aid++;
423				pc->attr[i*4+c].index = i;
424			}
425		}
426	}
427
428	NOUVEAU_ERR("%d result regs\n", pc->result_nr);
429	if (pc->result_nr) {
430		int rid = 0;
431
432		pc->result = calloc(pc->result_nr * 4, sizeof(struct nv50_reg));
433		if (!pc->result)
434			goto out_err;
435
436		for (i = 0; i < pc->result_nr; i++) {
437			for (c = 0; c < 4; c++) {
438				pc->result[i*4+c].type = P_RESULT;
439				pc->result[i*4+c].hw = rid++;
440				pc->result[i*4+c].index = i;
441			}
442		}
443	}
444
445	NOUVEAU_ERR("%d param regs\n", pc->param_nr);
446	if (pc->param_nr) {
447		int rid = 0;
448
449		pc->param = calloc(pc->param_nr * 4, sizeof(struct nv50_reg));
450		if (!pc->param)
451			goto out_err;
452
453		for (i = 0; i < pc->param_nr; i++) {
454			for (c = 0; c < 4; c++) {
455				pc->param[i*4+c].type = P_CONST;
456				pc->param[i*4+c].hw = rid++;
457				pc->param[i*4+c].index = i;
458			}
459		}
460	}
461
462	if (pc->immd_nr) {
463		int rid = 0;
464
465		pc->immd = calloc(pc->immd_nr * 4, sizeof(struct nv50_reg));
466		if (!pc->immd)
467			goto out_err;
468
469		for (i = 0; i < pc->immd_nr; i++) {
470			for (c = 0; c < 4; c++) {
471				pc->immd[i*4+c].type = P_IMMD;
472				pc->immd[i*4+c].hw = rid++;
473				pc->immd[i*4+c].index = i;
474			}
475		}
476	}
477
478	ret = TRUE;
479out_err:
480	tgsi_parse_free(&p);
481	return ret;
482}
483
484static boolean
485nv50_program_tx(struct nv50_program *p)
486{
487	struct tgsi_parse_context parse;
488	struct nv50_pc *pc;
489	boolean ret;
490
491	pc = CALLOC_STRUCT(nv50_pc);
492	if (!pc)
493		return FALSE;
494	pc->p = p;
495	pc->p->cfg.vp.high_temp = 4;
496
497	ret = nv50_program_tx_prep(pc);
498	if (ret == FALSE)
499		goto out_cleanup;
500
501	tgsi_parse_init(&parse, pc->p->pipe.tokens);
502	while (!tgsi_parse_end_of_tokens(&parse)) {
503		const union tgsi_full_token *tok = &parse.FullToken;
504
505		tgsi_parse_token(&parse);
506
507		switch (tok->Token.Type) {
508		case TGSI_TOKEN_TYPE_INSTRUCTION:
509			ret = nv50_program_tx_insn(pc, tok);
510			if (ret == FALSE)
511				goto out_err;
512			break;
513		default:
514			break;
515		}
516	}
517
518	p->immd_nr = pc->immd_nr * 4;
519	p->immd = pc->immd_buf;
520
521out_err:
522	tgsi_parse_free(&parse);
523
524out_cleanup:
525	return ret;
526}
527
528static void
529nv50_program_validate(struct nv50_context *nv50, struct nv50_program *p)
530{
531#if TX_FRAGPROG == 0
532	struct tgsi_parse_context pc;
533
534	tgsi_parse_init(&pc, p->pipe.tokens);
535
536	if (pc.FullHeader.Processor.Processor == TGSI_PROCESSOR_FRAGMENT) {
537		p->insns_nr = 8;
538		p->insns = malloc(p->insns_nr * sizeof(unsigned));
539		p->insns[0] = 0x80000000;
540		p->insns[1] = 0x9000000c;
541		p->insns[2] = 0x82010600;
542		p->insns[3] = 0x82020604;
543		p->insns[4] = 0x80030609;
544		p->insns[5] = 0x00020780;
545		p->insns[6] = 0x8004060d;
546		p->insns[7] = 0x00020781;
547	} else
548	if (pc.FullHeader.Processor.Processor == TGSI_PROCESSOR_VERTEX) {
549#endif
550		int i;
551
552		if (nv50_program_tx(p) == FALSE)
553			assert(0);
554		p->insns[p->insns_nr - 1] |= 0x00000001;
555
556		for (i = 0; i < p->insns_nr; i++)
557			NOUVEAU_ERR("%d 0x%08x\n", i, p->insns[i]);
558#if TX_FRAGPROG == 0
559	} else {
560		NOUVEAU_ERR("invalid TGSI processor\n");
561		tgsi_parse_free(&pc);
562		return;
563	}
564
565	tgsi_parse_free(&pc);
566#endif
567
568	p->translated = TRUE;
569}
570
571static void
572nv50_program_validate_data(struct nv50_context *nv50, struct nv50_program *p)
573{
574	int i;
575
576	for (i = 0; i < p->immd_nr; i++) {
577		BEGIN_RING(tesla, 0x0f00, 2);
578		OUT_RING  ((NV50_CB_PMISC << 16) | (i << 8));
579		OUT_RING  (fui(p->immd[i]));
580	}
581}
582
583static void
584nv50_program_validate_code(struct nv50_context *nv50, struct nv50_program *p)
585{
586	struct pipe_winsys *ws = nv50->pipe.winsys;
587	void *map;
588
589	if (!p->buffer)
590		p->buffer = ws->buffer_create(ws, 0x100, 0, p->insns_nr * 4);
591	map = ws->buffer_map(ws, p->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
592	memcpy(map, p->insns, p->insns_nr * 4);
593	ws->buffer_unmap(ws, p->buffer);
594}
595
596void
597nv50_vertprog_validate(struct nv50_context *nv50)
598{
599	struct nouveau_grobj *tesla = nv50->screen->tesla;
600	struct nv50_program *p = nv50->vertprog;
601	struct nouveau_stateobj *so;
602
603	if (!p->translated) {
604		nv50_program_validate(nv50, p);
605		if (!p->translated)
606			assert(0);
607	}
608
609	nv50_program_validate_data(nv50, p);
610	nv50_program_validate_code(nv50, p);
611
612	so = so_new(11, 2);
613	so_method(so, tesla, NV50TCL_VP_ADDRESS_HIGH, 2);
614	so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
615		  NOUVEAU_BO_HIGH, 0, 0);
616	so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
617		  NOUVEAU_BO_LOW, 0, 0);
618	so_method(so, tesla, 0x1650, 2);
619	so_data  (so, p->cfg.vp.attr[0]);
620	so_data  (so, p->cfg.vp.attr[1]);
621	so_method(so, tesla, 0x16ac, 2);
622	so_data  (so, 8);
623	so_data  (so, p->cfg.vp.high_temp);
624	so_method(so, tesla, 0x140c, 1);
625	so_data  (so, 0); /* program start offset */
626	so_emit(nv50->screen->nvws, so);
627	so_ref(NULL, &so);
628}
629
630void
631nv50_fragprog_validate(struct nv50_context *nv50)
632{
633	struct pipe_winsys *ws = nv50->pipe.winsys;
634	struct nouveau_grobj *tesla = nv50->screen->tesla;
635	struct nv50_program *p = nv50->fragprog;
636	struct nouveau_stateobj *so;
637	void *map;
638
639	if (!p->translated) {
640		nv50_program_validate(nv50, p);
641		if (!p->translated)
642			assert(0);
643	}
644
645	nv50_program_validate_data(nv50, p);
646	nv50_program_validate_code(nv50, p);
647
648	so = so_new(3, 2);
649	so_method(so, tesla, NV50TCL_FP_ADDRESS_HIGH, 2);
650	so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
651		  NOUVEAU_BO_HIGH, 0, 0);
652	so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
653		  NOUVEAU_BO_LOW, 0, 0);
654	so_emit(nv50->screen->nvws, so);
655	so_ref(NULL, &so);
656}
657
658void
659nv50_program_destroy(struct nv50_context *nv50, struct nv50_program *p)
660{
661	struct pipe_winsys *ws = nv50->pipe.winsys;
662
663	if (p->insns_nr) {
664		if (p->insns)
665			FREE(p->insns);
666		p->insns_nr = 0;
667	}
668
669	if (p->buffer)
670		pipe_buffer_reference(ws, &p->buffer, NULL);
671
672	p->translated = 0;
673}
674
675