3a5bce009951a9e39acf059fe1849a34d483d61f
[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_SAMPLER ||
142 file == PROGRAM_UNIFORM);
143 }
144
145
146 static GLboolean
147 link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
148 {
149 GLuint *map, i;
150
151 #if 0
152 printf("================ pre link uniforms ===============\n");
153 _mesa_print_parameter_list(shProg->Uniforms);
154 #endif
155
156 map = (GLuint *) malloc(prog->Parameters->NumParameters * sizeof(GLuint));
157 if (!map)
158 return GL_FALSE;
159
160 for (i = 0; i < prog->Parameters->NumParameters; /* incr below*/) {
161 /* see if this uniform is in the linked uniform list */
162 const struct gl_program_parameter *p = prog->Parameters->Parameters + i;
163 const GLfloat *pVals = prog->Parameters->ParameterValues[i];
164 GLint j;
165 GLint size;
166
167 /* sanity check */
168 assert(is_uniform(p->Type));
169
170 if (p->Name) {
171 j = _mesa_lookup_parameter_index(shProg->Uniforms, -1, p->Name);
172 }
173 else {
174 GLuint swizzle;
175 ASSERT(p->Type == PROGRAM_CONSTANT);
176 if (_mesa_lookup_parameter_constant(shProg->Uniforms, pVals,
177 p->Size, &j, &swizzle)) {
178 assert(j >= 0);
179 }
180 else {
181 j = -1;
182 }
183 }
184
185 if (j >= 0) {
186 /* already in list, check size XXX check this */
187 #if 0
188 assert(p->Size == shProg->Uniforms->Parameters[j].Size);
189 #endif
190 }
191 else {
192 /* not already in linked list */
193 switch (p->Type) {
194 case PROGRAM_ENV_PARAM:
195 j = _mesa_add_named_parameter(shProg->Uniforms, p->Name, pVals);
196 break;
197 case PROGRAM_CONSTANT:
198 j = _mesa_add_named_constant(shProg->Uniforms, p->Name, pVals, p->Size);
199 break;
200 case PROGRAM_STATE_VAR:
201 j = _mesa_add_state_reference(shProg->Uniforms, (const GLint *) p->StateIndexes);
202 break;
203 case PROGRAM_UNIFORM:
204 j = _mesa_add_uniform(shProg->Uniforms, p->Name, p->Size);
205 break;
206 case PROGRAM_SAMPLER:
207 j = _mesa_add_sampler(shProg->Uniforms, p->Name);
208 break;
209 default:
210 abort();
211 }
212
213 }
214 ASSERT(j >= 0);
215
216 size = p->Size;
217 while (size > 0) {
218 map[i] = j;
219 i++;
220 j++;
221 size -= 4;
222 }
223
224 }
225
226 #if 0
227 printf("================ post link uniforms ===============\n");
228 _mesa_print_parameter_list(shProg->Uniforms);
229 #endif
230
231 #if 0
232 {
233 GLuint i;
234 for (i = 0; i < prog->Parameters->NumParameters; i++) {
235 printf("map[%d] = %d\n", i, map[i]);
236 }
237 _mesa_print_parameter_list(shProg->Uniforms);
238 }
239 #endif
240
241 /* OK, now scan the program/shader instructions looking for uniform vars,
242 * replacing the old index with the new index.
243 */
244 for (i = 0; i < prog->NumInstructions; i++) {
245 struct prog_instruction *inst = prog->Instructions + i;
246 GLuint j;
247
248 if (is_uniform(inst->DstReg.File)) {
249 inst->DstReg.Index = map[ inst->DstReg.Index ];
250 }
251
252 for (j = 0; j < 3; j++) {
253 if (is_uniform(inst->SrcReg[j].File)) {
254 inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ];
255 }
256 }
257
258 if (inst->Opcode == OPCODE_TEX ||
259 inst->Opcode == OPCODE_TXB ||
260 inst->Opcode == OPCODE_TXP) {
261 printf("====== remap sampler from %d to %d\n",
262 inst->Sampler, map[ inst->Sampler ]);
263 inst->Sampler = map[ inst->Sampler ];
264 }
265 }
266
267 free(map);
268
269 return GL_TRUE;
270 }
271
272
273 /**
274 * XXX Temporary
275 */
276 static void
277 _slang_resolve_branches(struct gl_program *prog)
278 {
279 struct target {
280 const char *Name;
281 GLuint Pos;
282 };
283 struct target targets[500];
284 GLuint numTargets = 0;
285 GLuint i, j;
286
287 for (i = 0; i < prog->NumInstructions; i++) {
288 struct prog_instruction *inst = prog->Instructions + i;
289 if (inst->Opcode == OPCODE_NOP && inst->Comment) {
290 targets[numTargets].Name = inst->Comment;
291 targets[numTargets].Pos = i;
292 numTargets++;
293 }
294 }
295
296 for (i = 0; i < prog->NumInstructions; i++) {
297 struct prog_instruction *inst = prog->Instructions + i;
298 if (inst->Opcode == OPCODE_BRA) {
299 for (j = 0; j < numTargets; j++) {
300 if (!strcmp(inst->Comment, targets[j].Name)) {
301 inst->BranchTarget = targets[j].Pos;
302 break;
303 }
304 }
305 if (j == numTargets) {
306 abort();
307 }
308 }
309 }
310 }
311
312
313 /**
314 * Scan program for texture instructions, lookup sampler/uniform's value
315 * to determine which texture unit to use.
316 * Also, update the program's TexturesUsed[] array.
317 */
318 void
319 _slang_resolve_samplers(struct gl_shader_program *shProg,
320 struct gl_program *prog)
321 {
322 GLuint i;
323
324 for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
325 prog->TexturesUsed[i] = 0;
326
327 for (i = 0; i < prog->NumInstructions; i++) {
328 struct prog_instruction *inst = prog->Instructions + i;
329 if (inst->Opcode == OPCODE_TEX ||
330 inst->Opcode == OPCODE_TXB ||
331 inst->Opcode == OPCODE_TXP) {
332 GLint sampleUnit = (GLint) shProg->Uniforms->ParameterValues[inst->Sampler][0];
333 assert(sampleUnit < MAX_TEXTURE_IMAGE_UNITS);
334 inst->TexSrcUnit = sampleUnit;
335
336 prog->TexturesUsed[inst->TexSrcUnit] |= (1 << inst->TexSrcTarget);
337 }
338 }
339 }
340
341
342 /**
343 * Scan program instructions to update the program's InputsRead and
344 * OutputsWritten fields.
345 */
346 static void
347 _slang_update_inputs_outputs(struct gl_program *prog)
348 {
349 GLuint i, j;
350
351 prog->InputsRead = 0x0;
352 prog->OutputsWritten = 0x0;
353
354 for (i = 0; i < prog->NumInstructions; i++) {
355 const struct prog_instruction *inst = prog->Instructions + i;
356 const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
357 for (j = 0; j < numSrc; j++) {
358 if (inst->SrcReg[j].File == PROGRAM_INPUT) {
359 prog->InputsRead |= 1 << inst->SrcReg[j].Index;
360 }
361 }
362 if (inst->DstReg.File == PROGRAM_OUTPUT) {
363 prog->OutputsWritten |= 1 << inst->DstReg.Index;
364 }
365 }
366 }
367
368
369
370 /** cast wrapper */
371 static struct gl_vertex_program *
372 vertex_program(struct gl_program *prog)
373 {
374 assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
375 return (struct gl_vertex_program *) prog;
376 }
377
378
379 /** cast wrapper */
380 static struct gl_fragment_program *
381 fragment_program(struct gl_program *prog)
382 {
383 assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
384 return (struct gl_fragment_program *) prog;
385 }
386
387
388 /**
389 * Shader linker. Currently:
390 *
391 * 1. The last attached vertex shader and fragment shader are linked.
392 * 2. Varying vars in the two shaders are combined so their locations
393 * agree between the vertex and fragment stages. They're treated as
394 * vertex program output attribs and as fragment program input attribs.
395 * 3. Uniform vars (including state references, constants, etc) from the
396 * vertex and fragment shaders are merged into one group. Recall that
397 * GLSL uniforms are shared by all linked shaders.
398 * 4. The vertex and fragment programs are cloned and modified to update
399 * src/dst register references so they use the new, linked uniform/
400 * varying storage locations.
401 */
402 void
403 _slang_link2(GLcontext *ctx,
404 GLhandleARB programObj,
405 struct gl_shader_program *shProg)
406 {
407 struct gl_vertex_program *vertProg;
408 struct gl_fragment_program *fragProg;
409 GLuint i;
410
411 _mesa_free_shader_program_data(ctx, shProg);
412
413 shProg->Uniforms = _mesa_new_parameter_list();
414 shProg->Varying = _mesa_new_parameter_list();
415
416 /**
417 * Find attached vertex shader, fragment shader
418 */
419 vertProg = NULL;
420 fragProg = NULL;
421 for (i = 0; i < shProg->NumShaders; i++) {
422 if (shProg->Shaders[i]->Type == GL_VERTEX_SHADER)
423 vertProg = vertex_program(shProg->Shaders[i]->Programs[0]);
424 else if (shProg->Shaders[i]->Type == GL_FRAGMENT_SHADER)
425 fragProg = fragment_program(shProg->Shaders[i]->Programs[0]);
426 else
427 _mesa_problem(ctx, "unexpected shader target in slang_link2()");
428 }
429 if (!vertProg || !fragProg) {
430 /* XXX is it legal to have one but not the other?? */
431 /* XXX record error */
432 shProg->LinkStatus = GL_FALSE;
433 return;
434 }
435
436 if (!vertProg->Base.Varying || !fragProg->Base.Varying) {
437 /* temporary */
438 _mesa_problem(ctx, "vertex/fragment program lacks varying list!");
439 shProg->LinkStatus = GL_FALSE;
440 return;
441 }
442
443 /*
444 * Make copies of the vertex/fragment programs now since we'll be
445 * changing src/dst registers after merging the uniforms and varying vars.
446 */
447 shProg->VertexProgram
448 = vertex_program(_mesa_clone_program(ctx, &vertProg->Base));
449 shProg->FragmentProgram
450 = fragment_program(_mesa_clone_program(ctx, &fragProg->Base));
451
452 link_varying_vars(shProg, &shProg->VertexProgram->Base);
453 link_varying_vars(shProg, &shProg->FragmentProgram->Base);
454
455 link_uniform_vars(shProg, &shProg->VertexProgram->Base);
456 link_uniform_vars(shProg, &shProg->FragmentProgram->Base);
457
458 /* The vertex and fragment programs share a common set of uniforms now */
459 _mesa_free_parameter_list(shProg->VertexProgram->Base.Parameters);
460 _mesa_free_parameter_list(shProg->FragmentProgram->Base.Parameters);
461 shProg->VertexProgram->Base.Parameters = shProg->Uniforms;
462 shProg->FragmentProgram->Base.Parameters = shProg->Uniforms;
463
464 _slang_resolve_branches(&shProg->VertexProgram->Base);
465 _slang_resolve_branches(&shProg->FragmentProgram->Base);
466 #if 1
467 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
468 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
469 #endif
470 _slang_update_inputs_outputs(&shProg->VertexProgram->Base);
471 _slang_update_inputs_outputs(&shProg->FragmentProgram->Base);
472
473 #if 1
474 printf("************** original fragment program\n");
475 _mesa_print_program(&fragProg->Base);
476 _mesa_print_program_parameters(ctx, &fragProg->Base);
477 #endif
478 #if 1
479 printf("************** linked fragment prog\n");
480 _mesa_print_program(&shProg->FragmentProgram->Base);
481 _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base);
482 #endif
483 #if 1
484 printf("************** original vertex program\n");
485 _mesa_print_program(&vertProg->Base);
486 _mesa_print_program_parameters(ctx, &fragProg->Base);
487 #endif
488 #if 1
489 printf("************** linked vertex prog\n");
490 _mesa_print_program(&shProg->VertexProgram->Base);
491 _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base);
492 #endif
493
494 shProg->LinkStatus = (shProg->VertexProgram && shProg->FragmentProgram);
495 }
496