DDX DDY support, not very accurate
[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 "glheader.h"
34 #include "macros.h"
35 #include "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 = 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 + 1 - 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 /* Recalculate state dependency:
430 */
431 c->fp->param_state = paramList->StateFlags;
432
433 return src_reg(PROGRAM_STATE_VAR, idx);
434 }
435
436
437 static struct prog_src_register search_or_add_const4f( struct brw_wm_compile *c,
438 GLfloat s0,
439 GLfloat s1,
440 GLfloat s2,
441 GLfloat s3)
442 {
443 struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
444 GLfloat values[4];
445 GLuint idx;
446 GLuint swizzle;
447
448 values[0] = s0;
449 values[1] = s1;
450 values[2] = s2;
451 values[3] = s3;
452
453 /* Have to search, otherwise multiple compilations will each grow
454 * the parameter list.
455 */
456 for (idx = 0; idx < paramList->NumParameters; idx++) {
457 if (paramList->Parameters[idx].Type == PROGRAM_CONSTANT &&
458 memcmp(paramList->ParameterValues[idx], values, sizeof(values)) == 0)
459
460 /* XXX: this mimics the mesa bug which puts all constants and
461 * parameters into the "PROGRAM_STATE_VAR" category:
462 */
463 return src_reg(PROGRAM_STATE_VAR, idx);
464 }
465
466 idx = _mesa_add_unnamed_constant( paramList, values, 4, &swizzle );
467 /* XXX what about swizzle? */
468 return src_reg(PROGRAM_STATE_VAR, idx);
469 }
470
471
472
473 /***********************************************************************
474 * Expand various instructions here to simpler forms.
475 */
476 static void precalc_dst( struct brw_wm_compile *c,
477 const struct prog_instruction *inst )
478 {
479 struct prog_src_register src0 = inst->SrcReg[0];
480 struct prog_src_register src1 = inst->SrcReg[1];
481 struct prog_dst_register dst = inst->DstReg;
482
483 if (dst.WriteMask & WRITEMASK_Y) {
484 /* dst.y = mul src0.y, src1.y
485 */
486 emit_op(c,
487 OPCODE_MUL,
488 dst_mask(dst, WRITEMASK_Y),
489 inst->SaturateMode, 0, 0,
490 src0,
491 src1,
492 src_undef());
493 }
494
495
496 if (dst.WriteMask & WRITEMASK_XZ) {
497 GLuint z = GET_SWZ(src0.Swizzle, Z);
498
499 /* dst.xz = swz src0.1zzz
500 */
501 emit_op(c,
502 OPCODE_SWZ,
503 dst_mask(dst, WRITEMASK_XZ),
504 inst->SaturateMode, 0, 0,
505 src_swizzle(src0, SWIZZLE_ONE, z, z, z),
506 src_undef(),
507 src_undef());
508 }
509 if (dst.WriteMask & WRITEMASK_W) {
510 /* dst.w = mov src1.w
511 */
512 emit_op(c,
513 OPCODE_MOV,
514 dst_mask(dst, WRITEMASK_W),
515 inst->SaturateMode, 0, 0,
516 src1,
517 src_undef(),
518 src_undef());
519 }
520 }
521
522
523 static void precalc_lit( struct brw_wm_compile *c,
524 const struct prog_instruction *inst )
525 {
526 struct prog_src_register src0 = inst->SrcReg[0];
527 struct prog_dst_register dst = inst->DstReg;
528
529 if (dst.WriteMask & WRITEMASK_XW) {
530 /* dst.xw = swz src0.1111
531 */
532 emit_op(c,
533 OPCODE_SWZ,
534 dst_mask(dst, WRITEMASK_XW),
535 0, 0, 0,
536 src_swizzle1(src0, SWIZZLE_ONE),
537 src_undef(),
538 src_undef());
539 }
540
541
542 if (dst.WriteMask & WRITEMASK_YZ) {
543 emit_op(c,
544 OPCODE_LIT,
545 dst_mask(dst, WRITEMASK_YZ),
546 inst->SaturateMode, 0, 0,
547 src0,
548 src_undef(),
549 src_undef());
550 }
551 }
552
553 static void precalc_tex( struct brw_wm_compile *c,
554 const struct prog_instruction *inst )
555 {
556 struct prog_src_register coord;
557 struct prog_dst_register tmpcoord;
558
559 if (inst->TexSrcTarget == TEXTURE_RECT_INDEX) {
560 struct prog_src_register scale =
561 search_or_add_param5( c,
562 STATE_INTERNAL,
563 STATE_TEXRECT_SCALE,
564 inst->TexSrcUnit,
565 0,0 );
566
567 tmpcoord = get_temp(c);
568
569 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
570 */
571 emit_op(c,
572 OPCODE_MUL,
573 tmpcoord,
574 0, 0, 0,
575 inst->SrcReg[0],
576 scale,
577 src_undef());
578
579 coord = src_reg_from_dst(tmpcoord);
580 }
581 else {
582 coord = inst->SrcReg[0];
583 }
584
585 /* Need to emit YUV texture conversions by hand. Probably need to
586 * do this here - the alternative is in brw_wm_emit.c, but the
587 * conversion requires allocating a temporary variable which we
588 * don't have the facility to do that late in the compilation.
589 */
590 if (!(c->key.yuvtex_mask & (1<<inst->TexSrcUnit))) {
591 emit_op(c,
592 OPCODE_TEX,
593 inst->DstReg,
594 inst->SaturateMode,
595 inst->TexSrcUnit,
596 inst->TexSrcTarget,
597 coord,
598 src_undef(),
599 src_undef());
600 }
601 else {
602 /*
603 CONST C0 = { -.5, -.0625, -.5, 1.164 }
604 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
605 UYV = TEX ...
606 UYV.xyz = ADD UYV, C0
607 UYV.y = MUL UYV.y, C0.w
608 RGB.xyz = MAD UYV.xxz, C1, UYV.y
609 RGB.y = MAD UYV.z, C1.w, RGB.y
610 */
611 struct prog_dst_register dst = inst->DstReg;
612 struct prog_src_register src0 = inst->SrcReg[0];
613 struct prog_dst_register tmp = get_temp(c);
614 struct prog_src_register tmpsrc = src_reg_from_dst(tmp);
615 struct prog_src_register C0 = search_or_add_const4f( c, -.5, -.0625, -.5, 1.164 );
616 struct prog_src_register C1 = search_or_add_const4f( c, 1.596, -0.813, 2.018, -.391 );
617
618 /* tmp = TEX ...
619 */
620 emit_op(c,
621 OPCODE_TEX,
622 tmp,
623 inst->SaturateMode,
624 inst->TexSrcUnit,
625 inst->TexSrcTarget,
626 src0,
627 src_undef(),
628 src_undef());
629
630 /* tmp.xyz = ADD TMP, C0
631 */
632 emit_op(c,
633 OPCODE_ADD,
634 dst_mask(tmp, WRITEMASK_XYZ),
635 0, 0, 0,
636 tmpsrc,
637 C0,
638 src_undef());
639
640 /* YUV.y = MUL YUV.y, C0.w
641 */
642 emit_op(c,
643 OPCODE_MUL,
644 dst_mask(tmp, WRITEMASK_Y),
645 0, 0, 0,
646 tmpsrc,
647 src_swizzle1(C0, W),
648 src_undef());
649
650 /* RGB.xyz = MAD YUV.xxz, C1, YUV.y
651 */
652 emit_op(c,
653 OPCODE_MAD,
654 dst_mask(dst, WRITEMASK_XYZ),
655 0, 0, 0,
656 src_swizzle(tmpsrc, X,X,Z,Z),
657 C1,
658 src_swizzle1(tmpsrc, Y));
659
660 /* RGB.y = MAD YUV.z, C1.w, RGB.y
661 */
662 emit_op(c,
663 OPCODE_MAD,
664 dst_mask(dst, WRITEMASK_Y),
665 0, 0, 0,
666 src_swizzle1(tmpsrc, Z),
667 src_swizzle1(C1, W),
668 src_swizzle1(src_reg_from_dst(dst), Y));
669
670 release_temp(c, tmp);
671 }
672
673 if (inst->TexSrcTarget == GL_TEXTURE_RECTANGLE_NV)
674 release_temp(c, tmpcoord);
675 }
676
677
678 static GLboolean projtex( struct brw_wm_compile *c,
679 const struct prog_instruction *inst )
680 {
681 struct prog_src_register src = inst->SrcReg[0];
682
683 /* Only try to detect the simplest cases. Could detect (later)
684 * cases where we are trying to emit code like RCP {1.0}, MUL x,
685 * {1.0}, and so on.
686 *
687 * More complex cases than this typically only arise from
688 * user-provided fragment programs anyway:
689 */
690 if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX)
691 return 0; /* ut2004 gun rendering !?! */
692 else if (src.File == PROGRAM_INPUT &&
693 GET_SWZ(src.Swizzle, W) == W &&
694 (c->key.projtex_mask & (1<<src.Index)) == 0)
695 return 0;
696 else
697 return 1;
698 }
699
700
701 static void precalc_txp( struct brw_wm_compile *c,
702 const struct prog_instruction *inst )
703 {
704 struct prog_src_register src0 = inst->SrcReg[0];
705
706 if (projtex(c, inst)) {
707 struct prog_dst_register tmp = get_temp(c);
708 struct prog_instruction tmp_inst;
709
710 /* tmp0.w = RCP inst.arg[0][3]
711 */
712 emit_op(c,
713 OPCODE_RCP,
714 dst_mask(tmp, WRITEMASK_W),
715 0, 0, 0,
716 src_swizzle1(src0, GET_SWZ(src0.Swizzle, W)),
717 src_undef(),
718 src_undef());
719
720 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
721 */
722 emit_op(c,
723 OPCODE_MUL,
724 dst_mask(tmp, WRITEMASK_XYZ),
725 0, 0, 0,
726 src0,
727 src_swizzle1(src_reg_from_dst(tmp), W),
728 src_undef());
729
730 /* dst = precalc(TEX tmp0)
731 */
732 tmp_inst = *inst;
733 tmp_inst.SrcReg[0] = src_reg_from_dst(tmp);
734 precalc_tex(c, &tmp_inst);
735
736 release_temp(c, tmp);
737 }
738 else
739 {
740 /* dst = precalc(TEX src0)
741 */
742 precalc_tex(c, inst);
743 }
744 }
745
746
747
748
749
750 /***********************************************************************
751 * Add instructions to perform fog blending
752 */
753
754 static void fog_blend( struct brw_wm_compile *c,
755 struct prog_src_register fog_factor )
756 {
757 struct prog_dst_register outcolor = dst_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
758 struct prog_src_register fogcolor = search_or_add_param5( c, STATE_FOG_COLOR, 0,0,0,0 );
759
760 /* color.xyz = LRP fog_factor.xxxx, output_color, fog_color */
761
762 emit_op(c,
763 OPCODE_LRP,
764 dst_mask(outcolor, WRITEMASK_XYZ),
765 0, 0, 0,
766 fog_factor,
767 src_reg_from_dst(outcolor),
768 fogcolor);
769 }
770
771
772
773 /* This one is simple - just take the interpolated fog coordinate and
774 * use it as the fog blend factor.
775 */
776 static void fog_interpolated( struct brw_wm_compile *c )
777 {
778 struct prog_src_register fogc = src_reg(PROGRAM_INPUT, FRAG_ATTRIB_FOGC);
779
780 if (!(c->fp_interp_emitted & (1<<FRAG_ATTRIB_FOGC)))
781 emit_interp(c, FRAG_ATTRIB_FOGC);
782
783 fog_blend( c, src_swizzle1(fogc, GET_SWZ(fogc.Swizzle,X)));
784 }
785
786 static void emit_fog( struct brw_wm_compile *c )
787 {
788 if (!c->fp->program.FogOption)
789 return;
790
791 if (1)
792 fog_interpolated( c );
793 else {
794 /* TODO: per-pixel fog */
795 assert(0);
796 }
797 }
798
799 static void emit_fb_write( struct brw_wm_compile *c )
800 {
801 struct prog_src_register outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
802 struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
803 struct prog_src_register outdepth = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DEPR);
804
805 emit_op(c,
806 WM_FB_WRITE,
807 dst_mask(dst_undef(),0),
808 0, 0, 0,
809 outcolor,
810 payload_r0_depth,
811 outdepth);
812 }
813
814
815
816
817 /***********************************************************************
818 * Emit INTERP instructions ahead of first use of each attrib.
819 */
820
821 static void validate_src_regs( struct brw_wm_compile *c,
822 const struct prog_instruction *inst )
823 {
824 GLuint nr_args = brw_wm_nr_args( inst->Opcode );
825 GLuint i;
826
827 for (i = 0; i < nr_args; i++) {
828 if (inst->SrcReg[i].File == PROGRAM_INPUT) {
829 GLuint idx = inst->SrcReg[i].Index;
830 if (!(c->fp_interp_emitted & (1<<idx))) {
831 emit_interp(c, idx);
832 }
833 }
834 }
835 }
836
837
838
839 static void print_insns( const struct prog_instruction *insn,
840 GLuint nr )
841 {
842 GLuint i;
843 for (i = 0; i < nr; i++, insn++) {
844 _mesa_printf("%3d: ", i);
845 if (insn->Opcode < MAX_OPCODE)
846 _mesa_print_instruction(insn);
847 else if (insn->Opcode < MAX_WM_OPCODE) {
848 GLuint idx = insn->Opcode - MAX_OPCODE;
849
850 _mesa_print_alu_instruction(insn,
851 wm_opcode_strings[idx],
852 3);
853 }
854 else
855 _mesa_printf("UNKNOWN\n");
856
857 }
858 }
859
860 void brw_wm_pass_fp( struct brw_wm_compile *c )
861 {
862 struct brw_fragment_program *fp = c->fp;
863 GLuint insn;
864
865 if (INTEL_DEBUG & DEBUG_WM) {
866 _mesa_printf("\n\n\npre-fp:\n");
867 _mesa_print_program(&fp->program.Base);
868 _mesa_printf("\n");
869 }
870
871 c->pixel_xy = src_undef();
872 c->delta_xy = src_undef();
873 c->pixel_w = src_undef();
874 c->nr_fp_insns = 0;
875
876 /* Emit preamble instructions:
877 */
878
879
880 for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
881 const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
882 struct prog_instruction *out;
883
884 /* Check for INPUT values, emit INTERP instructions where
885 * necessary:
886 */
887 validate_src_regs(c, inst);
888
889
890 switch (inst->Opcode) {
891 case OPCODE_SWZ:
892 out = emit_insn(c, inst);
893 out->Opcode = OPCODE_MOV;
894 break;
895
896 case OPCODE_ABS:
897 out = emit_insn(c, inst);
898 out->Opcode = OPCODE_MOV;
899 out->SrcReg[0].NegateBase = 0;
900 out->SrcReg[0].Abs = 1;
901 break;
902
903 case OPCODE_SUB:
904 out = emit_insn(c, inst);
905 out->Opcode = OPCODE_ADD;
906 out->SrcReg[1].NegateBase ^= 0xf;
907 break;
908
909 case OPCODE_SCS:
910 out = emit_insn(c, inst);
911 /* This should probably be done in the parser.
912 */
913 out->DstReg.WriteMask &= WRITEMASK_XY;
914 break;
915
916 case OPCODE_DST:
917 precalc_dst(c, inst);
918 break;
919
920 case OPCODE_LIT:
921 precalc_lit(c, inst);
922 break;
923
924 case OPCODE_TXP:
925 precalc_txp(c, inst);
926 break;
927
928 case OPCODE_XPD:
929 out = emit_insn(c, inst);
930 /* This should probably be done in the parser.
931 */
932 out->DstReg.WriteMask &= WRITEMASK_XYZ;
933 break;
934
935 case OPCODE_KIL:
936 out = emit_insn(c, inst);
937 /* This should probably be done in the parser.
938 */
939 out->DstReg.WriteMask = 0;
940 break;
941 case OPCODE_DDX:
942 emit_ddx(c, inst);
943 break;
944 case OPCODE_DDY:
945 emit_ddy(c, inst);
946 break;
947 case OPCODE_END:
948 emit_fog(c);
949 emit_fb_write(c);
950 break;
951 case OPCODE_PRINT:
952 break;
953
954 default:
955 emit_insn(c, inst);
956 break;
957 }
958 }
959
960 if (INTEL_DEBUG & DEBUG_WM) {
961 _mesa_printf("\n\n\npass_fp:\n");
962 print_insns( c->prog_instructions, c->nr_fp_insns );
963 _mesa_printf("\n");
964 }
965 }
966