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>
36 #include "brw_context.h"
40 #include "shader/program.h"
41 #include "shader/program_instruction.h"
42 #include "shader/arbprogparse.h"
44 #define FIRST_INTERNAL_TEMP MAX_NV_FRAGMENT_PROGRAM_TEMPS
52 static const char *wm_opcode_strings
[] = {
63 static const char *wm_file_strings
[] = {
68 /***********************************************************************
72 static struct prog_src_register
src_reg(GLuint file
, GLuint idx
)
74 struct prog_src_register reg
;
77 reg
.Swizzle
= SWIZZLE_NOOP
;
85 static struct prog_src_register
src_reg_from_dst(struct prog_dst_register dst
)
87 return src_reg(dst
.File
, dst
.Index
);
90 static struct prog_src_register
src_undef( void )
92 return src_reg(PROGRAM_UNDEFINED
, 0);
95 static GLboolean
src_is_undef(struct prog_src_register src
)
97 return src
.File
== PROGRAM_UNDEFINED
;
100 static struct prog_src_register
src_swizzle( struct prog_src_register reg
, int x
, int y
, int z
, int w
)
102 reg
.Swizzle
= MAKE_SWIZZLE4(x
,y
,z
,w
);
106 static struct prog_src_register
src_swizzle1( struct prog_src_register reg
, int x
)
108 return src_swizzle(reg
, x
, x
, x
, x
);
112 /***********************************************************************
116 static struct prog_dst_register
dst_reg(GLuint file
, GLuint idx
)
118 struct prog_dst_register reg
;
121 reg
.WriteMask
= WRITEMASK_XYZW
;
129 static struct prog_dst_register
dst_mask( struct prog_dst_register reg
, int mask
)
131 reg
.WriteMask
&= mask
;
135 static struct prog_dst_register
dst_undef( void )
137 return dst_reg(PROGRAM_UNDEFINED
, 0);
142 static struct prog_dst_register
get_temp( struct brw_wm_compile
*c
)
144 int bit
= ffs( ~c
->fp_temp
);
147 _mesa_printf("%s: out of temporaries\n", __FILE__
);
151 c
->fp_temp
|= 1<<(bit
-1);
152 return dst_reg(PROGRAM_TEMPORARY
, FIRST_INTERNAL_TEMP
+(bit
-1));
156 static void release_temp( struct brw_wm_compile
*c
, struct prog_dst_register temp
)
158 c
->fp_temp
&= ~1<<(temp
.Index
+ 1 - FIRST_INTERNAL_TEMP
);
162 /***********************************************************************
166 static struct prog_instruction
*get_fp_inst(struct brw_wm_compile
*c
)
168 return &c
->prog_instructions
[c
->nr_fp_insns
++];
171 static struct prog_instruction
*emit_insn(struct brw_wm_compile
*c
,
172 const struct prog_instruction
*inst0
)
174 struct prog_instruction
*inst
= get_fp_inst(c
);
179 static struct prog_instruction
* emit_op(struct brw_wm_compile
*c
,
181 struct prog_dst_register dest
,
184 GLuint tex_src_target
,
185 struct prog_src_register src0
,
186 struct prog_src_register src1
,
187 struct prog_src_register src2
)
189 struct prog_instruction
*inst
= get_fp_inst(c
);
191 memset(inst
, 0, sizeof(*inst
));
195 inst
->SaturateMode
= saturate
;
196 inst
->TexSrcUnit
= tex_src_unit
;
197 inst
->TexSrcTarget
= tex_src_target
;
198 inst
->SrcReg
[0] = src0
;
199 inst
->SrcReg
[1] = src1
;
200 inst
->SrcReg
[2] = src2
;
208 /***********************************************************************
209 * Special instructions for interpolation and other tasks
212 static struct prog_src_register
get_pixel_xy( struct brw_wm_compile
*c
)
214 if (src_is_undef(c
->pixel_xy
)) {
215 struct prog_dst_register pixel_xy
= get_temp(c
);
216 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
219 /* Emit the out calculations, and hold onto the results. Use
220 * two instructions as a temporary is required.
222 /* pixel_xy.xy = PIXELXY payload[0];
226 dst_mask(pixel_xy
, WRITEMASK_XY
),
232 c
->pixel_xy
= src_reg_from_dst(pixel_xy
);
238 static struct prog_src_register
get_delta_xy( struct brw_wm_compile
*c
)
240 if (src_is_undef(c
->delta_xy
)) {
241 struct prog_dst_register delta_xy
= get_temp(c
);
242 struct prog_src_register pixel_xy
= get_pixel_xy(c
);
243 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
245 /* deltas.xy = DELTAXY pixel_xy, payload[0]
249 dst_mask(delta_xy
, WRITEMASK_XY
),
255 c
->delta_xy
= src_reg_from_dst(delta_xy
);
261 static struct prog_src_register
get_pixel_w( struct brw_wm_compile
*c
)
263 if (src_is_undef(c
->pixel_w
)) {
264 struct prog_dst_register pixel_w
= get_temp(c
);
265 struct prog_src_register deltas
= get_delta_xy(c
);
266 struct prog_src_register interp_wpos
= src_reg(PROGRAM_PAYLOAD
, FRAG_ATTRIB_WPOS
);
269 /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
273 dst_mask(pixel_w
, WRITEMASK_W
),
280 c
->pixel_w
= src_reg_from_dst(pixel_w
);
286 static void emit_interp( struct brw_wm_compile
*c
,
289 struct prog_dst_register dst
= dst_reg(PROGRAM_INPUT
, idx
);
290 struct prog_src_register interp
= src_reg(PROGRAM_PAYLOAD
, idx
);
291 struct prog_src_register deltas
= get_delta_xy(c
);
292 struct prog_src_register arg2
;
295 /* Need to use PINTERP on attributes which have been
296 * multiplied by 1/W in the SF program, and LINTERP on those
300 case FRAG_ATTRIB_WPOS
:
304 /* Have to treat wpos.xy specially:
308 dst_mask(dst
, WRITEMASK_XY
),
314 dst
= dst_mask(dst
, WRITEMASK_ZW
);
316 /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
326 case FRAG_ATTRIB_COL0
:
327 case FRAG_ATTRIB_COL1
:
328 if (c
->key
.flat_shade
) {
358 c
->fp_interp_emitted
|= 1<<idx
;
362 /***********************************************************************
363 * Hacks to extend the program parameter and constant lists.
366 /* Add the fog parameters to the parameter list of the original
367 * program, rather than creating a new list. Doesn't really do any
368 * harm and it's not as if the parameter handling isn't a big hack
371 static struct prog_src_register
search_or_add_param6( struct brw_wm_compile
*c
,
379 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
389 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
390 if (paramList
->Parameters
[idx
].Type
== PROGRAM_STATE_VAR
&&
391 memcmp(paramList
->Parameters
[idx
].StateIndexes
, tokens
, sizeof(tokens
)) == 0)
392 return src_reg(PROGRAM_STATE_VAR
, idx
);
395 idx
= _mesa_add_state_reference( paramList
, tokens
);
397 /* Recalculate state dependency:
399 c
->fp
->param_state
= brw_parameter_list_state_flags( paramList
);
401 return src_reg(PROGRAM_STATE_VAR
, idx
);
405 static struct prog_src_register
search_or_add_const4f( struct brw_wm_compile
*c
,
411 struct gl_program_parameter_list
*paramList
= c
->fp
->program
.Base
.Parameters
;
420 /* Have to search, otherwise multiple compilations will each grow
421 * the parameter list.
423 for (idx
= 0; idx
< paramList
->NumParameters
; idx
++) {
424 if (paramList
->Parameters
[idx
].Type
== PROGRAM_CONSTANT
&&
425 memcmp(paramList
->ParameterValues
[idx
], values
, sizeof(values
)) == 0)
427 /* XXX: this mimics the mesa bug which puts all constants and
428 * parameters into the "PROGRAM_STATE_VAR" category:
430 return src_reg(PROGRAM_STATE_VAR
, idx
);
433 idx
= _mesa_add_unnamed_constant( paramList
, values
);
435 return src_reg(PROGRAM_STATE_VAR
, idx
);
440 /***********************************************************************
441 * Expand various instructions here to simpler forms.
443 static void precalc_dst( struct brw_wm_compile
*c
,
444 const struct prog_instruction
*inst
)
446 struct prog_src_register src0
= inst
->SrcReg
[0];
447 struct prog_src_register src1
= inst
->SrcReg
[1];
448 struct prog_dst_register dst
= inst
->DstReg
;
450 if (dst
.WriteMask
& WRITEMASK_Y
) {
451 /* dst.y = mul src0.y, src1.y
455 dst_mask(dst
, WRITEMASK_Y
),
456 inst
->SaturateMode
, 0, 0,
463 if (dst
.WriteMask
& WRITEMASK_XZ
) {
464 GLuint z
= GET_SWZ(src0
.Swizzle
, Z
);
466 /* dst.xz = swz src0.1zzz
470 dst_mask(dst
, WRITEMASK_XZ
),
471 inst
->SaturateMode
, 0, 0,
472 src_swizzle(src0
, SWIZZLE_ONE
, z
, z
, z
),
476 if (dst
.WriteMask
& WRITEMASK_W
) {
477 /* dst.w = mov src1.w
481 dst_mask(dst
, WRITEMASK_W
),
482 inst
->SaturateMode
, 0, 0,
490 static void precalc_lit( struct brw_wm_compile
*c
,
491 const struct prog_instruction
*inst
)
493 struct prog_src_register src0
= inst
->SrcReg
[0];
494 struct prog_dst_register dst
= inst
->DstReg
;
496 if (dst
.WriteMask
& WRITEMASK_XW
) {
497 /* dst.xw = swz src0.1111
501 dst_mask(dst
, WRITEMASK_XW
),
503 src_swizzle1(src0
, SWIZZLE_ONE
),
509 if (dst
.WriteMask
& WRITEMASK_YZ
) {
512 dst_mask(dst
, WRITEMASK_YZ
),
513 inst
->SaturateMode
, 0, 0,
520 static void precalc_tex( struct brw_wm_compile
*c
,
521 const struct prog_instruction
*inst
)
523 /* Need to emit YUV texture conversions by hand. Probably need to
524 * do this here - the alternative is in brw_wm_emit.c, but the
525 * conversion requires allocating a temporary variable which we
526 * don't have the facility to do that late in the compilation.
528 if (!(c
->key
.yuvtex_mask
& (1<<inst
->TexSrcUnit
))) {
541 CONST C0 = { -.5, -.0625, -.5, 1.164 }
542 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
544 UYV.xyz = ADD UYV, C0
545 UYV.y = MUL UYV.y, C0.w
546 RGB.xyz = MAD UYV.xxz, C1, UYV.y
547 RGB.y = MAD UYV.z, C1.w, RGB.y
549 struct prog_dst_register dst
= inst
->DstReg
;
550 struct prog_src_register src0
= inst
->SrcReg
[0];
551 struct prog_dst_register tmp
= get_temp(c
);
552 struct prog_src_register tmpsrc
= src_reg_from_dst(tmp
);
553 struct prog_src_register C0
= search_or_add_const4f( c
, -.5, -.0625, -.5, 1.164 );
554 struct prog_src_register C1
= search_or_add_const4f( c
, 1.596, -0.813, 2.018, -.391 );
568 /* tmp.xyz = ADD TMP, C0
572 dst_mask(tmp
, WRITEMASK_XYZ
),
578 /* YUV.y = MUL YUV.y, C0.w
582 dst_mask(tmp
, WRITEMASK_Y
),
588 /* RGB.xyz = MAD YUV.xxz, C1, YUV.y
592 dst_mask(dst
, WRITEMASK_XYZ
),
594 src_swizzle(tmpsrc
, X
,X
,Z
,Z
),
596 src_swizzle1(tmpsrc
, Y
));
598 /* RGB.y = MAD YUV.z, C1.w, RGB.y
602 dst_mask(dst
, WRITEMASK_Y
),
604 src_swizzle1(tmpsrc
, Z
),
606 src_swizzle1(src_reg_from_dst(dst
), Y
));
611 static GLboolean
projtex( struct brw_wm_compile
*c
,
612 const struct prog_instruction
*inst
)
614 struct prog_src_register src
= inst
->SrcReg
[0];
616 /* Only try to detect the simplest cases. Could detect (later)
617 * cases where we are trying to emit code like RCP {1.0}, MUL x,
620 * More complex cases than this typically only arise from
621 * user-provided fragment programs anyway:
623 if (inst
->TexSrcTarget
== TEXTURE_CUBE_INDEX
)
624 return 0; /* ut2004 gun rendering !?! */
625 else if (src
.File
== PROGRAM_INPUT
&&
626 GET_SWZ(src
.Swizzle
, W
) == W
&&
627 (c
->key
.projtex_mask
& (1<<src
.Index
)) == 0)
634 static void precalc_txp( struct brw_wm_compile
*c
,
635 const struct prog_instruction
*inst
)
637 struct prog_src_register src0
= inst
->SrcReg
[0];
639 if (projtex(c
, inst
)) {
640 struct prog_dst_register tmp
= get_temp(c
);
641 struct prog_instruction tmp_inst
;
643 /* tmp0.w = RCP inst.arg[0][3]
647 dst_mask(tmp
, WRITEMASK_W
),
649 src_swizzle1(src0
, GET_SWZ(src0
.Swizzle
, W
)),
653 /* tmp0.xyz = MUL inst.arg[0], tmp0.wwww
657 dst_mask(tmp
, WRITEMASK_XYZ
),
660 src_swizzle1(src_reg_from_dst(tmp
), W
),
663 /* dst = precalc(TEX tmp0)
666 tmp_inst
.SrcReg
[0] = src_reg_from_dst(tmp
);
667 precalc_tex(c
, &tmp_inst
);
669 release_temp(c
, tmp
);
673 /* dst = precalc(TEX src0)
675 precalc_tex(c
, inst
);
683 /***********************************************************************
684 * Add instructions to perform fog blending
687 static void fog_blend( struct brw_wm_compile
*c
,
688 struct prog_src_register fog_factor
)
690 struct prog_dst_register outcolor
= dst_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLR
);
691 struct prog_src_register fogcolor
= search_or_add_param6( c
, STATE_FOG_COLOR
, 0,0,0,0,0 );
693 /* color.xyz = LRP fog_factor.xxxx, output_color, fog_color */
697 dst_mask(outcolor
, WRITEMASK_XYZ
),
700 src_reg_from_dst(outcolor
),
706 /* This one is simple - just take the interpolated fog coordinate and
707 * use it as the fog blend factor.
709 static void fog_interpolated( struct brw_wm_compile
*c
)
711 struct prog_src_register fogc
= src_reg(PROGRAM_INPUT
, FRAG_ATTRIB_FOGC
);
713 if (!(c
->fp_interp_emitted
& (1<<FRAG_ATTRIB_FOGC
)))
714 emit_interp(c
, FRAG_ATTRIB_FOGC
);
716 fog_blend( c
, src_swizzle1(fogc
, GET_SWZ(fogc
.Swizzle
,X
)));
719 static void emit_fog( struct brw_wm_compile
*c
)
721 if (!c
->fp
->program
.FogOption
)
725 fog_interpolated( c
);
727 /* TODO: per-pixel fog */
732 static void emit_fb_write( struct brw_wm_compile
*c
)
734 struct prog_src_register outcolor
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_COLR
);
735 struct prog_src_register payload_r0_depth
= src_reg(PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
);
736 struct prog_src_register outdepth
= src_reg(PROGRAM_OUTPUT
, FRAG_RESULT_DEPR
);
740 dst_mask(dst_undef(),0),
750 /***********************************************************************
751 * Emit INTERP instructions ahead of first use of each attrib.
754 static void validate_src_regs( struct brw_wm_compile
*c
,
755 const struct prog_instruction
*inst
)
757 GLuint nr_args
= brw_wm_nr_args( inst
->Opcode
);
760 for (i
= 0; i
< nr_args
; i
++) {
761 if (inst
->SrcReg
[i
].File
== PROGRAM_INPUT
) {
762 GLuint idx
= inst
->SrcReg
[i
].Index
;
763 if (!(c
->fp_interp_emitted
& (1<<idx
))) {
772 void brw_wm_pass_fp( struct brw_wm_compile
*c
)
774 struct brw_fragment_program
*fp
= c
->fp
;
777 if (INTEL_DEBUG
& DEBUG_WM
) {
778 _mesa_printf("\n\n\npre-fp:\n");
779 /* _mesa_print_program(&fp->program); */
783 c
->pixel_xy
= src_undef();
784 c
->delta_xy
= src_undef();
785 c
->pixel_w
= src_undef();
788 /* Emit preamble instructions:
792 for (insn
= 0; insn
< fp
->program
.Base
.NumInstructions
; insn
++) {
793 const struct prog_instruction
*inst
= &fp
->program
.Base
.Instructions
[insn
];
794 struct prog_instruction
*out
;
796 /* Check for INPUT values, emit INTERP instructions where
799 validate_src_regs(c
, inst
);
802 switch (inst
->Opcode
) {
804 out
= emit_insn(c
, inst
);
805 out
->Opcode
= OPCODE_MOV
;
809 out
= emit_insn(c
, inst
);
810 out
->Opcode
= OPCODE_MOV
;
811 out
->SrcReg
[0].NegateBase
= 0;
812 out
->SrcReg
[0].Abs
= 1;
816 out
= emit_insn(c
, inst
);
817 out
->Opcode
= OPCODE_ADD
;
818 out
->SrcReg
[1].NegateBase
^= 0xf;
822 out
= emit_insn(c
, inst
);
823 /* This should probably be done in the parser.
825 out
->DstReg
.WriteMask
&= WRITEMASK_XY
;
829 precalc_dst(c
, inst
);
833 precalc_lit(c
, inst
);
837 precalc_txp(c
, inst
);
841 out
= emit_insn(c
, inst
);
842 /* This should probably be done in the parser.
844 out
->DstReg
.WriteMask
&= WRITEMASK_XYZ
;
848 out
= emit_insn(c
, inst
);
849 /* This should probably be done in the parser.
851 out
->DstReg
.WriteMask
= 0;
868 if (INTEL_DEBUG
& DEBUG_WM
) {
869 _mesa_printf("\n\n\npass_fp:\n");
870 /* _mesa_debug_fp_inst(c->nr_fp_insns, c->prog_instructions, wm_opcode_strings, wm_file_strings); */