4827c8c4cdecfb3ea559880eba8d64d0fc7fd18e
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 "shaderobjects.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 */
233 free_linked_program_data(GLcontext
*ctx
, struct gl_linked_program
*linked
)
235 if (linked
->VertexProgram
) {
236 if (linked
->VertexProgram
->Base
.Parameters
== linked
->Uniforms
) {
237 /* to prevent a double-free in the next call */
238 linked
->VertexProgram
->Base
.Parameters
= NULL
;
240 _mesa_delete_program(ctx
, &linked
->VertexProgram
->Base
);
241 linked
->VertexProgram
= NULL
;
244 if (linked
->FragmentProgram
) {
245 if (linked
->FragmentProgram
->Base
.Parameters
== linked
->Uniforms
) {
246 /* to prevent a double-free in the next call */
247 linked
->FragmentProgram
->Base
.Parameters
= NULL
;
249 _mesa_delete_program(ctx
, &linked
->FragmentProgram
->Base
);
250 linked
->FragmentProgram
= NULL
;
254 if (linked
->Uniforms
) {
255 _mesa_free_parameter_list(linked
->Uniforms
);
256 linked
->Uniforms
= NULL
;
259 if (linked
->Varying
) {
260 _mesa_free_parameter_list(linked
->Varying
);
261 linked
->Varying
= NULL
;
267 * Shader linker. Currently:
269 * 1. The last attached vertex shader and fragment shader are linked.
270 * 2. Varying vars in the two shaders are combined so their locations
271 * agree between the vertex and fragment stages. They're treated as
272 * vertex program output attribs and as fragment program input attribs.
273 * 3. Uniform vars (including state references, constants, etc) from the
274 * vertex and fragment shaders are merged into one group. Recall that
275 * GLSL uniforms are shared by all linked shaders.
276 * 4. The vertex and fragment programs are cloned and modified to update
277 * src/dst register references so they use the new, linked uniform/
278 * varying storage locations.
281 _slang_link2(GLcontext
*ctx
,
282 GLhandleARB programObj
,
283 struct gl_linked_program
*linked
)
285 struct gl_vertex_program
*vertProg
;
286 struct gl_fragment_program
*fragProg
;
289 free_linked_program_data(ctx
, linked
);
291 linked
->Uniforms
= _mesa_new_parameter_list();
292 linked
->Varying
= _mesa_new_parameter_list();
295 * Find attached vertex shader, fragment shader
299 for (i
= 0; i
< linked
->NumShaders
; i
++) {
300 if (linked
->Shaders
[i
]->Target
== GL_VERTEX_PROGRAM_ARB
)
301 vertProg
= (struct gl_vertex_program
*) linked
->Shaders
[i
];
302 else if (linked
->Shaders
[i
]->Target
== GL_FRAGMENT_PROGRAM_ARB
)
303 fragProg
= (struct gl_fragment_program
*) linked
->Shaders
[i
];
305 _mesa_problem(ctx
, "unexpected shader target in slang_link2()");
307 if (!vertProg
|| !fragProg
) {
308 /* XXX is it legal to have one but not the other?? */
309 /* XXX record error */
310 linked
->LinkStatus
= GL_FALSE
;
315 * Make copies of the vertex/fragment programs now since we'll be
316 * changing src/dst registers after merging the uniforms and varying vars.
318 linked
->VertexProgram
= (struct gl_vertex_program
*)
319 _mesa_clone_program(ctx
, &vertProg
->Base
);
320 linked
->FragmentProgram
= (struct gl_fragment_program
*)
321 _mesa_clone_program(ctx
, &fragProg
->Base
);
324 printf("************** orig program\n");
325 _mesa_print_program(&fragProg
->Base
);
326 _mesa_print_program_parameters(ctx
, &fragProg
->Base
);
329 link_varying_vars(linked
, &linked
->VertexProgram
->Base
);
330 link_varying_vars(linked
, &linked
->FragmentProgram
->Base
);
332 link_uniform_vars(linked
, &linked
->VertexProgram
->Base
);
333 link_uniform_vars(linked
, &linked
->FragmentProgram
->Base
);
335 /* The vertex and fragment programs share a common set of uniforms now */
336 _mesa_free_parameter_list(linked
->VertexProgram
->Base
.Parameters
);
337 _mesa_free_parameter_list(linked
->FragmentProgram
->Base
.Parameters
);
338 linked
->VertexProgram
->Base
.Parameters
= linked
->Uniforms
;
339 linked
->FragmentProgram
->Base
.Parameters
= linked
->Uniforms
;
342 printf("************** linked/cloned\n");
343 _mesa_print_program(&linked
->FragmentProgram
->Base
);
344 _mesa_print_program_parameters(ctx
, &linked
->FragmentProgram
->Base
);
347 linked
->LinkStatus
= (linked
->VertexProgram
&& linked
->FragmentProgram
);