r300: add hw accelerated support for different vertex data formats
[mesa.git] / src / mesa / drivers / dri / r300 / r300_fragprog_common.c
1 /*
2 * Copyright (C) 2009 Maciej Cencora <m.cencora@gmail.com>
3 *
4 * All Rights Reserved.
5 *
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:
13 *
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.
17 *
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.
25 *
26 */
27
28 /**
29 * \file
30 *
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.
34 *
35 * \author Ben Skeggs <darktama@iinet.net.au>
36 * \author Jerome Glisse <j.glisse@gmail.com>
37 */
38
39 #include "r300_fragprog_common.h"
40
41 #include "shader/program.h"
42 #include "shader/prog_parameter.h"
43 #include "shader/prog_print.h"
44
45 #include "r300_state.h"
46 #include "r300_fragprog.h"
47 #include "r300_fragprog_swizzle.h"
48 #include "r500_fragprog.h"
49
50 #include "radeon_program.h"
51 #include "radeon_program_alu.h"
52
53 static void update_params(GLcontext *ctx, struct gl_fragment_program *fp)
54 {
55 /* Ask Mesa nicely to fill in ParameterValues for us */
56 if (fp->Base.Parameters)
57 _mesa_load_state_parameters(ctx, fp->Base.Parameters);
58 }
59
60 static void nqssadce_init(struct nqssadce_state* s)
61 {
62 s->Outputs[FRAG_RESULT_COLOR].Sourced = WRITEMASK_XYZW;
63 s->Outputs[FRAG_RESULT_DEPTH].Sourced = WRITEMASK_W;
64 }
65
66 /**
67 * Transform the program to support fragment.position.
68 *
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.
73 *
74 */
75 static void insert_WPOS_trailer(struct r300_fragment_program_compiler *compiler)
76 {
77 GLuint InputsRead = compiler->fp->Base.Base.InputsRead;
78
79 if (!(InputsRead & FRAG_BIT_WPOS))
80 return;
81
82 static gl_state_index tokens[STATE_LENGTH] = {
83 STATE_INTERNAL, STATE_R300_WINDOW_DIMENSION, 0, 0, 0
84 };
85 struct prog_instruction *fpi;
86 GLuint window_index;
87 int i = 0;
88 GLuint tempregi = _mesa_find_free_register(compiler->program, PROGRAM_TEMPORARY);
89
90 _mesa_insert_instructions(compiler->program, 0, 3);
91 fpi = compiler->program->Instructions;
92
93 /* perspective divide */
94 fpi[i].Opcode = OPCODE_RCP;
95
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;
100
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;
104 i++;
105
106 fpi[i].Opcode = OPCODE_MUL;
107
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;
112
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;
116
117 fpi[i].SrcReg[1].File = PROGRAM_TEMPORARY;
118 fpi[i].SrcReg[1].Index = tempregi;
119 fpi[i].SrcReg[1].Swizzle = SWIZZLE_WWWW;
120 i++;
121
122 /* viewport transformation */
123 window_index = _mesa_add_state_reference(compiler->program->Parameters, tokens);
124
125 fpi[i].Opcode = OPCODE_MAD;
126
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;
131
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);
135
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);
139
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);
143 i++;
144
145 for (; i < compiler->program->NumInstructions; ++i) {
146 int reg;
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;
152 }
153 }
154 }
155 }
156
157 static GLuint build_dtm(GLuint depthmode)
158 {
159 switch(depthmode) {
160 default:
161 case GL_LUMINANCE: return 0;
162 case GL_INTENSITY: return 1;
163 case GL_ALPHA: return 2;
164 }
165 }
166
167 static GLuint build_func(GLuint comparefunc)
168 {
169 return comparefunc - GL_NEVER;
170 }
171
172 /**
173 * Collect all external state that is relevant for compiling the given
174 * fragment program.
175 */
176 static void build_state(
177 r300ContextPtr r300,
178 struct r300_fragment_program *fp,
179 struct r300_fragment_program_external_state *state)
180 {
181 int unit;
182
183 _mesa_bzero(state, sizeof(*state));
184
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;
188
189 state->unit[unit].depth_texture_mode = build_dtm(tex->DepthMode);
190 state->unit[unit].texture_compare_func = build_func(tex->CompareFunc);
191 }
192 }
193 }
194
195 void r300TranslateFragmentShader(GLcontext *ctx, struct gl_fragment_program *fp)
196 {
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;
200
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));
206 }
207
208 if (!r300_fp->translated) {
209 struct r300_fragment_program_compiler compiler;
210
211 compiler.r300 = r300;
212 compiler.fp = r300_fp;
213 compiler.code = &r300_fp->code;
214 compiler.program = _mesa_clone_program(ctx, &fp->Base);
215
216 if (RADEON_DEBUG & DEBUG_PIXEL) {
217 fflush(stdout);
218 _mesa_printf("Fragment Program: Initial program:\n");
219 _mesa_print_program(compiler.program);
220 fflush(stdout);
221 }
222
223 insert_WPOS_trailer(&compiler);
224
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 }
231 };
232 radeonLocalTransform(ctx, compiler.program, 4, transformations);
233 } else {
234 struct radeon_program_transformation transformations[] = {
235 { &r300_transform_TEX, &compiler },
236 { &radeonTransformALU, 0 },
237 { &radeonTransformTrigSimple, 0 }
238 };
239 radeonLocalTransform(ctx, compiler.program, 3, transformations);
240 }
241
242 if (RADEON_DEBUG & DEBUG_PIXEL) {
243 _mesa_printf("Fragment Program: After native rewrite:\n");
244 _mesa_print_program(compiler.program);
245 fflush(stdout);
246 }
247
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
254 };
255 radeonNqssaDce(ctx, compiler.program, &nqssadce);
256 } else {
257 struct radeon_nqssadce_descr nqssadce = {
258 .Init = &nqssadce_init,
259 .IsNativeSwizzle = &r300FPIsNativeSwizzle,
260 .BuildSwizzle = &r300FPBuildSwizzle,
261 .RewriteDepthOut = GL_TRUE
262 };
263 radeonNqssaDce(ctx, compiler.program, &nqssadce);
264 }
265
266 if (RADEON_DEBUG & DEBUG_PIXEL) {
267 _mesa_printf("Compiler: after NqSSA-DCE:\n");
268 _mesa_print_program(compiler.program);
269 fflush(stdout);
270 }
271
272 if (!r300->vtbl.BuildFragmentProgramHwCode(&compiler))
273 r300_fp->error = GL_TRUE;
274
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;
279
280 _mesa_reference_program(ctx, &compiler.program, NULL);
281
282 r300_fp->translated = GL_TRUE;
283
284 r300UpdateStateParameters(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
285
286 if (r300_fp->error || (RADEON_DEBUG & DEBUG_PIXEL))
287 r300->vtbl.FragmentProgramDump(&r300_fp->code);
288 }
289
290 update_params(ctx, fp);
291 }