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 /* This is only called for producing 1/w in pre-gen6 interp. for
340 * gen6, the interp opcodes don't use this argument.
342 if (c
->func
.brw
->intel
.gen
>= 6)
345 if (src_is_undef(c
->pixel_w
)) {
346 struct prog_dst_register pixel_w
= get_temp(c
);
347 struct prog_src_register deltas
= get_delta_xy(c
);
348 struct prog_src_register interp_wpos
= src_reg(PROGRAM_PAYLOAD
, FRAG_ATTRIB_WPOS
);
350 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
354 dst_mask(pixel_w
, WRITEMASK_W
),
361 c
->pixel_w
= src_reg_from_dst(pixel_w
);
367 static void emit_interp( struct brw_wm_compile
*c
,
370 struct prog_dst_register dst
= dst_reg(PROGRAM_INPUT
, idx
);
371 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
372 struct prog_src_register deltas
;
374 if (c
->func
.brw
->intel
.gen
< 6) {
375 deltas
= get_delta_xy(c
);
377 deltas
= src_undef();
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 if (c
->key
.linear_color
) {
430 /* perspective-corrected color interpolation */
441 case FRAG_ATTRIB_FOGC
:
442 /* Interpolate the fog coordinate */
445 dst_mask(dst
, WRITEMASK_X
),
453 dst_mask(dst
, WRITEMASK_YZW
),
464 case FRAG_ATTRIB_FACE
:
467 dst_mask(dst
, WRITEMASK_X
),
474 case FRAG_ATTRIB_PNTC
:
475 /* XXX review/test this case */
478 dst_mask(dst
, WRITEMASK_XY
),
486 dst_mask(dst
, WRITEMASK_ZW
),
508 c
->fp_interp_emitted
|= 1<<idx
;
511 /***********************************************************************
512 * Hacks to extend the program parameter and constant lists.
515 /* Add the fog parameters to the parameter list of the original
516 * program, rather than creating a new list. Doesn't really do any
517 * harm and it's not as if the parameter handling isn't a big hack
520 static struct prog_src_register
search_or_add_param5(struct brw_wm_compile
*c
,
527 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
528 gl_state_index tokens
[STATE_LENGTH
];
536 idx
= _mesa_add_state_reference( paramList
, tokens
);
538 return src_reg(PROGRAM_STATE_VAR
, idx
);
542 static struct prog_src_register
search_or_add_const4f( struct brw_wm_compile
*c
,
548 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
552 struct prog_src_register reg
;
559 idx
= _mesa_add_unnamed_constant( paramList
, values
, 4, &swizzle
);
560 reg
= src_reg(PROGRAM_STATE_VAR
, idx
);
561 reg
.Swizzle
= swizzle
;
568 /***********************************************************************
569 * Expand various instructions here to simpler forms.
571 static void precalc_dst( struct brw_wm_compile
*c
,
572 const struct prog_instruction
*inst
)
574 struct prog_src_register src0
= inst
->SrcReg
[0];
575 struct prog_src_register src1
= inst
->SrcReg
[1];
576 struct prog_dst_register dst
= inst
->DstReg
;
578 if (dst
.WriteMask
& WRITEMASK_Y
) {
579 /* dst.y = mul src0.y, src1.y
583 dst_mask(dst
, WRITEMASK_Y
),
590 if (dst
.WriteMask
& WRITEMASK_XZ
) {
591 struct prog_instruction
*swz
;
592 GLuint z
= GET_SWZ(src0
.Swizzle
, Z
);
594 /* dst.xz = swz src0.1zzz
598 dst_mask(dst
, WRITEMASK_XZ
),
600 src_swizzle(src0
, SWIZZLE_ONE
, z
, z
, z
),
603 /* Avoid letting negation flag of src0 affect our 1 constant. */
604 swz
->SrcReg
[0].Negate
&= ~NEGATE_X
;
606 if (dst
.WriteMask
& WRITEMASK_W
) {
607 /* dst.w = mov src1.w
611 dst_mask(dst
, WRITEMASK_W
),
620 static void precalc_lit( struct brw_wm_compile
*c
,
621 const struct prog_instruction
*inst
)
623 struct prog_src_register src0
= inst
->SrcReg
[0];
624 struct prog_dst_register dst
= inst
->DstReg
;
626 if (dst
.WriteMask
& WRITEMASK_XW
) {
627 struct prog_instruction
*swz
;
629 /* dst.xw = swz src0.1111
633 dst_mask(dst
, WRITEMASK_XW
),
635 src_swizzle1(src0
, SWIZZLE_ONE
),
638 /* Avoid letting the negation flag of src0 affect our 1 constant. */
639 swz
->SrcReg
[0].Negate
= NEGATE_NONE
;
642 if (dst
.WriteMask
& WRITEMASK_YZ
) {
645 dst_mask(dst
, WRITEMASK_YZ
),
655 * Some TEX instructions require extra code, cube map coordinate
656 * normalization, or coordinate scaling for RECT textures, etc.
657 * This function emits those extra instructions and the TEX
658 * instruction itself.
660 static void precalc_tex( struct brw_wm_compile
*c
,
661 const struct prog_instruction
*inst
)
663 struct prog_src_register coord
;
664 struct prog_dst_register tmpcoord
;
665 const GLuint unit
= c
->fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
667 assert(unit
< BRW_MAX_TEX_UNIT
);
669 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
) {
670 struct prog_instruction
*out
;
671 struct prog_dst_register tmp0
= get_temp(c
);
672 struct prog_src_register tmp0src
= src_reg_from_dst(tmp0
);
673 struct prog_dst_register tmp1
= get_temp(c
);
674 struct prog_src_register tmp1src
= src_reg_from_dst(tmp1
);
675 struct prog_src_register src0
= inst
->SrcReg
[0];
677 /* find longest component of coord vector and normalize it */
678 tmpcoord
= get_temp(c
);
679 coord
= src_reg_from_dst(tmpcoord
);
681 /* tmpcoord = src0 (i.e.: coord = src0) */
682 out
= emit_op(c
, OPCODE_MOV
,
688 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
689 out
->SrcReg
[0].Abs
= 1;
691 /* tmp0 = MAX(coord.X, coord.Y) */
692 emit_op(c
, OPCODE_MAX
,
695 src_swizzle1(coord
, X
),
696 src_swizzle1(coord
, Y
),
699 /* tmp1 = MAX(tmp0, coord.Z) */
700 emit_op(c
, OPCODE_MAX
,
704 src_swizzle1(coord
, Z
),
707 /* tmp0 = 1 / tmp1 */
708 emit_op(c
, OPCODE_RCP
,
709 dst_mask(tmp0
, WRITEMASK_X
),
715 /* tmpCoord = src0 * tmp0 */
716 emit_op(c
, OPCODE_MUL
,
720 src_swizzle1(tmp0src
, SWIZZLE_X
),
723 release_temp(c
, tmp0
);
724 release_temp(c
, tmp1
);
726 else if (inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) {
727 struct prog_src_register scale
=
728 search_or_add_param5( c
,
734 tmpcoord
= get_temp(c
);
736 /* coord.xy = MUL inst->SrcReg[0], { 1/width, 1/height }
750 coord
= src_reg_from_dst(tmpcoord
);
753 coord
= inst
->SrcReg
[0];
756 /* Need to emit YUV texture conversions by hand. Probably need to
757 * do this here - the alternative is in brw_wm_emit.c, but the
758 * conversion requires allocating a temporary variable which we
759 * don't have the facility to do that late in the compilation.
761 if (c
->key
.yuvtex_mask
& (1 << unit
)) {
762 /* convert ycbcr to RGBA */
763 GLboolean swap_uv
= c
->key
.yuvtex_swap_mask
& (1<<unit
);
766 CONST C0 = { -.5, -.0625, -.5, 1.164 }
767 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
769 UYV.xyz = ADD UYV, C0
770 UYV.y = MUL UYV.y, C0.w
772 RGB.xyz = MAD UYV.zzx, C1, UYV.y
774 RGB.xyz = MAD UYV.xxz, C1, UYV.y
775 RGB.y = MAD UYV.z, C1.w, RGB.y
777 struct prog_dst_register dst
= inst
->DstReg
;
778 struct prog_dst_register tmp
= get_temp(c
);
779 struct prog_src_register tmpsrc
= src_reg_from_dst(tmp
);
780 struct prog_src_register C0
= search_or_add_const4f( c
, -.5, -.0625, -.5, 1.164 );
781 struct prog_src_register C1
= search_or_add_const4f( c
, 1.596, -0.813, 2.018, -.391 );
796 /* tmp.xyz = ADD TMP, C0
800 dst_mask(tmp
, WRITEMASK_XYZ
),
806 /* YUV.y = MUL YUV.y, C0.w
811 dst_mask(tmp
, WRITEMASK_Y
),
819 * RGB.xyz = MAD YUV.zzx, C1, YUV.y
821 * RGB.xyz = MAD YUV.xxz, C1, YUV.y
826 dst_mask(dst
, WRITEMASK_XYZ
),
828 swap_uv
?src_swizzle(tmpsrc
, Z
,Z
,X
,X
):src_swizzle(tmpsrc
, X
,X
,Z
,Z
),
830 src_swizzle1(tmpsrc
, Y
));
832 /* RGB.y = MAD YUV.z, C1.w, RGB.y
836 dst_mask(dst
, WRITEMASK_Y
),
838 src_swizzle1(tmpsrc
, Z
),
840 src_swizzle1(src_reg_from_dst(dst
), Y
));
842 release_temp(c
, tmp
);
845 /* ordinary RGBA tex instruction */
858 /* For GL_EXT_texture_swizzle: */
859 if (c
->key
.tex_swizzles
[unit
] != SWIZZLE_NOOP
) {
860 /* swizzle the result of the TEX instruction */
861 struct prog_src_register tmpsrc
= src_reg_from_dst(inst
->DstReg
);
862 emit_op(c
, OPCODE_SWZ
,
864 SATURATE_OFF
, /* saturate already done above */
865 src_swizzle4(tmpsrc
, c
->key
.tex_swizzles
[unit
]),
870 if ((inst
->TexSrcTarget
== TEXTURE_RECT_INDEX
) ||
871 (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
))
872 release_temp(c
, tmpcoord
);
877 * Check if the given TXP instruction really needs the divide-by-W step.
879 static GLboolean
projtex( struct brw_wm_compile
*c
,
880 const struct prog_instruction
*inst
)
882 const struct prog_src_register src
= inst
->SrcReg
[0];
885 assert(inst
->Opcode
== OPCODE_TXP
);
887 /* Only try to detect the simplest cases. Could detect (later)
888 * cases where we are trying to emit code like RCP {1.0}, MUL x,
891 * More complex cases than this typically only arise from
892 * user-provided fragment programs anyway:
894 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
)
895 retVal
= GL_FALSE
; /* ut2004 gun rendering !?! */
896 else if (src
.File
== PROGRAM_INPUT
&&
897 GET_SWZ(src
.Swizzle
, W
) == W
&&
898 (c
->key
.proj_attrib_mask
& (1 << src
.Index
)) == 0)
910 static void precalc_txp( struct brw_wm_compile
*c
,
911 const struct prog_instruction
*inst
)
913 struct prog_src_register src0
= inst
->SrcReg
[0];
915 if (projtex(c
, inst
)) {
916 struct prog_dst_register tmp
= get_temp(c
);
917 struct prog_instruction tmp_inst
;
919 /* tmp0.w = RCP inst.arg[0][3]
923 dst_mask(tmp
, WRITEMASK_W
),
925 src_swizzle1(src0
, GET_SWZ(src0
.Swizzle
, W
)),
929 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
933 dst_mask(tmp
, WRITEMASK_XYZ
),
936 src_swizzle1(src_reg_from_dst(tmp
), W
),
939 /* dst = precalc(TEX tmp0)
942 tmp_inst
.SrcReg
[0] = src_reg_from_dst(tmp
);
943 precalc_tex(c
, &tmp_inst
);
945 release_temp(c
, tmp
);
949 /* dst = precalc(TEX src0)
951 precalc_tex(c
, inst
);
957 static void emit_render_target_writes( struct brw_wm_compile
*c
)
959 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
960 struct prog_src_register outdepth
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DEPTH
);
961 struct prog_src_register outcolor
;
964 struct prog_instruction
*inst
, *last_inst
;
966 /* The inst->Aux field is used for FB write target and the EOT marker */
968 if (c
->key
.nr_color_regions
> 1) {
969 for (i
= 0 ; i
< c
->key
.nr_color_regions
; i
++) {
970 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
+ i
);
971 last_inst
= inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(), 0),
972 0, outcolor
, payload_r0_depth
, outdepth
);
973 inst
->Aux
= INST_AUX_TARGET(i
);
974 if (c
->fp_fragcolor_emitted
) {
975 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
976 last_inst
= inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(), 0),
977 0, outcolor
, payload_r0_depth
, outdepth
);
978 inst
->Aux
= INST_AUX_TARGET(i
);
981 last_inst
->Aux
|= INST_AUX_EOT
;
984 /* if gl_FragData[0] is written, use it, else use gl_FragColor */
985 if (c
->fp
->program
.Base
.OutputsWritten
& BITFIELD64_BIT(FRAG_RESULT_DATA0
))
986 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DATA0
);
988 outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLOR
);
990 inst
= emit_op(c
, WM_FB_WRITE
, dst_mask(dst_undef(),0),
991 0, outcolor
, payload_r0_depth
, outdepth
);
992 inst
->Aux
= INST_AUX_EOT
| INST_AUX_TARGET(0);
999 /***********************************************************************
1000 * Emit INTERP instructions ahead of first use of each attrib.
1003 static void validate_src_regs( struct brw_wm_compile
*c
,
1004 const struct prog_instruction
*inst
)
1006 GLuint nr_args
= brw_wm_nr_args( inst
->Opcode
);
1009 for (i
= 0; i
< nr_args
; i
++) {
1010 if (inst
->SrcReg
[i
].File
== PROGRAM_INPUT
) {
1011 GLuint idx
= inst
->SrcReg
[i
].Index
;
1012 if (!(c
->fp_interp_emitted
& (1<<idx
))) {
1013 emit_interp(c
, idx
);
1019 static void validate_dst_regs( struct brw_wm_compile
*c
,
1020 const struct prog_instruction
*inst
)
1022 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
) {
1023 GLuint idx
= inst
->DstReg
.Index
;
1024 if (idx
== FRAG_RESULT_COLOR
)
1025 c
->fp_fragcolor_emitted
= 1;
1029 static void print_insns( const struct prog_instruction
*insn
,
1033 for (i
= 0; i
< nr
; i
++, insn
++) {
1035 if (insn
->Opcode
< MAX_OPCODE
)
1036 _mesa_fprint_instruction_opt(stdout
, insn
, 0, PROG_PRINT_DEBUG
, NULL
);
1037 else if (insn
->Opcode
< MAX_WM_OPCODE
) {
1038 GLuint idx
= insn
->Opcode
- MAX_OPCODE
;
1040 _mesa_fprint_alu_instruction(stdout
, insn
, wm_opcode_strings
[idx
],
1041 3, PROG_PRINT_DEBUG
, NULL
);
1044 printf("965 Opcode %d\n", insn
->Opcode
);
1050 * Initial pass for fragment program code generation.
1051 * This function is used by both the GLSL and non-GLSL paths.
1053 void brw_wm_pass_fp( struct brw_wm_compile
*c
)
1055 struct intel_context
*intel
= &c
->func
.brw
->intel
;
1056 struct brw_fragment_program
*fp
= c
->fp
;
1059 if (INTEL_DEBUG
& DEBUG_WM
) {
1060 printf("pre-fp:\n");
1061 _mesa_fprint_program_opt(stdout
, &fp
->program
.Base
, PROG_PRINT_DEBUG
,
1066 c
->pixel_xy
= src_undef();
1067 if (intel
->gen
>= 6) {
1068 /* The interpolation deltas come in as the perspective pixel
1069 * location barycentric params.
1071 c
->delta_xy
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
1073 c
->delta_xy
= src_undef();
1075 c
->pixel_w
= src_undef();
1077 c
->fp
->tex_units_used
= 0x0;
1079 /* Emit preamble instructions. This is where special instructions such as
1080 * WM_CINTERP, WM_LINTERP, WM_PINTERP and WM_WPOSXY are emitted to
1081 * compute shader inputs from varying vars.
1083 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1084 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1085 validate_src_regs(c
, inst
);
1086 validate_dst_regs(c
, inst
);
1089 /* Loop over all instructions doing assorted simplifications and
1092 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
1093 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
1094 struct prog_instruction
*out
;
1096 /* Check for INPUT values, emit INTERP instructions where
1100 switch (inst
->Opcode
) {
1102 out
= emit_insn(c
, inst
);
1103 out
->Opcode
= OPCODE_MOV
;
1107 out
= emit_insn(c
, inst
);
1108 out
->Opcode
= OPCODE_MOV
;
1109 out
->SrcReg
[0].Negate
= NEGATE_NONE
;
1110 out
->SrcReg
[0].Abs
= 1;
1114 out
= emit_insn(c
, inst
);
1115 out
->Opcode
= OPCODE_ADD
;
1116 out
->SrcReg
[1].Negate
^= NEGATE_XYZW
;
1120 out
= emit_insn(c
, inst
);
1121 /* This should probably be done in the parser.
1123 out
->DstReg
.WriteMask
&= WRITEMASK_XY
;
1127 precalc_dst(c
, inst
);
1131 precalc_lit(c
, inst
);
1135 precalc_tex(c
, inst
);
1139 precalc_txp(c
, inst
);
1143 out
= emit_insn(c
, inst
);
1144 out
->TexSrcUnit
= fp
->program
.Base
.SamplerUnits
[inst
->TexSrcUnit
];
1145 assert(out
->TexSrcUnit
< BRW_MAX_TEX_UNIT
);
1149 out
= emit_insn(c
, inst
);
1150 /* This should probably be done in the parser.
1152 out
->DstReg
.WriteMask
&= WRITEMASK_XYZ
;
1156 out
= emit_insn(c
, inst
);
1157 /* This should probably be done in the parser.
1159 out
->DstReg
.WriteMask
= 0;
1162 emit_render_target_writes(c
);
1167 if (brw_wm_is_scalar_result(inst
->Opcode
))
1168 emit_scalar_insn(c
, inst
);
1175 if (INTEL_DEBUG
& DEBUG_WM
) {
1176 printf("pass_fp:\n");
1177 print_insns( c
->prog_instructions
, c
->nr_fp_insns
);