Merge branch 'gallium-0.1' into gallium-tex-surfaces
[mesa.git] / src / mesa / state_tracker / st_atom_shader.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * 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, sub license, 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 portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * State validation for vertex/fragment shaders.
30 * Note that we have to delay most vertex/fragment shader translation
31 * until rendering time since the linkage between the vertex outputs and
32 * fragment inputs can vary depending on the pairing of shaders.
33 *
34 * Authors:
35 * Brian Paul
36 */
37
38
39
40 #include "main/imports.h"
41 #include "main/mtypes.h"
42 #include "shader/program.h"
43
44 #include "pipe/p_context.h"
45 #include "pipe/p_shader_tokens.h"
46
47 #include "util/u_simple_shaders.h"
48
49 #include "cso_cache/cso_context.h"
50
51 #include "st_context.h"
52 #include "st_atom.h"
53 #include "st_program.h"
54 #include "st_atom_shader.h"
55 #include "st_mesa_to_tgsi.h"
56
57
58 /**
59 * This represents a vertex program, especially translated to match
60 * the inputs of a particular fragment shader.
61 */
62 struct translated_vertex_program
63 {
64 struct st_vertex_program *master;
65
66 /** The fragment shader "signature" this vertex shader is meant for: */
67 GLbitfield frag_inputs;
68
69 /** Compared against master vertex program's serialNo: */
70 GLuint serialNo;
71
72 /** Maps VERT_RESULT_x to slot */
73 GLuint output_to_slot[VERT_RESULT_MAX];
74
75 /** Pointer to the translated vertex program */
76 struct st_vertex_program *vp;
77
78 struct translated_vertex_program *next; /**< next in linked list */
79 };
80
81
82
83 /**
84 * Given a vertex program output attribute, return the corresponding
85 * fragment program input attribute.
86 * \return -1 for vertex outputs that have no corresponding fragment input
87 */
88 static GLint
89 vp_out_to_fp_in(GLuint vertResult)
90 {
91 if (vertResult >= VERT_RESULT_TEX0 &&
92 vertResult < VERT_RESULT_TEX0 + MAX_TEXTURE_COORD_UNITS)
93 return FRAG_ATTRIB_TEX0 + (vertResult - VERT_RESULT_TEX0);
94
95 if (vertResult >= VERT_RESULT_VAR0 &&
96 vertResult < VERT_RESULT_VAR0 + MAX_VARYING)
97 return FRAG_ATTRIB_VAR0 + (vertResult - VERT_RESULT_VAR0);
98
99 switch (vertResult) {
100 case VERT_RESULT_HPOS:
101 return FRAG_ATTRIB_WPOS;
102 case VERT_RESULT_COL0:
103 return FRAG_ATTRIB_COL0;
104 case VERT_RESULT_COL1:
105 return FRAG_ATTRIB_COL1;
106 case VERT_RESULT_FOGC:
107 return FRAG_ATTRIB_FOGC;
108 default:
109 /* Back-face colors, edge flags, etc */
110 return -1;
111 }
112 }
113
114
115 /**
116 * Find a translated vertex program that corresponds to stvp and
117 * has outputs matched to stfp's inputs.
118 * This performs vertex and fragment translation (to TGSI) when needed.
119 */
120 static struct translated_vertex_program *
121 find_translated_vp(struct st_context *st,
122 struct st_vertex_program *stvp,
123 struct st_fragment_program *stfp)
124 {
125 static const GLuint UNUSED = ~0;
126 struct translated_vertex_program *xvp;
127 const GLbitfield fragInputsRead = stfp->Base.Base.InputsRead;
128
129 /*
130 * Translate fragment program if needed.
131 */
132 if (!stfp->state.tokens) {
133 GLuint inAttr, numIn = 0;
134
135 for (inAttr = 0; inAttr < FRAG_ATTRIB_MAX; inAttr++) {
136 if (fragInputsRead & (1 << inAttr)) {
137 stfp->input_to_slot[inAttr] = numIn;
138 numIn++;
139 }
140 else {
141 stfp->input_to_slot[inAttr] = UNUSED;
142 }
143 }
144
145 stfp->num_input_slots = numIn;
146
147 assert(stfp->Base.Base.NumInstructions > 1);
148
149 st_translate_fragment_program(st, stfp, stfp->input_to_slot);
150 }
151
152
153 /* See if we've got a translated vertex program whose outputs match
154 * the fragment program's inputs.
155 * XXX This could be a hash lookup, using InputsRead as the key.
156 */
157 for (xvp = stfp->vertex_programs; xvp; xvp = xvp->next) {
158 if (xvp->master == stvp && xvp->frag_inputs == fragInputsRead) {
159 break;
160 }
161 }
162
163 /* No? Allocate translated vp object now */
164 if (!xvp) {
165 xvp = CALLOC_STRUCT(translated_vertex_program);
166 xvp->frag_inputs = fragInputsRead;
167 xvp->master = stvp;
168
169 xvp->next = stfp->vertex_programs;
170 stfp->vertex_programs = xvp;
171 }
172
173 /* See if we need to translate vertex program to TGSI form */
174 if (xvp->serialNo != stvp->serialNo) {
175 GLuint outAttr, dummySlot;
176 const GLbitfield outputsWritten = stvp->Base.Base.OutputsWritten;
177 GLuint numVpOuts = 0;
178
179 /* Compute mapping of vertex program outputs to slots, which depends
180 * on the fragment program's input->slot mapping.
181 */
182 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) {
183 /* set default: */
184 xvp->output_to_slot[outAttr] = UNUSED;
185
186 if (outAttr == VERT_RESULT_HPOS) {
187 /* always put xformed position into slot zero */
188 xvp->output_to_slot[VERT_RESULT_HPOS] = 0;
189 numVpOuts++;
190 }
191 else if (outputsWritten & (1 << outAttr)) {
192 /* see if the frag prog wants this vert output */
193 GLint fpInAttrib = vp_out_to_fp_in(outAttr);
194 if (fpInAttrib >= 0) {
195 GLuint fpInSlot = stfp->input_to_slot[fpInAttrib];
196 if (fpInSlot != ~0) {
197 GLuint vpOutSlot = stfp->input_map[fpInSlot];
198 xvp->output_to_slot[outAttr] = vpOutSlot;
199 numVpOuts++;
200 }
201 }
202 else if (outAttr == VERT_RESULT_PSIZ ||
203 outAttr == VERT_RESULT_BFC0 ||
204 outAttr == VERT_RESULT_BFC1) {
205 /* backface colors go into last slots */
206 xvp->output_to_slot[outAttr] = numVpOuts++;
207 }
208 }
209 /*
210 printf("output_to_slot[%d] = %d\n", outAttr,
211 xvp->output_to_slot[outAttr]);
212 */
213 }
214
215 /* Unneeded vertex program outputs will go to this slot.
216 * We could use this info to do dead code elimination in the
217 * vertex program.
218 */
219 dummySlot = numVpOuts;
220
221 /* Map vert program outputs that aren't used to the dummy slot */
222 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) {
223 if (outputsWritten & (1 << outAttr)) {
224 if (xvp->output_to_slot[outAttr] == UNUSED)
225 xvp->output_to_slot[outAttr] = dummySlot;
226 }
227 }
228
229 assert(stvp->Base.Base.NumInstructions > 1);
230
231 st_translate_vertex_program(st, stvp, xvp->output_to_slot);
232
233 xvp->vp = stvp;
234
235 /* translated VP is up to date now */
236 xvp->serialNo = stvp->serialNo;
237 }
238
239 return xvp;
240 }
241
242
243 void
244 st_free_translated_vertex_programs(struct st_context *st,
245 struct translated_vertex_program *xvp)
246 {
247 struct translated_vertex_program *next;
248
249 while (xvp) {
250 next = xvp->next;
251 free(xvp);
252 xvp = next;
253 }
254 }
255
256
257 static void *
258 get_passthrough_fs(struct st_context *st)
259 {
260 struct pipe_shader_state shader;
261
262 if (!st->passthrough_fs) {
263 st->passthrough_fs =
264 util_make_fragment_passthrough_shader(st->pipe, &shader);
265 #if 0 /* We actually need to keep the tokens around at this time */
266 free((void *) shader.tokens);
267 #endif
268 }
269
270 return st->passthrough_fs;
271 }
272
273
274 static void
275 update_linkage( struct st_context *st )
276 {
277 struct st_vertex_program *stvp;
278 struct st_fragment_program *stfp;
279 struct translated_vertex_program *xvp;
280
281 /* find active shader and params -- Should be covered by
282 * ST_NEW_VERTEX_PROGRAM
283 */
284 assert(st->ctx->VertexProgram._Current);
285 stvp = st_vertex_program(st->ctx->VertexProgram._Current);
286 assert(stvp->Base.Base.Target == GL_VERTEX_PROGRAM_ARB);
287
288 assert(st->ctx->FragmentProgram._Current);
289 stfp = st_fragment_program(st->ctx->FragmentProgram._Current);
290 assert(stfp->Base.Base.Target == GL_FRAGMENT_PROGRAM_ARB);
291
292 xvp = find_translated_vp(st, stvp, stfp);
293
294 st_reference_vertprog(st, &st->vp, stvp);
295 st_reference_fragprog(st, &st->fp, stfp);
296
297 cso_set_vertex_shader_handle(st->cso_context, stvp->driver_shader);
298
299 if (st->missing_textures) {
300 /* use a pass-through frag shader that uses no textures */
301 void *fs = get_passthrough_fs(st);
302 cso_set_fragment_shader_handle(st->cso_context, fs);
303 }
304 else {
305 cso_set_fragment_shader_handle(st->cso_context, stfp->driver_shader);
306 }
307
308 st->vertex_result_to_slot = xvp->output_to_slot;
309 }
310
311
312 const struct st_tracked_state st_update_shader = {
313 "st_update_shader", /* name */
314 { /* dirty */
315 0, /* mesa */
316 ST_NEW_VERTEX_PROGRAM | ST_NEW_FRAGMENT_PROGRAM /* st */
317 },
318 update_linkage /* update */
319 };