gallium: reorg tgsi directories.
[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
43 #include "pipe/p_context.h"
44 #include "pipe/p_shader_tokens.h"
45
46 #include "st_context.h"
47 #include "st_cache.h"
48 #include "st_atom.h"
49 #include "st_program.h"
50 #include "st_atom_shader.h"
51 #include "st_mesa_to_tgsi.h"
52
53
54 /**
55 * This represents a vertex program, especially translated to match
56 * the inputs of a particular fragment shader.
57 */
58 struct translated_vertex_program
59 {
60 struct st_vertex_program *master;
61
62 /** The fragment shader "signature" this vertex shader is meant for: */
63 GLbitfield frag_inputs;
64
65 /** Compared against master vertex program's serialNo: */
66 GLuint serialNo;
67
68 /** Maps VERT_RESULT_x to slot */
69 GLuint output_to_slot[VERT_RESULT_MAX];
70
71 /** The program in TGSI format */
72 struct tgsi_token tokens[ST_MAX_SHADER_TOKENS];
73
74 /** Pointer to the translated, cached vertex shader */
75 const struct cso_vertex_shader *vs;
76
77 struct translated_vertex_program *next; /**< next in linked list */
78 };
79
80
81
82 /**
83 * Free data hanging off the st vert prog.
84 */
85 void
86 st_remove_vertex_program(struct st_context *st, struct st_vertex_program *stvp)
87 {
88 /* no-op, for now? */
89 }
90
91
92 /**
93 * Free data hanging off the st frag prog.
94 */
95 void
96 st_remove_fragment_program(struct st_context *st,
97 struct st_fragment_program *stfp)
98 {
99 struct translated_vertex_program *xvp, *next;
100
101 for (xvp = stfp->vertex_programs; xvp; xvp = next) {
102 next = xvp->next;
103 /* XXX free xvp->vs */
104 free(xvp);
105 }
106 }
107
108
109
110 /**
111 * Given a vertex program output attribute, return the corresponding
112 * fragment program input attribute.
113 * \return -1 for vertex outputs that have no corresponding fragment input
114 */
115 static GLint
116 vp_out_to_fp_in(GLuint vertResult)
117 {
118 if (vertResult >= VERT_RESULT_TEX0 &&
119 vertResult < VERT_RESULT_TEX0 + MAX_TEXTURE_COORD_UNITS)
120 return FRAG_ATTRIB_TEX0 + (vertResult - VERT_RESULT_TEX0);
121
122 if (vertResult >= VERT_RESULT_VAR0 &&
123 vertResult < VERT_RESULT_VAR0 + MAX_VARYING)
124 return FRAG_ATTRIB_VAR0 + (vertResult - VERT_RESULT_VAR0);
125
126 switch (vertResult) {
127 case VERT_RESULT_HPOS:
128 return FRAG_ATTRIB_WPOS;
129 case VERT_RESULT_COL0:
130 return FRAG_ATTRIB_COL0;
131 case VERT_RESULT_COL1:
132 return FRAG_ATTRIB_COL1;
133 case VERT_RESULT_FOGC:
134 return FRAG_ATTRIB_FOGC;
135 default:
136 /* Back-face colors, edge flags, etc */
137 return -1;
138 }
139 }
140
141
142 /**
143 * Find a translated vertex program that corresponds to stvp and
144 * has outputs matched to stfp's inputs.
145 * This performs vertex and fragment translation (to TGSI) when needed.
146 */
147 static struct translated_vertex_program *
148 find_translated_vp(struct st_context *st,
149 struct st_vertex_program *stvp,
150 struct st_fragment_program *stfp)
151 {
152 static const GLuint UNUSED = ~0;
153 struct translated_vertex_program *xvp;
154 const GLbitfield fragInputsRead
155 = stfp->Base.Base.InputsRead | FRAG_BIT_WPOS;
156
157 /*
158 * Translate fragment program if needed.
159 */
160 if (!stfp->fs) {
161 GLuint inAttr, numIn = 0;
162
163 for (inAttr = 0; inAttr < FRAG_ATTRIB_MAX; inAttr++) {
164 if (fragInputsRead & (1 << inAttr)) {
165 stfp->input_to_slot[inAttr] = numIn;
166 numIn++;
167 }
168 else {
169 stfp->input_to_slot[inAttr] = UNUSED;
170 }
171 }
172
173 stfp->num_input_slots = numIn;
174
175 assert(stfp->Base.Base.NumInstructions > 1);
176
177 (void) st_translate_fragment_program(st, stfp,
178 stfp->input_to_slot,
179 stfp->tokens,
180 ST_MAX_SHADER_TOKENS);
181 assert(stfp->fs);
182 }
183
184
185 /* See if we've got a translated vertex program whose outputs match
186 * the fragment program's inputs.
187 * XXX This could be a hash lookup, using InputsRead as the key.
188 */
189 for (xvp = stfp->vertex_programs; xvp; xvp = xvp->next) {
190 if (xvp->master == stvp && xvp->frag_inputs == fragInputsRead) {
191 break;
192 }
193 }
194
195 /* No? Allocate translated vp object now */
196 if (!xvp) {
197 xvp = CALLOC_STRUCT(translated_vertex_program);
198 xvp->frag_inputs = fragInputsRead;
199 xvp->master = stvp;
200
201 xvp->next = stfp->vertex_programs;
202 stfp->vertex_programs = xvp;
203 }
204
205 /* See if we need to translate vertex program to TGSI form */
206 if (xvp->serialNo != stvp->serialNo) {
207 GLuint outAttr, dummySlot;
208 const GLbitfield outputsWritten = stvp->Base.Base.OutputsWritten;
209
210 /* Compute mapping of vertex program outputs to slots, which depends
211 * on the fragment program's input->slot mapping.
212 */
213 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) {
214 /* set default: */
215 xvp->output_to_slot[outAttr] = UNUSED;
216
217 if (outputsWritten & (1 << outAttr)) {
218 /* see if the frag prog wants this vert output */
219 GLint fpIn = vp_out_to_fp_in(outAttr);
220 if (fpIn >= 0) {
221 xvp->output_to_slot[outAttr] = stfp->input_to_slot[fpIn];
222 }
223 }
224 }
225
226 /* Unneeded vertex program outputs will go to this slot.
227 * We could use this info to do dead code elimination in the
228 * vertex program.
229 */
230 dummySlot = stfp->num_input_slots;
231
232 /* Map vert program outputs that aren't used to the dummy slot */
233 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) {
234 if (outputsWritten & (1 << outAttr)) {
235 if (xvp->output_to_slot[outAttr] == UNUSED)
236 xvp->output_to_slot[outAttr] = dummySlot;
237 }
238 }
239
240 assert(stvp->Base.Base.NumInstructions > 1);
241
242 xvp->vs = st_translate_vertex_program(st, stvp,
243 xvp->output_to_slot,
244 xvp->tokens,
245 ST_MAX_SHADER_TOKENS);
246 assert(xvp->vs);
247 stvp->vs = NULL; /* don't want to use this */
248
249 /* translated VP is up to date now */
250 xvp->serialNo = stvp->serialNo;
251 }
252
253 return xvp;
254 }
255
256
257 static void
258 update_linkage( struct st_context *st )
259 {
260 struct st_vertex_program *stvp;
261 struct st_fragment_program *stfp;
262 struct translated_vertex_program *xvp;
263
264 /* find active shader and params -- Should be covered by
265 * ST_NEW_VERTEX_PROGRAM
266 */
267 assert(st->ctx->VertexProgram._Current);
268 stvp = st_vertex_program(st->ctx->VertexProgram._Current);
269
270 assert(st->ctx->FragmentProgram._Current);
271 stfp = st_fragment_program(st->ctx->FragmentProgram._Current);
272
273 xvp = find_translated_vp(st, stvp, stfp);
274
275 st->vp = stvp;
276 st->state.vs = xvp->vs;
277 st->pipe->bind_vs_state(st->pipe, st->state.vs->data);
278
279 st->fp = stfp;
280 st->state.fs = stfp->fs;
281 st->pipe->bind_fs_state(st->pipe, st->state.fs->data);
282
283 st->vertex_result_to_slot = xvp->output_to_slot;
284 }
285
286
287 const struct st_tracked_state st_update_shader = {
288 .name = "st_update_shader",
289 .dirty = {
290 .mesa = 0,
291 .st = ST_NEW_VERTEX_PROGRAM | ST_NEW_FRAGMENT_PROGRAM
292 },
293 .update = update_linkage
294 };