Clean-up and re-org of the main GLSL object types.
[mesa.git] / src / mesa / shader / slang / slang_link2.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
4 *
5 * Copyright (C) 2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file slang_link2.c
27 * GLSL linker
28 * \author Brian Paul
29 */
30
31 #include "imports.h"
32 #include "context.h"
33 #include "hash.h"
34 #include "macros.h"
35 #include "program.h"
36 #include "prog_instruction.h"
37 #include "prog_parameter.h"
38 #include "prog_print.h"
39 #include "shader_api.h"
40 #include "slang_link.h"
41
42
43
44
45 static GLboolean
46 link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog)
47 {
48 GLuint *map, i, firstVarying, newFile;
49 GLbitfield varsWritten, varsRead;
50
51 map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint));
52 if (!map)
53 return GL_FALSE;
54
55 for (i = 0; i < prog->Varying->NumParameters; i++) {
56 /* see if this varying is in the linked varying list */
57 const struct gl_program_parameter *var
58 = prog->Varying->Parameters + i;
59
60 GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name);
61 if (j >= 0) {
62 /* already in list, check size */
63 if (var->Size != shProg->Varying->Parameters[j].Size) {
64 /* error */
65 return GL_FALSE;
66 }
67 }
68 else {
69 /* not already in linked list */
70 j = _mesa_add_varying(shProg->Varying, var->Name, var->Size);
71 }
72 ASSERT(j >= 0);
73
74 map[i] = j;
75 }
76
77
78 /* Varying variables are treated like other vertex program outputs
79 * (and like other fragment program inputs). The position of the
80 * first varying differs for vertex/fragment programs...
81 * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT.
82 */
83 if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
84 firstVarying = VERT_RESULT_VAR0;
85 newFile = PROGRAM_OUTPUT;
86 }
87 else {
88 assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
89 firstVarying = FRAG_ATTRIB_VAR0;
90 newFile = PROGRAM_INPUT;
91 }
92
93 /* keep track of which varying vars we read and write */
94 varsWritten = varsRead = 0x0;
95
96 /* OK, now scan the program/shader instructions looking for varying vars,
97 * replacing the old index with the new index.
98 */
99 for (i = 0; i < prog->NumInstructions; i++) {
100 struct prog_instruction *inst = prog->Instructions + i;
101 GLuint j;
102
103 if (inst->DstReg.File == PROGRAM_VARYING) {
104 inst->DstReg.File = newFile;
105 inst->DstReg.Index = map[ inst->DstReg.Index ] + firstVarying;
106 varsWritten |= (1 << inst->DstReg.Index);
107 }
108
109 for (j = 0; j < 3; j++) {
110 if (inst->SrcReg[j].File == PROGRAM_VARYING) {
111 inst->SrcReg[j].File = newFile;
112 inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + firstVarying;
113 varsRead |= (1 << inst->SrcReg[j].Index);
114 }
115 }
116 /* XXX update program OutputsWritten, InputsRead */
117 }
118
119 if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
120 prog->OutputsWritten |= varsWritten;
121 }
122 else {
123 assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
124 prog->InputsRead |= varsRead;
125 }
126
127
128 free(map);
129
130 return GL_TRUE;
131 }
132
133
134 static GLboolean
135 is_uniform(enum register_file file)
136 {
137 return (file == PROGRAM_ENV_PARAM ||
138 file == PROGRAM_STATE_VAR ||
139 file == PROGRAM_NAMED_PARAM ||
140 file == PROGRAM_CONSTANT ||
141 file == PROGRAM_UNIFORM);
142 }
143
144
145 static GLboolean
146 link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
147 {
148 GLuint *map, i;
149
150 map = (GLuint *) malloc(prog->Parameters->NumParameters * sizeof(GLuint));
151 if (!map)
152 return GL_FALSE;
153
154 for (i = 0; i < prog->Parameters->NumParameters; i++) {
155 /* see if this uniform is in the linked uniform list */
156 const struct gl_program_parameter *p = prog->Parameters->Parameters + i;
157 const GLfloat *pVals = prog->Parameters->ParameterValues[i];
158 GLint j;
159
160 /* sanity check */
161 assert(is_uniform(p->Type));
162
163 if (p->Name) {
164 j = _mesa_lookup_parameter_index(shProg->Uniforms, -1, p->Name);
165 }
166 else {
167 GLuint swizzle;
168 ASSERT(p->Type == PROGRAM_CONSTANT);
169 if (_mesa_lookup_parameter_constant(shProg->Uniforms, pVals,
170 p->Size, &j, &swizzle)) {
171 assert(j >= 0);
172 }
173 else {
174 j = -1;
175 }
176 }
177
178 if (j >= 0) {
179 /* already in list, check size XXX check this */
180 assert(p->Size == shProg->Uniforms->Parameters[j].Size);
181 }
182 else {
183 /* not already in linked list */
184 switch (p->Type) {
185 case PROGRAM_ENV_PARAM:
186 j = _mesa_add_named_parameter(shProg->Uniforms, p->Name, pVals);
187 case PROGRAM_CONSTANT:
188 j = _mesa_add_named_constant(shProg->Uniforms, p->Name, pVals, p->Size);
189 break;
190 case PROGRAM_STATE_VAR:
191 j = _mesa_add_state_reference(shProg->Uniforms, (const GLint *) p->StateIndexes);
192 break;
193 case PROGRAM_UNIFORM:
194 j = _mesa_add_uniform(shProg->Uniforms, p->Name, p->Size);
195 break;
196 default:
197 abort();
198 }
199
200 }
201 ASSERT(j >= 0);
202
203 map[i] = j;
204 }
205
206
207 /* OK, now scan the program/shader instructions looking for varying vars,
208 * replacing the old index with the new index.
209 */
210 for (i = 0; i < prog->NumInstructions; i++) {
211 struct prog_instruction *inst = prog->Instructions + i;
212 GLuint j;
213
214 if (is_uniform(inst->DstReg.File)) {
215 inst->DstReg.Index = map[ inst->DstReg.Index ];
216 }
217
218 for (j = 0; j < 3; j++) {
219 if (is_uniform(inst->SrcReg[j].File)) {
220 inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ];
221 }
222 }
223 /* XXX update program OutputsWritten, InputsRead */
224 }
225
226 free(map);
227
228 return GL_TRUE;
229 }
230
231
232 /**
233 * XXX Temporary
234 */
235 static void
236 slang_resolve_branches(struct gl_program *prog)
237 {
238 struct target {
239 const char *Name;
240 GLuint Pos;
241 };
242 struct target targets[500];
243 GLuint numTargets = 0;
244 GLuint i, j;
245
246 for (i = 0; i < prog->NumInstructions; i++) {
247 struct prog_instruction *inst = prog->Instructions + i;
248 if (inst->Opcode == OPCODE_NOP && inst->Comment) {
249 targets[numTargets].Name = inst->Comment;
250 targets[numTargets].Pos = i;
251 numTargets++;
252 }
253 }
254
255 for (i = 0; i < prog->NumInstructions; i++) {
256 struct prog_instruction *inst = prog->Instructions + i;
257 if (inst->Opcode == OPCODE_BRA) {
258 for (j = 0; j < numTargets; j++) {
259 if (!strcmp(inst->Comment, targets[j].Name)) {
260 inst->BranchTarget = targets[j].Pos;
261 break;
262 }
263 }
264 if (j == numTargets) {
265 abort();
266 }
267 }
268 }
269 }
270
271
272
273 /**
274 * Shader linker. Currently:
275 *
276 * 1. The last attached vertex shader and fragment shader are linked.
277 * 2. Varying vars in the two shaders are combined so their locations
278 * agree between the vertex and fragment stages. They're treated as
279 * vertex program output attribs and as fragment program input attribs.
280 * 3. Uniform vars (including state references, constants, etc) from the
281 * vertex and fragment shaders are merged into one group. Recall that
282 * GLSL uniforms are shared by all linked shaders.
283 * 4. The vertex and fragment programs are cloned and modified to update
284 * src/dst register references so they use the new, linked uniform/
285 * varying storage locations.
286 */
287 void
288 _slang_link2(GLcontext *ctx,
289 GLhandleARB programObj,
290 struct gl_shader_program *shProg)
291 {
292 struct gl_vertex_program *vertProg;
293 struct gl_fragment_program *fragProg;
294 GLuint i;
295
296 _mesa_free_shader_program_data(ctx, shProg);
297
298 shProg->Uniforms = _mesa_new_parameter_list();
299 shProg->Varying = _mesa_new_parameter_list();
300
301 /**
302 * Find attached vertex shader, fragment shader
303 */
304 vertProg = NULL;
305 fragProg = NULL;
306 for (i = 0; i < shProg->NumShaders; i++) {
307 if (shProg->Shaders[i]->Type == GL_VERTEX_SHADER)
308 vertProg = (struct gl_vertex_program *) shProg->Shaders[i]->Programs[0];
309 else if (shProg->Shaders[i]->Type == GL_FRAGMENT_SHADER)
310 fragProg = (struct gl_fragment_program *) shProg->Shaders[i]->Programs[0];
311 else
312 _mesa_problem(ctx, "unexpected shader target in slang_link2()");
313 }
314 if (!vertProg || !fragProg) {
315 /* XXX is it legal to have one but not the other?? */
316 /* XXX record error */
317 shProg->LinkStatus = GL_FALSE;
318 return;
319 }
320
321 if (!vertProg->Base.Varying || !fragProg->Base.Varying) {
322 /* temporary */
323 _mesa_problem(ctx, "vertex/fragment program lacks varying list!");
324 shProg->LinkStatus = GL_FALSE;
325 return;
326 }
327
328 /*
329 * Make copies of the vertex/fragment programs now since we'll be
330 * changing src/dst registers after merging the uniforms and varying vars.
331 */
332 shProg->VertexProgram = (struct gl_vertex_program *)
333 _mesa_clone_program(ctx, &vertProg->Base);
334 shProg->FragmentProgram = (struct gl_fragment_program *)
335 _mesa_clone_program(ctx, &fragProg->Base);
336
337 link_varying_vars(shProg, &shProg->VertexProgram->Base);
338 link_varying_vars(shProg, &shProg->FragmentProgram->Base);
339
340 link_uniform_vars(shProg, &shProg->VertexProgram->Base);
341 link_uniform_vars(shProg, &shProg->FragmentProgram->Base);
342
343 /* The vertex and fragment programs share a common set of uniforms now */
344 _mesa_free_parameter_list(shProg->VertexProgram->Base.Parameters);
345 _mesa_free_parameter_list(shProg->FragmentProgram->Base.Parameters);
346 shProg->VertexProgram->Base.Parameters = shProg->Uniforms;
347 shProg->FragmentProgram->Base.Parameters = shProg->Uniforms;
348
349 slang_resolve_branches(&shProg->VertexProgram->Base);
350 slang_resolve_branches(&shProg->FragmentProgram->Base);
351
352 #if 1
353 printf("************** original fragment program\n");
354 _mesa_print_program(&fragProg->Base);
355 _mesa_print_program_parameters(ctx, &fragProg->Base);
356 #endif
357 #if 1
358 printf("************** linked fragment prog\n");
359 _mesa_print_program(&shProg->FragmentProgram->Base);
360 _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base);
361 #endif
362 #if 1
363 printf("************** original vertex program\n");
364 _mesa_print_program(&vertProg->Base);
365 _mesa_print_program_parameters(ctx, &fragProg->Base);
366 #endif
367 #if 1
368 printf("************** linked vertex prog\n");
369 _mesa_print_program(&shProg->VertexProgram->Base);
370 _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base);
371 #endif
372
373 shProg->LinkStatus = (shProg->VertexProgram && shProg->FragmentProgram);
374 }
375