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 "program/prog_parameter.h"
41 #include "program/prog_print.h"
42 #include "program/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
;
95 static struct prog_src_register
src_reg_from_dst(struct prog_dst_register dst
)
97 return src_reg(dst
.File
, dst
.Index
);
100 static struct prog_src_register
src_undef( void )
102 return src_reg(PROGRAM_UNDEFINED
, 0);
105 static GLboolean
src_is_undef(struct prog_src_register src
)
107 return src
.File
== PROGRAM_UNDEFINED
;
110 static struct prog_src_register
src_swizzle( struct prog_src_register reg
, int x
, int y
, int z
, int w
)
112 reg
.Swizzle
= MAKE_SWIZZLE4(x
,y
,z
,w
);
116 static struct prog_src_register
src_swizzle1( struct prog_src_register reg
, int x
)
118 return src_swizzle(reg
, x
, x
, x
, x
);
121 static struct prog_src_register
src_swizzle4( struct prog_src_register reg
, uint swizzle
)
123 reg
.Swizzle
= swizzle
;
128 /***********************************************************************
132 static struct prog_dst_register
dst_reg(GLuint file
, GLuint idx
)
134 struct prog_dst_register reg
;
137 reg
.WriteMask
= WRITEMASK_XYZW
;
139 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 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 assert(c
->nr_fp_insns
< BRW_WM_MAX_INSN
);
185 memset(&c
->prog_instructions
[c
->nr_fp_insns
], 0,
186 sizeof(*c
->prog_instructions
));
187 return &c
->prog_instructions
[c
->nr_fp_insns
++];
190 static struct prog_instruction
*emit_insn(struct brw_wm_compile
*c
,
191 const struct prog_instruction
*inst0
)
193 struct prog_instruction
*inst
= get_fp_inst(c
);
198 static struct prog_instruction
* emit_tex_op(struct brw_wm_compile
*c
,
200 struct prog_dst_register dest
,
203 GLuint tex_src_target
,
205 struct prog_src_register src0
,
206 struct prog_src_register src1
,
207 struct prog_src_register src2
)
209 struct prog_instruction
*inst
= get_fp_inst(c
);
211 assert(tex_src_unit
< BRW_MAX_TEX_UNIT
||
212 tex_src_unit
== TEX_UNIT_NONE
);
213 assert(tex_src_target
< NUM_TEXTURE_TARGETS
||
214 tex_src_target
== TEX_TARGET_NONE
);
216 /* update mask of which texture units are referenced by this program */
217 if (tex_src_unit
!= TEX_UNIT_NONE
)
218 c
->fp
->tex_units_used
|= (1 << tex_src_unit
);
220 memset(inst
, 0, sizeof(*inst
));
224 inst
->SaturateMode
= saturate
;
225 inst
->TexSrcUnit
= tex_src_unit
;
226 inst
->TexSrcTarget
= tex_src_target
;
227 inst
->TexShadow
= tex_shadow
;
228 inst
->SrcReg
[0] = src0
;
229 inst
->SrcReg
[1] = src1
;
230 inst
->SrcReg
[2] = src2
;
235 static struct prog_instruction
* emit_op(struct brw_wm_compile
*c
,
237 struct prog_dst_register dest
,
239 struct prog_src_register src0
,
240 struct prog_src_register src1
,
241 struct prog_src_register src2
)
243 return emit_tex_op(c
, op
, dest
, saturate
,
244 TEX_UNIT_NONE
, TEX_TARGET_NONE
, 0, /* unit, tgt, shadow */
249 /* Many Mesa opcodes produce the same value across all the result channels.
250 * We'd rather not have to support that splatting in the opcode implementations,
251 * and brw_wm_pass*.c wants to optimize them out by shuffling references around
252 * anyway. We can easily get both by emitting the opcode to one channel, and
253 * then MOVing it to the others, which brw_wm_pass*.c already understands.
255 static struct prog_instruction
*emit_scalar_insn(struct brw_wm_compile
*c
,
256 const struct prog_instruction
*inst0
)
258 struct prog_instruction
*inst
;
259 unsigned int dst_chan
;
260 unsigned int other_channel_mask
;
262 if (inst0
->DstReg
.WriteMask
== 0)
265 dst_chan
= _mesa_ffs(inst0
->DstReg
.WriteMask
) - 1;
266 inst
= get_fp_inst(c
);
268 inst
->DstReg
.WriteMask
= 1 << dst_chan
;
270 other_channel_mask
= inst0
->DstReg
.WriteMask
& ~(1 << dst_chan
);
271 if (other_channel_mask
!= 0) {
274 dst_mask(inst0
->DstReg
, other_channel_mask
),
276 src_swizzle1(src_reg_from_dst(inst0
->DstReg
), dst_chan
),
284 /***********************************************************************
285 * Special instructions for interpolation and other tasks
288 static struct prog_src_register
get_pixel_xy( struct brw_wm_compile
*c
)
290 if (src_is_undef(c
->pixel_xy
)) {
291 struct prog_dst_register pixel_xy
= get_temp(c
);
292 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
295 /* Emit the out calculations, and hold onto the results. Use
296 * two instructions as a temporary is required.
298 /* pixel_xy.xy = PIXELXY payload[0];
302 dst_mask(pixel_xy
, WRITEMASK_XY
),
308 c
->pixel_xy
= src_reg_from_dst(pixel_xy
);
314 static struct prog_src_register
get_delta_xy( struct brw_wm_compile
*c
)
316 if (src_is_undef(c
->delta_xy
)) {
317 struct prog_dst_register delta_xy
= get_temp(c
);
318 struct prog_src_register pixel_xy
= get_pixel_xy(c
);
319 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
321 /* deltas.xy = DELTAXY pixel_xy, payload[0]
325 dst_mask(delta_xy
, WRITEMASK_XY
),
331 c
->delta_xy
= src_reg_from_dst(delta_xy
);
337 static struct prog_src_register
get_pixel_w( struct brw_wm_compile
*c
)
339 if (src_is_undef(c
->pixel_w
)) {
340 struct prog_dst_register pixel_w
= get_temp(c
);
341 struct prog_src_register deltas
= get_delta_xy(c
);
342 struct prog_src_register interp_wpos
= src_reg(PROGRAM_PAYLOAD
, FRAG_ATTRIB_WPOS
);
344 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
348 dst_mask(pixel_w
, WRITEMASK_W
),
355 c
->pixel_w
= src_reg_from_dst(pixel_w
);
361 static void emit_interp( struct brw_wm_compile
*c
,
364 struct prog_dst_register dst
= dst_reg(PROGRAM_INPUT
, idx
);
365 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
366 struct prog_src_register deltas
= get_delta_xy(c
);
368 /* Need to use PINTERP on attributes which have been
369 * multiplied by 1/W in the SF program, and LINTERP on those
373 case FRAG_ATTRIB_WPOS
:
374 /* Have to treat wpos.xy specially:
378 dst_mask(dst
, WRITEMASK_XY
),
384 dst
= dst_mask(dst
, WRITEMASK_ZW
);
386 /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
396 case FRAG_ATTRIB_COL0
:
397 case FRAG_ATTRIB_COL1
:
398 if (c
->key
.flat_shade
) {
408 if (c
->key
.linear_color
) {
418 /* perspective-corrected color interpolation */
429 case FRAG_ATTRIB_FOGC
:
430 /* Interpolate the fog coordinate */
433 dst_mask(dst
, WRITEMASK_X
),
441 dst_mask(dst
, WRITEMASK_YZW
),
452 case FRAG_ATTRIB_FACE
:
455 dst_mask(dst
, WRITEMASK_X
),
462 case FRAG_ATTRIB_PNTC
:
463 /* XXX review/test this case */
466 dst_mask(dst
, WRITEMASK_XY
),
474 dst_mask(dst
, WRITEMASK_ZW
),
496 c
->fp_interp_emitted
|= 1<<idx
;
499 /***********************************************************************
500 * Hacks to extend the program parameter and constant lists.
503 /* Add the fog parameters to the parameter list of the original
504 * program, rather than creating a new list. Doesn't really do any
505 * harm and it's not as if the parameter handling isn't a big hack
508 static struct prog_src_register
search_or_add_param5(struct brw_wm_compile
*c
,
515 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
516 gl_state_index tokens
[STATE_LENGTH
];
524 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
525 if (paramList
->Parameters
[idx
].Type
== PROGRAM_STATE_VAR
&&
526 memcmp(paramList
->Parameters
[idx
].StateIndexes
, tokens
, sizeof(tokens
)) == 0)
527 return src_reg(PROGRAM_STATE_VAR
, idx
);
530 idx
= _mesa_add_state_reference( paramList
, tokens
);
532 return src_reg(PROGRAM_STATE_VAR
, idx
);
536 static struct prog_src_register
search_or_add_const4f( struct brw_wm_compile
*c
,
542 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
552 /* Have to search, otherwise multiple compilations will each grow
553 * the parameter list.
555 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
556 if (paramList
->Parameters
[idx
].Type
== PROGRAM_CONSTANT
&&
557 memcmp(paramList
->ParameterValues
[idx
], values
, sizeof(values
)) == 0)
559 /* XXX: this mimics the mesa bug which puts all constants and
560 * parameters into the "PROGRAM_STATE_VAR" category:
562 return src_reg(PROGRAM_STATE_VAR
, idx
);
565 idx
= _mesa_add_unnamed_constant( paramList
, values
, 4, &swizzle
);
566 assert(swizzle
== SWIZZLE_NOOP
); /* Need to handle swizzle in reg setup */
567 return src_reg(PROGRAM_STATE_VAR
, idx
);
572 /***********************************************************************
573 * Expand various instructions here to simpler forms.
575 static void precalc_dst( struct brw_wm_compile
*c
,
576 const struct prog_instruction
*inst
)
578 struct prog_src_register src0
= inst
->SrcReg
[0];
579 struct prog_src_register src1
= inst
->SrcReg
[1];
580 struct prog_dst_register dst
= inst
->DstReg
;
582 if (dst
.WriteMask
& WRITEMASK_Y
) {
583 /* dst.y = mul src0.y, src1.y
587 dst_mask(dst
, WRITEMASK_Y
),
594 if (dst
.WriteMask
& WRITEMASK_XZ
) {
595 struct prog_instruction
*swz
;
596 GLuint z
= GET_SWZ(src0
.Swizzle
, Z
);
598 /* dst.xz = swz src0.1zzz
602 dst_mask(dst
, WRITEMASK_XZ
),
604 src_swizzle(src0
, SWIZZLE_ONE
, z
, z
, z
),
607 /* Avoid letting negation flag of src0 affect our 1 constant. */
608 swz
->SrcReg
[0].Negate
&= ~NEGATE_X
;
610 if (dst
.WriteMask
& WRITEMASK_W
) {
611 /* dst.w = mov src1.w
615 dst_mask(dst
, WRITEMASK_W
),
624 static void precalc_lit( struct brw_wm_compile
*c
,
625 const struct prog_instruction
*inst
)
627 struct prog_src_register src0
= inst
->SrcReg
[0];
628 struct prog_dst_register dst
= inst
->DstReg
;
630 if (dst
.WriteMask
& WRITEMASK_XW
) {
631 struct prog_instruction
*swz
;
633 /* dst.xw = swz src0.1111
637 dst_mask(dst
, WRITEMASK_XW
),
639 src_swizzle1(src0
, SWIZZLE_ONE
),
642 /* Avoid letting the negation flag of src0 affect our 1 constant. */
643 swz
->SrcReg
[0].Negate
= NEGATE_NONE
;
646 if (dst
.WriteMask
& WRITEMASK_YZ
) {
649 dst_mask(dst
, WRITEMASK_YZ
),
659 * Some TEX instructions require extra code, cube map coordinate
660 * normalization, or coordinate scaling for RECT textures, etc.
661 * This function emits those extra instructions and the TEX
662 * instruction itself.
664 static void precalc_tex( struct brw_wm_compile
*c
,
665 const struct prog_instruction
*inst
)
667 struct prog_src_register coord
;
668 struct prog_dst_register tmpcoord
;
669 const GLuint unit
= c
->fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
671 assert(unit
< BRW_MAX_TEX_UNIT
);
673 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
) {
674 struct prog_instruction
*out
;
675 struct prog_dst_register tmp0
= get_temp(c
);
676 struct prog_src_register tmp0src
= src_reg_from_dst(tmp0
);
677 struct prog_dst_register tmp1
= get_temp(c
);
678 struct prog_src_register tmp1src
= src_reg_from_dst(tmp1
);
679 struct prog_src_register src0
= inst
->SrcReg
[0];
681 /* find longest component of coord vector and normalize it */
682 tmpcoord
= get_temp(c
);
683 coord
= src_reg_from_dst(tmpcoord
);
685 /* tmpcoord = src0 (i.e.: coord = src0) */
686 out
= emit_op(c
, OPCODE_MOV
,
692 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
693 out
->SrcReg
[0].Abs
= 1;
695 /* tmp0 = MAX(coord.X, coord.Y) */
696 emit_op(c
, OPCODE_MAX
,
699 src_swizzle1(coord
, X
),
700 src_swizzle1(coord
, Y
),
703 /* tmp1 = MAX(tmp0, coord.Z) */
704 emit_op(c
, OPCODE_MAX
,
708 src_swizzle1(coord
, Z
),
711 /* tmp0 = 1 / tmp1 */
712 emit_op(c
, OPCODE_RCP
,
713 dst_mask(tmp0
, WRITEMASK_X
),
719 /* tmpCoord = src0 * tmp0 */
720 emit_op(c
, OPCODE_MUL
,
724 src_swizzle1(tmp0src
, SWIZZLE_X
),
727 release_temp(c
, tmp0
);
728 release_temp(c
, tmp1
);
730 else if (inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) {
731 struct prog_src_register scale
=
732 search_or_add_param5( c
,
738 tmpcoord
= get_temp(c
);
740 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
754 coord
= src_reg_from_dst(tmpcoord
);
757 coord
= inst
->SrcReg
[0];
760 /* Need to emit YUV texture conversions by hand. Probably need to
761 * do this here - the alternative is in brw_wm_emit.c, but the
762 * conversion requires allocating a temporary variable which we
763 * don't have the facility to do that late in the compilation.
765 if (c
->key
.yuvtex_mask
& (1 << unit
)) {
766 /* convert ycbcr to RGBA */
767 GLboolean swap_uv
= c
->key
.yuvtex_swap_mask
& (1<<unit
);
770 CONST C0 = { -.5, -.0625, -.5, 1.164 }
771 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
773 UYV.xyz = ADD UYV, C0
774 UYV.y = MUL UYV.y, C0.w
776 RGB.xyz = MAD UYV.zzx, C1, UYV.y
778 RGB.xyz = MAD UYV.xxz, C1, UYV.y
779 RGB.y = MAD UYV.z, C1.w, RGB.y
781 struct prog_dst_register dst
= inst
->DstReg
;
782 struct prog_dst_register tmp
= get_temp(c
);
783 struct prog_src_register tmpsrc
= src_reg_from_dst(tmp
);
784 struct prog_src_register C0
= search_or_add_const4f( c
, -.5, -.0625, -.5, 1.164 );
785 struct prog_src_register C1
= search_or_add_const4f( c
, 1.596, -0.813, 2.018, -.391 );
800 /* tmp.xyz = ADD TMP, C0
804 dst_mask(tmp
, WRITEMASK_XYZ
),
810 /* YUV.y = MUL YUV.y, C0.w
815 dst_mask(tmp
, WRITEMASK_Y
),
823 * RGB.xyz = MAD YUV.zzx, C1, YUV.y
825 * RGB.xyz = MAD YUV.xxz, C1, YUV.y
830 dst_mask(dst
, WRITEMASK_XYZ
),
832 swap_uv
?src_swizzle(tmpsrc
, Z
,Z
,X
,X
):src_swizzle(tmpsrc
, X
,X
,Z
,Z
),
834 src_swizzle1(tmpsrc
, Y
));
836 /* RGB.y = MAD YUV.z, C1.w, RGB.y
840 dst_mask(dst
, WRITEMASK_Y
),
842 src_swizzle1(tmpsrc
, Z
),
844 src_swizzle1(src_reg_from_dst(dst
), Y
));
846 release_temp(c
, tmp
);
849 /* ordinary RGBA tex instruction */
862 /* For GL_EXT_texture_swizzle: */
863 if (c
->key
.tex_swizzles
[unit
] != SWIZZLE_NOOP
) {
864 /* swizzle the result of the TEX instruction */
865 struct prog_src_register tmpsrc
= src_reg_from_dst(inst
->DstReg
);
866 emit_op(c
, OPCODE_SWZ
,
868 SATURATE_OFF
, /* saturate already done above */
869 src_swizzle4(tmpsrc
, c
->key
.tex_swizzles
[unit
]),
874 if ((inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) ||
875 (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
))
876 release_temp(c
, tmpcoord
);
881 * Check if the given TXP instruction really needs the divide-by-W step.
883 static GLboolean
projtex( struct brw_wm_compile
*c
,
884 const struct prog_instruction
*inst
)
886 const struct prog_src_register src
= inst
->SrcReg
[0];
889 assert(inst
->Opcode
== OPCODE_TXP
);
891 /* Only try to detect the simplest cases. Could detect (later)
892 * cases where we are trying to emit code like RCP {1.0}, MUL x,
895 * More complex cases than this typically only arise from
896 * user-provided fragment programs anyway:
898 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
)
899 retVal
= GL_FALSE
; /* ut2004 gun rendering !?! */
900 else if (src
.File
== PROGRAM_INPUT
&&
901 GET_SWZ(src
.Swizzle
, W
) == W
&&
902 (c
->key
.proj_attrib_mask
& (1 << src
.Index
)) == 0)
914 static void precalc_txp( struct brw_wm_compile
*c
,
915 const struct prog_instruction
*inst
)
917 struct prog_src_register src0
= inst
->SrcReg
[0];
919 if (projtex(c
, inst
)) {
920 struct prog_dst_register tmp
= get_temp(c
);
921 struct prog_instruction tmp_inst
;
923 /* tmp0.w = RCP inst.arg[0][3]
927 dst_mask(tmp
, WRITEMASK_W
),
929 src_swizzle1(src0
, GET_SWZ(src0
.Swizzle
, W
)),
933 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
937 dst_mask(tmp
, WRITEMASK_XYZ
),
940 src_swizzle1(src_reg_from_dst(tmp
), W
),
943 /* dst = precalc(TEX tmp0)
946 tmp_inst
.SrcReg
[0] = src_reg_from_dst(tmp
);
947 precalc_tex(c
, &tmp_inst
);
949 release_temp(c
, tmp
);
953 /* dst = precalc(TEX src0)
955 precalc_tex(c
, inst
);
961 static void emit_render_target_writes( struct brw_wm_compile
*c
)
963 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
964 struct prog_src_register outdepth
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DEPTH
);
965 struct prog_src_register outcolor
;
968 struct prog_instruction
*inst
, *last_inst
;
970 /* The inst->Aux field is used for FB write target and the EOT marker */
972 if (c
->key
.nr_color_regions
> 1) {
973 for (i
= 0 ; i
< c
->key
.nr_color_regions
; i
++) {
974 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
+ i
);
975 last_inst
= inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(), 0),
976 0, outcolor
, payload_r0_depth
, outdepth
);
977 inst
->Aux
= INST_AUX_TARGET(i
);
978 if (c
->fp_fragcolor_emitted
) {
979 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
980 last_inst
= inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(), 0),
981 0, outcolor
, payload_r0_depth
, outdepth
);
982 inst
->Aux
= INST_AUX_TARGET(i
);
985 last_inst
->Aux
|= INST_AUX_EOT
;
988 /* if gl_FragData[0] is written, use it, else use gl_FragColor */
989 if (c
->fp
->program
.Base
.OutputsWritten
& BITFIELD64_BIT(FRAG_RESULT_DATA0
))
990 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
);
992 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
994 inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(),0),
995 0, outcolor
, payload_r0_depth
, outdepth
);
996 inst
->Aux
= INST_AUX_EOT
| INST_AUX_TARGET(0);
1003 /***********************************************************************
1004 * Emit INTERP instructions ahead of first use of each attrib.
1007 static void validate_src_regs( struct brw_wm_compile
*c
,
1008 const struct prog_instruction
*inst
)
1010 GLuint nr_args
= brw_wm_nr_args( inst
->Opcode
);
1013 for (i
= 0; i
< nr_args
; i
++) {
1014 if (inst
->SrcReg
[i
].File
== PROGRAM_INPUT
) {
1015 GLuint idx
= inst
->SrcReg
[i
].Index
;
1016 if (!(c
->fp_interp_emitted
& (1<<idx
))) {
1017 emit_interp(c
, idx
);
1023 static void validate_dst_regs( struct brw_wm_compile
*c
,
1024 const struct prog_instruction
*inst
)
1026 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
) {
1027 GLuint idx
= inst
->DstReg
.Index
;
1028 if (idx
== FRAG_RESULT_COLOR
)
1029 c
->fp_fragcolor_emitted
= 1;
1033 static void print_insns( const struct prog_instruction
*insn
,
1037 for (i
= 0; i
< nr
; i
++, insn
++) {
1039 if (insn
->Opcode
< MAX_OPCODE
)
1040 _mesa_fprint_instruction_opt(stdout
, insn
, 0, PROG_PRINT_DEBUG
, NULL
);
1041 else if (insn
->Opcode
< MAX_WM_OPCODE
) {
1042 GLuint idx
= insn
->Opcode
- MAX_OPCODE
;
1044 _mesa_fprint_alu_instruction(stdout
, insn
, wm_opcode_strings
[idx
],
1045 3, PROG_PRINT_DEBUG
, NULL
);
1048 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 printf("pre-fp:\n");
1064 _mesa_fprint_program_opt(stdout
, &fp
->program
.Base
, PROG_PRINT_DEBUG
,
1069 c
->pixel_xy
= src_undef();
1070 c
->delta_xy
= src_undef();
1071 c
->pixel_w
= src_undef();
1073 c
->fp
->tex_units_used
= 0x0;
1075 /* Emit preamble instructions. This is where special instructions such as
1076 * WM_CINTERP, WM_LINTERP, WM_PINTERP and WM_WPOSXY are emitted to
1077 * compute shader inputs from varying vars.
1079 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1080 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1081 validate_src_regs(c
, inst
);
1082 validate_dst_regs(c
, inst
);
1085 /* Loop over all instructions doing assorted simplifications and
1088 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1089 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1090 struct prog_instruction
*out
;
1092 /* Check for INPUT values, emit INTERP instructions where
1096 switch (inst
->Opcode
) {
1098 out
= emit_insn(c
, inst
);
1099 out
->Opcode
= OPCODE_MOV
;
1103 out
= emit_insn(c
, inst
);
1104 out
->Opcode
= OPCODE_MOV
;
1105 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
1106 out
->SrcReg
[0].Abs
= 1;
1110 out
= emit_insn(c
, inst
);
1111 out
->Opcode
= OPCODE_ADD
;
1112 out
->SrcReg
[1].Negate
^= NEGATE_XYZW
;
1116 out
= emit_insn(c
, inst
);
1117 /* This should probably be done in the parser.
1119 out
->DstReg
.WriteMask
&= WRITEMASK_XY
;
1123 precalc_dst(c
, inst
);
1127 precalc_lit(c
, inst
);
1131 precalc_tex(c
, inst
);
1135 precalc_txp(c
, inst
);
1139 out
= emit_insn(c
, inst
);
1140 out
->TexSrcUnit
= fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
1141 assert(out
->TexSrcUnit
< BRW_MAX_TEX_UNIT
);
1145 out
= emit_insn(c
, inst
);
1146 /* This should probably be done in the parser.
1148 out
->DstReg
.WriteMask
&= WRITEMASK_XYZ
;
1152 out
= emit_insn(c
, inst
);
1153 /* This should probably be done in the parser.
1155 out
->DstReg
.WriteMask
= 0;
1158 emit_render_target_writes(c
);
1163 if (brw_wm_is_scalar_result(inst
->Opcode
))
1164 emit_scalar_insn(c
, inst
);
1171 if (INTEL_DEBUG
& DEBUG_WM
) {
1172 printf("pass_fp:\n");
1173 print_insns( c
->prog_instructions
, c
->nr_fp_insns
);