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 /** An invalid texture target */
46 #define TEX_TARGET_NONE NUM_TEXTURE_TARGETS
48 /** An invalid texture unit */
49 #define TEX_UNIT_NONE BRW_MAX_TEX_UNIT
51 #define FIRST_INTERNAL_TEMP MAX_NV_FRAGMENT_PROGRAM_TEMPS
59 static const char *wm_opcode_strings
[] = {
72 static const char *wm_file_strings
[] = {
78 /***********************************************************************
82 static struct prog_src_register
src_reg(GLuint file
, GLuint idx
)
84 struct prog_src_register reg
;
87 reg
.Swizzle
= SWIZZLE_NOOP
;
89 reg
.Negate
= NEGATE_NONE
;
94 static struct prog_src_register
src_reg_from_dst(struct prog_dst_register dst
)
96 return src_reg(dst
.File
, dst
.Index
);
99 static struct prog_src_register
src_undef( void )
101 return src_reg(PROGRAM_UNDEFINED
, 0);
104 static GLboolean
src_is_undef(struct prog_src_register src
)
106 return src
.File
== PROGRAM_UNDEFINED
;
109 static struct prog_src_register
src_swizzle( struct prog_src_register reg
, int x
, int y
, int z
, int w
)
111 reg
.Swizzle
= MAKE_SWIZZLE4(x
,y
,z
,w
);
115 static struct prog_src_register
src_swizzle1( struct prog_src_register reg
, int x
)
117 return src_swizzle(reg
, x
, x
, x
, x
);
120 static struct prog_src_register
src_swizzle4( struct prog_src_register reg
, uint swizzle
)
122 reg
.Swizzle
= swizzle
;
127 /***********************************************************************
131 static struct prog_dst_register
dst_reg(GLuint file
, GLuint idx
)
133 struct prog_dst_register reg
;
136 reg
.WriteMask
= WRITEMASK_XYZW
;
138 reg
.CondMask
= COND_TR
;
145 static struct prog_dst_register
dst_mask( struct prog_dst_register reg
, int mask
)
147 reg
.WriteMask
&= mask
;
151 static struct prog_dst_register
dst_undef( void )
153 return dst_reg(PROGRAM_UNDEFINED
, 0);
158 static struct prog_dst_register
get_temp( struct brw_wm_compile
*c
)
160 int bit
= _mesa_ffs( ~c
->fp_temp
);
163 _mesa_printf("%s: out of temporaries\n", __FILE__
);
167 c
->fp_temp
|= 1<<(bit
-1);
168 return dst_reg(PROGRAM_TEMPORARY
, FIRST_INTERNAL_TEMP
+(bit
-1));
172 static void release_temp( struct brw_wm_compile
*c
, struct prog_dst_register temp
)
174 c
->fp_temp
&= ~(1 << (temp
.Index
- FIRST_INTERNAL_TEMP
));
178 /***********************************************************************
182 static struct prog_instruction
*get_fp_inst(struct brw_wm_compile
*c
)
184 return &c
->prog_instructions
[c
->nr_fp_insns
++];
187 static struct prog_instruction
*emit_insn(struct brw_wm_compile
*c
,
188 const struct prog_instruction
*inst0
)
190 struct prog_instruction
*inst
= get_fp_inst(c
);
195 static struct prog_instruction
* emit_tex_op(struct brw_wm_compile
*c
,
197 struct prog_dst_register dest
,
200 GLuint tex_src_target
,
202 struct prog_src_register src0
,
203 struct prog_src_register src1
,
204 struct prog_src_register src2
)
206 struct prog_instruction
*inst
= get_fp_inst(c
);
208 assert(tex_src_unit
< BRW_MAX_TEX_UNIT
||
209 tex_src_unit
== TEX_UNIT_NONE
);
210 assert(tex_src_target
< NUM_TEXTURE_TARGETS
||
211 tex_src_target
== TEX_TARGET_NONE
);
213 /* update mask of which texture units are referenced by this program */
214 if (tex_src_unit
!= TEX_UNIT_NONE
)
215 c
->fp
->tex_units_used
|= (1 << tex_src_unit
);
217 memset(inst
, 0, sizeof(*inst
));
221 inst
->SaturateMode
= saturate
;
222 inst
->TexSrcUnit
= tex_src_unit
;
223 inst
->TexSrcTarget
= tex_src_target
;
224 inst
->TexShadow
= tex_shadow
;
225 inst
->SrcReg
[0] = src0
;
226 inst
->SrcReg
[1] = src1
;
227 inst
->SrcReg
[2] = src2
;
232 static struct prog_instruction
* emit_op(struct brw_wm_compile
*c
,
234 struct prog_dst_register dest
,
236 struct prog_src_register src0
,
237 struct prog_src_register src1
,
238 struct prog_src_register src2
)
240 return emit_tex_op(c
, op
, dest
, saturate
,
241 TEX_UNIT_NONE
, TEX_TARGET_NONE
, 0, /* unit, tgt, shadow */
246 /* Many Mesa opcodes produce the same value across all the result channels.
247 * We'd rather not have to support that splatting in the opcode implementations,
248 * and brw_wm_pass*.c wants to optimize them out by shuffling references around
249 * anyway. We can easily get both by emitting the opcode to one channel, and
250 * then MOVing it to the others, which brw_wm_pass*.c already understands.
252 static struct prog_instruction
*emit_scalar_insn(struct brw_wm_compile
*c
,
253 const struct prog_instruction
*inst0
)
255 struct prog_instruction
*inst
;
256 unsigned int dst_chan
;
257 unsigned int other_channel_mask
;
259 if (inst0
->DstReg
.WriteMask
== 0)
262 dst_chan
= _mesa_ffs(inst0
->DstReg
.WriteMask
) - 1;
263 inst
= get_fp_inst(c
);
265 inst
->DstReg
.WriteMask
= 1 << dst_chan
;
267 other_channel_mask
= inst0
->DstReg
.WriteMask
& ~(1 << dst_chan
);
268 if (other_channel_mask
!= 0) {
271 dst_mask(inst0
->DstReg
, other_channel_mask
),
273 src_swizzle1(src_reg_from_dst(inst0
->DstReg
), dst_chan
),
281 /***********************************************************************
282 * Special instructions for interpolation and other tasks
285 static struct prog_src_register
get_pixel_xy( struct brw_wm_compile
*c
)
287 if (src_is_undef(c
->pixel_xy
)) {
288 struct prog_dst_register pixel_xy
= get_temp(c
);
289 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
292 /* Emit the out calculations, and hold onto the results. Use
293 * two instructions as a temporary is required.
295 /* pixel_xy.xy = PIXELXY payload[0];
299 dst_mask(pixel_xy
, WRITEMASK_XY
),
305 c
->pixel_xy
= src_reg_from_dst(pixel_xy
);
311 static struct prog_src_register
get_delta_xy( struct brw_wm_compile
*c
)
313 if (src_is_undef(c
->delta_xy
)) {
314 struct prog_dst_register delta_xy
= get_temp(c
);
315 struct prog_src_register pixel_xy
= get_pixel_xy(c
);
316 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
318 /* deltas.xy = DELTAXY pixel_xy, payload[0]
322 dst_mask(delta_xy
, WRITEMASK_XY
),
328 c
->delta_xy
= src_reg_from_dst(delta_xy
);
334 static struct prog_src_register
get_pixel_w( struct brw_wm_compile
*c
)
336 if (src_is_undef(c
->pixel_w
)) {
337 struct prog_dst_register pixel_w
= get_temp(c
);
338 struct prog_src_register deltas
= get_delta_xy(c
);
339 struct prog_src_register interp_wpos
= src_reg(PROGRAM_PAYLOAD
, FRAG_ATTRIB_WPOS
);
341 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
345 dst_mask(pixel_w
, WRITEMASK_W
),
352 c
->pixel_w
= src_reg_from_dst(pixel_w
);
358 static void emit_interp( struct brw_wm_compile
*c
,
361 struct prog_dst_register dst
= dst_reg(PROGRAM_INPUT
, idx
);
362 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
363 struct prog_src_register deltas
= get_delta_xy(c
);
365 /* Need to use PINTERP on attributes which have been
366 * multiplied by 1/W in the SF program, and LINTERP on those
370 case FRAG_ATTRIB_WPOS
:
371 /* Have to treat wpos.xy specially:
375 dst_mask(dst
, WRITEMASK_XY
),
381 dst
= dst_mask(dst
, WRITEMASK_ZW
);
383 /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
393 case FRAG_ATTRIB_COL0
:
394 case FRAG_ATTRIB_COL1
:
395 if (c
->key
.flat_shade
) {
405 if (c
->key
.linear_color
) {
415 /* perspective-corrected color interpolation */
426 case FRAG_ATTRIB_FOGC
:
427 /* Interpolate the fog coordinate */
430 dst_mask(dst
, WRITEMASK_X
),
438 dst_mask(dst
, WRITEMASK_YZW
),
449 case FRAG_ATTRIB_FACE
:
450 /* XXX review/test this case */
453 dst_mask(dst
, WRITEMASK_X
),
460 case FRAG_ATTRIB_PNTC
:
461 /* XXX review/test this case */
464 dst_mask(dst
, WRITEMASK_XY
),
472 dst_mask(dst
, WRITEMASK_ZW
),
494 c
->fp_interp_emitted
|= 1<<idx
;
497 static void emit_ddx( struct brw_wm_compile
*c
,
498 const struct prog_instruction
*inst
)
500 GLuint idx
= inst
->SrcReg
[0].Index
;
501 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
503 c
->fp_deriv_emitted
|= 1<<idx
;
513 static void emit_ddy( struct brw_wm_compile
*c
,
514 const struct prog_instruction
*inst
)
516 GLuint idx
= inst
->SrcReg
[0].Index
;
517 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
519 c
->fp_deriv_emitted
|= 1<<idx
;
529 /***********************************************************************
530 * Hacks to extend the program parameter and constant lists.
533 /* Add the fog parameters to the parameter list of the original
534 * program, rather than creating a new list. Doesn't really do any
535 * harm and it's not as if the parameter handling isn't a big hack
538 static struct prog_src_register
search_or_add_param5(struct brw_wm_compile
*c
,
545 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
546 gl_state_index tokens
[STATE_LENGTH
];
554 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
555 if (paramList
->Parameters
[idx
].Type
== PROGRAM_STATE_VAR
&&
556 memcmp(paramList
->Parameters
[idx
].StateIndexes
, tokens
, sizeof(tokens
)) == 0)
557 return src_reg(PROGRAM_STATE_VAR
, idx
);
560 idx
= _mesa_add_state_reference( paramList
, tokens
);
562 return src_reg(PROGRAM_STATE_VAR
, idx
);
566 static struct prog_src_register
search_or_add_const4f( struct brw_wm_compile
*c
,
572 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
582 /* Have to search, otherwise multiple compilations will each grow
583 * the parameter list.
585 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
586 if (paramList
->Parameters
[idx
].Type
== PROGRAM_CONSTANT
&&
587 memcmp(paramList
->ParameterValues
[idx
], values
, sizeof(values
)) == 0)
589 /* XXX: this mimics the mesa bug which puts all constants and
590 * parameters into the "PROGRAM_STATE_VAR" category:
592 return src_reg(PROGRAM_STATE_VAR
, idx
);
595 idx
= _mesa_add_unnamed_constant( paramList
, values
, 4, &swizzle
);
596 assert(swizzle
== SWIZZLE_NOOP
); /* Need to handle swizzle in reg setup */
597 return src_reg(PROGRAM_STATE_VAR
, idx
);
602 /***********************************************************************
603 * Expand various instructions here to simpler forms.
605 static void precalc_dst( struct brw_wm_compile
*c
,
606 const struct prog_instruction
*inst
)
608 struct prog_src_register src0
= inst
->SrcReg
[0];
609 struct prog_src_register src1
= inst
->SrcReg
[1];
610 struct prog_dst_register dst
= inst
->DstReg
;
612 if (dst
.WriteMask
& WRITEMASK_Y
) {
613 /* dst.y = mul src0.y, src1.y
617 dst_mask(dst
, WRITEMASK_Y
),
624 if (dst
.WriteMask
& WRITEMASK_XZ
) {
625 struct prog_instruction
*swz
;
626 GLuint z
= GET_SWZ(src0
.Swizzle
, Z
);
628 /* dst.xz = swz src0.1zzz
632 dst_mask(dst
, WRITEMASK_XZ
),
634 src_swizzle(src0
, SWIZZLE_ONE
, z
, z
, z
),
637 /* Avoid letting negation flag of src0 affect our 1 constant. */
638 swz
->SrcReg
[0].Negate
&= ~NEGATE_X
;
640 if (dst
.WriteMask
& WRITEMASK_W
) {
641 /* dst.w = mov src1.w
645 dst_mask(dst
, WRITEMASK_W
),
654 static void precalc_lit( struct brw_wm_compile
*c
,
655 const struct prog_instruction
*inst
)
657 struct prog_src_register src0
= inst
->SrcReg
[0];
658 struct prog_dst_register dst
= inst
->DstReg
;
660 if (dst
.WriteMask
& WRITEMASK_XW
) {
661 struct prog_instruction
*swz
;
663 /* dst.xw = swz src0.1111
667 dst_mask(dst
, WRITEMASK_XW
),
669 src_swizzle1(src0
, SWIZZLE_ONE
),
672 /* Avoid letting the negation flag of src0 affect our 1 constant. */
673 swz
->SrcReg
[0].Negate
= NEGATE_NONE
;
676 if (dst
.WriteMask
& WRITEMASK_YZ
) {
679 dst_mask(dst
, WRITEMASK_YZ
),
689 * Some TEX instructions require extra code, cube map coordinate
690 * normalization, or coordinate scaling for RECT textures, etc.
691 * This function emits those extra instructions and the TEX
692 * instruction itself.
694 static void precalc_tex( struct brw_wm_compile
*c
,
695 const struct prog_instruction
*inst
)
697 struct prog_src_register coord
;
698 struct prog_dst_register tmpcoord
;
699 const GLuint unit
= c
->fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
701 assert(unit
< BRW_MAX_TEX_UNIT
);
703 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
) {
704 struct prog_instruction
*out
;
705 struct prog_dst_register tmp0
= get_temp(c
);
706 struct prog_src_register tmp0src
= src_reg_from_dst(tmp0
);
707 struct prog_dst_register tmp1
= get_temp(c
);
708 struct prog_src_register tmp1src
= src_reg_from_dst(tmp1
);
709 struct prog_src_register src0
= inst
->SrcReg
[0];
711 /* find longest component of coord vector and normalize it */
712 tmpcoord
= get_temp(c
);
713 coord
= src_reg_from_dst(tmpcoord
);
715 /* tmpcoord = src0 (i.e.: coord = src0) */
716 out
= emit_op(c
, OPCODE_MOV
,
722 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
723 out
->SrcReg
[0].Abs
= 1;
725 /* tmp0 = MAX(coord.X, coord.Y) */
726 emit_op(c
, OPCODE_MAX
,
729 src_swizzle1(coord
, X
),
730 src_swizzle1(coord
, Y
),
733 /* tmp1 = MAX(tmp0, coord.Z) */
734 emit_op(c
, OPCODE_MAX
,
738 src_swizzle1(coord
, Z
),
741 /* tmp0 = 1 / tmp1 */
742 emit_op(c
, OPCODE_RCP
,
743 dst_mask(tmp0
, WRITEMASK_X
),
749 /* tmpCoord = src0 * tmp0 */
750 emit_op(c
, OPCODE_MUL
,
754 src_swizzle1(tmp0src
, SWIZZLE_X
),
757 release_temp(c
, tmp0
);
758 release_temp(c
, tmp1
);
760 else if (inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) {
761 struct prog_src_register scale
=
762 search_or_add_param5( c
,
768 tmpcoord
= get_temp(c
);
770 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
784 coord
= src_reg_from_dst(tmpcoord
);
787 coord
= inst
->SrcReg
[0];
790 /* Need to emit YUV texture conversions by hand. Probably need to
791 * do this here - the alternative is in brw_wm_emit.c, but the
792 * conversion requires allocating a temporary variable which we
793 * don't have the facility to do that late in the compilation.
795 if (c
->key
.yuvtex_mask
& (1 << unit
)) {
796 /* convert ycbcr to RGBA */
797 GLboolean swap_uv
= c
->key
.yuvtex_swap_mask
& (1<<unit
);
800 CONST C0 = { -.5, -.0625, -.5, 1.164 }
801 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
803 UYV.xyz = ADD UYV, C0
804 UYV.y = MUL UYV.y, C0.w
806 RGB.xyz = MAD UYV.zzx, C1, UYV.y
808 RGB.xyz = MAD UYV.xxz, C1, UYV.y
809 RGB.y = MAD UYV.z, C1.w, RGB.y
811 struct prog_dst_register dst
= inst
->DstReg
;
812 struct prog_dst_register tmp
= get_temp(c
);
813 struct prog_src_register tmpsrc
= src_reg_from_dst(tmp
);
814 struct prog_src_register C0
= search_or_add_const4f( c
, -.5, -.0625, -.5, 1.164 );
815 struct prog_src_register C1
= search_or_add_const4f( c
, 1.596, -0.813, 2.018, -.391 );
830 /* tmp.xyz = ADD TMP, C0
834 dst_mask(tmp
, WRITEMASK_XYZ
),
840 /* YUV.y = MUL YUV.y, C0.w
845 dst_mask(tmp
, WRITEMASK_Y
),
853 * RGB.xyz = MAD YUV.zzx, C1, YUV.y
855 * RGB.xyz = MAD YUV.xxz, C1, YUV.y
860 dst_mask(dst
, WRITEMASK_XYZ
),
862 swap_uv
?src_swizzle(tmpsrc
, Z
,Z
,X
,X
):src_swizzle(tmpsrc
, X
,X
,Z
,Z
),
864 src_swizzle1(tmpsrc
, Y
));
866 /* RGB.y = MAD YUV.z, C1.w, RGB.y
870 dst_mask(dst
, WRITEMASK_Y
),
872 src_swizzle1(tmpsrc
, Z
),
874 src_swizzle1(src_reg_from_dst(dst
), Y
));
876 release_temp(c
, tmp
);
879 /* ordinary RGBA tex instruction */
892 /* For GL_EXT_texture_swizzle: */
893 if (c
->key
.tex_swizzles
[unit
] != SWIZZLE_NOOP
) {
894 /* swizzle the result of the TEX instruction */
895 struct prog_src_register tmpsrc
= src_reg_from_dst(inst
->DstReg
);
896 emit_op(c
, OPCODE_SWZ
,
898 SATURATE_OFF
, /* saturate already done above */
899 src_swizzle4(tmpsrc
, c
->key
.tex_swizzles
[unit
]),
904 if ((inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) ||
905 (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
))
906 release_temp(c
, tmpcoord
);
911 * Check if the given TXP instruction really needs the divide-by-W step.
913 static GLboolean
projtex( struct brw_wm_compile
*c
,
914 const struct prog_instruction
*inst
)
916 const struct prog_src_register src
= inst
->SrcReg
[0];
919 assert(inst
->Opcode
== OPCODE_TXP
);
921 /* Only try to detect the simplest cases. Could detect (later)
922 * cases where we are trying to emit code like RCP {1.0}, MUL x,
925 * More complex cases than this typically only arise from
926 * user-provided fragment programs anyway:
928 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
)
929 retVal
= GL_FALSE
; /* ut2004 gun rendering !?! */
930 else if (src
.File
== PROGRAM_INPUT
&&
931 GET_SWZ(src
.Swizzle
, W
) == W
&&
932 (c
->key
.proj_attrib_mask
& (1 << src
.Index
)) == 0)
944 static void precalc_txp( struct brw_wm_compile
*c
,
945 const struct prog_instruction
*inst
)
947 struct prog_src_register src0
= inst
->SrcReg
[0];
949 if (projtex(c
, inst
)) {
950 struct prog_dst_register tmp
= get_temp(c
);
951 struct prog_instruction tmp_inst
;
953 /* tmp0.w = RCP inst.arg[0][3]
957 dst_mask(tmp
, WRITEMASK_W
),
959 src_swizzle1(src0
, GET_SWZ(src0
.Swizzle
, W
)),
963 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
967 dst_mask(tmp
, WRITEMASK_XYZ
),
970 src_swizzle1(src_reg_from_dst(tmp
), W
),
973 /* dst = precalc(TEX tmp0)
976 tmp_inst
.SrcReg
[0] = src_reg_from_dst(tmp
);
977 precalc_tex(c
, &tmp_inst
);
979 release_temp(c
, tmp
);
983 /* dst = precalc(TEX src0)
985 precalc_tex(c
, inst
);
991 static void emit_fb_write( struct brw_wm_compile
*c
)
993 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
994 struct prog_src_register outdepth
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DEPTH
);
995 struct prog_src_register outcolor
;
998 struct prog_instruction
*inst
, *last_inst
;
999 struct brw_context
*brw
= c
->func
.brw
;
1001 /* The inst->Aux field is used for FB write target and the EOT marker */
1003 if (brw
->state
.nr_color_regions
> 1) {
1004 for (i
= 0 ; i
< brw
->state
.nr_color_regions
; i
++) {
1005 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
+ i
);
1006 last_inst
= inst
= emit_op(c
,
1007 WM_FB_WRITE
, dst_mask(dst_undef(),0), 0,
1008 outcolor
, payload_r0_depth
, outdepth
);
1010 if (c
->fp_fragcolor_emitted
) {
1011 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
1012 last_inst
= inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(),0),
1013 0, outcolor
, payload_r0_depth
, outdepth
);
1017 last_inst
->Aux
|= 1; //eot
1020 /* if gl_FragData[0] is written, use it, else use gl_FragColor */
1021 if (c
->fp
->program
.Base
.OutputsWritten
& (1 << FRAG_RESULT_DATA0
))
1022 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
);
1024 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
1026 inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(),0),
1027 0, outcolor
, payload_r0_depth
, outdepth
);
1028 inst
->Aux
= 1|(0<<1);
1035 /***********************************************************************
1036 * Emit INTERP instructions ahead of first use of each attrib.
1039 static void validate_src_regs( struct brw_wm_compile
*c
,
1040 const struct prog_instruction
*inst
)
1042 GLuint nr_args
= brw_wm_nr_args( inst
->Opcode
);
1045 for (i
= 0; i
< nr_args
; i
++) {
1046 if (inst
->SrcReg
[i
].File
== PROGRAM_INPUT
) {
1047 GLuint idx
= inst
->SrcReg
[i
].Index
;
1048 if (!(c
->fp_interp_emitted
& (1<<idx
))) {
1049 emit_interp(c
, idx
);
1055 static void validate_dst_regs( struct brw_wm_compile
*c
,
1056 const struct prog_instruction
*inst
)
1058 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
) {
1059 GLuint idx
= inst
->DstReg
.Index
;
1060 if (idx
== FRAG_RESULT_COLOR
)
1061 c
->fp_fragcolor_emitted
= 1;
1065 static void print_insns( const struct prog_instruction
*insn
,
1069 for (i
= 0; i
< nr
; i
++, insn
++) {
1070 _mesa_printf("%3d: ", i
);
1071 if (insn
->Opcode
< MAX_OPCODE
)
1072 _mesa_print_instruction(insn
);
1073 else if (insn
->Opcode
< MAX_WM_OPCODE
) {
1074 GLuint idx
= insn
->Opcode
- MAX_OPCODE
;
1076 _mesa_print_alu_instruction(insn
,
1077 wm_opcode_strings
[idx
],
1081 _mesa_printf("965 Opcode %d\n", insn
->Opcode
);
1087 * Initial pass for fragment program code generation.
1088 * This function is used by both the GLSL and non-GLSL paths.
1090 void brw_wm_pass_fp( struct brw_wm_compile
*c
)
1092 struct brw_fragment_program
*fp
= c
->fp
;
1095 if (INTEL_DEBUG
& DEBUG_WM
) {
1096 _mesa_printf("pre-fp:\n");
1097 _mesa_print_program(&fp
->program
.Base
);
1101 c
->pixel_xy
= src_undef();
1102 c
->delta_xy
= src_undef();
1103 c
->pixel_w
= src_undef();
1105 c
->fp
->tex_units_used
= 0x0;
1107 /* Emit preamble instructions. This is where special instructions such as
1108 * WM_CINTERP, WM_LINTERP, WM_PINTERP and WM_WPOSXY are emitted to
1109 * compute shader inputs from varying vars.
1111 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1112 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1113 validate_src_regs(c
, inst
);
1114 validate_dst_regs(c
, inst
);
1117 /* Loop over all instructions doing assorted simplifications and
1120 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1121 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1122 struct prog_instruction
*out
;
1124 /* Check for INPUT values, emit INTERP instructions where
1128 switch (inst
->Opcode
) {
1130 out
= emit_insn(c
, inst
);
1131 out
->Opcode
= OPCODE_MOV
;
1135 out
= emit_insn(c
, inst
);
1136 out
->Opcode
= OPCODE_MOV
;
1137 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
1138 out
->SrcReg
[0].Abs
= 1;
1142 out
= emit_insn(c
, inst
);
1143 out
->Opcode
= OPCODE_ADD
;
1144 out
->SrcReg
[1].Negate
^= NEGATE_XYZW
;
1148 out
= emit_insn(c
, inst
);
1149 /* This should probably be done in the parser.
1151 out
->DstReg
.WriteMask
&= WRITEMASK_XY
;
1155 precalc_dst(c
, inst
);
1159 precalc_lit(c
, inst
);
1163 precalc_tex(c
, inst
);
1167 precalc_txp(c
, inst
);
1171 out
= emit_insn(c
, inst
);
1172 out
->TexSrcUnit
= fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
1173 assert(out
->TexSrcUnit
< BRW_MAX_TEX_UNIT
);
1177 out
= emit_insn(c
, inst
);
1178 /* This should probably be done in the parser.
1180 out
->DstReg
.WriteMask
&= WRITEMASK_XYZ
;
1184 out
= emit_insn(c
, inst
);
1185 /* This should probably be done in the parser.
1187 out
->DstReg
.WriteMask
= 0;
1201 if (brw_wm_is_scalar_result(inst
->Opcode
))
1202 emit_scalar_insn(c
, inst
);
1209 if (INTEL_DEBUG
& DEBUG_WM
) {
1210 _mesa_printf("pass_fp:\n");
1211 print_insns( c
->prog_instructions
, c
->nr_fp_insns
);