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
;
144 static struct prog_dst_register
dst_mask( struct prog_dst_register reg
, int mask
)
146 reg
.WriteMask
&= mask
;
150 static struct prog_dst_register
dst_undef( void )
152 return dst_reg(PROGRAM_UNDEFINED
, 0);
157 static struct prog_dst_register
get_temp( struct brw_wm_compile
*c
)
159 int bit
= _mesa_ffs( ~c
->fp_temp
);
162 _mesa_printf("%s: out of temporaries\n", __FILE__
);
166 c
->fp_temp
|= 1<<(bit
-1);
167 return dst_reg(PROGRAM_TEMPORARY
, FIRST_INTERNAL_TEMP
+(bit
-1));
171 static void release_temp( struct brw_wm_compile
*c
, struct prog_dst_register temp
)
173 c
->fp_temp
&= ~(1 << (temp
.Index
- FIRST_INTERNAL_TEMP
));
177 /***********************************************************************
181 static struct prog_instruction
*get_fp_inst(struct brw_wm_compile
*c
)
183 assert(c
->nr_fp_insns
< BRW_WM_MAX_INSN
);
184 memset(&c
->prog_instructions
[c
->nr_fp_insns
], 0,
185 sizeof(*c
->prog_instructions
));
186 return &c
->prog_instructions
[c
->nr_fp_insns
++];
189 static struct prog_instruction
*emit_insn(struct brw_wm_compile
*c
,
190 const struct prog_instruction
*inst0
)
192 struct prog_instruction
*inst
= get_fp_inst(c
);
197 static struct prog_instruction
* emit_tex_op(struct brw_wm_compile
*c
,
199 struct prog_dst_register dest
,
202 GLuint tex_src_target
,
204 struct prog_src_register src0
,
205 struct prog_src_register src1
,
206 struct prog_src_register src2
)
208 struct prog_instruction
*inst
= get_fp_inst(c
);
210 assert(tex_src_unit
< BRW_MAX_TEX_UNIT
||
211 tex_src_unit
== TEX_UNIT_NONE
);
212 assert(tex_src_target
< NUM_TEXTURE_TARGETS
||
213 tex_src_target
== TEX_TARGET_NONE
);
215 /* update mask of which texture units are referenced by this program */
216 if (tex_src_unit
!= TEX_UNIT_NONE
)
217 c
->fp
->tex_units_used
|= (1 << tex_src_unit
);
219 memset(inst
, 0, sizeof(*inst
));
223 inst
->SaturateMode
= saturate
;
224 inst
->TexSrcUnit
= tex_src_unit
;
225 inst
->TexSrcTarget
= tex_src_target
;
226 inst
->TexShadow
= tex_shadow
;
227 inst
->SrcReg
[0] = src0
;
228 inst
->SrcReg
[1] = src1
;
229 inst
->SrcReg
[2] = src2
;
234 static struct prog_instruction
* emit_op(struct brw_wm_compile
*c
,
236 struct prog_dst_register dest
,
238 struct prog_src_register src0
,
239 struct prog_src_register src1
,
240 struct prog_src_register src2
)
242 return emit_tex_op(c
, op
, dest
, saturate
,
243 TEX_UNIT_NONE
, TEX_TARGET_NONE
, 0, /* unit, tgt, shadow */
248 /* Many Mesa opcodes produce the same value across all the result channels.
249 * We'd rather not have to support that splatting in the opcode implementations,
250 * and brw_wm_pass*.c wants to optimize them out by shuffling references around
251 * anyway. We can easily get both by emitting the opcode to one channel, and
252 * then MOVing it to the others, which brw_wm_pass*.c already understands.
254 static struct prog_instruction
*emit_scalar_insn(struct brw_wm_compile
*c
,
255 const struct prog_instruction
*inst0
)
257 struct prog_instruction
*inst
;
258 unsigned int dst_chan
;
259 unsigned int other_channel_mask
;
261 if (inst0
->DstReg
.WriteMask
== 0)
264 dst_chan
= _mesa_ffs(inst0
->DstReg
.WriteMask
) - 1;
265 inst
= get_fp_inst(c
);
267 inst
->DstReg
.WriteMask
= 1 << dst_chan
;
269 other_channel_mask
= inst0
->DstReg
.WriteMask
& ~(1 << dst_chan
);
270 if (other_channel_mask
!= 0) {
273 dst_mask(inst0
->DstReg
, other_channel_mask
),
275 src_swizzle1(src_reg_from_dst(inst0
->DstReg
), dst_chan
),
283 /***********************************************************************
284 * Special instructions for interpolation and other tasks
287 static struct prog_src_register
get_pixel_xy( struct brw_wm_compile
*c
)
289 if (src_is_undef(c
->pixel_xy
)) {
290 struct prog_dst_register pixel_xy
= get_temp(c
);
291 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
294 /* Emit the out calculations, and hold onto the results. Use
295 * two instructions as a temporary is required.
297 /* pixel_xy.xy = PIXELXY payload[0];
301 dst_mask(pixel_xy
, WRITEMASK_XY
),
307 c
->pixel_xy
= src_reg_from_dst(pixel_xy
);
313 static struct prog_src_register
get_delta_xy( struct brw_wm_compile
*c
)
315 if (src_is_undef(c
->delta_xy
)) {
316 struct prog_dst_register delta_xy
= get_temp(c
);
317 struct prog_src_register pixel_xy
= get_pixel_xy(c
);
318 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
320 /* deltas.xy = DELTAXY pixel_xy, payload[0]
324 dst_mask(delta_xy
, WRITEMASK_XY
),
330 c
->delta_xy
= src_reg_from_dst(delta_xy
);
336 static struct prog_src_register
get_pixel_w( struct brw_wm_compile
*c
)
338 if (src_is_undef(c
->pixel_w
)) {
339 struct prog_dst_register pixel_w
= get_temp(c
);
340 struct prog_src_register deltas
= get_delta_xy(c
);
341 struct prog_src_register interp_wpos
= src_reg(PROGRAM_PAYLOAD
, FRAG_ATTRIB_WPOS
);
343 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
347 dst_mask(pixel_w
, WRITEMASK_W
),
354 c
->pixel_w
= src_reg_from_dst(pixel_w
);
360 static void emit_interp( struct brw_wm_compile
*c
,
363 struct prog_dst_register dst
= dst_reg(PROGRAM_INPUT
, idx
);
364 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
365 struct prog_src_register deltas
= get_delta_xy(c
);
367 /* Need to use PINTERP on attributes which have been
368 * multiplied by 1/W in the SF program, and LINTERP on those
372 case FRAG_ATTRIB_WPOS
:
373 /* Have to treat wpos.xy specially:
377 dst_mask(dst
, WRITEMASK_XY
),
383 dst
= dst_mask(dst
, WRITEMASK_ZW
);
385 /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
395 case FRAG_ATTRIB_COL0
:
396 case FRAG_ATTRIB_COL1
:
397 if (c
->key
.flat_shade
) {
407 if (c
->key
.linear_color
) {
417 /* perspective-corrected color interpolation */
428 case FRAG_ATTRIB_FOGC
:
429 /* Interpolate the fog coordinate */
432 dst_mask(dst
, WRITEMASK_X
),
440 dst_mask(dst
, WRITEMASK_YZW
),
451 case FRAG_ATTRIB_FACE
:
454 dst_mask(dst
, WRITEMASK_X
),
461 case FRAG_ATTRIB_PNTC
:
462 /* XXX review/test this case */
465 dst_mask(dst
, WRITEMASK_XY
),
473 dst_mask(dst
, WRITEMASK_ZW
),
495 c
->fp_interp_emitted
|= 1<<idx
;
498 /***********************************************************************
499 * Hacks to extend the program parameter and constant lists.
502 /* Add the fog parameters to the parameter list of the original
503 * program, rather than creating a new list. Doesn't really do any
504 * harm and it's not as if the parameter handling isn't a big hack
507 static struct prog_src_register
search_or_add_param5(struct brw_wm_compile
*c
,
514 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
515 gl_state_index tokens
[STATE_LENGTH
];
523 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
524 if (paramList
->Parameters
[idx
].Type
== PROGRAM_STATE_VAR
&&
525 memcmp(paramList
->Parameters
[idx
].StateIndexes
, tokens
, sizeof(tokens
)) == 0)
526 return src_reg(PROGRAM_STATE_VAR
, idx
);
529 idx
= _mesa_add_state_reference( paramList
, tokens
);
531 return src_reg(PROGRAM_STATE_VAR
, idx
);
535 static struct prog_src_register
search_or_add_const4f( struct brw_wm_compile
*c
,
541 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
551 /* Have to search, otherwise multiple compilations will each grow
552 * the parameter list.
554 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
555 if (paramList
->Parameters
[idx
].Type
== PROGRAM_CONSTANT
&&
556 memcmp(paramList
->ParameterValues
[idx
], values
, sizeof(values
)) == 0)
558 /* XXX: this mimics the mesa bug which puts all constants and
559 * parameters into the "PROGRAM_STATE_VAR" category:
561 return src_reg(PROGRAM_STATE_VAR
, idx
);
564 idx
= _mesa_add_unnamed_constant( paramList
, values
, 4, &swizzle
);
565 assert(swizzle
== SWIZZLE_NOOP
); /* Need to handle swizzle in reg setup */
566 return src_reg(PROGRAM_STATE_VAR
, idx
);
571 /***********************************************************************
572 * Expand various instructions here to simpler forms.
574 static void precalc_dst( struct brw_wm_compile
*c
,
575 const struct prog_instruction
*inst
)
577 struct prog_src_register src0
= inst
->SrcReg
[0];
578 struct prog_src_register src1
= inst
->SrcReg
[1];
579 struct prog_dst_register dst
= inst
->DstReg
;
581 if (dst
.WriteMask
& WRITEMASK_Y
) {
582 /* dst.y = mul src0.y, src1.y
586 dst_mask(dst
, WRITEMASK_Y
),
593 if (dst
.WriteMask
& WRITEMASK_XZ
) {
594 struct prog_instruction
*swz
;
595 GLuint z
= GET_SWZ(src0
.Swizzle
, Z
);
597 /* dst.xz = swz src0.1zzz
601 dst_mask(dst
, WRITEMASK_XZ
),
603 src_swizzle(src0
, SWIZZLE_ONE
, z
, z
, z
),
606 /* Avoid letting negation flag of src0 affect our 1 constant. */
607 swz
->SrcReg
[0].Negate
&= ~NEGATE_X
;
609 if (dst
.WriteMask
& WRITEMASK_W
) {
610 /* dst.w = mov src1.w
614 dst_mask(dst
, WRITEMASK_W
),
623 static void precalc_lit( struct brw_wm_compile
*c
,
624 const struct prog_instruction
*inst
)
626 struct prog_src_register src0
= inst
->SrcReg
[0];
627 struct prog_dst_register dst
= inst
->DstReg
;
629 if (dst
.WriteMask
& WRITEMASK_XW
) {
630 struct prog_instruction
*swz
;
632 /* dst.xw = swz src0.1111
636 dst_mask(dst
, WRITEMASK_XW
),
638 src_swizzle1(src0
, SWIZZLE_ONE
),
641 /* Avoid letting the negation flag of src0 affect our 1 constant. */
642 swz
->SrcReg
[0].Negate
= NEGATE_NONE
;
645 if (dst
.WriteMask
& WRITEMASK_YZ
) {
648 dst_mask(dst
, WRITEMASK_YZ
),
658 * Some TEX instructions require extra code, cube map coordinate
659 * normalization, or coordinate scaling for RECT textures, etc.
660 * This function emits those extra instructions and the TEX
661 * instruction itself.
663 static void precalc_tex( struct brw_wm_compile
*c
,
664 const struct prog_instruction
*inst
)
666 struct prog_src_register coord
;
667 struct prog_dst_register tmpcoord
;
668 const GLuint unit
= c
->fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
670 assert(unit
< BRW_MAX_TEX_UNIT
);
672 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
) {
673 struct prog_instruction
*out
;
674 struct prog_dst_register tmp0
= get_temp(c
);
675 struct prog_src_register tmp0src
= src_reg_from_dst(tmp0
);
676 struct prog_dst_register tmp1
= get_temp(c
);
677 struct prog_src_register tmp1src
= src_reg_from_dst(tmp1
);
678 struct prog_src_register src0
= inst
->SrcReg
[0];
680 /* find longest component of coord vector and normalize it */
681 tmpcoord
= get_temp(c
);
682 coord
= src_reg_from_dst(tmpcoord
);
684 /* tmpcoord = src0 (i.e.: coord = src0) */
685 out
= emit_op(c
, OPCODE_MOV
,
691 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
692 out
->SrcReg
[0].Abs
= 1;
694 /* tmp0 = MAX(coord.X, coord.Y) */
695 emit_op(c
, OPCODE_MAX
,
698 src_swizzle1(coord
, X
),
699 src_swizzle1(coord
, Y
),
702 /* tmp1 = MAX(tmp0, coord.Z) */
703 emit_op(c
, OPCODE_MAX
,
707 src_swizzle1(coord
, Z
),
710 /* tmp0 = 1 / tmp1 */
711 emit_op(c
, OPCODE_RCP
,
712 dst_mask(tmp0
, WRITEMASK_X
),
718 /* tmpCoord = src0 * tmp0 */
719 emit_op(c
, OPCODE_MUL
,
723 src_swizzle1(tmp0src
, SWIZZLE_X
),
726 release_temp(c
, tmp0
);
727 release_temp(c
, tmp1
);
729 else if (inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) {
730 struct prog_src_register scale
=
731 search_or_add_param5( c
,
737 tmpcoord
= get_temp(c
);
739 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
753 coord
= src_reg_from_dst(tmpcoord
);
756 coord
= inst
->SrcReg
[0];
759 /* Need to emit YUV texture conversions by hand. Probably need to
760 * do this here - the alternative is in brw_wm_emit.c, but the
761 * conversion requires allocating a temporary variable which we
762 * don't have the facility to do that late in the compilation.
764 if (c
->key
.yuvtex_mask
& (1 << unit
)) {
765 /* convert ycbcr to RGBA */
766 GLboolean swap_uv
= c
->key
.yuvtex_swap_mask
& (1<<unit
);
769 CONST C0 = { -.5, -.0625, -.5, 1.164 }
770 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
772 UYV.xyz = ADD UYV, C0
773 UYV.y = MUL UYV.y, C0.w
775 RGB.xyz = MAD UYV.zzx, C1, UYV.y
777 RGB.xyz = MAD UYV.xxz, C1, UYV.y
778 RGB.y = MAD UYV.z, C1.w, RGB.y
780 struct prog_dst_register dst
= inst
->DstReg
;
781 struct prog_dst_register tmp
= get_temp(c
);
782 struct prog_src_register tmpsrc
= src_reg_from_dst(tmp
);
783 struct prog_src_register C0
= search_or_add_const4f( c
, -.5, -.0625, -.5, 1.164 );
784 struct prog_src_register C1
= search_or_add_const4f( c
, 1.596, -0.813, 2.018, -.391 );
799 /* tmp.xyz = ADD TMP, C0
803 dst_mask(tmp
, WRITEMASK_XYZ
),
809 /* YUV.y = MUL YUV.y, C0.w
814 dst_mask(tmp
, WRITEMASK_Y
),
822 * RGB.xyz = MAD YUV.zzx, C1, YUV.y
824 * RGB.xyz = MAD YUV.xxz, C1, YUV.y
829 dst_mask(dst
, WRITEMASK_XYZ
),
831 swap_uv
?src_swizzle(tmpsrc
, Z
,Z
,X
,X
):src_swizzle(tmpsrc
, X
,X
,Z
,Z
),
833 src_swizzle1(tmpsrc
, Y
));
835 /* RGB.y = MAD YUV.z, C1.w, RGB.y
839 dst_mask(dst
, WRITEMASK_Y
),
841 src_swizzle1(tmpsrc
, Z
),
843 src_swizzle1(src_reg_from_dst(dst
), Y
));
845 release_temp(c
, tmp
);
848 /* ordinary RGBA tex instruction */
861 /* For GL_EXT_texture_swizzle: */
862 if (c
->key
.tex_swizzles
[unit
] != SWIZZLE_NOOP
) {
863 /* swizzle the result of the TEX instruction */
864 struct prog_src_register tmpsrc
= src_reg_from_dst(inst
->DstReg
);
865 emit_op(c
, OPCODE_SWZ
,
867 SATURATE_OFF
, /* saturate already done above */
868 src_swizzle4(tmpsrc
, c
->key
.tex_swizzles
[unit
]),
873 if ((inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) ||
874 (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
))
875 release_temp(c
, tmpcoord
);
880 * Check if the given TXP instruction really needs the divide-by-W step.
882 static GLboolean
projtex( struct brw_wm_compile
*c
,
883 const struct prog_instruction
*inst
)
885 const struct prog_src_register src
= inst
->SrcReg
[0];
888 assert(inst
->Opcode
== OPCODE_TXP
);
890 /* Only try to detect the simplest cases. Could detect (later)
891 * cases where we are trying to emit code like RCP {1.0}, MUL x,
894 * More complex cases than this typically only arise from
895 * user-provided fragment programs anyway:
897 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
)
898 retVal
= GL_FALSE
; /* ut2004 gun rendering !?! */
899 else if (src
.File
== PROGRAM_INPUT
&&
900 GET_SWZ(src
.Swizzle
, W
) == W
&&
901 (c
->key
.proj_attrib_mask
& (1 << src
.Index
)) == 0)
913 static void precalc_txp( struct brw_wm_compile
*c
,
914 const struct prog_instruction
*inst
)
916 struct prog_src_register src0
= inst
->SrcReg
[0];
918 if (projtex(c
, inst
)) {
919 struct prog_dst_register tmp
= get_temp(c
);
920 struct prog_instruction tmp_inst
;
922 /* tmp0.w = RCP inst.arg[0][3]
926 dst_mask(tmp
, WRITEMASK_W
),
928 src_swizzle1(src0
, GET_SWZ(src0
.Swizzle
, W
)),
932 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
936 dst_mask(tmp
, WRITEMASK_XYZ
),
939 src_swizzle1(src_reg_from_dst(tmp
), W
),
942 /* dst = precalc(TEX tmp0)
945 tmp_inst
.SrcReg
[0] = src_reg_from_dst(tmp
);
946 precalc_tex(c
, &tmp_inst
);
948 release_temp(c
, tmp
);
952 /* dst = precalc(TEX src0)
954 precalc_tex(c
, inst
);
960 static void emit_render_target_writes( struct brw_wm_compile
*c
)
962 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
963 struct prog_src_register outdepth
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DEPTH
);
964 struct prog_src_register outcolor
;
967 struct prog_instruction
*inst
, *last_inst
;
969 /* The inst->Aux field is used for FB write target and the EOT marker */
971 if (c
->key
.nr_color_regions
> 1) {
972 for (i
= 0 ; i
< c
->key
.nr_color_regions
; i
++) {
973 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
+ i
);
974 last_inst
= inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(), 0),
975 0, outcolor
, payload_r0_depth
, outdepth
);
976 inst
->Aux
= INST_AUX_TARGET(i
);
977 if (c
->fp_fragcolor_emitted
) {
978 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
979 last_inst
= inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(), 0),
980 0, outcolor
, payload_r0_depth
, outdepth
);
981 inst
->Aux
= INST_AUX_TARGET(i
);
984 last_inst
->Aux
|= INST_AUX_EOT
;
987 /* if gl_FragData[0] is written, use it, else use gl_FragColor */
988 if (c
->fp
->program
.Base
.OutputsWritten
& BITFIELD64_BIT(FRAG_RESULT_DATA0
))
989 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
);
991 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
993 inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(),0),
994 0, outcolor
, payload_r0_depth
, outdepth
);
995 inst
->Aux
= INST_AUX_EOT
| INST_AUX_TARGET(0);
1002 /***********************************************************************
1003 * Emit INTERP instructions ahead of first use of each attrib.
1006 static void validate_src_regs( struct brw_wm_compile
*c
,
1007 const struct prog_instruction
*inst
)
1009 GLuint nr_args
= brw_wm_nr_args( inst
->Opcode
);
1012 for (i
= 0; i
< nr_args
; i
++) {
1013 if (inst
->SrcReg
[i
].File
== PROGRAM_INPUT
) {
1014 GLuint idx
= inst
->SrcReg
[i
].Index
;
1015 if (!(c
->fp_interp_emitted
& (1<<idx
))) {
1016 emit_interp(c
, idx
);
1022 static void validate_dst_regs( struct brw_wm_compile
*c
,
1023 const struct prog_instruction
*inst
)
1025 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
) {
1026 GLuint idx
= inst
->DstReg
.Index
;
1027 if (idx
== FRAG_RESULT_COLOR
)
1028 c
->fp_fragcolor_emitted
= 1;
1032 static void print_insns( const struct prog_instruction
*insn
,
1036 for (i
= 0; i
< nr
; i
++, insn
++) {
1037 _mesa_printf("%3d: ", i
);
1038 if (insn
->Opcode
< MAX_OPCODE
)
1039 _mesa_print_instruction(insn
);
1040 else if (insn
->Opcode
< MAX_WM_OPCODE
) {
1041 GLuint idx
= insn
->Opcode
- MAX_OPCODE
;
1043 _mesa_print_alu_instruction(insn
,
1044 wm_opcode_strings
[idx
],
1048 _mesa_printf("965 Opcode %d\n", insn
->Opcode
);
1054 * Initial pass for fragment program code generation.
1055 * This function is used by both the GLSL and non-GLSL paths.
1057 void brw_wm_pass_fp( struct brw_wm_compile
*c
)
1059 struct brw_fragment_program
*fp
= c
->fp
;
1062 if (INTEL_DEBUG
& DEBUG_WM
) {
1063 _mesa_printf("pre-fp:\n");
1064 _mesa_print_program(&fp
->program
.Base
);
1068 c
->pixel_xy
= src_undef();
1069 c
->delta_xy
= src_undef();
1070 c
->pixel_w
= src_undef();
1072 c
->fp
->tex_units_used
= 0x0;
1074 /* Emit preamble instructions. This is where special instructions such as
1075 * WM_CINTERP, WM_LINTERP, WM_PINTERP and WM_WPOSXY are emitted to
1076 * compute shader inputs from varying vars.
1078 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1079 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1080 validate_src_regs(c
, inst
);
1081 validate_dst_regs(c
, inst
);
1084 /* Loop over all instructions doing assorted simplifications and
1087 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1088 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1089 struct prog_instruction
*out
;
1091 /* Check for INPUT values, emit INTERP instructions where
1095 switch (inst
->Opcode
) {
1097 out
= emit_insn(c
, inst
);
1098 out
->Opcode
= OPCODE_MOV
;
1102 out
= emit_insn(c
, inst
);
1103 out
->Opcode
= OPCODE_MOV
;
1104 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
1105 out
->SrcReg
[0].Abs
= 1;
1109 out
= emit_insn(c
, inst
);
1110 out
->Opcode
= OPCODE_ADD
;
1111 out
->SrcReg
[1].Negate
^= NEGATE_XYZW
;
1115 out
= emit_insn(c
, inst
);
1116 /* This should probably be done in the parser.
1118 out
->DstReg
.WriteMask
&= WRITEMASK_XY
;
1122 precalc_dst(c
, inst
);
1126 precalc_lit(c
, inst
);
1130 precalc_tex(c
, inst
);
1134 precalc_txp(c
, inst
);
1138 out
= emit_insn(c
, inst
);
1139 out
->TexSrcUnit
= fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
1140 assert(out
->TexSrcUnit
< BRW_MAX_TEX_UNIT
);
1144 out
= emit_insn(c
, inst
);
1145 /* This should probably be done in the parser.
1147 out
->DstReg
.WriteMask
&= WRITEMASK_XYZ
;
1151 out
= emit_insn(c
, inst
);
1152 /* This should probably be done in the parser.
1154 out
->DstReg
.WriteMask
= 0;
1157 emit_render_target_writes(c
);
1162 if (brw_wm_is_scalar_result(inst
->Opcode
))
1163 emit_scalar_insn(c
, inst
);
1170 if (INTEL_DEBUG
& DEBUG_WM
) {
1171 _mesa_printf("pass_fp:\n");
1172 print_insns( c
->prog_instructions
, c
->nr_fp_insns
);