Merge branch 'mesa_7_5_branch'
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / r3xx_vertprog.c
1 /*
2 * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #include "radeon_compiler.h"
24
25 #include "../r300_reg.h"
26
27 #include "radeon_nqssadce.h"
28 #include "radeon_program.h"
29 #include "radeon_program_alu.h"
30
31 #include "shader/prog_print.h"
32
33
34 /*
35 * Take an already-setup and valid source then swizzle it appropriately to
36 * obtain a constant ZERO or ONE source.
37 */
38 #define __CONST(x, y) \
39 (PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[x]), \
40 t_swizzle(y), \
41 t_swizzle(y), \
42 t_swizzle(y), \
43 t_swizzle(y), \
44 t_src_class(vpi->SrcReg[x].File), \
45 NEGATE_NONE) | (vpi->SrcReg[x].RelAddr << 4))
46
47
48 static unsigned long t_dst_mask(GLuint mask)
49 {
50 /* WRITEMASK_* is equivalent to VSF_FLAG_* */
51 return mask & WRITEMASK_XYZW;
52 }
53
54 static unsigned long t_dst_class(gl_register_file file)
55 {
56
57 switch (file) {
58 case PROGRAM_TEMPORARY:
59 return PVS_DST_REG_TEMPORARY;
60 case PROGRAM_OUTPUT:
61 return PVS_DST_REG_OUT;
62 case PROGRAM_ADDRESS:
63 return PVS_DST_REG_A0;
64 /*
65 case PROGRAM_INPUT:
66 case PROGRAM_LOCAL_PARAM:
67 case PROGRAM_ENV_PARAM:
68 case PROGRAM_NAMED_PARAM:
69 case PROGRAM_STATE_VAR:
70 case PROGRAM_WRITE_ONLY:
71 case PROGRAM_ADDRESS:
72 */
73 default:
74 fprintf(stderr, "problem in %s", __FUNCTION__);
75 _mesa_exit(-1);
76 return -1;
77 }
78 }
79
80 static unsigned long t_dst_index(struct r300_vertex_program_code *vp,
81 struct prog_dst_register *dst)
82 {
83 if (dst->File == PROGRAM_OUTPUT)
84 return vp->outputs[dst->Index];
85
86 return dst->Index;
87 }
88
89 static unsigned long t_src_class(gl_register_file file)
90 {
91 switch (file) {
92 case PROGRAM_TEMPORARY:
93 return PVS_SRC_REG_TEMPORARY;
94 case PROGRAM_INPUT:
95 return PVS_SRC_REG_INPUT;
96 case PROGRAM_LOCAL_PARAM:
97 case PROGRAM_ENV_PARAM:
98 case PROGRAM_NAMED_PARAM:
99 case PROGRAM_CONSTANT:
100 case PROGRAM_STATE_VAR:
101 return PVS_SRC_REG_CONSTANT;
102 /*
103 case PROGRAM_OUTPUT:
104 case PROGRAM_WRITE_ONLY:
105 case PROGRAM_ADDRESS:
106 */
107 default:
108 fprintf(stderr, "problem in %s", __FUNCTION__);
109 _mesa_exit(-1);
110 return -1;
111 }
112 }
113
114 static GLboolean t_src_conflict(struct prog_src_register a, struct prog_src_register b)
115 {
116 unsigned long aclass = t_src_class(a.File);
117 unsigned long bclass = t_src_class(b.File);
118
119 if (aclass != bclass)
120 return GL_FALSE;
121 if (aclass == PVS_SRC_REG_TEMPORARY)
122 return GL_FALSE;
123
124 if (a.RelAddr || b.RelAddr)
125 return GL_TRUE;
126 if (a.Index != b.Index)
127 return GL_TRUE;
128
129 return GL_FALSE;
130 }
131
132 static INLINE unsigned long t_swizzle(GLubyte swizzle)
133 {
134 /* this is in fact a NOP as the Mesa SWIZZLE_* are all identical to VSF_IN_COMPONENT_* */
135 return swizzle;
136 }
137
138 static unsigned long t_src_index(struct r300_vertex_program_code *vp,
139 struct prog_src_register *src)
140 {
141 if (src->File == PROGRAM_INPUT) {
142 assert(vp->inputs[src->Index] != -1);
143 return vp->inputs[src->Index];
144 } else {
145 if (src->Index < 0) {
146 fprintf(stderr,
147 "negative offsets for indirect addressing do not work.\n");
148 return 0;
149 }
150 return src->Index;
151 }
152 }
153
154 /* these two functions should probably be merged... */
155
156 static unsigned long t_src(struct r300_vertex_program_code *vp,
157 struct prog_src_register *src)
158 {
159 /* src->Negate uses the NEGATE_ flags from program_instruction.h,
160 * which equal our VSF_FLAGS_ values, so it's safe to just pass it here.
161 */
162 return PVS_SRC_OPERAND(t_src_index(vp, src),
163 t_swizzle(GET_SWZ(src->Swizzle, 0)),
164 t_swizzle(GET_SWZ(src->Swizzle, 1)),
165 t_swizzle(GET_SWZ(src->Swizzle, 2)),
166 t_swizzle(GET_SWZ(src->Swizzle, 3)),
167 t_src_class(src->File),
168 src->Negate) | (src->RelAddr << 4);
169 }
170
171 static unsigned long t_src_scalar(struct r300_vertex_program_code *vp,
172 struct prog_src_register *src)
173 {
174 /* src->Negate uses the NEGATE_ flags from program_instruction.h,
175 * which equal our VSF_FLAGS_ values, so it's safe to just pass it here.
176 */
177 return PVS_SRC_OPERAND(t_src_index(vp, src),
178 t_swizzle(GET_SWZ(src->Swizzle, 0)),
179 t_swizzle(GET_SWZ(src->Swizzle, 0)),
180 t_swizzle(GET_SWZ(src->Swizzle, 0)),
181 t_swizzle(GET_SWZ(src->Swizzle, 0)),
182 t_src_class(src->File),
183 src->Negate ? NEGATE_XYZW : NEGATE_NONE) |
184 (src->RelAddr << 4);
185 }
186
187 static GLboolean valid_dst(struct r300_vertex_program_code *vp,
188 struct prog_dst_register *dst)
189 {
190 if (dst->File == PROGRAM_OUTPUT && vp->outputs[dst->Index] == -1) {
191 return GL_FALSE;
192 } else if (dst->File == PROGRAM_ADDRESS) {
193 assert(dst->Index == 0);
194 }
195
196 return GL_TRUE;
197 }
198
199 static void ei_vector1(struct r300_vertex_program_code *vp,
200 GLuint hw_opcode,
201 struct prog_instruction *vpi,
202 GLuint * inst)
203 {
204 inst[0] = PVS_OP_DST_OPERAND(hw_opcode,
205 GL_FALSE,
206 GL_FALSE,
207 t_dst_index(vp, &vpi->DstReg),
208 t_dst_mask(vpi->DstReg.WriteMask),
209 t_dst_class(vpi->DstReg.File));
210 inst[1] = t_src(vp, &vpi->SrcReg[0]);
211 inst[2] = __CONST(0, SWIZZLE_ZERO);
212 inst[3] = __CONST(0, SWIZZLE_ZERO);
213 }
214
215 static void ei_vector2(struct r300_vertex_program_code *vp,
216 GLuint hw_opcode,
217 struct prog_instruction *vpi,
218 GLuint * inst)
219 {
220 inst[0] = PVS_OP_DST_OPERAND(hw_opcode,
221 GL_FALSE,
222 GL_FALSE,
223 t_dst_index(vp, &vpi->DstReg),
224 t_dst_mask(vpi->DstReg.WriteMask),
225 t_dst_class(vpi->DstReg.File));
226 inst[1] = t_src(vp, &vpi->SrcReg[0]);
227 inst[2] = t_src(vp, &vpi->SrcReg[1]);
228 inst[3] = __CONST(1, SWIZZLE_ZERO);
229 }
230
231 static void ei_math1(struct r300_vertex_program_code *vp,
232 GLuint hw_opcode,
233 struct prog_instruction *vpi,
234 GLuint * inst)
235 {
236 inst[0] = PVS_OP_DST_OPERAND(hw_opcode,
237 GL_TRUE,
238 GL_FALSE,
239 t_dst_index(vp, &vpi->DstReg),
240 t_dst_mask(vpi->DstReg.WriteMask),
241 t_dst_class(vpi->DstReg.File));
242 inst[1] = t_src_scalar(vp, &vpi->SrcReg[0]);
243 inst[2] = __CONST(0, SWIZZLE_ZERO);
244 inst[3] = __CONST(0, SWIZZLE_ZERO);
245 }
246
247 static void ei_lit(struct r300_vertex_program_code *vp,
248 struct prog_instruction *vpi,
249 GLuint * inst)
250 {
251 //LIT TMP 1.Y Z TMP 1{} {X W Z Y} TMP 1{} {Y W Z X} TMP 1{} {Y X Z W}
252
253 inst[0] = PVS_OP_DST_OPERAND(ME_LIGHT_COEFF_DX,
254 GL_TRUE,
255 GL_FALSE,
256 t_dst_index(vp, &vpi->DstReg),
257 t_dst_mask(vpi->DstReg.WriteMask),
258 t_dst_class(vpi->DstReg.File));
259 /* NOTE: Users swizzling might not work. */
260 inst[1] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X
261 t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W
262 PVS_SRC_SELECT_FORCE_0, // Z
263 t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y
264 t_src_class(vpi->SrcReg[0].File),
265 vpi->SrcReg[0].Negate ? NEGATE_XYZW : NEGATE_NONE) |
266 (vpi->SrcReg[0].RelAddr << 4);
267 inst[2] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y
268 t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W
269 PVS_SRC_SELECT_FORCE_0, // Z
270 t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X
271 t_src_class(vpi->SrcReg[0].File),
272 vpi->SrcReg[0].Negate ? NEGATE_XYZW : NEGATE_NONE) |
273 (vpi->SrcReg[0].RelAddr << 4);
274 inst[3] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y
275 t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X
276 PVS_SRC_SELECT_FORCE_0, // Z
277 t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W
278 t_src_class(vpi->SrcReg[0].File),
279 vpi->SrcReg[0].Negate ? NEGATE_XYZW : NEGATE_NONE) |
280 (vpi->SrcReg[0].RelAddr << 4);
281 }
282
283 static void ei_mad(struct r300_vertex_program_code *vp,
284 struct prog_instruction *vpi,
285 GLuint * inst)
286 {
287 inst[0] = PVS_OP_DST_OPERAND(PVS_MACRO_OP_2CLK_MADD,
288 GL_FALSE,
289 GL_TRUE,
290 t_dst_index(vp, &vpi->DstReg),
291 t_dst_mask(vpi->DstReg.WriteMask),
292 t_dst_class(vpi->DstReg.File));
293 inst[1] = t_src(vp, &vpi->SrcReg[0]);
294 inst[2] = t_src(vp, &vpi->SrcReg[1]);
295 inst[3] = t_src(vp, &vpi->SrcReg[2]);
296 }
297
298 static void ei_pow(struct r300_vertex_program_code *vp,
299 struct prog_instruction *vpi,
300 GLuint * inst)
301 {
302 inst[0] = PVS_OP_DST_OPERAND(ME_POWER_FUNC_FF,
303 GL_TRUE,
304 GL_FALSE,
305 t_dst_index(vp, &vpi->DstReg),
306 t_dst_mask(vpi->DstReg.WriteMask),
307 t_dst_class(vpi->DstReg.File));
308 inst[1] = t_src_scalar(vp, &vpi->SrcReg[0]);
309 inst[2] = __CONST(0, SWIZZLE_ZERO);
310 inst[3] = t_src_scalar(vp, &vpi->SrcReg[1]);
311 }
312
313
314 static void translate_vertex_program(struct r300_vertex_program_compiler * compiler)
315 {
316 struct rc_instruction *rci;
317
318 compiler->code->pos_end = 0; /* Not supported yet */
319 compiler->code->length = 0;
320
321 compiler->SetHwInputOutput(compiler);
322
323 for(rci = compiler->Base.Program.Instructions.Next; rci != &compiler->Base.Program.Instructions; rci = rci->Next) {
324 struct prog_instruction *vpi = &rci->I;
325 GLuint *inst = compiler->code->body.d + compiler->code->length;
326
327 /* Skip instructions writing to non-existing destination */
328 if (!valid_dst(compiler->code, &vpi->DstReg))
329 continue;
330
331 if (compiler->code->length >= VSF_MAX_FRAGMENT_LENGTH) {
332 rc_error(&compiler->Base, "Vertex program has too many instructions\n");
333 return;
334 }
335
336 switch (vpi->Opcode) {
337 case OPCODE_ADD: ei_vector2(compiler->code, VE_ADD, vpi, inst); break;
338 case OPCODE_ARL: ei_vector1(compiler->code, VE_FLT2FIX_DX, vpi, inst); break;
339 case OPCODE_DP4: ei_vector2(compiler->code, VE_DOT_PRODUCT, vpi, inst); break;
340 case OPCODE_DST: ei_vector2(compiler->code, VE_DISTANCE_VECTOR, vpi, inst); break;
341 case OPCODE_EX2: ei_math1(compiler->code, ME_EXP_BASE2_FULL_DX, vpi, inst); break;
342 case OPCODE_EXP: ei_math1(compiler->code, ME_EXP_BASE2_DX, vpi, inst); break;
343 case OPCODE_FRC: ei_vector1(compiler->code, VE_FRACTION, vpi, inst); break;
344 case OPCODE_LG2: ei_math1(compiler->code, ME_LOG_BASE2_FULL_DX, vpi, inst); break;
345 case OPCODE_LIT: ei_lit(compiler->code, vpi, inst); break;
346 case OPCODE_LOG: ei_math1(compiler->code, ME_LOG_BASE2_DX, vpi, inst); break;
347 case OPCODE_MAD: ei_mad(compiler->code, vpi, inst); break;
348 case OPCODE_MAX: ei_vector2(compiler->code, VE_MAXIMUM, vpi, inst); break;
349 case OPCODE_MIN: ei_vector2(compiler->code, VE_MINIMUM, vpi, inst); break;
350 case OPCODE_MOV: ei_vector1(compiler->code, VE_ADD, vpi, inst); break;
351 case OPCODE_MUL: ei_vector2(compiler->code, VE_MULTIPLY, vpi, inst); break;
352 case OPCODE_POW: ei_pow(compiler->code, vpi, inst); break;
353 case OPCODE_RCP: ei_math1(compiler->code, ME_RECIP_DX, vpi, inst); break;
354 case OPCODE_RSQ: ei_math1(compiler->code, ME_RECIP_SQRT_DX, vpi, inst); break;
355 case OPCODE_SGE: ei_vector2(compiler->code, VE_SET_GREATER_THAN_EQUAL, vpi, inst); break;
356 case OPCODE_SLT: ei_vector2(compiler->code, VE_SET_LESS_THAN, vpi, inst); break;
357 default:
358 rc_error(&compiler->Base, "Unknown opcode %i\n", vpi->Opcode);
359 return;
360 }
361
362 compiler->code->length += 4;
363
364 if (compiler->Base.Error)
365 return;
366 }
367 }
368
369 struct temporary_allocation {
370 GLuint Allocated:1;
371 GLuint HwTemp:15;
372 struct rc_instruction * LastRead;
373 };
374
375 static void allocate_temporary_registers(struct r300_vertex_program_compiler * compiler)
376 {
377 struct rc_instruction *inst;
378 GLuint num_orig_temps = 0;
379 GLboolean hwtemps[VSF_MAX_FRAGMENT_TEMPS];
380 struct temporary_allocation * ta;
381 GLuint i, j;
382
383 compiler->code->num_temporaries = 0;
384 memset(hwtemps, 0, sizeof(hwtemps));
385
386 /* Pass 1: Count original temporaries and allocate structures */
387 for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
388 GLuint numsrcs = _mesa_num_inst_src_regs(inst->I.Opcode);
389 GLuint numdsts = _mesa_num_inst_dst_regs(inst->I.Opcode);
390
391 for (i = 0; i < numsrcs; ++i) {
392 if (inst->I.SrcReg[i].File == PROGRAM_TEMPORARY) {
393 if (inst->I.SrcReg[i].Index >= num_orig_temps)
394 num_orig_temps = inst->I.SrcReg[i].Index + 1;
395 }
396 }
397
398 if (numdsts) {
399 if (inst->I.DstReg.File == PROGRAM_TEMPORARY) {
400 if (inst->I.DstReg.Index >= num_orig_temps)
401 num_orig_temps = inst->I.DstReg.Index + 1;
402 }
403 }
404 }
405
406 ta = (struct temporary_allocation*)memory_pool_malloc(&compiler->Base.Pool,
407 sizeof(struct temporary_allocation) * num_orig_temps);
408 memset(ta, 0, sizeof(struct temporary_allocation) * num_orig_temps);
409
410 /* Pass 2: Determine original temporary lifetimes */
411 for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
412 GLuint numsrcs = _mesa_num_inst_src_regs(inst->I.Opcode);
413
414 for (i = 0; i < numsrcs; ++i) {
415 if (inst->I.SrcReg[i].File == PROGRAM_TEMPORARY)
416 ta[inst->I.SrcReg[i].Index].LastRead = inst;
417 }
418 }
419
420 /* Pass 3: Register allocation */
421 for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
422 GLuint numsrcs = _mesa_num_inst_src_regs(inst->I.Opcode);
423 GLuint numdsts = _mesa_num_inst_dst_regs(inst->I.Opcode);
424
425 for (i = 0; i < numsrcs; ++i) {
426 if (inst->I.SrcReg[i].File == PROGRAM_TEMPORARY) {
427 GLuint orig = inst->I.SrcReg[i].Index;
428 inst->I.SrcReg[i].Index = ta[orig].HwTemp;
429
430 if (ta[orig].Allocated && inst == ta[orig].LastRead)
431 hwtemps[ta[orig].HwTemp] = GL_FALSE;
432 }
433 }
434
435 if (numdsts) {
436 if (inst->I.DstReg.File == PROGRAM_TEMPORARY) {
437 GLuint orig = inst->I.DstReg.Index;
438
439 if (!ta[orig].Allocated) {
440 for(j = 0; j < VSF_MAX_FRAGMENT_TEMPS; ++j) {
441 if (!hwtemps[j])
442 break;
443 }
444 if (j >= VSF_MAX_FRAGMENT_TEMPS) {
445 fprintf(stderr, "Out of hw temporaries\n");
446 } else {
447 ta[orig].Allocated = GL_TRUE;
448 ta[orig].HwTemp = j;
449 hwtemps[j] = GL_TRUE;
450
451 if (j >= compiler->code->num_temporaries)
452 compiler->code->num_temporaries = j + 1;
453 }
454 }
455
456 inst->I.DstReg.Index = ta[orig].HwTemp;
457 }
458 }
459 }
460 }
461
462
463 /**
464 * Vertex engine cannot read two inputs or two constants at the same time.
465 * Introduce intermediate MOVs to temporary registers to account for this.
466 */
467 static GLboolean transform_source_conflicts(
468 struct radeon_compiler *c,
469 struct rc_instruction* inst,
470 void* unused)
471 {
472 GLuint num_operands = _mesa_num_inst_src_regs(inst->I.Opcode);
473
474 if (num_operands == 3) {
475 if (t_src_conflict(inst->I.SrcReg[1], inst->I.SrcReg[2])
476 || t_src_conflict(inst->I.SrcReg[0], inst->I.SrcReg[2])) {
477 int tmpreg = rc_find_free_temporary(c);
478 struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev);
479 inst_mov->I.Opcode = OPCODE_MOV;
480 inst_mov->I.DstReg.File = PROGRAM_TEMPORARY;
481 inst_mov->I.DstReg.Index = tmpreg;
482 inst_mov->I.SrcReg[0] = inst->I.SrcReg[2];
483
484 reset_srcreg(&inst->I.SrcReg[2]);
485 inst->I.SrcReg[2].File = PROGRAM_TEMPORARY;
486 inst->I.SrcReg[2].Index = tmpreg;
487 }
488 }
489
490 if (num_operands >= 2) {
491 if (t_src_conflict(inst->I.SrcReg[1], inst->I.SrcReg[0])) {
492 int tmpreg = rc_find_free_temporary(c);
493 struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev);
494 inst_mov->I.Opcode = OPCODE_MOV;
495 inst_mov->I.DstReg.File = PROGRAM_TEMPORARY;
496 inst_mov->I.DstReg.Index = tmpreg;
497 inst_mov->I.SrcReg[0] = inst->I.SrcReg[1];
498
499 reset_srcreg(&inst->I.SrcReg[1]);
500 inst->I.SrcReg[1].File = PROGRAM_TEMPORARY;
501 inst->I.SrcReg[1].Index = tmpreg;
502 }
503 }
504
505 return GL_TRUE;
506 }
507
508 static void addArtificialOutputs(struct r300_vertex_program_compiler * compiler)
509 {
510 int i;
511
512 for(i = 0; i < 32; ++i) {
513 if ((compiler->RequiredOutputs & (1 << i)) &&
514 !(compiler->Base.Program.OutputsWritten & (1 << i))) {
515 struct rc_instruction * inst = rc_insert_new_instruction(&compiler->Base, compiler->Base.Program.Instructions.Prev);
516 inst->I.Opcode = OPCODE_MOV;
517
518 inst->I.DstReg.File = PROGRAM_OUTPUT;
519 inst->I.DstReg.Index = i;
520 inst->I.DstReg.WriteMask = WRITEMASK_XYZW;
521
522 inst->I.SrcReg[0].File = PROGRAM_CONSTANT;
523 inst->I.SrcReg[0].Index = 0;
524 inst->I.SrcReg[0].Swizzle = SWIZZLE_XYZW;
525
526 compiler->Base.Program.OutputsWritten |= 1 << i;
527 }
528 }
529 }
530
531 static void nqssadceInit(struct nqssadce_state* s)
532 {
533 struct r300_vertex_program_compiler * compiler = s->UserData;
534 int i;
535
536 for(i = 0; i < VERT_RESULT_MAX; ++i) {
537 if (compiler->RequiredOutputs & (1 << i))
538 s->Outputs[i].Sourced = WRITEMASK_XYZW;
539 }
540 }
541
542 static GLboolean swizzleIsNative(GLuint opcode, struct prog_src_register reg)
543 {
544 (void) opcode;
545 (void) reg;
546
547 return GL_TRUE;
548 }
549
550
551
552 void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler)
553 {
554 addArtificialOutputs(compiler);
555
556 {
557 struct radeon_program_transformation transformations[] = {
558 { &r300_transform_vertex_alu, 0 },
559 };
560 radeonLocalTransform(&compiler->Base, 1, transformations);
561 }
562
563 if (compiler->Base.Debug) {
564 fprintf(stderr, "Vertex program after native rewrite:\n");
565 rc_print_program(&compiler->Base.Program);
566 fflush(stdout);
567 }
568
569 {
570 /* Note: This pass has to be done seperately from ALU rewrite,
571 * otherwise non-native ALU instructions with source conflits
572 * will not be treated properly.
573 */
574 struct radeon_program_transformation transformations[] = {
575 { &transform_source_conflicts, 0 },
576 };
577 radeonLocalTransform(&compiler->Base, 1, transformations);
578 }
579
580 if (compiler->Base.Debug) {
581 fprintf(stderr, "Vertex program after source conflict resolve:\n");
582 rc_print_program(&compiler->Base.Program);
583 fflush(stdout);
584 }
585
586 {
587 struct radeon_nqssadce_descr nqssadce = {
588 .Init = &nqssadceInit,
589 .IsNativeSwizzle = &swizzleIsNative,
590 .BuildSwizzle = NULL
591 };
592 radeonNqssaDce(&compiler->Base, &nqssadce, compiler);
593
594 /* We need this step for reusing temporary registers */
595 allocate_temporary_registers(compiler);
596
597 if (compiler->Base.Debug) {
598 fprintf(stderr, "Vertex program after NQSSADCE:\n");
599 rc_print_program(&compiler->Base.Program);
600 fflush(stdout);
601 }
602 }
603
604 translate_vertex_program(compiler);
605
606 rc_constants_copy(&compiler->code->constants, &compiler->Base.Program.Constants);
607
608 compiler->code->InputsRead = compiler->Base.Program.InputsRead;
609 compiler->code->OutputsWritten = compiler->Base.Program.OutputsWritten;
610
611 if (compiler->Base.Debug) {
612 printf("Final vertex program code:\n");
613 r300_vertex_program_dump(compiler->code);
614 }
615 }