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_linked_program
*linked
, 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(linked
->Varying
, -1, var
->Name
);
62 /* already in list, check size */
63 if (var
->Size
!= linked
->Varying
->Parameters
[j
].Size
) {
69 /* not already in linked list */
70 j
= _mesa_add_varying(linked
->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_UNIFORM
);
146 link_uniform_vars(struct gl_linked_program
*linked
, struct gl_program
*prog
)
150 map
= (GLuint
*) malloc(prog
->Parameters
->NumParameters
* sizeof(GLuint
));
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
];
161 assert(is_uniform(p
->Type
));
164 j
= _mesa_lookup_parameter_index(linked
->Uniforms
, -1, p
->Name
);
168 ASSERT(p
->Type
== PROGRAM_CONSTANT
);
169 if (_mesa_lookup_parameter_constant(linked
->Uniforms
, pVals
,
170 p
->Size
, &j
, &swizzle
)) {
179 /* already in list, check size XXX check this */
180 assert(p
->Size
== linked
->Uniforms
->Parameters
[j
].Size
);
183 /* not already in linked list */
185 case PROGRAM_ENV_PARAM
:
186 j
= _mesa_add_named_parameter(linked
->Uniforms
, p
->Name
, pVals
);
187 case PROGRAM_CONSTANT
:
188 j
= _mesa_add_named_constant(linked
->Uniforms
, p
->Name
, pVals
, p
->Size
);
190 case PROGRAM_STATE_VAR
:
191 j
= _mesa_add_state_reference(linked
->Uniforms
, (const GLint
*) p
->StateIndexes
);
193 case PROGRAM_UNIFORM
:
194 j
= _mesa_add_uniform(linked
->Uniforms
, p
->Name
, p
->Size
);
207 /* OK, now scan the program/shader instructions looking for varying vars,
208 * replacing the old index with the new index.
210 for (i
= 0; i
< prog
->NumInstructions
; i
++) {
211 struct prog_instruction
*inst
= prog
->Instructions
+ i
;
214 if (is_uniform(inst
->DstReg
.File
)) {
215 inst
->DstReg
.Index
= map
[ inst
->DstReg
.Index
];
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
];
223 /* XXX update program OutputsWritten, InputsRead */
236 slang_resolve_branches(struct gl_program
*prog
)
242 struct target targets
[500];
243 GLuint numTargets
= 0;
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
;
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
;
264 if (j
== numTargets
) {
274 * Shader linker. Currently:
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.
288 _slang_link2(GLcontext
*ctx
,
289 GLhandleARB programObj
,
290 struct gl_linked_program
*linked
)
292 struct gl_vertex_program
*vertProg
;
293 struct gl_fragment_program
*fragProg
;
296 _mesa_free_linked_program_data(ctx
, linked
);
298 linked
->Uniforms
= _mesa_new_parameter_list();
299 linked
->Varying
= _mesa_new_parameter_list();
302 * Find attached vertex shader, fragment shader
306 for (i
= 0; i
< linked
->NumShaders
; i
++) {
307 if (linked
->Shaders
[i
]->Target
== GL_VERTEX_PROGRAM_ARB
)
308 vertProg
= (struct gl_vertex_program
*) linked
->Shaders
[i
];
309 else if (linked
->Shaders
[i
]->Target
== GL_FRAGMENT_PROGRAM_ARB
)
310 fragProg
= (struct gl_fragment_program
*) linked
->Shaders
[i
];
312 _mesa_problem(ctx
, "unexpected shader target in slang_link2()");
314 if (!vertProg
|| !fragProg
) {
315 /* XXX is it legal to have one but not the other?? */
316 /* XXX record error */
317 linked
->LinkStatus
= GL_FALSE
;
322 * Make copies of the vertex/fragment programs now since we'll be
323 * changing src/dst registers after merging the uniforms and varying vars.
325 linked
->VertexProgram
= (struct gl_vertex_program
*)
326 _mesa_clone_program(ctx
, &vertProg
->Base
);
327 linked
->FragmentProgram
= (struct gl_fragment_program
*)
328 _mesa_clone_program(ctx
, &fragProg
->Base
);
330 link_varying_vars(linked
, &linked
->VertexProgram
->Base
);
331 link_varying_vars(linked
, &linked
->FragmentProgram
->Base
);
333 link_uniform_vars(linked
, &linked
->VertexProgram
->Base
);
334 link_uniform_vars(linked
, &linked
->FragmentProgram
->Base
);
336 /* The vertex and fragment programs share a common set of uniforms now */
337 _mesa_free_parameter_list(linked
->VertexProgram
->Base
.Parameters
);
338 _mesa_free_parameter_list(linked
->FragmentProgram
->Base
.Parameters
);
339 linked
->VertexProgram
->Base
.Parameters
= linked
->Uniforms
;
340 linked
->FragmentProgram
->Base
.Parameters
= linked
->Uniforms
;
342 slang_resolve_branches(&linked
->VertexProgram
->Base
);
343 slang_resolve_branches(&linked
->FragmentProgram
->Base
);
346 printf("************** original fragment program\n");
347 _mesa_print_program(&fragProg
->Base
);
348 _mesa_print_program_parameters(ctx
, &fragProg
->Base
);
351 printf("************** linked fragment prog\n");
352 _mesa_print_program(&linked
->FragmentProgram
->Base
);
353 _mesa_print_program_parameters(ctx
, &linked
->FragmentProgram
->Base
);
356 printf("************** original vertex program\n");
357 _mesa_print_program(&vertProg
->Base
);
358 _mesa_print_program_parameters(ctx
, &fragProg
->Base
);
361 printf("************** linked vertex prog\n");
362 _mesa_print_program(&linked
->VertexProgram
->Base
);
363 _mesa_print_program_parameters(ctx
, &linked
->VertexProgram
->Base
);
366 linked
->LinkStatus
= (linked
->VertexProgram
&& linked
->FragmentProgram
);