2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
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:
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.
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.
26 **********************************************************************/
29 * Keith Whitwell <keith@tungstengraphics.com>
33 #include "main/glheader.h"
34 #include "main/macros.h"
35 #include "main/enums.h"
36 #include "brw_context.h"
40 #include "shader/prog_parameter.h"
41 #include "shader/prog_print.h"
42 #include "shader/prog_statevars.h"
45 #define FIRST_INTERNAL_TEMP MAX_NV_FRAGMENT_PROGRAM_TEMPS
53 static const char *wm_opcode_strings
[] = {
66 static const char *wm_file_strings
[] = {
72 /***********************************************************************
76 static struct prog_src_register
src_reg(GLuint file
, GLuint idx
)
78 struct prog_src_register reg
;
81 reg
.Swizzle
= SWIZZLE_NOOP
;
83 reg
.Negate
= NEGATE_NONE
;
88 static struct prog_src_register
src_reg_from_dst(struct prog_dst_register dst
)
90 return src_reg(dst
.File
, dst
.Index
);
93 static struct prog_src_register
src_undef( void )
95 return src_reg(PROGRAM_UNDEFINED
, 0);
98 static GLboolean
src_is_undef(struct prog_src_register src
)
100 return src
.File
== PROGRAM_UNDEFINED
;
103 static struct prog_src_register
src_swizzle( struct prog_src_register reg
, int x
, int y
, int z
, int w
)
105 reg
.Swizzle
= MAKE_SWIZZLE4(x
,y
,z
,w
);
109 static struct prog_src_register
src_swizzle1( struct prog_src_register reg
, int x
)
111 return src_swizzle(reg
, x
, x
, x
, x
);
114 static struct prog_src_register
src_swizzle4( struct prog_src_register reg
, uint swizzle
)
116 reg
.Swizzle
= swizzle
;
121 /***********************************************************************
125 static struct prog_dst_register
dst_reg(GLuint file
, GLuint idx
)
127 struct prog_dst_register reg
;
130 reg
.WriteMask
= WRITEMASK_XYZW
;
132 reg
.CondMask
= COND_TR
;
139 static struct prog_dst_register
dst_mask( struct prog_dst_register reg
, int mask
)
141 reg
.WriteMask
&= mask
;
145 static struct prog_dst_register
dst_undef( void )
147 return dst_reg(PROGRAM_UNDEFINED
, 0);
152 static struct prog_dst_register
get_temp( struct brw_wm_compile
*c
)
154 int bit
= _mesa_ffs( ~c
->fp_temp
);
157 _mesa_printf("%s: out of temporaries\n", __FILE__
);
161 c
->fp_temp
|= 1<<(bit
-1);
162 return dst_reg(PROGRAM_TEMPORARY
, FIRST_INTERNAL_TEMP
+(bit
-1));
166 static void release_temp( struct brw_wm_compile
*c
, struct prog_dst_register temp
)
168 c
->fp_temp
&= ~(1 << (temp
.Index
- FIRST_INTERNAL_TEMP
));
172 /***********************************************************************
176 static struct prog_instruction
*get_fp_inst(struct brw_wm_compile
*c
)
178 return &c
->prog_instructions
[c
->nr_fp_insns
++];
181 static struct prog_instruction
*emit_insn(struct brw_wm_compile
*c
,
182 const struct prog_instruction
*inst0
)
184 struct prog_instruction
*inst
= get_fp_inst(c
);
189 static struct prog_instruction
* emit_tex_op(struct brw_wm_compile
*c
,
191 struct prog_dst_register dest
,
194 GLuint tex_src_target
,
196 struct prog_src_register src0
,
197 struct prog_src_register src1
,
198 struct prog_src_register src2
)
200 struct prog_instruction
*inst
= get_fp_inst(c
);
202 memset(inst
, 0, sizeof(*inst
));
206 inst
->SaturateMode
= saturate
;
207 inst
->TexSrcUnit
= tex_src_unit
;
208 inst
->TexSrcTarget
= tex_src_target
;
209 inst
->TexShadow
= tex_shadow
;
210 inst
->SrcReg
[0] = src0
;
211 inst
->SrcReg
[1] = src1
;
212 inst
->SrcReg
[2] = src2
;
217 static struct prog_instruction
* emit_op(struct brw_wm_compile
*c
,
219 struct prog_dst_register dest
,
221 struct prog_src_register src0
,
222 struct prog_src_register src1
,
223 struct prog_src_register src2
)
225 return emit_tex_op(c
, op
, dest
, saturate
,
226 0, 0, 0, /* tex unit, target, shadow */
231 /* Many Mesa opcodes produce the same value across all the result channels.
232 * We'd rather not have to support that splatting in the opcode implementations,
233 * and brw_wm_pass*.c wants to optimize them out by shuffling references around
234 * anyway. We can easily get both by emitting the opcode to one channel, and
235 * then MOVing it to the others, which brw_wm_pass*.c already understands.
237 static struct prog_instruction
*emit_scalar_insn(struct brw_wm_compile
*c
,
238 const struct prog_instruction
*inst0
)
240 struct prog_instruction
*inst
;
241 unsigned int dst_chan
;
242 unsigned int other_channel_mask
;
244 if (inst0
->DstReg
.WriteMask
== 0)
247 dst_chan
= _mesa_ffs(inst0
->DstReg
.WriteMask
) - 1;
248 inst
= get_fp_inst(c
);
250 inst
->DstReg
.WriteMask
= 1 << dst_chan
;
252 other_channel_mask
= inst0
->DstReg
.WriteMask
& ~(1 << dst_chan
);
253 if (other_channel_mask
!= 0) {
256 dst_mask(inst0
->DstReg
, other_channel_mask
),
258 src_swizzle1(src_reg_from_dst(inst0
->DstReg
), dst_chan
),
266 /***********************************************************************
267 * Special instructions for interpolation and other tasks
270 static struct prog_src_register
get_pixel_xy( struct brw_wm_compile
*c
)
272 if (src_is_undef(c
->pixel_xy
)) {
273 struct prog_dst_register pixel_xy
= get_temp(c
);
274 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
277 /* Emit the out calculations, and hold onto the results. Use
278 * two instructions as a temporary is required.
280 /* pixel_xy.xy = PIXELXY payload[0];
284 dst_mask(pixel_xy
, WRITEMASK_XY
),
290 c
->pixel_xy
= src_reg_from_dst(pixel_xy
);
296 static struct prog_src_register
get_delta_xy( struct brw_wm_compile
*c
)
298 if (src_is_undef(c
->delta_xy
)) {
299 struct prog_dst_register delta_xy
= get_temp(c
);
300 struct prog_src_register pixel_xy
= get_pixel_xy(c
);
301 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
303 /* deltas.xy = DELTAXY pixel_xy, payload[0]
307 dst_mask(delta_xy
, WRITEMASK_XY
),
313 c
->delta_xy
= src_reg_from_dst(delta_xy
);
319 static struct prog_src_register
get_pixel_w( struct brw_wm_compile
*c
)
321 if (src_is_undef(c
->pixel_w
)) {
322 struct prog_dst_register pixel_w
= get_temp(c
);
323 struct prog_src_register deltas
= get_delta_xy(c
);
324 struct prog_src_register interp_wpos
= src_reg(PROGRAM_PAYLOAD
, FRAG_ATTRIB_WPOS
);
326 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
330 dst_mask(pixel_w
, WRITEMASK_W
),
337 c
->pixel_w
= src_reg_from_dst(pixel_w
);
343 static void emit_interp( struct brw_wm_compile
*c
,
346 struct prog_dst_register dst
= dst_reg(PROGRAM_INPUT
, idx
);
347 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
348 struct prog_src_register deltas
= get_delta_xy(c
);
350 /* Need to use PINTERP on attributes which have been
351 * multiplied by 1/W in the SF program, and LINTERP on those
355 case FRAG_ATTRIB_WPOS
:
356 /* Have to treat wpos.xy specially:
360 dst_mask(dst
, WRITEMASK_XY
),
366 dst
= dst_mask(dst
, WRITEMASK_ZW
);
368 /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
378 case FRAG_ATTRIB_COL0
:
379 case FRAG_ATTRIB_COL1
:
380 if (c
->key
.flat_shade
) {
390 if (c
->key
.linear_color
) {
400 /* perspective-corrected color interpolation */
411 case FRAG_ATTRIB_FOGC
:
412 /* The FOGC input is really special. When a program uses glFogFragCoord,
413 * the results returned are supposed to be (f,0,0,1). But for Mesa GLSL,
414 * the glFrontFacing and glPointCoord values are also stashed in FOGC.
415 * So, write the interpolated fog value to X, then either 0, 1, or the
416 * stashed values to Y, Z, W. Note that this means that
417 * glFogFragCoord.yzw can be wrong in those cases!
420 /* Interpolate the fog coordinate */
423 dst_mask(dst
, WRITEMASK_X
),
429 /* Move the front facing value into FOGC.y if it's needed. */
430 if (c
->fp
->program
.UsesFrontFacing
) {
433 dst_mask(dst
, WRITEMASK_Y
),
441 dst_mask(dst
, WRITEMASK_Y
),
443 src_swizzle1(interp
, SWIZZLE_ZERO
),
448 /* Should do the PointCoord thing here. */
451 dst_mask(dst
, WRITEMASK_ZW
),
472 c
->fp_interp_emitted
|= 1<<idx
;
475 static void emit_ddx( struct brw_wm_compile
*c
,
476 const struct prog_instruction
*inst
)
478 GLuint idx
= inst
->SrcReg
[0].Index
;
479 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
481 c
->fp_deriv_emitted
|= 1<<idx
;
491 static void emit_ddy( struct brw_wm_compile
*c
,
492 const struct prog_instruction
*inst
)
494 GLuint idx
= inst
->SrcReg
[0].Index
;
495 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
497 c
->fp_deriv_emitted
|= 1<<idx
;
507 /***********************************************************************
508 * Hacks to extend the program parameter and constant lists.
511 /* Add the fog parameters to the parameter list of the original
512 * program, rather than creating a new list. Doesn't really do any
513 * harm and it's not as if the parameter handling isn't a big hack
516 static struct prog_src_register
search_or_add_param5(struct brw_wm_compile
*c
,
523 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
524 gl_state_index tokens
[STATE_LENGTH
];
532 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
533 if (paramList
->Parameters
[idx
].Type
== PROGRAM_STATE_VAR
&&
534 memcmp(paramList
->Parameters
[idx
].StateIndexes
, tokens
, sizeof(tokens
)) == 0)
535 return src_reg(PROGRAM_STATE_VAR
, idx
);
538 idx
= _mesa_add_state_reference( paramList
, tokens
);
540 return src_reg(PROGRAM_STATE_VAR
, idx
);
544 static struct prog_src_register
search_or_add_const4f( struct brw_wm_compile
*c
,
550 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
560 /* Have to search, otherwise multiple compilations will each grow
561 * the parameter list.
563 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
564 if (paramList
->Parameters
[idx
].Type
== PROGRAM_CONSTANT
&&
565 memcmp(paramList
->ParameterValues
[idx
], values
, sizeof(values
)) == 0)
567 /* XXX: this mimics the mesa bug which puts all constants and
568 * parameters into the "PROGRAM_STATE_VAR" category:
570 return src_reg(PROGRAM_STATE_VAR
, idx
);
573 idx
= _mesa_add_unnamed_constant( paramList
, values
, 4, &swizzle
);
574 assert(swizzle
== SWIZZLE_NOOP
); /* Need to handle swizzle in reg setup */
575 return src_reg(PROGRAM_STATE_VAR
, idx
);
580 /***********************************************************************
581 * Expand various instructions here to simpler forms.
583 static void precalc_dst( struct brw_wm_compile
*c
,
584 const struct prog_instruction
*inst
)
586 struct prog_src_register src0
= inst
->SrcReg
[0];
587 struct prog_src_register src1
= inst
->SrcReg
[1];
588 struct prog_dst_register dst
= inst
->DstReg
;
590 if (dst
.WriteMask
& WRITEMASK_Y
) {
591 /* dst.y = mul src0.y, src1.y
595 dst_mask(dst
, WRITEMASK_Y
),
602 if (dst
.WriteMask
& WRITEMASK_XZ
) {
603 struct prog_instruction
*swz
;
604 GLuint z
= GET_SWZ(src0
.Swizzle
, Z
);
606 /* dst.xz = swz src0.1zzz
610 dst_mask(dst
, WRITEMASK_XZ
),
612 src_swizzle(src0
, SWIZZLE_ONE
, z
, z
, z
),
615 /* Avoid letting negation flag of src0 affect our 1 constant. */
616 swz
->SrcReg
[0].Negate
&= ~NEGATE_X
;
618 if (dst
.WriteMask
& WRITEMASK_W
) {
619 /* dst.w = mov src1.w
623 dst_mask(dst
, WRITEMASK_W
),
632 static void precalc_lit( struct brw_wm_compile
*c
,
633 const struct prog_instruction
*inst
)
635 struct prog_src_register src0
= inst
->SrcReg
[0];
636 struct prog_dst_register dst
= inst
->DstReg
;
638 if (dst
.WriteMask
& WRITEMASK_XW
) {
639 struct prog_instruction
*swz
;
641 /* dst.xw = swz src0.1111
645 dst_mask(dst
, WRITEMASK_XW
),
647 src_swizzle1(src0
, SWIZZLE_ONE
),
650 /* Avoid letting the negation flag of src0 affect our 1 constant. */
651 swz
->SrcReg
[0].Negate
= NEGATE_NONE
;
654 if (dst
.WriteMask
& WRITEMASK_YZ
) {
657 dst_mask(dst
, WRITEMASK_YZ
),
667 * Some TEX instructions require extra code, cube map coordinate
668 * normalization, or coordinate scaling for RECT textures, etc.
669 * This function emits those extra instructions and the TEX
670 * instruction itself.
672 static void precalc_tex( struct brw_wm_compile
*c
,
673 const struct prog_instruction
*inst
)
675 struct prog_src_register coord
;
676 struct prog_dst_register tmpcoord
;
677 const GLuint unit
= c
->fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
679 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
) {
680 struct prog_instruction
*out
;
681 struct prog_dst_register tmp0
= get_temp(c
);
682 struct prog_src_register tmp0src
= src_reg_from_dst(tmp0
);
683 struct prog_dst_register tmp1
= get_temp(c
);
684 struct prog_src_register tmp1src
= src_reg_from_dst(tmp1
);
685 struct prog_src_register src0
= inst
->SrcReg
[0];
687 /* find longest component of coord vector and normalize it */
688 tmpcoord
= get_temp(c
);
689 coord
= src_reg_from_dst(tmpcoord
);
691 /* tmpcoord = src0 (i.e.: coord = src0) */
692 out
= emit_op(c
, OPCODE_MOV
,
698 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
699 out
->SrcReg
[0].Abs
= 1;
701 /* tmp0 = MAX(coord.X, coord.Y) */
702 emit_op(c
, OPCODE_MAX
,
705 src_swizzle1(coord
, X
),
706 src_swizzle1(coord
, Y
),
709 /* tmp1 = MAX(tmp0, coord.Z) */
710 emit_op(c
, OPCODE_MAX
,
714 src_swizzle1(coord
, Z
),
717 /* tmp0 = 1 / tmp1 */
718 emit_op(c
, OPCODE_RCP
,
725 /* tmpCoord = src0 * tmp0 */
726 emit_op(c
, OPCODE_MUL
,
733 release_temp(c
, tmp0
);
734 release_temp(c
, tmp1
);
736 else if (inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) {
737 struct prog_src_register scale
=
738 search_or_add_param5( c
,
744 tmpcoord
= get_temp(c
);
746 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
760 coord
= src_reg_from_dst(tmpcoord
);
763 coord
= inst
->SrcReg
[0];
766 /* Need to emit YUV texture conversions by hand. Probably need to
767 * do this here - the alternative is in brw_wm_emit.c, but the
768 * conversion requires allocating a temporary variable which we
769 * don't have the facility to do that late in the compilation.
771 if (c
->key
.yuvtex_mask
& (1 << unit
)) {
772 /* convert ycbcr to RGBA */
773 GLboolean swap_uv
= c
->key
.yuvtex_swap_mask
& (1<<unit
);
776 CONST C0 = { -.5, -.0625, -.5, 1.164 }
777 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
779 UYV.xyz = ADD UYV, C0
780 UYV.y = MUL UYV.y, C0.w
782 RGB.xyz = MAD UYV.zzx, C1, UYV.y
784 RGB.xyz = MAD UYV.xxz, C1, UYV.y
785 RGB.y = MAD UYV.z, C1.w, RGB.y
787 struct prog_dst_register dst
= inst
->DstReg
;
788 struct prog_dst_register tmp
= get_temp(c
);
789 struct prog_src_register tmpsrc
= src_reg_from_dst(tmp
);
790 struct prog_src_register C0
= search_or_add_const4f( c
, -.5, -.0625, -.5, 1.164 );
791 struct prog_src_register C1
= search_or_add_const4f( c
, 1.596, -0.813, 2.018, -.391 );
806 /* tmp.xyz = ADD TMP, C0
810 dst_mask(tmp
, WRITEMASK_XYZ
),
816 /* YUV.y = MUL YUV.y, C0.w
821 dst_mask(tmp
, WRITEMASK_Y
),
829 * RGB.xyz = MAD YUV.zzx, C1, YUV.y
831 * RGB.xyz = MAD YUV.xxz, C1, YUV.y
836 dst_mask(dst
, WRITEMASK_XYZ
),
838 swap_uv
?src_swizzle(tmpsrc
, Z
,Z
,X
,X
):src_swizzle(tmpsrc
, X
,X
,Z
,Z
),
840 src_swizzle1(tmpsrc
, Y
));
842 /* RGB.y = MAD YUV.z, C1.w, RGB.y
846 dst_mask(dst
, WRITEMASK_Y
),
848 src_swizzle1(tmpsrc
, Z
),
850 src_swizzle1(src_reg_from_dst(dst
), Y
));
852 release_temp(c
, tmp
);
855 /* ordinary RGBA tex instruction */
868 /* For GL_EXT_texture_swizzle: */
869 if (c
->key
.tex_swizzles
[unit
] != SWIZZLE_NOOP
) {
870 /* swizzle the result of the TEX instruction */
871 struct prog_src_register tmpsrc
= src_reg_from_dst(inst
->DstReg
);
872 emit_op(c
, OPCODE_SWZ
,
874 SATURATE_OFF
, /* saturate already done above */
875 src_swizzle4(tmpsrc
, c
->key
.tex_swizzles
[unit
]),
880 if ((inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) ||
881 (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
))
882 release_temp(c
, tmpcoord
);
887 * Check if the given TXP instruction really needs the divide-by-W step.
889 static GLboolean
projtex( struct brw_wm_compile
*c
,
890 const struct prog_instruction
*inst
)
892 const struct prog_src_register src
= inst
->SrcReg
[0];
895 assert(inst
->Opcode
== OPCODE_TXP
);
897 /* Only try to detect the simplest cases. Could detect (later)
898 * cases where we are trying to emit code like RCP {1.0}, MUL x,
901 * More complex cases than this typically only arise from
902 * user-provided fragment programs anyway:
904 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
)
905 retVal
= GL_FALSE
; /* ut2004 gun rendering !?! */
906 else if (src
.File
== PROGRAM_INPUT
&&
907 GET_SWZ(src
.Swizzle
, W
) == W
&&
908 (c
->key
.proj_attrib_mask
& (1 << src
.Index
)) == 0)
920 static void precalc_txp( struct brw_wm_compile
*c
,
921 const struct prog_instruction
*inst
)
923 struct prog_src_register src0
= inst
->SrcReg
[0];
925 if (projtex(c
, inst
)) {
926 struct prog_dst_register tmp
= get_temp(c
);
927 struct prog_instruction tmp_inst
;
929 /* tmp0.w = RCP inst.arg[0][3]
933 dst_mask(tmp
, WRITEMASK_W
),
935 src_swizzle1(src0
, GET_SWZ(src0
.Swizzle
, W
)),
939 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
943 dst_mask(tmp
, WRITEMASK_XYZ
),
946 src_swizzle1(src_reg_from_dst(tmp
), W
),
949 /* dst = precalc(TEX tmp0)
952 tmp_inst
.SrcReg
[0] = src_reg_from_dst(tmp
);
953 precalc_tex(c
, &tmp_inst
);
955 release_temp(c
, tmp
);
959 /* dst = precalc(TEX src0)
961 precalc_tex(c
, inst
);
967 static void emit_fb_write( struct brw_wm_compile
*c
)
969 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
970 struct prog_src_register outdepth
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DEPTH
);
971 struct prog_src_register outcolor
;
974 struct prog_instruction
*inst
, *last_inst
;
975 struct brw_context
*brw
= c
->func
.brw
;
977 /* The inst->Aux field is used for FB write target and the EOT marker */
979 if (brw
->state
.nr_color_regions
> 1) {
980 for (i
= 0 ; i
< brw
->state
.nr_color_regions
; i
++) {
981 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
+ i
);
982 last_inst
= inst
= emit_op(c
,
983 WM_FB_WRITE
, dst_mask(dst_undef(),0), 0,
984 outcolor
, payload_r0_depth
, outdepth
);
986 if (c
->fp_fragcolor_emitted
) {
987 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
988 last_inst
= inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(),0),
989 0, outcolor
, payload_r0_depth
, outdepth
);
993 last_inst
->Aux
|= 1; //eot
996 /* if gl_FragData[0] is written, use it, else use gl_FragColor */
997 if (c
->fp
->program
.Base
.OutputsWritten
& (1 << FRAG_RESULT_DATA0
))
998 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
);
1000 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
1002 inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(),0),
1003 0, outcolor
, payload_r0_depth
, outdepth
);
1004 inst
->Aux
= 1|(0<<1);
1011 /***********************************************************************
1012 * Emit INTERP instructions ahead of first use of each attrib.
1015 static void validate_src_regs( struct brw_wm_compile
*c
,
1016 const struct prog_instruction
*inst
)
1018 GLuint nr_args
= brw_wm_nr_args( inst
->Opcode
);
1021 for (i
= 0; i
< nr_args
; i
++) {
1022 if (inst
->SrcReg
[i
].File
== PROGRAM_INPUT
) {
1023 GLuint idx
= inst
->SrcReg
[i
].Index
;
1024 if (!(c
->fp_interp_emitted
& (1<<idx
))) {
1025 emit_interp(c
, idx
);
1031 static void validate_dst_regs( struct brw_wm_compile
*c
,
1032 const struct prog_instruction
*inst
)
1034 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
) {
1035 GLuint idx
= inst
->DstReg
.Index
;
1036 if (idx
== FRAG_RESULT_COLOR
)
1037 c
->fp_fragcolor_emitted
= 1;
1041 static void print_insns( const struct prog_instruction
*insn
,
1045 for (i
= 0; i
< nr
; i
++, insn
++) {
1046 _mesa_printf("%3d: ", i
);
1047 if (insn
->Opcode
< MAX_OPCODE
)
1048 _mesa_print_instruction(insn
);
1049 else if (insn
->Opcode
< MAX_WM_OPCODE
) {
1050 GLuint idx
= insn
->Opcode
- MAX_OPCODE
;
1052 _mesa_print_alu_instruction(insn
,
1053 wm_opcode_strings
[idx
],
1057 _mesa_printf("965 Opcode %d\n", insn
->Opcode
);
1063 * Initial pass for fragment program code generation.
1064 * This function is used by both the GLSL and non-GLSL paths.
1066 void brw_wm_pass_fp( struct brw_wm_compile
*c
)
1068 struct brw_fragment_program
*fp
= c
->fp
;
1071 if (INTEL_DEBUG
& DEBUG_WM
) {
1072 _mesa_printf("pre-fp:\n");
1073 _mesa_print_program(&fp
->program
.Base
);
1077 c
->pixel_xy
= src_undef();
1078 c
->delta_xy
= src_undef();
1079 c
->pixel_w
= src_undef();
1082 /* Emit preamble instructions. This is where special instructions such as
1083 * WM_CINTERP, WM_LINTERP, WM_PINTERP and WM_WPOSXY are emitted to
1084 * compute shader inputs from varying vars.
1086 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1087 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1088 validate_src_regs(c
, inst
);
1089 validate_dst_regs(c
, inst
);
1092 /* Loop over all instructions doing assorted simplifications and
1095 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1096 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1097 struct prog_instruction
*out
;
1099 /* Check for INPUT values, emit INTERP instructions where
1103 switch (inst
->Opcode
) {
1105 out
= emit_insn(c
, inst
);
1106 out
->Opcode
= OPCODE_MOV
;
1110 out
= emit_insn(c
, inst
);
1111 out
->Opcode
= OPCODE_MOV
;
1112 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
1113 out
->SrcReg
[0].Abs
= 1;
1117 out
= emit_insn(c
, inst
);
1118 out
->Opcode
= OPCODE_ADD
;
1119 out
->SrcReg
[1].Negate
^= NEGATE_XYZW
;
1123 out
= emit_insn(c
, inst
);
1124 /* This should probably be done in the parser.
1126 out
->DstReg
.WriteMask
&= WRITEMASK_XY
;
1130 precalc_dst(c
, inst
);
1134 precalc_lit(c
, inst
);
1138 precalc_tex(c
, inst
);
1142 precalc_txp(c
, inst
);
1146 out
= emit_insn(c
, inst
);
1147 out
->TexSrcUnit
= fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
1151 out
= emit_insn(c
, inst
);
1152 /* This should probably be done in the parser.
1154 out
->DstReg
.WriteMask
&= WRITEMASK_XYZ
;
1158 out
= emit_insn(c
, inst
);
1159 /* This should probably be done in the parser.
1161 out
->DstReg
.WriteMask
= 0;
1175 if (brw_wm_is_scalar_result(inst
->Opcode
))
1176 emit_scalar_insn(c
, inst
);
1183 if (INTEL_DEBUG
& DEBUG_WM
) {
1184 _mesa_printf("pass_fp:\n");
1185 print_insns( c
->prog_instructions
, c
->nr_fp_insns
);