04c7555b9b84af0743549380f081ac06151322e6
[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/program.h"
41 #include "shader/program_instruction.h"
42 #include "shader/arbprogparse.h"
43
44 #define FIRST_INTERNAL_TEMP MAX_NV_FRAGMENT_PROGRAM_TEMPS
45
46 #define X 0
47 #define Y 1
48 #define Z 2
49 #define W 3
50
51
52 static const char *wm_opcode_strings[] = {
53 "PIXELXY",
54 "DELTAXY",
55 "PIXELW",
56 "LINTERP",
57 "PINTERP",
58 "CINTERP",
59 "WPOSXY",
60 "FB_WRITE"
61 };
62
63 #if 0
64 static const char *wm_file_strings[] = {
65 "PAYLOAD"
66 };
67 #endif
68
69
70 /***********************************************************************
71 * Source regs
72 */
73
74 static struct prog_src_register src_reg(GLuint file, GLuint idx)
75 {
76 struct prog_src_register reg;
77 reg.File = file;
78 reg.Index = idx;
79 reg.Swizzle = SWIZZLE_NOOP;
80 reg.RelAddr = 0;
81 reg.NegateBase = 0;
82 reg.Abs = 0;
83 reg.NegateAbs = 0;
84 return reg;
85 }
86
87 static struct prog_src_register src_reg_from_dst(struct prog_dst_register dst)
88 {
89 return src_reg(dst.File, dst.Index);
90 }
91
92 static struct prog_src_register src_undef( void )
93 {
94 return src_reg(PROGRAM_UNDEFINED, 0);
95 }
96
97 static GLboolean src_is_undef(struct prog_src_register src)
98 {
99 return src.File == PROGRAM_UNDEFINED;
100 }
101
102 static struct prog_src_register src_swizzle( struct prog_src_register reg, int x, int y, int z, int w )
103 {
104 reg.Swizzle = MAKE_SWIZZLE4(x,y,z,w);
105 return reg;
106 }
107
108 static struct prog_src_register src_swizzle1( struct prog_src_register reg, int x )
109 {
110 return src_swizzle(reg, x, x, x, x);
111 }
112
113
114 /***********************************************************************
115 * Dest regs
116 */
117
118 static struct prog_dst_register dst_reg(GLuint file, GLuint idx)
119 {
120 struct prog_dst_register reg;
121 reg.File = file;
122 reg.Index = idx;
123 reg.WriteMask = WRITEMASK_XYZW;
124 reg.CondMask = 0;
125 reg.CondSwizzle = 0;
126 reg.pad = 0;
127 reg.CondSrc = 0;
128 return reg;
129 }
130
131 static struct prog_dst_register dst_mask( struct prog_dst_register reg, int mask )
132 {
133 reg.WriteMask &= mask;
134 return reg;
135 }
136
137 static struct prog_dst_register dst_undef( void )
138 {
139 return dst_reg(PROGRAM_UNDEFINED, 0);
140 }
141
142
143
144 static struct prog_dst_register get_temp( struct brw_wm_compile *c )
145 {
146 int bit = ffs( ~c->fp_temp );
147
148 if (!bit) {
149 _mesa_printf("%s: out of temporaries\n", __FILE__);
150 exit(1);
151 }
152
153 c->fp_temp |= 1<<(bit-1);
154 return dst_reg(PROGRAM_TEMPORARY, FIRST_INTERNAL_TEMP+(bit-1));
155 }
156
157
158 static void release_temp( struct brw_wm_compile *c, struct prog_dst_register temp )
159 {
160 c->fp_temp &= ~1<<(temp.Index + 1 - FIRST_INTERNAL_TEMP);
161 }
162
163
164 /***********************************************************************
165 * Instructions
166 */
167
168 static struct prog_instruction *get_fp_inst(struct brw_wm_compile *c)
169 {
170 return &c->prog_instructions[c->nr_fp_insns++];
171 }
172
173 static struct prog_instruction *emit_insn(struct brw_wm_compile *c,
174 const struct prog_instruction *inst0)
175 {
176 struct prog_instruction *inst = get_fp_inst(c);
177 *inst = *inst0;
178 return inst;
179 }
180
181 static struct prog_instruction * emit_op(struct brw_wm_compile *c,
182 GLuint op,
183 struct prog_dst_register dest,
184 GLuint saturate,
185 GLuint tex_src_unit,
186 GLuint tex_src_target,
187 struct prog_src_register src0,
188 struct prog_src_register src1,
189 struct prog_src_register src2 )
190 {
191 struct prog_instruction *inst = get_fp_inst(c);
192
193 memset(inst, 0, sizeof(*inst));
194
195 inst->Opcode = op;
196 inst->DstReg = dest;
197 inst->SaturateMode = saturate;
198 inst->TexSrcUnit = tex_src_unit;
199 inst->TexSrcTarget = tex_src_target;
200 inst->SrcReg[0] = src0;
201 inst->SrcReg[1] = src1;
202 inst->SrcReg[2] = src2;
203
204 return inst;
205 }
206
207
208
209
210 /***********************************************************************
211 * Special instructions for interpolation and other tasks
212 */
213
214 static struct prog_src_register get_pixel_xy( struct brw_wm_compile *c )
215 {
216 if (src_is_undef(c->pixel_xy)) {
217 struct prog_dst_register pixel_xy = get_temp(c);
218 struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
219
220
221 /* Emit the out calculations, and hold onto the results. Use
222 * two instructions as a temporary is required.
223 */
224 /* pixel_xy.xy = PIXELXY payload[0];
225 */
226 emit_op(c,
227 WM_PIXELXY,
228 dst_mask(pixel_xy, WRITEMASK_XY),
229 0, 0, 0,
230 payload_r0_depth,
231 src_undef(),
232 src_undef());
233
234 c->pixel_xy = src_reg_from_dst(pixel_xy);
235 }
236
237 return c->pixel_xy;
238 }
239
240 static struct prog_src_register get_delta_xy( struct brw_wm_compile *c )
241 {
242 if (src_is_undef(c->delta_xy)) {
243 struct prog_dst_register delta_xy = get_temp(c);
244 struct prog_src_register pixel_xy = get_pixel_xy(c);
245 struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
246
247 /* deltas.xy = DELTAXY pixel_xy, payload[0]
248 */
249 emit_op(c,
250 WM_DELTAXY,
251 dst_mask(delta_xy, WRITEMASK_XY),
252 0, 0, 0,
253 pixel_xy,
254 payload_r0_depth,
255 src_undef());
256
257 c->delta_xy = src_reg_from_dst(delta_xy);
258 }
259
260 return c->delta_xy;
261 }
262
263 static struct prog_src_register get_pixel_w( struct brw_wm_compile *c )
264 {
265 if (src_is_undef(c->pixel_w)) {
266 struct prog_dst_register pixel_w = get_temp(c);
267 struct prog_src_register deltas = get_delta_xy(c);
268 struct prog_src_register interp_wpos = src_reg(PROGRAM_PAYLOAD, FRAG_ATTRIB_WPOS);
269
270
271 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
272 */
273 emit_op(c,
274 WM_PIXELW,
275 dst_mask(pixel_w, WRITEMASK_W),
276 0, 0, 0,
277 interp_wpos,
278 deltas,
279 src_undef());
280
281
282 c->pixel_w = src_reg_from_dst(pixel_w);
283 }
284
285 return c->pixel_w;
286 }
287
288 static void emit_interp( struct brw_wm_compile *c,
289 GLuint idx )
290 {
291 struct prog_dst_register dst = dst_reg(PROGRAM_INPUT, idx);
292 struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
293 struct prog_src_register deltas = get_delta_xy(c);
294 struct prog_src_register arg2;
295 GLuint opcode;
296
297 /* Need to use PINTERP on attributes which have been
298 * multiplied by 1/W in the SF program, and LINTERP on those
299 * which have not:
300 */
301 switch (idx) {
302 case FRAG_ATTRIB_WPOS:
303 opcode = WM_LINTERP;
304 arg2 = src_undef();
305
306 /* Have to treat wpos.xy specially:
307 */
308 emit_op(c,
309 WM_WPOSXY,
310 dst_mask(dst, WRITEMASK_XY),
311 0, 0, 0,
312 get_pixel_xy(c),
313 src_undef(),
314 src_undef());
315
316 dst = dst_mask(dst, WRITEMASK_ZW);
317
318 /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
319 */
320 emit_op(c,
321 WM_LINTERP,
322 dst,
323 0, 0, 0,
324 interp,
325 deltas,
326 arg2);
327 break;
328 case FRAG_ATTRIB_COL0:
329 case FRAG_ATTRIB_COL1:
330 if (c->key.flat_shade) {
331 emit_op(c,
332 WM_CINTERP,
333 dst,
334 0, 0, 0,
335 interp,
336 src_undef(),
337 src_undef());
338 }
339 else {
340 emit_op(c,
341 WM_LINTERP,
342 dst,
343 0, 0, 0,
344 interp,
345 deltas,
346 src_undef());
347 }
348 break;
349 default:
350 emit_op(c,
351 WM_PINTERP,
352 dst,
353 0, 0, 0,
354 interp,
355 deltas,
356 get_pixel_w(c));
357 break;
358 }
359
360 c->fp_interp_emitted |= 1<<idx;
361 }
362
363
364 /***********************************************************************
365 * Hacks to extend the program parameter and constant lists.
366 */
367
368 /* Add the fog parameters to the parameter list of the original
369 * program, rather than creating a new list. Doesn't really do any
370 * harm and it's not as if the parameter handling isn't a big hack
371 * anyway.
372 */
373 static struct prog_src_register search_or_add_param6( struct brw_wm_compile *c,
374 GLint s0,
375 GLint s1,
376 GLint s2,
377 GLint s3,
378 GLint s4,
379 GLint s5)
380 {
381 struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
382 GLint tokens[6];
383 GLuint idx;
384 tokens[0] = s0;
385 tokens[1] = s1;
386 tokens[2] = s2;
387 tokens[3] = s3;
388 tokens[4] = s4;
389 tokens[5] = s5;
390
391 for (idx = 0; idx < paramList->NumParameters; idx++) {
392 if (paramList->Parameters[idx].Type == PROGRAM_STATE_VAR &&
393 memcmp(paramList->Parameters[idx].StateIndexes, tokens, sizeof(tokens)) == 0)
394 return src_reg(PROGRAM_STATE_VAR, idx);
395 }
396
397 idx = _mesa_add_state_reference( paramList, tokens );
398
399 /* Recalculate state dependency:
400 */
401 c->fp->param_state = brw_parameter_list_state_flags( paramList );
402
403 return src_reg(PROGRAM_STATE_VAR, idx);
404 }
405
406
407 static struct prog_src_register search_or_add_const4f( struct brw_wm_compile *c,
408 GLfloat s0,
409 GLfloat s1,
410 GLfloat s2,
411 GLfloat s3)
412 {
413 struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
414 GLfloat values[4];
415 GLuint idx;
416
417 values[0] = s0;
418 values[1] = s1;
419 values[2] = s2;
420 values[3] = s3;
421
422 /* Have to search, otherwise multiple compilations will each grow
423 * the parameter list.
424 */
425 for (idx = 0; idx < paramList->NumParameters; idx++) {
426 if (paramList->Parameters[idx].Type == PROGRAM_CONSTANT &&
427 memcmp(paramList->ParameterValues[idx], values, sizeof(values)) == 0)
428
429 /* XXX: this mimics the mesa bug which puts all constants and
430 * parameters into the "PROGRAM_STATE_VAR" category:
431 */
432 return src_reg(PROGRAM_STATE_VAR, idx);
433 }
434
435 idx = _mesa_add_unnamed_constant( paramList, values );
436
437 return src_reg(PROGRAM_STATE_VAR, idx);
438 }
439
440
441
442 /***********************************************************************
443 * Expand various instructions here to simpler forms.
444 */
445 static void precalc_dst( struct brw_wm_compile *c,
446 const struct prog_instruction *inst )
447 {
448 struct prog_src_register src0 = inst->SrcReg[0];
449 struct prog_src_register src1 = inst->SrcReg[1];
450 struct prog_dst_register dst = inst->DstReg;
451
452 if (dst.WriteMask & WRITEMASK_Y) {
453 /* dst.y = mul src0.y, src1.y
454 */
455 emit_op(c,
456 OPCODE_MUL,
457 dst_mask(dst, WRITEMASK_Y),
458 inst->SaturateMode, 0, 0,
459 src0,
460 src1,
461 src_undef());
462 }
463
464
465 if (dst.WriteMask & WRITEMASK_XZ) {
466 GLuint z = GET_SWZ(src0.Swizzle, Z);
467
468 /* dst.xz = swz src0.1zzz
469 */
470 emit_op(c,
471 OPCODE_SWZ,
472 dst_mask(dst, WRITEMASK_XZ),
473 inst->SaturateMode, 0, 0,
474 src_swizzle(src0, SWIZZLE_ONE, z, z, z),
475 src_undef(),
476 src_undef());
477 }
478 if (dst.WriteMask & WRITEMASK_W) {
479 /* dst.w = mov src1.w
480 */
481 emit_op(c,
482 OPCODE_MOV,
483 dst_mask(dst, WRITEMASK_W),
484 inst->SaturateMode, 0, 0,
485 src1,
486 src_undef(),
487 src_undef());
488 }
489 }
490
491
492 static void precalc_lit( struct brw_wm_compile *c,
493 const struct prog_instruction *inst )
494 {
495 struct prog_src_register src0 = inst->SrcReg[0];
496 struct prog_dst_register dst = inst->DstReg;
497
498 if (dst.WriteMask & WRITEMASK_XW) {
499 /* dst.xw = swz src0.1111
500 */
501 emit_op(c,
502 OPCODE_SWZ,
503 dst_mask(dst, WRITEMASK_XW),
504 0, 0, 0,
505 src_swizzle1(src0, SWIZZLE_ONE),
506 src_undef(),
507 src_undef());
508 }
509
510
511 if (dst.WriteMask & WRITEMASK_YZ) {
512 emit_op(c,
513 OPCODE_LIT,
514 dst_mask(dst, WRITEMASK_YZ),
515 inst->SaturateMode, 0, 0,
516 src0,
517 src_undef(),
518 src_undef());
519 }
520 }
521
522 static void precalc_tex( struct brw_wm_compile *c,
523 const struct prog_instruction *inst )
524 {
525 struct prog_src_register coord;
526 struct prog_dst_register tmpcoord;
527
528 if (inst->TexSrcTarget == TEXTURE_RECT_INDEX) {
529 struct prog_src_register scale =
530 search_or_add_param6( c,
531 STATE_INTERNAL,
532 STATE_TEXRECT_SCALE,
533 inst->TexSrcUnit,
534 0,0,0 );
535
536 tmpcoord = get_temp(c);
537
538 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
539 */
540 emit_op(c,
541 OPCODE_MUL,
542 tmpcoord,
543 0, 0, 0,
544 inst->SrcReg[0],
545 scale,
546 src_undef());
547
548 coord = src_reg_from_dst(tmpcoord);
549 }
550 else {
551 coord = inst->SrcReg[0];
552 }
553
554 /* Need to emit YUV texture conversions by hand. Probably need to
555 * do this here - the alternative is in brw_wm_emit.c, but the
556 * conversion requires allocating a temporary variable which we
557 * don't have the facility to do that late in the compilation.
558 */
559 if (!(c->key.yuvtex_mask & (1<<inst->TexSrcUnit))) {
560 emit_op(c,
561 OPCODE_TEX,
562 inst->DstReg,
563 inst->SaturateMode,
564 inst->TexSrcUnit,
565 inst->TexSrcTarget,
566 coord,
567 src_undef(),
568 src_undef());
569 }
570 else {
571 /*
572 CONST C0 = { -.5, -.0625, -.5, 1.164 }
573 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
574 UYV = TEX ...
575 UYV.xyz = ADD UYV, C0
576 UYV.y = MUL UYV.y, C0.w
577 RGB.xyz = MAD UYV.xxz, C1, UYV.y
578 RGB.y = MAD UYV.z, C1.w, RGB.y
579 */
580 struct prog_dst_register dst = inst->DstReg;
581 struct prog_src_register src0 = inst->SrcReg[0];
582 struct prog_dst_register tmp = get_temp(c);
583 struct prog_src_register tmpsrc = src_reg_from_dst(tmp);
584 struct prog_src_register C0 = search_or_add_const4f( c, -.5, -.0625, -.5, 1.164 );
585 struct prog_src_register C1 = search_or_add_const4f( c, 1.596, -0.813, 2.018, -.391 );
586
587 /* tmp = TEX ...
588 */
589 emit_op(c,
590 OPCODE_TEX,
591 tmp,
592 inst->SaturateMode,
593 inst->TexSrcUnit,
594 inst->TexSrcTarget,
595 src0,
596 src_undef(),
597 src_undef());
598
599 /* tmp.xyz = ADD TMP, C0
600 */
601 emit_op(c,
602 OPCODE_ADD,
603 dst_mask(tmp, WRITEMASK_XYZ),
604 0, 0, 0,
605 tmpsrc,
606 C0,
607 src_undef());
608
609 /* YUV.y = MUL YUV.y, C0.w
610 */
611 emit_op(c,
612 OPCODE_MUL,
613 dst_mask(tmp, WRITEMASK_Y),
614 0, 0, 0,
615 tmpsrc,
616 src_swizzle1(C0, W),
617 src_undef());
618
619 /* RGB.xyz = MAD YUV.xxz, C1, YUV.y
620 */
621 emit_op(c,
622 OPCODE_MAD,
623 dst_mask(dst, WRITEMASK_XYZ),
624 0, 0, 0,
625 src_swizzle(tmpsrc, X,X,Z,Z),
626 C1,
627 src_swizzle1(tmpsrc, Y));
628
629 /* RGB.y = MAD YUV.z, C1.w, RGB.y
630 */
631 emit_op(c,
632 OPCODE_MAD,
633 dst_mask(dst, WRITEMASK_Y),
634 0, 0, 0,
635 src_swizzle1(tmpsrc, Z),
636 src_swizzle1(C1, W),
637 src_swizzle1(src_reg_from_dst(dst), Y));
638
639 release_temp(c, tmp);
640 }
641
642 if (inst->TexSrcTarget == GL_TEXTURE_RECTANGLE_NV)
643 release_temp(c, tmpcoord);
644 }
645
646
647 static GLboolean projtex( struct brw_wm_compile *c,
648 const struct prog_instruction *inst )
649 {
650 struct prog_src_register src = inst->SrcReg[0];
651
652 /* Only try to detect the simplest cases. Could detect (later)
653 * cases where we are trying to emit code like RCP {1.0}, MUL x,
654 * {1.0}, and so on.
655 *
656 * More complex cases than this typically only arise from
657 * user-provided fragment programs anyway:
658 */
659 if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX)
660 return 0; /* ut2004 gun rendering !?! */
661 else if (src.File == PROGRAM_INPUT &&
662 GET_SWZ(src.Swizzle, W) == W &&
663 (c->key.projtex_mask & (1<<src.Index)) == 0)
664 return 0;
665 else
666 return 1;
667 }
668
669
670 static void precalc_txp( struct brw_wm_compile *c,
671 const struct prog_instruction *inst )
672 {
673 struct prog_src_register src0 = inst->SrcReg[0];
674
675 if (projtex(c, inst)) {
676 struct prog_dst_register tmp = get_temp(c);
677 struct prog_instruction tmp_inst;
678
679 /* tmp0.w = RCP inst.arg[0][3]
680 */
681 emit_op(c,
682 OPCODE_RCP,
683 dst_mask(tmp, WRITEMASK_W),
684 0, 0, 0,
685 src_swizzle1(src0, GET_SWZ(src0.Swizzle, W)),
686 src_undef(),
687 src_undef());
688
689 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
690 */
691 emit_op(c,
692 OPCODE_MUL,
693 dst_mask(tmp, WRITEMASK_XYZ),
694 0, 0, 0,
695 src0,
696 src_swizzle1(src_reg_from_dst(tmp), W),
697 src_undef());
698
699 /* dst = precalc(TEX tmp0)
700 */
701 tmp_inst = *inst;
702 tmp_inst.SrcReg[0] = src_reg_from_dst(tmp);
703 precalc_tex(c, &tmp_inst);
704
705 release_temp(c, tmp);
706 }
707 else
708 {
709 /* dst = precalc(TEX src0)
710 */
711 precalc_tex(c, inst);
712 }
713 }
714
715
716
717
718
719 /***********************************************************************
720 * Add instructions to perform fog blending
721 */
722
723 static void fog_blend( struct brw_wm_compile *c,
724 struct prog_src_register fog_factor )
725 {
726 struct prog_dst_register outcolor = dst_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
727 struct prog_src_register fogcolor = search_or_add_param6( c, STATE_FOG_COLOR, 0,0,0,0,0 );
728
729 /* color.xyz = LRP fog_factor.xxxx, output_color, fog_color */
730
731 emit_op(c,
732 OPCODE_LRP,
733 dst_mask(outcolor, WRITEMASK_XYZ),
734 0, 0, 0,
735 fog_factor,
736 src_reg_from_dst(outcolor),
737 fogcolor);
738 }
739
740
741
742 /* This one is simple - just take the interpolated fog coordinate and
743 * use it as the fog blend factor.
744 */
745 static void fog_interpolated( struct brw_wm_compile *c )
746 {
747 struct prog_src_register fogc = src_reg(PROGRAM_INPUT, FRAG_ATTRIB_FOGC);
748
749 if (!(c->fp_interp_emitted & (1<<FRAG_ATTRIB_FOGC)))
750 emit_interp(c, FRAG_ATTRIB_FOGC);
751
752 fog_blend( c, src_swizzle1(fogc, GET_SWZ(fogc.Swizzle,X)));
753 }
754
755 static void emit_fog( struct brw_wm_compile *c )
756 {
757 if (!c->fp->program.FogOption)
758 return;
759
760 if (1)
761 fog_interpolated( c );
762 else {
763 /* TODO: per-pixel fog */
764 assert(0);
765 }
766 }
767
768 static void emit_fb_write( struct brw_wm_compile *c )
769 {
770 struct prog_src_register outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
771 struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
772 struct prog_src_register outdepth = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DEPR);
773
774 emit_op(c,
775 WM_FB_WRITE,
776 dst_mask(dst_undef(),0),
777 0, 0, 0,
778 outcolor,
779 payload_r0_depth,
780 outdepth);
781 }
782
783
784
785
786 /***********************************************************************
787 * Emit INTERP instructions ahead of first use of each attrib.
788 */
789
790 static void validate_src_regs( struct brw_wm_compile *c,
791 const struct prog_instruction *inst )
792 {
793 GLuint nr_args = brw_wm_nr_args( inst->Opcode );
794 GLuint i;
795
796 for (i = 0; i < nr_args; i++) {
797 if (inst->SrcReg[i].File == PROGRAM_INPUT) {
798 GLuint idx = inst->SrcReg[i].Index;
799 if (!(c->fp_interp_emitted & (1<<idx))) {
800 emit_interp(c, idx);
801 }
802 }
803 }
804 }
805
806
807
808 static void print_insns( const struct prog_instruction *insn,
809 GLuint nr )
810 {
811 GLuint i;
812 for (i = 0; i < nr; i++, insn++) {
813 _mesa_printf("%3d: ", i);
814 if (insn->Opcode < MAX_OPCODE)
815 _mesa_print_instruction(insn);
816 else if (insn->Opcode < MAX_WM_OPCODE) {
817 GLuint idx = insn->Opcode - MAX_OPCODE;
818
819 _mesa_print_alu_instruction(insn,
820 wm_opcode_strings[idx],
821 3);
822 }
823 else
824 _mesa_printf("UNKNOWN\n");
825
826 }
827 }
828
829 void brw_wm_pass_fp( struct brw_wm_compile *c )
830 {
831 struct brw_fragment_program *fp = c->fp;
832 GLuint insn;
833
834 if (INTEL_DEBUG & DEBUG_WM) {
835 _mesa_printf("\n\n\npre-fp:\n");
836 _mesa_print_program(&fp->program.Base);
837 _mesa_printf("\n");
838 }
839
840 c->pixel_xy = src_undef();
841 c->delta_xy = src_undef();
842 c->pixel_w = src_undef();
843 c->nr_fp_insns = 0;
844
845 /* Emit preamble instructions:
846 */
847
848
849 for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
850 const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
851 struct prog_instruction *out;
852
853 /* Check for INPUT values, emit INTERP instructions where
854 * necessary:
855 */
856 validate_src_regs(c, inst);
857
858
859 switch (inst->Opcode) {
860 case OPCODE_SWZ:
861 out = emit_insn(c, inst);
862 out->Opcode = OPCODE_MOV;
863 break;
864
865 case OPCODE_ABS:
866 out = emit_insn(c, inst);
867 out->Opcode = OPCODE_MOV;
868 out->SrcReg[0].NegateBase = 0;
869 out->SrcReg[0].Abs = 1;
870 break;
871
872 case OPCODE_SUB:
873 out = emit_insn(c, inst);
874 out->Opcode = OPCODE_ADD;
875 out->SrcReg[1].NegateBase ^= 0xf;
876 break;
877
878 case OPCODE_SCS:
879 out = emit_insn(c, inst);
880 /* This should probably be done in the parser.
881 */
882 out->DstReg.WriteMask &= WRITEMASK_XY;
883 break;
884
885 case OPCODE_DST:
886 precalc_dst(c, inst);
887 break;
888
889 case OPCODE_LIT:
890 precalc_lit(c, inst);
891 break;
892
893 case OPCODE_TXP:
894 precalc_txp(c, inst);
895 break;
896
897 case OPCODE_XPD:
898 out = emit_insn(c, inst);
899 /* This should probably be done in the parser.
900 */
901 out->DstReg.WriteMask &= WRITEMASK_XYZ;
902 break;
903
904 case OPCODE_KIL:
905 out = emit_insn(c, inst);
906 /* This should probably be done in the parser.
907 */
908 out->DstReg.WriteMask = 0;
909 break;
910
911 case OPCODE_END:
912 case OPCODE_PRINT:
913 break;
914
915 default:
916 emit_insn(c, inst);
917 break;
918 }
919 }
920
921 emit_fog(c);
922 emit_fb_write(c);
923
924
925 if (INTEL_DEBUG & DEBUG_WM) {
926 _mesa_printf("\n\n\npass_fp:\n");
927 print_insns( c->prog_instructions, c->nr_fp_insns );
928 _mesa_printf("\n");
929 }
930 }
931