Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_fp.c
1 /*
2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial
16 portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **********************************************************************/
27 /*
28 * Authors:
29 * Keith Whitwell <keith@tungstengraphics.com>
30 */
31
32
33 #include "main/glheader.h"
34 #include "main/macros.h"
35 #include "main/enums.h"
36 #include "brw_context.h"
37 #include "brw_wm.h"
38 #include "brw_util.h"
39
40 #include "shader/prog_parameter.h"
41 #include "shader/prog_print.h"
42 #include "shader/prog_statevars.h"
43
44
45 #define FIRST_INTERNAL_TEMP MAX_NV_FRAGMENT_PROGRAM_TEMPS
46
47 #define X 0
48 #define Y 1
49 #define Z 2
50 #define W 3
51
52
53 static const char *wm_opcode_strings[] = {
54 "PIXELXY",
55 "DELTAXY",
56 "PIXELW",
57 "LINTERP",
58 "PINTERP",
59 "CINTERP",
60 "WPOSXY",
61 "FB_WRITE"
62 };
63
64 #if 0
65 static const char *wm_file_strings[] = {
66 "PAYLOAD"
67 };
68 #endif
69
70
71 /***********************************************************************
72 * Source regs
73 */
74
75 static struct prog_src_register src_reg(GLuint file, GLuint idx)
76 {
77 struct prog_src_register reg;
78 reg.File = file;
79 reg.Index = idx;
80 reg.Swizzle = SWIZZLE_NOOP;
81 reg.RelAddr = 0;
82 reg.NegateBase = 0;
83 reg.Abs = 0;
84 reg.NegateAbs = 0;
85 return reg;
86 }
87
88 static struct prog_src_register src_reg_from_dst(struct prog_dst_register dst)
89 {
90 return src_reg(dst.File, dst.Index);
91 }
92
93 static struct prog_src_register src_undef( void )
94 {
95 return src_reg(PROGRAM_UNDEFINED, 0);
96 }
97
98 static GLboolean src_is_undef(struct prog_src_register src)
99 {
100 return src.File == PROGRAM_UNDEFINED;
101 }
102
103 static struct prog_src_register src_swizzle( struct prog_src_register reg, int x, int y, int z, int w )
104 {
105 reg.Swizzle = MAKE_SWIZZLE4(x,y,z,w);
106 return reg;
107 }
108
109 static struct prog_src_register src_swizzle1( struct prog_src_register reg, int x )
110 {
111 return src_swizzle(reg, x, x, x, x);
112 }
113
114
115 /***********************************************************************
116 * Dest regs
117 */
118
119 static struct prog_dst_register dst_reg(GLuint file, GLuint idx)
120 {
121 struct prog_dst_register reg;
122 reg.File = file;
123 reg.Index = idx;
124 reg.WriteMask = WRITEMASK_XYZW;
125 reg.CondMask = 0;
126 reg.CondSwizzle = 0;
127 reg.pad = 0;
128 reg.CondSrc = 0;
129 return reg;
130 }
131
132 static struct prog_dst_register dst_mask( struct prog_dst_register reg, int mask )
133 {
134 reg.WriteMask &= mask;
135 return reg;
136 }
137
138 static struct prog_dst_register dst_undef( void )
139 {
140 return dst_reg(PROGRAM_UNDEFINED, 0);
141 }
142
143
144
145 static struct prog_dst_register get_temp( struct brw_wm_compile *c )
146 {
147 int bit = _mesa_ffs( ~c->fp_temp );
148
149 if (!bit) {
150 _mesa_printf("%s: out of temporaries\n", __FILE__);
151 exit(1);
152 }
153
154 c->fp_temp |= 1<<(bit-1);
155 return dst_reg(PROGRAM_TEMPORARY, FIRST_INTERNAL_TEMP+(bit-1));
156 }
157
158
159 static void release_temp( struct brw_wm_compile *c, struct prog_dst_register temp )
160 {
161 c->fp_temp &= ~(1 << (temp.Index - FIRST_INTERNAL_TEMP));
162 }
163
164
165 /***********************************************************************
166 * Instructions
167 */
168
169 static struct prog_instruction *get_fp_inst(struct brw_wm_compile *c)
170 {
171 return &c->prog_instructions[c->nr_fp_insns++];
172 }
173
174 static struct prog_instruction *emit_insn(struct brw_wm_compile *c,
175 const struct prog_instruction *inst0)
176 {
177 struct prog_instruction *inst = get_fp_inst(c);
178 *inst = *inst0;
179 inst->Data = (void *)inst0;
180 return inst;
181 }
182
183 static struct prog_instruction * emit_op(struct brw_wm_compile *c,
184 GLuint op,
185 struct prog_dst_register dest,
186 GLuint saturate,
187 GLuint tex_src_unit,
188 GLuint tex_src_target,
189 struct prog_src_register src0,
190 struct prog_src_register src1,
191 struct prog_src_register src2 )
192 {
193 struct prog_instruction *inst = get_fp_inst(c);
194
195 memset(inst, 0, sizeof(*inst));
196
197 inst->Opcode = op;
198 inst->DstReg = dest;
199 inst->SaturateMode = saturate;
200 inst->TexSrcUnit = tex_src_unit;
201 inst->TexSrcTarget = tex_src_target;
202 inst->SrcReg[0] = src0;
203 inst->SrcReg[1] = src1;
204 inst->SrcReg[2] = src2;
205 return inst;
206 }
207
208
209
210
211 /***********************************************************************
212 * Special instructions for interpolation and other tasks
213 */
214
215 static struct prog_src_register get_pixel_xy( struct brw_wm_compile *c )
216 {
217 if (src_is_undef(c->pixel_xy)) {
218 struct prog_dst_register pixel_xy = get_temp(c);
219 struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
220
221
222 /* Emit the out calculations, and hold onto the results. Use
223 * two instructions as a temporary is required.
224 */
225 /* pixel_xy.xy = PIXELXY payload[0];
226 */
227 emit_op(c,
228 WM_PIXELXY,
229 dst_mask(pixel_xy, WRITEMASK_XY),
230 0, 0, 0,
231 payload_r0_depth,
232 src_undef(),
233 src_undef());
234
235 c->pixel_xy = src_reg_from_dst(pixel_xy);
236 }
237
238 return c->pixel_xy;
239 }
240
241 static struct prog_src_register get_delta_xy( struct brw_wm_compile *c )
242 {
243 if (src_is_undef(c->delta_xy)) {
244 struct prog_dst_register delta_xy = get_temp(c);
245 struct prog_src_register pixel_xy = get_pixel_xy(c);
246 struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
247
248 /* deltas.xy = DELTAXY pixel_xy, payload[0]
249 */
250 emit_op(c,
251 WM_DELTAXY,
252 dst_mask(delta_xy, WRITEMASK_XY),
253 0, 0, 0,
254 pixel_xy,
255 payload_r0_depth,
256 src_undef());
257
258 c->delta_xy = src_reg_from_dst(delta_xy);
259 }
260
261 return c->delta_xy;
262 }
263
264 static struct prog_src_register get_pixel_w( struct brw_wm_compile *c )
265 {
266 if (src_is_undef(c->pixel_w)) {
267 struct prog_dst_register pixel_w = get_temp(c);
268 struct prog_src_register deltas = get_delta_xy(c);
269 struct prog_src_register interp_wpos = src_reg(PROGRAM_PAYLOAD, FRAG_ATTRIB_WPOS);
270
271
272 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
273 */
274 emit_op(c,
275 WM_PIXELW,
276 dst_mask(pixel_w, WRITEMASK_W),
277 0, 0, 0,
278 interp_wpos,
279 deltas,
280 src_undef());
281
282
283 c->pixel_w = src_reg_from_dst(pixel_w);
284 }
285
286 return c->pixel_w;
287 }
288
289 static void emit_interp( struct brw_wm_compile *c,
290 GLuint idx )
291 {
292 struct prog_dst_register dst = dst_reg(PROGRAM_INPUT, idx);
293 struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
294 struct prog_src_register deltas = get_delta_xy(c);
295 struct prog_src_register arg2;
296 GLuint opcode;
297
298 /* Need to use PINTERP on attributes which have been
299 * multiplied by 1/W in the SF program, and LINTERP on those
300 * which have not:
301 */
302 switch (idx) {
303 case FRAG_ATTRIB_WPOS:
304 opcode = WM_LINTERP;
305 arg2 = src_undef();
306
307 /* Have to treat wpos.xy specially:
308 */
309 emit_op(c,
310 WM_WPOSXY,
311 dst_mask(dst, WRITEMASK_XY),
312 0, 0, 0,
313 get_pixel_xy(c),
314 src_undef(),
315 src_undef());
316
317 dst = dst_mask(dst, WRITEMASK_ZW);
318
319 /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
320 */
321 emit_op(c,
322 WM_LINTERP,
323 dst,
324 0, 0, 0,
325 interp,
326 deltas,
327 arg2);
328 break;
329 case FRAG_ATTRIB_COL0:
330 case FRAG_ATTRIB_COL1:
331 if (c->key.flat_shade) {
332 emit_op(c,
333 WM_CINTERP,
334 dst,
335 0, 0, 0,
336 interp,
337 src_undef(),
338 src_undef());
339 }
340 else {
341 emit_op(c,
342 WM_LINTERP,
343 dst,
344 0, 0, 0,
345 interp,
346 deltas,
347 src_undef());
348 }
349 break;
350 default:
351 emit_op(c,
352 WM_PINTERP,
353 dst,
354 0, 0, 0,
355 interp,
356 deltas,
357 get_pixel_w(c));
358 break;
359 }
360
361 c->fp_interp_emitted |= 1<<idx;
362 }
363
364 static void emit_ddx( struct brw_wm_compile *c,
365 const struct prog_instruction *inst )
366 {
367 GLuint idx = inst->SrcReg[0].Index;
368 struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
369
370 c->fp_deriv_emitted |= 1<<idx;
371 emit_op(c,
372 OPCODE_DDX,
373 inst->DstReg,
374 0, 0, 0,
375 interp,
376 get_pixel_w(c),
377 src_undef());
378 }
379
380 static void emit_ddy( struct brw_wm_compile *c,
381 const struct prog_instruction *inst )
382 {
383 GLuint idx = inst->SrcReg[0].Index;
384 struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
385
386 c->fp_deriv_emitted |= 1<<idx;
387 emit_op(c,
388 OPCODE_DDY,
389 inst->DstReg,
390 0, 0, 0,
391 interp,
392 get_pixel_w(c),
393 src_undef());
394 }
395
396 /***********************************************************************
397 * Hacks to extend the program parameter and constant lists.
398 */
399
400 /* Add the fog parameters to the parameter list of the original
401 * program, rather than creating a new list. Doesn't really do any
402 * harm and it's not as if the parameter handling isn't a big hack
403 * anyway.
404 */
405 static struct prog_src_register search_or_add_param5(struct brw_wm_compile *c,
406 GLint s0,
407 GLint s1,
408 GLint s2,
409 GLint s3,
410 GLint s4)
411 {
412 struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
413 gl_state_index tokens[STATE_LENGTH];
414 GLuint idx;
415 tokens[0] = s0;
416 tokens[1] = s1;
417 tokens[2] = s2;
418 tokens[3] = s3;
419 tokens[4] = s4;
420
421 for (idx = 0; idx < paramList->NumParameters; idx++) {
422 if (paramList->Parameters[idx].Type == PROGRAM_STATE_VAR &&
423 memcmp(paramList->Parameters[idx].StateIndexes, tokens, sizeof(tokens)) == 0)
424 return src_reg(PROGRAM_STATE_VAR, idx);
425 }
426
427 idx = _mesa_add_state_reference( paramList, tokens );
428
429 return src_reg(PROGRAM_STATE_VAR, idx);
430 }
431
432
433 static struct prog_src_register search_or_add_const4f( struct brw_wm_compile *c,
434 GLfloat s0,
435 GLfloat s1,
436 GLfloat s2,
437 GLfloat s3)
438 {
439 struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
440 GLfloat values[4];
441 GLuint idx;
442 GLuint swizzle;
443
444 values[0] = s0;
445 values[1] = s1;
446 values[2] = s2;
447 values[3] = s3;
448
449 /* Have to search, otherwise multiple compilations will each grow
450 * the parameter list.
451 */
452 for (idx = 0; idx < paramList->NumParameters; idx++) {
453 if (paramList->Parameters[idx].Type == PROGRAM_CONSTANT &&
454 memcmp(paramList->ParameterValues[idx], values, sizeof(values)) == 0)
455
456 /* XXX: this mimics the mesa bug which puts all constants and
457 * parameters into the "PROGRAM_STATE_VAR" category:
458 */
459 return src_reg(PROGRAM_STATE_VAR, idx);
460 }
461
462 idx = _mesa_add_unnamed_constant( paramList, values, 4, &swizzle );
463 assert(swizzle == SWIZZLE_NOOP); /* Need to handle swizzle in reg setup */
464 return src_reg(PROGRAM_STATE_VAR, idx);
465 }
466
467
468
469 /***********************************************************************
470 * Expand various instructions here to simpler forms.
471 */
472 static void precalc_dst( struct brw_wm_compile *c,
473 const struct prog_instruction *inst )
474 {
475 struct prog_src_register src0 = inst->SrcReg[0];
476 struct prog_src_register src1 = inst->SrcReg[1];
477 struct prog_dst_register dst = inst->DstReg;
478
479 if (dst.WriteMask & WRITEMASK_Y) {
480 /* dst.y = mul src0.y, src1.y
481 */
482 emit_op(c,
483 OPCODE_MUL,
484 dst_mask(dst, WRITEMASK_Y),
485 inst->SaturateMode, 0, 0,
486 src0,
487 src1,
488 src_undef());
489 }
490
491
492 if (dst.WriteMask & WRITEMASK_XZ) {
493 struct prog_instruction *swz;
494 GLuint z = GET_SWZ(src0.Swizzle, Z);
495
496 /* dst.xz = swz src0.1zzz
497 */
498 swz = emit_op(c,
499 OPCODE_SWZ,
500 dst_mask(dst, WRITEMASK_XZ),
501 inst->SaturateMode, 0, 0,
502 src_swizzle(src0, SWIZZLE_ONE, z, z, z),
503 src_undef(),
504 src_undef());
505 /* Avoid letting negation flag of src0 affect our 1 constant. */
506 swz->SrcReg[0].NegateBase &= ~NEGATE_X;
507 }
508 if (dst.WriteMask & WRITEMASK_W) {
509 /* dst.w = mov src1.w
510 */
511 emit_op(c,
512 OPCODE_MOV,
513 dst_mask(dst, WRITEMASK_W),
514 inst->SaturateMode, 0, 0,
515 src1,
516 src_undef(),
517 src_undef());
518 }
519 }
520
521
522 static void precalc_lit( struct brw_wm_compile *c,
523 const struct prog_instruction *inst )
524 {
525 struct prog_src_register src0 = inst->SrcReg[0];
526 struct prog_dst_register dst = inst->DstReg;
527
528 if (dst.WriteMask & WRITEMASK_XW) {
529 struct prog_instruction *swz;
530
531 /* dst.xw = swz src0.1111
532 */
533 swz = emit_op(c,
534 OPCODE_SWZ,
535 dst_mask(dst, WRITEMASK_XW),
536 0, 0, 0,
537 src_swizzle1(src0, SWIZZLE_ONE),
538 src_undef(),
539 src_undef());
540 /* Avoid letting the negation flag of src0 affect our 1 constant. */
541 swz->SrcReg[0].NegateBase = 0;
542 }
543
544
545 if (dst.WriteMask & WRITEMASK_YZ) {
546 emit_op(c,
547 OPCODE_LIT,
548 dst_mask(dst, WRITEMASK_YZ),
549 inst->SaturateMode, 0, 0,
550 src0,
551 src_undef(),
552 src_undef());
553 }
554 }
555
556 static void precalc_tex( struct brw_wm_compile *c,
557 const struct prog_instruction *inst )
558 {
559 struct prog_src_register coord;
560 struct prog_dst_register tmpcoord;
561 GLuint unit = c->fp->program.Base.SamplerUnits[inst->TexSrcUnit];
562
563 if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX) {
564 struct prog_instruction *out;
565 struct prog_dst_register tmp0 = get_temp(c);
566 struct prog_src_register tmp0src = src_reg_from_dst(tmp0);
567 struct prog_dst_register tmp1 = get_temp(c);
568 struct prog_src_register tmp1src = src_reg_from_dst(tmp1);
569 struct prog_src_register src0 = inst->SrcReg[0];
570
571 tmpcoord = get_temp(c);
572 coord = src_reg_from_dst(tmpcoord);
573
574 out = emit_op(c, OPCODE_MOV,
575 tmpcoord,
576 0, 0, 0,
577 src0,
578 src_undef(),
579 src_undef());
580 out->SrcReg[0].NegateBase = 0;
581 out->SrcReg[0].Abs = 1;
582
583 emit_op(c, OPCODE_MAX,
584 tmp0,
585 0, 0, 0,
586 src_swizzle1(coord, X),
587 src_swizzle1(coord, Y),
588 src_undef());
589
590 emit_op(c, OPCODE_MAX,
591 tmp1,
592 0, 0, 0,
593 tmp0src,
594 src_swizzle1(coord, Z),
595 src_undef());
596
597 emit_op(c, OPCODE_RCP,
598 tmp0,
599 0, 0, 0,
600 tmp1src,
601 src_undef(),
602 src_undef());
603
604 emit_op(c, OPCODE_MUL,
605 tmpcoord,
606 0, 0, 0,
607 src0,
608 tmp0src,
609 src_undef());
610
611 release_temp(c, tmp0);
612 release_temp(c, tmp1);
613 } else if (inst->TexSrcTarget == TEXTURE_RECT_INDEX) {
614 struct prog_src_register scale =
615 search_or_add_param5( c,
616 STATE_INTERNAL,
617 STATE_TEXRECT_SCALE,
618 unit,
619 0,0 );
620
621 tmpcoord = get_temp(c);
622
623 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
624 */
625 emit_op(c,
626 OPCODE_MUL,
627 tmpcoord,
628 0, 0, 0,
629 inst->SrcReg[0],
630 scale,
631 src_undef());
632
633 coord = src_reg_from_dst(tmpcoord);
634 }
635 else {
636 coord = inst->SrcReg[0];
637 }
638
639 /* Need to emit YUV texture conversions by hand. Probably need to
640 * do this here - the alternative is in brw_wm_emit.c, but the
641 * conversion requires allocating a temporary variable which we
642 * don't have the facility to do that late in the compilation.
643 */
644 if (!(c->key.yuvtex_mask & (1<<unit))) {
645 emit_op(c,
646 OPCODE_TEX,
647 inst->DstReg,
648 inst->SaturateMode,
649 unit,
650 inst->TexSrcTarget,
651 coord,
652 src_undef(),
653 src_undef());
654 }
655 else {
656 GLboolean swap_uv = c->key.yuvtex_swap_mask & (1<<unit);
657
658 /*
659 CONST C0 = { -.5, -.0625, -.5, 1.164 }
660 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
661 UYV = TEX ...
662 UYV.xyz = ADD UYV, C0
663 UYV.y = MUL UYV.y, C0.w
664 if (UV swaped)
665 RGB.xyz = MAD UYV.zzx, C1, UYV.y
666 else
667 RGB.xyz = MAD UYV.xxz, C1, UYV.y
668 RGB.y = MAD UYV.z, C1.w, RGB.y
669 */
670 struct prog_dst_register dst = inst->DstReg;
671 struct prog_dst_register tmp = get_temp(c);
672 struct prog_src_register tmpsrc = src_reg_from_dst(tmp);
673 struct prog_src_register C0 = search_or_add_const4f( c, -.5, -.0625, -.5, 1.164 );
674 struct prog_src_register C1 = search_or_add_const4f( c, 1.596, -0.813, 2.018, -.391 );
675
676 /* tmp = TEX ...
677 */
678 emit_op(c,
679 OPCODE_TEX,
680 tmp,
681 inst->SaturateMode,
682 unit,
683 inst->TexSrcTarget,
684 coord,
685 src_undef(),
686 src_undef());
687
688 /* tmp.xyz = ADD TMP, C0
689 */
690 emit_op(c,
691 OPCODE_ADD,
692 dst_mask(tmp, WRITEMASK_XYZ),
693 0, 0, 0,
694 tmpsrc,
695 C0,
696 src_undef());
697
698 /* YUV.y = MUL YUV.y, C0.w
699 */
700
701 emit_op(c,
702 OPCODE_MUL,
703 dst_mask(tmp, WRITEMASK_Y),
704 0, 0, 0,
705 tmpsrc,
706 src_swizzle1(C0, W),
707 src_undef());
708
709 /*
710 * if (UV swaped)
711 * RGB.xyz = MAD YUV.zzx, C1, YUV.y
712 * else
713 * RGB.xyz = MAD YUV.xxz, C1, YUV.y
714 */
715
716 emit_op(c,
717 OPCODE_MAD,
718 dst_mask(dst, WRITEMASK_XYZ),
719 0, 0, 0,
720 swap_uv?src_swizzle(tmpsrc, Z,Z,X,X):src_swizzle(tmpsrc, X,X,Z,Z),
721 C1,
722 src_swizzle1(tmpsrc, Y));
723
724 /* RGB.y = MAD YUV.z, C1.w, RGB.y
725 */
726 emit_op(c,
727 OPCODE_MAD,
728 dst_mask(dst, WRITEMASK_Y),
729 0, 0, 0,
730 src_swizzle1(tmpsrc, Z),
731 src_swizzle1(C1, W),
732 src_swizzle1(src_reg_from_dst(dst), Y));
733
734 release_temp(c, tmp);
735 }
736
737 if ((inst->TexSrcTarget == TEXTURE_RECT_INDEX) ||
738 (inst->TexSrcTarget == TEXTURE_CUBE_INDEX))
739 release_temp(c, tmpcoord);
740 }
741
742
743 static GLboolean projtex( struct brw_wm_compile *c,
744 const struct prog_instruction *inst )
745 {
746 struct prog_src_register src = inst->SrcReg[0];
747
748 /* Only try to detect the simplest cases. Could detect (later)
749 * cases where we are trying to emit code like RCP {1.0}, MUL x,
750 * {1.0}, and so on.
751 *
752 * More complex cases than this typically only arise from
753 * user-provided fragment programs anyway:
754 */
755 if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX)
756 return 0; /* ut2004 gun rendering !?! */
757 else if (src.File == PROGRAM_INPUT &&
758 GET_SWZ(src.Swizzle, W) == W &&
759 (c->key.projtex_mask & (1<<(src.Index + FRAG_ATTRIB_WPOS - FRAG_ATTRIB_TEX0))) == 0)
760 return 0;
761 else
762 return 1;
763 }
764
765
766 static void precalc_txp( struct brw_wm_compile *c,
767 const struct prog_instruction *inst )
768 {
769 struct prog_src_register src0 = inst->SrcReg[0];
770
771 if (projtex(c, inst)) {
772 struct prog_dst_register tmp = get_temp(c);
773 struct prog_instruction tmp_inst;
774
775 /* tmp0.w = RCP inst.arg[0][3]
776 */
777 emit_op(c,
778 OPCODE_RCP,
779 dst_mask(tmp, WRITEMASK_W),
780 0, 0, 0,
781 src_swizzle1(src0, GET_SWZ(src0.Swizzle, W)),
782 src_undef(),
783 src_undef());
784
785 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
786 */
787 emit_op(c,
788 OPCODE_MUL,
789 dst_mask(tmp, WRITEMASK_XYZ),
790 0, 0, 0,
791 src0,
792 src_swizzle1(src_reg_from_dst(tmp), W),
793 src_undef());
794
795 /* dst = precalc(TEX tmp0)
796 */
797 tmp_inst = *inst;
798 tmp_inst.SrcReg[0] = src_reg_from_dst(tmp);
799 precalc_tex(c, &tmp_inst);
800
801 release_temp(c, tmp);
802 }
803 else
804 {
805 /* dst = precalc(TEX src0)
806 */
807 precalc_tex(c, inst);
808 }
809 }
810
811
812
813
814
815 /***********************************************************************
816 * Add instructions to perform fog blending
817 */
818
819 static void fog_blend( struct brw_wm_compile *c,
820 struct prog_src_register fog_factor )
821 {
822 struct prog_dst_register outcolor = dst_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
823 struct prog_src_register fogcolor = search_or_add_param5( c, STATE_FOG_COLOR, 0,0,0,0 );
824
825 /* color.xyz = LRP fog_factor.xxxx, output_color, fog_color */
826
827 emit_op(c,
828 OPCODE_LRP,
829 dst_mask(outcolor, WRITEMASK_XYZ),
830 0, 0, 0,
831 fog_factor,
832 src_reg_from_dst(outcolor),
833 fogcolor);
834 }
835
836
837
838 /* This one is simple - just take the interpolated fog coordinate and
839 * use it as the fog blend factor.
840 */
841 static void fog_interpolated( struct brw_wm_compile *c )
842 {
843 struct prog_src_register fogc = src_reg(PROGRAM_INPUT, FRAG_ATTRIB_FOGC);
844
845 if (!(c->fp_interp_emitted & (1<<FRAG_ATTRIB_FOGC)))
846 emit_interp(c, FRAG_ATTRIB_FOGC);
847
848 fog_blend( c, src_swizzle1(fogc, GET_SWZ(fogc.Swizzle,X)));
849 }
850
851 static void emit_fog( struct brw_wm_compile *c )
852 {
853 if (!c->fp->program.FogOption)
854 return;
855
856 if (1)
857 fog_interpolated( c );
858 else {
859 /* TODO: per-pixel fog */
860 assert(0);
861 }
862 }
863
864 static void emit_fb_write( struct brw_wm_compile *c )
865 {
866 struct prog_src_register outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
867 struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
868 struct prog_src_register outdepth = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DEPR);
869 GLuint i;
870
871 struct prog_instruction *inst, *last_inst;
872 struct brw_context *brw = c->func.brw;
873
874 /* inst->Sampler is not used by backend,
875 use it for fb write target and eot */
876
877 if (brw->state.nr_draw_regions > 1) {
878 for (i = 0 ; i < brw->state.nr_draw_regions; i++) {
879 outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DATA0 + i);
880 last_inst = inst = emit_op(c,
881 WM_FB_WRITE, dst_mask(dst_undef(),0), 0, 0, 0,
882 outcolor, payload_r0_depth, outdepth);
883 inst->Sampler = (i<<1);
884 if (c->fp_fragcolor_emitted) {
885 outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
886 last_inst = inst = emit_op(c, WM_FB_WRITE, dst_mask(dst_undef(),0),
887 0, 0, 0, outcolor, payload_r0_depth, outdepth);
888 inst->Sampler = (i<<1);
889 }
890 }
891 last_inst->Sampler |= 1; //eot
892 }else {
893 inst = emit_op(c, WM_FB_WRITE, dst_mask(dst_undef(),0),
894 0, 0, 0, outcolor, payload_r0_depth, outdepth);
895 inst->Sampler = 1|(0<<1);
896 }
897 }
898
899
900
901
902 /***********************************************************************
903 * Emit INTERP instructions ahead of first use of each attrib.
904 */
905
906 static void validate_src_regs( struct brw_wm_compile *c,
907 const struct prog_instruction *inst )
908 {
909 GLuint nr_args = brw_wm_nr_args( inst->Opcode );
910 GLuint i;
911
912 for (i = 0; i < nr_args; i++) {
913 if (inst->SrcReg[i].File == PROGRAM_INPUT) {
914 GLuint idx = inst->SrcReg[i].Index;
915 if (!(c->fp_interp_emitted & (1<<idx))) {
916 emit_interp(c, idx);
917 }
918 }
919 }
920 }
921
922 static void validate_dst_regs( struct brw_wm_compile *c,
923 const struct prog_instruction *inst )
924 {
925 if (inst->DstReg.File == PROGRAM_OUTPUT) {
926 GLuint idx = inst->DstReg.Index;
927 if (idx == FRAG_RESULT_COLR)
928 c->fp_fragcolor_emitted = 1;
929 }
930 }
931
932 static void print_insns( const struct prog_instruction *insn,
933 GLuint nr )
934 {
935 GLuint i;
936 for (i = 0; i < nr; i++, insn++) {
937 _mesa_printf("%3d: ", i);
938 if (insn->Opcode < MAX_OPCODE)
939 _mesa_print_instruction(insn);
940 else if (insn->Opcode < MAX_WM_OPCODE) {
941 GLuint idx = insn->Opcode - MAX_OPCODE;
942
943 _mesa_print_alu_instruction(insn,
944 wm_opcode_strings[idx],
945 3);
946 }
947 else
948 _mesa_printf("UNKNOWN\n");
949
950 }
951 }
952
953 void brw_wm_pass_fp( struct brw_wm_compile *c )
954 {
955 struct brw_fragment_program *fp = c->fp;
956 GLuint insn;
957
958 if (INTEL_DEBUG & DEBUG_WM) {
959 _mesa_printf("\n\n\npre-fp:\n");
960 _mesa_print_program(&fp->program.Base);
961 _mesa_printf("\n");
962 }
963
964 c->pixel_xy = src_undef();
965 c->delta_xy = src_undef();
966 c->pixel_w = src_undef();
967 c->nr_fp_insns = 0;
968
969 /* Emit preamble instructions:
970 */
971
972
973 for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
974 const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
975 validate_src_regs(c, inst);
976 validate_dst_regs(c, inst);
977 }
978 for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
979 const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
980 struct prog_instruction *out;
981
982 /* Check for INPUT values, emit INTERP instructions where
983 * necessary:
984 */
985
986
987 switch (inst->Opcode) {
988 case OPCODE_SWZ:
989 out = emit_insn(c, inst);
990 out->Opcode = OPCODE_MOV;
991 break;
992
993 case OPCODE_ABS:
994 out = emit_insn(c, inst);
995 out->Opcode = OPCODE_MOV;
996 out->SrcReg[0].NegateBase = 0;
997 out->SrcReg[0].Abs = 1;
998 break;
999
1000 case OPCODE_SUB:
1001 out = emit_insn(c, inst);
1002 out->Opcode = OPCODE_ADD;
1003 out->SrcReg[1].NegateBase ^= 0xf;
1004 break;
1005
1006 case OPCODE_SCS:
1007 out = emit_insn(c, inst);
1008 /* This should probably be done in the parser.
1009 */
1010 out->DstReg.WriteMask &= WRITEMASK_XY;
1011 break;
1012
1013 case OPCODE_DST:
1014 precalc_dst(c, inst);
1015 break;
1016
1017 case OPCODE_LIT:
1018 precalc_lit(c, inst);
1019 break;
1020
1021 case OPCODE_TEX:
1022 precalc_tex(c, inst);
1023 break;
1024
1025 case OPCODE_TXP:
1026 precalc_txp(c, inst);
1027 break;
1028
1029 case OPCODE_TXB:
1030 out = emit_insn(c, inst);
1031 out->TexSrcUnit = fp->program.Base.SamplerUnits[inst->TexSrcUnit];
1032 break;
1033
1034 case OPCODE_XPD:
1035 out = emit_insn(c, inst);
1036 /* This should probably be done in the parser.
1037 */
1038 out->DstReg.WriteMask &= WRITEMASK_XYZ;
1039 break;
1040
1041 case OPCODE_KIL:
1042 out = emit_insn(c, inst);
1043 /* This should probably be done in the parser.
1044 */
1045 out->DstReg.WriteMask = 0;
1046 break;
1047 case OPCODE_DDX:
1048 emit_ddx(c, inst);
1049 break;
1050 case OPCODE_DDY:
1051 emit_ddy(c, inst);
1052 break;
1053 case OPCODE_END:
1054 emit_fog(c);
1055 emit_fb_write(c);
1056 break;
1057 case OPCODE_PRINT:
1058 break;
1059
1060 default:
1061 emit_insn(c, inst);
1062 break;
1063 }
1064 }
1065
1066 if (INTEL_DEBUG & DEBUG_WM) {
1067 _mesa_printf("\n\n\npass_fp:\n");
1068 print_insns( c->prog_instructions, c->nr_fp_insns );
1069 _mesa_printf("\n");
1070 }
1071 }
1072