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
;
97 static struct prog_src_register
src_reg_from_dst(struct prog_dst_register dst
)
99 return src_reg(dst
.File
, dst
.Index
);
102 static struct prog_src_register
src_undef( void )
104 return src_reg(PROGRAM_UNDEFINED
, 0);
107 static GLboolean
src_is_undef(struct prog_src_register src
)
109 return src
.File
== PROGRAM_UNDEFINED
;
112 static struct prog_src_register
src_swizzle( struct prog_src_register reg
, int x
, int y
, int z
, int w
)
114 reg
.Swizzle
= MAKE_SWIZZLE4(x
,y
,z
,w
);
118 static struct prog_src_register
src_swizzle1( struct prog_src_register reg
, int x
)
120 return src_swizzle(reg
, x
, x
, x
, x
);
123 static struct prog_src_register
src_swizzle4( struct prog_src_register reg
, uint swizzle
)
125 reg
.Swizzle
= swizzle
;
130 /***********************************************************************
134 static struct prog_dst_register
dst_reg(GLuint file
, GLuint idx
)
136 struct prog_dst_register reg
;
139 reg
.WriteMask
= WRITEMASK_XYZW
;
141 reg
.CondMask
= COND_TR
;
147 static struct prog_dst_register
dst_mask( struct prog_dst_register reg
, int mask
)
149 reg
.WriteMask
&= mask
;
153 static struct prog_dst_register
dst_undef( void )
155 return dst_reg(PROGRAM_UNDEFINED
, 0);
160 static struct prog_dst_register
get_temp( struct brw_wm_compile
*c
)
162 int bit
= _mesa_ffs( ~c
->fp_temp
);
165 printf("%s: out of temporaries\n", __FILE__
);
169 c
->fp_temp
|= 1<<(bit
-1);
170 return dst_reg(PROGRAM_TEMPORARY
, FIRST_INTERNAL_TEMP
+(bit
-1));
174 static void release_temp( struct brw_wm_compile
*c
, struct prog_dst_register temp
)
176 c
->fp_temp
&= ~(1 << (temp
.Index
- FIRST_INTERNAL_TEMP
));
180 /***********************************************************************
184 static struct prog_instruction
*get_fp_inst(struct brw_wm_compile
*c
)
186 assert(c
->nr_fp_insns
< BRW_WM_MAX_INSN
);
187 memset(&c
->prog_instructions
[c
->nr_fp_insns
], 0,
188 sizeof(*c
->prog_instructions
));
189 return &c
->prog_instructions
[c
->nr_fp_insns
++];
192 static struct prog_instruction
*emit_insn(struct brw_wm_compile
*c
,
193 const struct prog_instruction
*inst0
)
195 struct prog_instruction
*inst
= get_fp_inst(c
);
200 static struct prog_instruction
* emit_tex_op(struct brw_wm_compile
*c
,
202 struct prog_dst_register dest
,
205 GLuint tex_src_target
,
207 struct prog_src_register src0
,
208 struct prog_src_register src1
,
209 struct prog_src_register src2
)
211 struct prog_instruction
*inst
= get_fp_inst(c
);
213 assert(tex_src_unit
< BRW_MAX_TEX_UNIT
||
214 tex_src_unit
== TEX_UNIT_NONE
);
215 assert(tex_src_target
< NUM_TEXTURE_TARGETS
||
216 tex_src_target
== TEX_TARGET_NONE
);
218 /* update mask of which texture units are referenced by this program */
219 if (tex_src_unit
!= TEX_UNIT_NONE
)
220 c
->fp
->tex_units_used
|= (1 << tex_src_unit
);
222 memset(inst
, 0, sizeof(*inst
));
226 inst
->SaturateMode
= saturate
;
227 inst
->TexSrcUnit
= tex_src_unit
;
228 inst
->TexSrcTarget
= tex_src_target
;
229 inst
->TexShadow
= tex_shadow
;
230 inst
->SrcReg
[0] = src0
;
231 inst
->SrcReg
[1] = src1
;
232 inst
->SrcReg
[2] = src2
;
237 static struct prog_instruction
* emit_op(struct brw_wm_compile
*c
,
239 struct prog_dst_register dest
,
241 struct prog_src_register src0
,
242 struct prog_src_register src1
,
243 struct prog_src_register src2
)
245 return emit_tex_op(c
, op
, dest
, saturate
,
246 TEX_UNIT_NONE
, TEX_TARGET_NONE
, 0, /* unit, tgt, shadow */
251 /* Many Mesa opcodes produce the same value across all the result channels.
252 * We'd rather not have to support that splatting in the opcode implementations,
253 * and brw_wm_pass*.c wants to optimize them out by shuffling references around
254 * anyway. We can easily get both by emitting the opcode to one channel, and
255 * then MOVing it to the others, which brw_wm_pass*.c already understands.
257 static struct prog_instruction
*emit_scalar_insn(struct brw_wm_compile
*c
,
258 const struct prog_instruction
*inst0
)
260 struct prog_instruction
*inst
;
261 unsigned int dst_chan
;
262 unsigned int other_channel_mask
;
264 if (inst0
->DstReg
.WriteMask
== 0)
267 dst_chan
= _mesa_ffs(inst0
->DstReg
.WriteMask
) - 1;
268 inst
= get_fp_inst(c
);
270 inst
->DstReg
.WriteMask
= 1 << dst_chan
;
272 other_channel_mask
= inst0
->DstReg
.WriteMask
& ~(1 << dst_chan
);
273 if (other_channel_mask
!= 0) {
276 dst_mask(inst0
->DstReg
, other_channel_mask
),
278 src_swizzle1(src_reg_from_dst(inst0
->DstReg
), dst_chan
),
286 /***********************************************************************
287 * Special instructions for interpolation and other tasks
290 static struct prog_src_register
get_pixel_xy( struct brw_wm_compile
*c
)
292 if (src_is_undef(c
->pixel_xy
)) {
293 struct prog_dst_register pixel_xy
= get_temp(c
);
294 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
297 /* Emit the out calculations, and hold onto the results. Use
298 * two instructions as a temporary is required.
300 /* pixel_xy.xy = PIXELXY payload[0];
304 dst_mask(pixel_xy
, WRITEMASK_XY
),
310 c
->pixel_xy
= src_reg_from_dst(pixel_xy
);
316 static struct prog_src_register
get_delta_xy( struct brw_wm_compile
*c
)
318 if (src_is_undef(c
->delta_xy
)) {
319 struct prog_dst_register delta_xy
= get_temp(c
);
320 struct prog_src_register pixel_xy
= get_pixel_xy(c
);
321 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
323 /* deltas.xy = DELTAXY pixel_xy, payload[0]
327 dst_mask(delta_xy
, WRITEMASK_XY
),
333 c
->delta_xy
= src_reg_from_dst(delta_xy
);
339 static struct prog_src_register
get_pixel_w( struct brw_wm_compile
*c
)
341 /* This is called for producing 1/w in pre-gen6 interp. for gen6,
342 * the interp opcodes don't use this argument. But to keep the
343 * nr_args = 3 expectations of pinterp happy, just stuff delta_xy
346 if (c
->func
.brw
->intel
.gen
>= 6)
349 if (src_is_undef(c
->pixel_w
)) {
350 struct prog_dst_register pixel_w
= get_temp(c
);
351 struct prog_src_register deltas
= get_delta_xy(c
);
352 struct prog_src_register interp_wpos
= src_reg(PROGRAM_PAYLOAD
, FRAG_ATTRIB_WPOS
);
354 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
358 dst_mask(pixel_w
, WRITEMASK_W
),
365 c
->pixel_w
= src_reg_from_dst(pixel_w
);
371 static void emit_interp( struct brw_wm_compile
*c
,
374 struct prog_dst_register dst
= dst_reg(PROGRAM_INPUT
, idx
);
375 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
376 struct prog_src_register deltas
;
378 deltas
= get_delta_xy(c
);
380 /* Need to use PINTERP on attributes which have been
381 * multiplied by 1/W in the SF program, and LINTERP on those
385 case FRAG_ATTRIB_WPOS
:
386 /* Have to treat wpos.xy specially:
390 dst_mask(dst
, WRITEMASK_XY
),
396 dst
= dst_mask(dst
, WRITEMASK_ZW
);
398 /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
408 case FRAG_ATTRIB_COL0
:
409 case FRAG_ATTRIB_COL1
:
410 if (c
->key
.flat_shade
) {
420 /* perspective-corrected color interpolation */
430 case FRAG_ATTRIB_FOGC
:
431 /* Interpolate the fog coordinate */
434 dst_mask(dst
, WRITEMASK_X
),
442 dst_mask(dst
, WRITEMASK_YZW
),
453 case FRAG_ATTRIB_FACE
:
456 dst_mask(dst
, WRITEMASK_X
),
463 case FRAG_ATTRIB_PNTC
:
464 /* XXX review/test this case */
467 dst_mask(dst
, WRITEMASK_XY
),
475 dst_mask(dst
, WRITEMASK_ZW
),
497 c
->fp_interp_emitted
|= 1<<idx
;
500 /***********************************************************************
501 * Hacks to extend the program parameter and constant lists.
504 /* Add the fog parameters to the parameter list of the original
505 * program, rather than creating a new list. Doesn't really do any
506 * harm and it's not as if the parameter handling isn't a big hack
509 static struct prog_src_register
search_or_add_param5(struct brw_wm_compile
*c
,
516 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
517 gl_state_index tokens
[STATE_LENGTH
];
525 idx
= _mesa_add_state_reference( paramList
, tokens
);
527 return src_reg(PROGRAM_STATE_VAR
, idx
);
531 static struct prog_src_register
search_or_add_const4f( struct brw_wm_compile
*c
,
537 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
538 gl_constant_value values
[4];
541 struct prog_src_register reg
;
548 idx
= _mesa_add_unnamed_constant( paramList
, values
, 4, &swizzle
);
549 reg
= src_reg(PROGRAM_STATE_VAR
, idx
);
550 reg
.Swizzle
= swizzle
;
557 /***********************************************************************
558 * Expand various instructions here to simpler forms.
560 static void precalc_dst( struct brw_wm_compile
*c
,
561 const struct prog_instruction
*inst
)
563 struct prog_src_register src0
= inst
->SrcReg
[0];
564 struct prog_src_register src1
= inst
->SrcReg
[1];
565 struct prog_dst_register dst
= inst
->DstReg
;
566 struct prog_dst_register temp
= get_temp(c
);
568 if (dst
.WriteMask
& WRITEMASK_Y
) {
569 /* dst.y = mul src0.y, src1.y
573 dst_mask(temp
, WRITEMASK_Y
),
580 if (dst
.WriteMask
& WRITEMASK_XZ
) {
581 struct prog_instruction
*swz
;
582 GLuint z
= GET_SWZ(src0
.Swizzle
, Z
);
584 /* dst.xz = swz src0.1zzz
588 dst_mask(temp
, WRITEMASK_XZ
),
590 src_swizzle(src0
, SWIZZLE_ONE
, z
, z
, z
),
593 /* Avoid letting negation flag of src0 affect our 1 constant. */
594 swz
->SrcReg
[0].Negate
&= ~NEGATE_X
;
596 if (dst
.WriteMask
& WRITEMASK_W
) {
597 /* dst.w = mov src1.w
601 dst_mask(temp
, WRITEMASK_W
),
608 /* This will get optimized out in general, but it ensures that we
609 * don't overwrite src operands in our channel-wise splitting
610 * above. See piglit fp-dst-aliasing-[12].
616 src_reg_from_dst(temp
),
620 release_temp(c
, temp
);
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_YZ
) {
633 dst_mask(dst
, WRITEMASK_YZ
),
640 if (dst
.WriteMask
& WRITEMASK_XW
) {
641 struct prog_instruction
*swz
;
643 /* dst.xw = swz src0.1111
647 dst_mask(dst
, WRITEMASK_XW
),
649 src_swizzle1(src0
, SWIZZLE_ONE
),
652 /* Avoid letting the negation flag of src0 affect our 1 constant. */
653 swz
->SrcReg
[0].Negate
= NEGATE_NONE
;
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 brw_compile
*p
= &c
->func
;
668 struct intel_context
*intel
= &p
->brw
->intel
;
669 struct prog_src_register coord
;
670 struct prog_dst_register tmpcoord
= { 0 };
671 const GLuint unit
= c
->fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
673 assert(unit
< BRW_MAX_TEX_UNIT
);
675 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
) {
676 struct prog_instruction
*out
;
677 struct prog_dst_register tmp0
= get_temp(c
);
678 struct prog_src_register tmp0src
= src_reg_from_dst(tmp0
);
679 struct prog_dst_register tmp1
= get_temp(c
);
680 struct prog_src_register tmp1src
= src_reg_from_dst(tmp1
);
681 struct prog_src_register src0
= inst
->SrcReg
[0];
683 /* find longest component of coord vector and normalize it */
684 tmpcoord
= get_temp(c
);
685 coord
= src_reg_from_dst(tmpcoord
);
687 /* tmpcoord = src0 (i.e.: coord = src0) */
688 out
= emit_op(c
, OPCODE_MOV
,
694 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
695 out
->SrcReg
[0].Abs
= 1;
697 /* tmp0 = MAX(coord.X, coord.Y) */
698 emit_op(c
, OPCODE_MAX
,
701 src_swizzle1(coord
, X
),
702 src_swizzle1(coord
, Y
),
705 /* tmp1 = MAX(tmp0, coord.Z) */
706 emit_op(c
, OPCODE_MAX
,
710 src_swizzle1(coord
, Z
),
713 /* tmp0 = 1 / tmp1 */
714 emit_op(c
, OPCODE_RCP
,
715 dst_mask(tmp0
, WRITEMASK_X
),
721 /* tmpCoord = src0 * tmp0 */
722 emit_op(c
, OPCODE_MUL
,
726 src_swizzle1(tmp0src
, SWIZZLE_X
),
729 release_temp(c
, tmp0
);
730 release_temp(c
, tmp1
);
732 else if (intel
->gen
< 6 && inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) {
733 struct prog_src_register scale
=
734 search_or_add_param5( c
,
740 tmpcoord
= get_temp(c
);
742 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
756 coord
= src_reg_from_dst(tmpcoord
);
759 coord
= inst
->SrcReg
[0];
762 /* Need to emit YUV texture conversions by hand. Probably need to
763 * do this here - the alternative is in brw_wm_emit.c, but the
764 * conversion requires allocating a temporary variable which we
765 * don't have the facility to do that late in the compilation.
767 if (c
->key
.yuvtex_mask
& (1 << unit
)) {
768 /* convert ycbcr to RGBA */
769 GLboolean swap_uv
= c
->key
.yuvtex_swap_mask
& (1<<unit
);
772 CONST C0 = { -.5, -.0625, -.5, 1.164 }
773 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
775 UYV.xyz = ADD UYV, C0
776 UYV.y = MUL UYV.y, C0.w
778 RGB.xyz = MAD UYV.zzx, C1, UYV.y
780 RGB.xyz = MAD UYV.xxz, C1, UYV.y
781 RGB.y = MAD UYV.z, C1.w, RGB.y
783 struct prog_dst_register dst
= inst
->DstReg
;
784 struct prog_dst_register tmp
= get_temp(c
);
785 struct prog_src_register tmpsrc
= src_reg_from_dst(tmp
);
786 struct prog_src_register C0
= search_or_add_const4f( c
, -.5, -.0625, -.5, 1.164 );
787 struct prog_src_register C1
= search_or_add_const4f( c
, 1.596, -0.813, 2.018, -.391 );
802 /* tmp.xyz = ADD TMP, C0
806 dst_mask(tmp
, WRITEMASK_XYZ
),
812 /* YUV.y = MUL YUV.y, C0.w
817 dst_mask(tmp
, WRITEMASK_Y
),
825 * RGB.xyz = MAD YUV.zzx, C1, YUV.y
827 * RGB.xyz = MAD YUV.xxz, C1, YUV.y
832 dst_mask(dst
, WRITEMASK_XYZ
),
834 swap_uv
?src_swizzle(tmpsrc
, Z
,Z
,X
,X
):src_swizzle(tmpsrc
, X
,X
,Z
,Z
),
836 src_swizzle1(tmpsrc
, Y
));
838 /* RGB.y = MAD YUV.z, C1.w, RGB.y
842 dst_mask(dst
, WRITEMASK_Y
),
844 src_swizzle1(tmpsrc
, Z
),
846 src_swizzle1(src_reg_from_dst(dst
), Y
));
848 release_temp(c
, tmp
);
851 /* ordinary RGBA tex instruction */
864 /* For GL_EXT_texture_swizzle: */
865 if (c
->key
.tex_swizzles
[unit
] != SWIZZLE_NOOP
) {
866 /* swizzle the result of the TEX instruction */
867 struct prog_src_register tmpsrc
= src_reg_from_dst(inst
->DstReg
);
868 emit_op(c
, OPCODE_SWZ
,
870 SATURATE_OFF
, /* saturate already done above */
871 src_swizzle4(tmpsrc
, c
->key
.tex_swizzles
[unit
]),
876 if ((inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) ||
877 (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
))
878 release_temp(c
, tmpcoord
);
883 * Check if the given TXP instruction really needs the divide-by-W step.
885 static GLboolean
projtex( struct brw_wm_compile
*c
,
886 const struct prog_instruction
*inst
)
888 const struct prog_src_register src
= inst
->SrcReg
[0];
891 assert(inst
->Opcode
== OPCODE_TXP
);
893 /* Only try to detect the simplest cases. Could detect (later)
894 * cases where we are trying to emit code like RCP {1.0}, MUL x,
897 * More complex cases than this typically only arise from
898 * user-provided fragment programs anyway:
900 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
)
901 retVal
= GL_FALSE
; /* ut2004 gun rendering !?! */
902 else if (src
.File
== PROGRAM_INPUT
&&
903 GET_SWZ(src
.Swizzle
, W
) == W
&&
904 (c
->key
.proj_attrib_mask
& (1 << src
.Index
)) == 0)
916 static void precalc_txp( struct brw_wm_compile
*c
,
917 const struct prog_instruction
*inst
)
919 struct prog_src_register src0
= inst
->SrcReg
[0];
921 if (projtex(c
, inst
)) {
922 struct prog_dst_register tmp
= get_temp(c
);
923 struct prog_instruction tmp_inst
;
925 /* tmp0.w = RCP inst.arg[0][3]
929 dst_mask(tmp
, WRITEMASK_W
),
931 src_swizzle1(src0
, GET_SWZ(src0
.Swizzle
, W
)),
935 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
939 dst_mask(tmp
, WRITEMASK_XYZ
),
942 src_swizzle1(src_reg_from_dst(tmp
), W
),
945 /* dst = precalc(TEX tmp0)
948 tmp_inst
.SrcReg
[0] = src_reg_from_dst(tmp
);
949 precalc_tex(c
, &tmp_inst
);
951 release_temp(c
, tmp
);
955 /* dst = precalc(TEX src0)
957 precalc_tex(c
, inst
);
963 static void emit_render_target_writes( struct brw_wm_compile
*c
)
965 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
966 struct prog_src_register outdepth
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DEPTH
);
967 struct prog_src_register outcolor
;
970 struct prog_instruction
*inst
= NULL
;
972 /* The inst->Aux field is used for FB write target and the EOT marker */
974 for (i
= 0; i
< c
->key
.nr_color_regions
; i
++) {
975 if (c
->fp
->program
.Base
.OutputsWritten
& (1 << FRAG_RESULT_COLOR
)) {
976 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
978 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
+ i
);
980 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 /* Mark the last FB write as final, or emit a dummy write if we had
986 * no render targets bound.
988 if (c
->key
.nr_color_regions
!= 0) {
989 inst
->Aux
|= INST_AUX_EOT
;
991 inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(), 0),
992 0, src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
),
993 payload_r0_depth
, outdepth
);
994 inst
->Aux
= INST_AUX_TARGET(0) | INST_AUX_EOT
;
1001 /***********************************************************************
1002 * Emit INTERP instructions ahead of first use of each attrib.
1005 static void validate_src_regs( struct brw_wm_compile
*c
,
1006 const struct prog_instruction
*inst
)
1008 GLuint nr_args
= brw_wm_nr_args( inst
->Opcode
);
1011 for (i
= 0; i
< nr_args
; i
++) {
1012 if (inst
->SrcReg
[i
].File
== PROGRAM_INPUT
) {
1013 GLuint idx
= inst
->SrcReg
[i
].Index
;
1014 if (!(c
->fp_interp_emitted
& (1<<idx
))) {
1015 emit_interp(c
, idx
);
1021 static void print_insns( const struct prog_instruction
*insn
,
1025 for (i
= 0; i
< nr
; i
++, insn
++) {
1027 if (insn
->Opcode
< MAX_OPCODE
)
1028 _mesa_fprint_instruction_opt(stdout
, insn
, 0, PROG_PRINT_DEBUG
, NULL
);
1029 else if (insn
->Opcode
< MAX_WM_OPCODE
) {
1030 GLuint idx
= insn
->Opcode
- MAX_OPCODE
;
1032 _mesa_fprint_alu_instruction(stdout
, insn
, wm_opcode_strings
[idx
],
1033 3, PROG_PRINT_DEBUG
, NULL
);
1036 printf("965 Opcode %d\n", insn
->Opcode
);
1042 * Initial pass for fragment program code generation.
1043 * This function is used by both the GLSL and non-GLSL paths.
1045 void brw_wm_pass_fp( struct brw_wm_compile
*c
)
1047 struct intel_context
*intel
= &c
->func
.brw
->intel
;
1048 struct brw_fragment_program
*fp
= c
->fp
;
1051 if (unlikely(INTEL_DEBUG
& DEBUG_WM
)) {
1052 printf("pre-fp:\n");
1053 _mesa_fprint_program_opt(stdout
, &fp
->program
.Base
, PROG_PRINT_DEBUG
,
1058 c
->pixel_xy
= src_undef();
1059 if (intel
->gen
>= 6) {
1060 /* The interpolation deltas come in as the perspective pixel
1061 * location barycentric params.
1063 c
->delta_xy
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
1065 c
->delta_xy
= src_undef();
1067 c
->pixel_w
= src_undef();
1069 c
->fp
->tex_units_used
= 0x0;
1071 /* Emit preamble instructions. This is where special instructions such as
1072 * WM_CINTERP, WM_LINTERP, WM_PINTERP and WM_WPOSXY are emitted to
1073 * compute shader inputs from varying vars.
1075 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1076 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1077 validate_src_regs(c
, inst
);
1080 /* Loop over all instructions doing assorted simplifications and
1083 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1084 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1085 struct prog_instruction
*out
;
1087 /* Check for INPUT values, emit INTERP instructions where
1091 switch (inst
->Opcode
) {
1093 out
= emit_insn(c
, inst
);
1094 out
->Opcode
= OPCODE_MOV
;
1098 out
= emit_insn(c
, inst
);
1099 out
->Opcode
= OPCODE_MOV
;
1100 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
1101 out
->SrcReg
[0].Abs
= 1;
1105 out
= emit_insn(c
, inst
);
1106 out
->Opcode
= OPCODE_ADD
;
1107 out
->SrcReg
[1].Negate
^= NEGATE_XYZW
;
1111 out
= emit_insn(c
, inst
);
1112 /* This should probably be done in the parser.
1114 out
->DstReg
.WriteMask
&= WRITEMASK_XY
;
1118 precalc_dst(c
, inst
);
1122 precalc_lit(c
, inst
);
1126 out
= emit_scalar_insn(c
, inst
);
1127 out
->SrcReg
[0].Abs
= GL_TRUE
;
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 (unlikely(INTEL_DEBUG
& DEBUG_WM
)) {
1172 printf("pass_fp:\n");
1173 print_insns( c
->prog_instructions
, c
->nr_fp_insns
);