3a5bce009951a9e39acf059fe1849a34d483d61f
2 * Mesa 3-D graphics library
5 * Copyright (C) 2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
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"
46 link_varying_vars(struct gl_shader_program
*shProg
, struct gl_program
*prog
)
48 GLuint
*map
, i
, firstVarying
, newFile
;
49 GLbitfield varsWritten
, varsRead
;
51 map
= (GLuint
*) malloc(prog
->Varying
->NumParameters
* sizeof(GLuint
));
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
;
60 GLint j
= _mesa_lookup_parameter_index(shProg
->Varying
, -1, var
->Name
);
62 /* already in list, check size */
63 if (var
->Size
!= shProg
->Varying
->Parameters
[j
].Size
) {
69 /* not already in linked list */
70 j
= _mesa_add_varying(shProg
->Varying
, var
->Name
, var
->Size
);
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.
83 if (prog
->Target
== GL_VERTEX_PROGRAM_ARB
) {
84 firstVarying
= VERT_RESULT_VAR0
;
85 newFile
= PROGRAM_OUTPUT
;
88 assert(prog
->Target
== GL_FRAGMENT_PROGRAM_ARB
);
89 firstVarying
= FRAG_ATTRIB_VAR0
;
90 newFile
= PROGRAM_INPUT
;
93 /* keep track of which varying vars we read and write */
94 varsWritten
= varsRead
= 0x0;
96 /* OK, now scan the program/shader instructions looking for varying vars,
97 * replacing the old index with the new index.
99 for (i
= 0; i
< prog
->NumInstructions
; i
++) {
100 struct prog_instruction
*inst
= prog
->Instructions
+ i
;
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
);
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
);
116 /* XXX update program OutputsWritten, InputsRead */
119 if (prog
->Target
== GL_VERTEX_PROGRAM_ARB
) {
120 prog
->OutputsWritten
|= varsWritten
;
123 assert(prog
->Target
== GL_FRAGMENT_PROGRAM_ARB
);
124 prog
->InputsRead
|= varsRead
;
135 is_uniform(enum register_file file
)
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
);
147 link_uniform_vars(struct gl_shader_program
*shProg
, struct gl_program
*prog
)
152 printf("================ pre link uniforms ===============\n");
153 _mesa_print_parameter_list(shProg
->Uniforms
);
156 map
= (GLuint
*) malloc(prog
->Parameters
->NumParameters
* sizeof(GLuint
));
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
];
168 assert(is_uniform(p
->Type
));
171 j
= _mesa_lookup_parameter_index(shProg
->Uniforms
, -1, p
->Name
);
175 ASSERT(p
->Type
== PROGRAM_CONSTANT
);
176 if (_mesa_lookup_parameter_constant(shProg
->Uniforms
, pVals
,
177 p
->Size
, &j
, &swizzle
)) {
186 /* already in list, check size XXX check this */
188 assert(p
->Size
== shProg
->Uniforms
->Parameters
[j
].Size
);
192 /* not already in linked list */
194 case PROGRAM_ENV_PARAM
:
195 j
= _mesa_add_named_parameter(shProg
->Uniforms
, p
->Name
, pVals
);
197 case PROGRAM_CONSTANT
:
198 j
= _mesa_add_named_constant(shProg
->Uniforms
, p
->Name
, pVals
, p
->Size
);
200 case PROGRAM_STATE_VAR
:
201 j
= _mesa_add_state_reference(shProg
->Uniforms
, (const GLint
*) p
->StateIndexes
);
203 case PROGRAM_UNIFORM
:
204 j
= _mesa_add_uniform(shProg
->Uniforms
, p
->Name
, p
->Size
);
206 case PROGRAM_SAMPLER
:
207 j
= _mesa_add_sampler(shProg
->Uniforms
, p
->Name
);
227 printf("================ post link uniforms ===============\n");
228 _mesa_print_parameter_list(shProg
->Uniforms
);
234 for (i
= 0; i
< prog
->Parameters
->NumParameters
; i
++) {
235 printf("map[%d] = %d\n", i
, map
[i
]);
237 _mesa_print_parameter_list(shProg
->Uniforms
);
241 /* OK, now scan the program/shader instructions looking for uniform vars,
242 * replacing the old index with the new index.
244 for (i
= 0; i
< prog
->NumInstructions
; i
++) {
245 struct prog_instruction
*inst
= prog
->Instructions
+ i
;
248 if (is_uniform(inst
->DstReg
.File
)) {
249 inst
->DstReg
.Index
= map
[ inst
->DstReg
.Index
];
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
];
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
];
277 _slang_resolve_branches(struct gl_program
*prog
)
283 struct target targets
[500];
284 GLuint numTargets
= 0;
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
;
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
;
305 if (j
== numTargets
) {
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.
319 _slang_resolve_samplers(struct gl_shader_program
*shProg
,
320 struct gl_program
*prog
)
324 for (i
= 0; i
< MAX_TEXTURE_IMAGE_UNITS
; i
++)
325 prog
->TexturesUsed
[i
] = 0;
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
;
336 prog
->TexturesUsed
[inst
->TexSrcUnit
] |= (1 << inst
->TexSrcTarget
);
343 * Scan program instructions to update the program's InputsRead and
344 * OutputsWritten fields.
347 _slang_update_inputs_outputs(struct gl_program
*prog
)
351 prog
->InputsRead
= 0x0;
352 prog
->OutputsWritten
= 0x0;
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
;
362 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
) {
363 prog
->OutputsWritten
|= 1 << inst
->DstReg
.Index
;
371 static struct gl_vertex_program
*
372 vertex_program(struct gl_program
*prog
)
374 assert(prog
->Target
== GL_VERTEX_PROGRAM_ARB
);
375 return (struct gl_vertex_program
*) prog
;
380 static struct gl_fragment_program
*
381 fragment_program(struct gl_program
*prog
)
383 assert(prog
->Target
== GL_FRAGMENT_PROGRAM_ARB
);
384 return (struct gl_fragment_program
*) prog
;
389 * Shader linker. Currently:
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.
403 _slang_link2(GLcontext
*ctx
,
404 GLhandleARB programObj
,
405 struct gl_shader_program
*shProg
)
407 struct gl_vertex_program
*vertProg
;
408 struct gl_fragment_program
*fragProg
;
411 _mesa_free_shader_program_data(ctx
, shProg
);
413 shProg
->Uniforms
= _mesa_new_parameter_list();
414 shProg
->Varying
= _mesa_new_parameter_list();
417 * Find attached vertex shader, fragment shader
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]);
427 _mesa_problem(ctx
, "unexpected shader target in slang_link2()");
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
;
436 if (!vertProg
->Base
.Varying
|| !fragProg
->Base
.Varying
) {
438 _mesa_problem(ctx
, "vertex/fragment program lacks varying list!");
439 shProg
->LinkStatus
= GL_FALSE
;
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.
447 shProg
->VertexProgram
448 = vertex_program(_mesa_clone_program(ctx
, &vertProg
->Base
));
449 shProg
->FragmentProgram
450 = fragment_program(_mesa_clone_program(ctx
, &fragProg
->Base
));
452 link_varying_vars(shProg
, &shProg
->VertexProgram
->Base
);
453 link_varying_vars(shProg
, &shProg
->FragmentProgram
->Base
);
455 link_uniform_vars(shProg
, &shProg
->VertexProgram
->Base
);
456 link_uniform_vars(shProg
, &shProg
->FragmentProgram
->Base
);
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
;
464 _slang_resolve_branches(&shProg
->VertexProgram
->Base
);
465 _slang_resolve_branches(&shProg
->FragmentProgram
->Base
);
467 _slang_resolve_samplers(shProg
, &shProg
->VertexProgram
->Base
);
468 _slang_resolve_samplers(shProg
, &shProg
->FragmentProgram
->Base
);
470 _slang_update_inputs_outputs(&shProg
->VertexProgram
->Base
);
471 _slang_update_inputs_outputs(&shProg
->FragmentProgram
->Base
);
474 printf("************** original fragment program\n");
475 _mesa_print_program(&fragProg
->Base
);
476 _mesa_print_program_parameters(ctx
, &fragProg
->Base
);
479 printf("************** linked fragment prog\n");
480 _mesa_print_program(&shProg
->FragmentProgram
->Base
);
481 _mesa_print_program_parameters(ctx
, &shProg
->FragmentProgram
->Base
);
484 printf("************** original vertex program\n");
485 _mesa_print_program(&vertProg
->Base
);
486 _mesa_print_program_parameters(ctx
, &fragProg
->Base
);
489 printf("************** linked vertex prog\n");
490 _mesa_print_program(&shProg
->VertexProgram
->Base
);
491 _mesa_print_program_parameters(ctx
, &shProg
->VertexProgram
->Base
);
494 shProg
->LinkStatus
= (shProg
->VertexProgram
&& shProg
->FragmentProgram
);