2 * Copyright (C) 2009 Maciej Cencora <m.cencora@gmail.com>
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.
31 * Fragment program compiler. Perform transformations on the intermediate
32 * representation until the program is in a form where we can translate
33 * it more or less directly into machine-readable form.
35 * \author Ben Skeggs <darktama@iinet.net.au>
36 * \author Jerome Glisse <j.glisse@gmail.com>
39 #include "r300_fragprog_common.h"
41 #include "shader/program.h"
42 #include "shader/prog_parameter.h"
43 #include "shader/prog_print.h"
45 #include "r300_state.h"
46 #include "r300_fragprog.h"
47 #include "r300_fragprog_swizzle.h"
48 #include "r500_fragprog.h"
50 #include "radeon_program.h"
51 #include "radeon_program_alu.h"
53 static void update_params(GLcontext
*ctx
, struct gl_fragment_program
*fp
)
55 /* Ask Mesa nicely to fill in ParameterValues for us */
56 if (fp
->Base
.Parameters
)
57 _mesa_load_state_parameters(ctx
, fp
->Base
.Parameters
);
60 static void nqssadce_init(struct nqssadce_state
* s
)
62 s
->Outputs
[FRAG_RESULT_COLOR
].Sourced
= WRITEMASK_XYZW
;
63 s
->Outputs
[FRAG_RESULT_DEPTH
].Sourced
= WRITEMASK_W
;
67 * Transform the program to support fragment.position.
69 * Introduce a small fragment at the start of the program that will be
70 * the only code that directly reads the FRAG_ATTRIB_WPOS input.
71 * All other code pieces that reference that input will be rewritten
72 * to read from a newly allocated temporary.
75 static void insert_WPOS_trailer(struct r300_fragment_program_compiler
*compiler
)
77 GLuint InputsRead
= compiler
->fp
->Base
.Base
.InputsRead
;
79 if (!(InputsRead
& FRAG_BIT_WPOS
))
82 static gl_state_index tokens
[STATE_LENGTH
] = {
83 STATE_INTERNAL
, STATE_R300_WINDOW_DIMENSION
, 0, 0, 0
85 struct prog_instruction
*fpi
;
88 GLuint tempregi
= _mesa_find_free_register(compiler
->program
, PROGRAM_TEMPORARY
);
90 _mesa_insert_instructions(compiler
->program
, 0, 3);
91 fpi
= compiler
->program
->Instructions
;
93 /* perspective divide */
94 fpi
[i
].Opcode
= OPCODE_RCP
;
96 fpi
[i
].DstReg
.File
= PROGRAM_TEMPORARY
;
97 fpi
[i
].DstReg
.Index
= tempregi
;
98 fpi
[i
].DstReg
.WriteMask
= WRITEMASK_W
;
99 fpi
[i
].DstReg
.CondMask
= COND_TR
;
101 fpi
[i
].SrcReg
[0].File
= PROGRAM_INPUT
;
102 fpi
[i
].SrcReg
[0].Index
= FRAG_ATTRIB_WPOS
;
103 fpi
[i
].SrcReg
[0].Swizzle
= SWIZZLE_WWWW
;
106 fpi
[i
].Opcode
= OPCODE_MUL
;
108 fpi
[i
].DstReg
.File
= PROGRAM_TEMPORARY
;
109 fpi
[i
].DstReg
.Index
= tempregi
;
110 fpi
[i
].DstReg
.WriteMask
= WRITEMASK_XYZ
;
111 fpi
[i
].DstReg
.CondMask
= COND_TR
;
113 fpi
[i
].SrcReg
[0].File
= PROGRAM_INPUT
;
114 fpi
[i
].SrcReg
[0].Index
= FRAG_ATTRIB_WPOS
;
115 fpi
[i
].SrcReg
[0].Swizzle
= SWIZZLE_XYZW
;
117 fpi
[i
].SrcReg
[1].File
= PROGRAM_TEMPORARY
;
118 fpi
[i
].SrcReg
[1].Index
= tempregi
;
119 fpi
[i
].SrcReg
[1].Swizzle
= SWIZZLE_WWWW
;
122 /* viewport transformation */
123 window_index
= _mesa_add_state_reference(compiler
->program
->Parameters
, tokens
);
125 fpi
[i
].Opcode
= OPCODE_MAD
;
127 fpi
[i
].DstReg
.File
= PROGRAM_TEMPORARY
;
128 fpi
[i
].DstReg
.Index
= tempregi
;
129 fpi
[i
].DstReg
.WriteMask
= WRITEMASK_XYZ
;
130 fpi
[i
].DstReg
.CondMask
= COND_TR
;
132 fpi
[i
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
133 fpi
[i
].SrcReg
[0].Index
= tempregi
;
134 fpi
[i
].SrcReg
[0].Swizzle
= MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_ZERO
);
136 fpi
[i
].SrcReg
[1].File
= PROGRAM_STATE_VAR
;
137 fpi
[i
].SrcReg
[1].Index
= window_index
;
138 fpi
[i
].SrcReg
[1].Swizzle
= MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_ZERO
);
140 fpi
[i
].SrcReg
[2].File
= PROGRAM_STATE_VAR
;
141 fpi
[i
].SrcReg
[2].Index
= window_index
;
142 fpi
[i
].SrcReg
[2].Swizzle
= MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_ZERO
);
145 for (; i
< compiler
->program
->NumInstructions
; ++i
) {
147 for (reg
= 0; reg
< 3; reg
++) {
148 if (fpi
[i
].SrcReg
[reg
].File
== PROGRAM_INPUT
&&
149 fpi
[i
].SrcReg
[reg
].Index
== FRAG_ATTRIB_WPOS
) {
150 fpi
[i
].SrcReg
[reg
].File
= PROGRAM_TEMPORARY
;
151 fpi
[i
].SrcReg
[reg
].Index
= tempregi
;
157 static GLuint
build_dtm(GLuint depthmode
)
161 case GL_LUMINANCE
: return 0;
162 case GL_INTENSITY
: return 1;
163 case GL_ALPHA
: return 2;
167 static GLuint
build_func(GLuint comparefunc
)
169 return comparefunc
- GL_NEVER
;
173 * Collect all external state that is relevant for compiling the given
176 static void build_state(
178 struct r300_fragment_program
*fp
,
179 struct r300_fragment_program_external_state
*state
)
183 _mesa_bzero(state
, sizeof(*state
));
185 for(unit
= 0; unit
< 16; ++unit
) {
186 if (fp
->Base
.Base
.ShadowSamplers
& (1 << unit
)) {
187 struct gl_texture_object
* tex
= r300
->radeon
.glCtx
->Texture
.Unit
[unit
]._Current
;
189 state
->unit
[unit
].depth_texture_mode
= build_dtm(tex
->DepthMode
);
190 state
->unit
[unit
].texture_compare_func
= build_func(tex
->CompareFunc
);
195 void r300TranslateFragmentShader(GLcontext
*ctx
, struct gl_fragment_program
*fp
)
197 r300ContextPtr r300
= R300_CONTEXT(ctx
);
198 struct r300_fragment_program
*r300_fp
= (struct r300_fragment_program
*)fp
;
199 struct r300_fragment_program_external_state state
;
201 build_state(r300
, r300_fp
, &state
);
202 if (_mesa_memcmp(&r300_fp
->state
, &state
, sizeof(state
))) {
203 /* TODO: cache compiled programs */
204 r300_fp
->translated
= GL_FALSE
;
205 _mesa_memcpy(&r300_fp
->state
, &state
, sizeof(state
));
208 if (!r300_fp
->translated
) {
209 struct r300_fragment_program_compiler compiler
;
211 compiler
.r300
= r300
;
212 compiler
.fp
= r300_fp
;
213 compiler
.code
= &r300_fp
->code
;
214 compiler
.program
= _mesa_clone_program(ctx
, &fp
->Base
);
216 if (RADEON_DEBUG
& DEBUG_PIXEL
) {
218 _mesa_printf("Fragment Program: Initial program:\n");
219 _mesa_print_program(compiler
.program
);
223 insert_WPOS_trailer(&compiler
);
225 if (r300
->radeon
.radeonScreen
->chip_family
>= CHIP_FAMILY_RV515
) {
226 struct radeon_program_transformation transformations
[] = {
227 { &r500_transform_TEX
, &compiler
},
228 { &radeonTransformALU
, 0 },
229 { &radeonTransformDeriv
, 0 },
230 { &radeonTransformTrigScale
, 0 }
232 radeonLocalTransform(ctx
, compiler
.program
, 4, transformations
);
234 struct radeon_program_transformation transformations
[] = {
235 { &r300_transform_TEX
, &compiler
},
236 { &radeonTransformALU
, 0 },
237 { &radeonTransformTrigSimple
, 0 }
239 radeonLocalTransform(ctx
, compiler
.program
, 3, transformations
);
242 if (RADEON_DEBUG
& DEBUG_PIXEL
) {
243 _mesa_printf("Fragment Program: After native rewrite:\n");
244 _mesa_print_program(compiler
.program
);
248 if (r300
->radeon
.radeonScreen
->chip_family
>= CHIP_FAMILY_RV515
) {
249 struct radeon_nqssadce_descr nqssadce
= {
250 .Init
= &nqssadce_init
,
251 .IsNativeSwizzle
= &r500FPIsNativeSwizzle
,
252 .BuildSwizzle
= &r500FPBuildSwizzle
,
253 .RewriteDepthOut
= GL_TRUE
255 radeonNqssaDce(ctx
, compiler
.program
, &nqssadce
);
257 struct radeon_nqssadce_descr nqssadce
= {
258 .Init
= &nqssadce_init
,
259 .IsNativeSwizzle
= &r300FPIsNativeSwizzle
,
260 .BuildSwizzle
= &r300FPBuildSwizzle
,
261 .RewriteDepthOut
= GL_TRUE
263 radeonNqssaDce(ctx
, compiler
.program
, &nqssadce
);
266 if (RADEON_DEBUG
& DEBUG_PIXEL
) {
267 _mesa_printf("Compiler: after NqSSA-DCE:\n");
268 _mesa_print_program(compiler
.program
);
272 if (!r300
->vtbl
.BuildFragmentProgramHwCode(&compiler
))
273 r300_fp
->error
= GL_TRUE
;
275 /* Subtle: Rescue any parameters that have been added during transformations */
276 _mesa_free_parameter_list(fp
->Base
.Parameters
);
277 fp
->Base
.Parameters
= compiler
.program
->Parameters
;
278 compiler
.program
->Parameters
= 0;
280 _mesa_reference_program(ctx
, &compiler
.program
, NULL
);
282 r300_fp
->translated
= GL_TRUE
;
284 r300UpdateStateParameters(ctx
, _NEW_PROGRAM
| _NEW_PROGRAM_CONSTANTS
);
286 if (r300_fp
->error
|| (RADEON_DEBUG
& DEBUG_PIXEL
))
287 r300
->vtbl
.FragmentProgramDump(&r300_fp
->code
);
290 update_params(ctx
, fp
);