blob: f634e38800b41fc0b9d2ea970d195f7ed9aca16f [file] [log] [blame]
Brian00cdc0a2006-12-14 15:01:06 -07001/*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-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 prog_parameter.c
27 * Program parameter lists and functions.
28 * \author Brian Paul
29 */
30
31
32#include "glheader.h"
33#include "imports.h"
34#include "macros.h"
35#include "mtypes.h"
36#include "program.h"
37#include "prog_instruction.h"
38#include "prog_parameter.h"
39#include "prog_statevars.h"
40
41
42struct gl_program_parameter_list *
43_mesa_new_parameter_list(void)
44{
45 return (struct gl_program_parameter_list *)
46 _mesa_calloc(sizeof(struct gl_program_parameter_list));
47}
48
49
50/**
51 * Free a parameter list and all its parameters
52 */
53void
54_mesa_free_parameter_list(struct gl_program_parameter_list *paramList)
55{
56 GLuint i;
57 for (i = 0; i < paramList->NumParameters; i++) {
58 if (paramList->Parameters[i].Name)
59 _mesa_free((void *) paramList->Parameters[i].Name);
60 }
61 _mesa_free(paramList->Parameters);
62 if (paramList->ParameterValues)
63 _mesa_align_free(paramList->ParameterValues);
64 _mesa_free(paramList);
65}
66
67
68
69/**
70 * Add a new parameter to a parameter list.
71 * \param paramList the list to add the parameter to
72 * \param name the parameter name, will be duplicated/copied!
73 * \param values initial parameter value, up to 4 GLfloats
74 * \param size number of elements in 'values' vector (1..4)
75 * \param type type of parameter, such as
76 * \return index of new parameter in the list, or -1 if error (out of mem)
77 */
78GLint
79_mesa_add_parameter(struct gl_program_parameter_list *paramList,
80 const char *name, const GLfloat values[4], GLuint size,
81 enum register_file type)
82{
83 const GLuint n = paramList->NumParameters;
84
85 if (n == paramList->Size) {
86 /* Need to grow the parameter list array */
87 if (paramList->Size == 0)
88 paramList->Size = 8;
89 else
90 paramList->Size *= 2;
91
92 /* realloc arrays */
93 paramList->Parameters = (struct gl_program_parameter *)
94 _mesa_realloc(paramList->Parameters,
95 n * sizeof(struct gl_program_parameter),
96 paramList->Size * sizeof(struct gl_program_parameter));
97
98 paramList->ParameterValues = (GLfloat (*)[4])
99 _mesa_align_realloc(paramList->ParameterValues, /* old buf */
100 n * 4 * sizeof(GLfloat), /* old size */
101 paramList->Size * 4 *sizeof(GLfloat), /* new sz */
102 16);
103 }
104
105 if (!paramList->Parameters ||
106 !paramList->ParameterValues) {
107 /* out of memory */
108 paramList->NumParameters = 0;
109 paramList->Size = 0;
110 return -1;
111 }
112 else {
113 paramList->NumParameters = n + 1;
114
115 _mesa_memset(&paramList->Parameters[n], 0,
116 sizeof(struct gl_program_parameter));
117
118 paramList->Parameters[n].Name = name ? _mesa_strdup(name) : NULL;
119 paramList->Parameters[n].Type = type;
120 paramList->Parameters[n].Size = size;
121 if (values)
122 COPY_4V(paramList->ParameterValues[n], values);
123 return (GLint) n;
124 }
125}
126
127
128/**
129 * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
130 * \return index of the new entry in the parameter list
131 */
132GLint
133_mesa_add_named_parameter(struct gl_program_parameter_list *paramList,
134 const char *name, const GLfloat values[4])
135{
136 return _mesa_add_parameter(paramList, name, values, 4, PROGRAM_NAMED_PARAM);
137}
138
139
140/**
141 * Add a new named constant to the parameter list.
142 * This will be used when the program contains something like this:
143 * PARAM myVals = { 0, 1, 2, 3 };
144 *
145 * \param paramList the parameter list
146 * \param name the name for the constant
147 * \param values four float values
148 * \return index/position of the new parameter in the parameter list
149 */
150GLint
151_mesa_add_named_constant(struct gl_program_parameter_list *paramList,
152 const char *name, const GLfloat values[4],
153 GLuint size)
154{
155#if 0 /* disable this for now -- we need to save the name! */
156 GLint pos;
157 GLuint swizzle;
158 ASSERT(size == 4); /* XXX future feature */
159 /* check if we already have this constant */
160 if (_mesa_lookup_parameter_constant(paramList, values, 4, &pos, &swizzle)) {
161 return pos;
162 }
163#endif
164 size = 4; /** XXX fix */
165 return _mesa_add_parameter(paramList, name, values, size, PROGRAM_CONSTANT);
166}
167
168
169/**
170 * Add a new unnamed constant to the parameter list.
171 * This will be used when the program contains something like this:
172 * MOV r, { 0, 1, 2, 3 };
173 *
174 * \param paramList the parameter list
175 * \param values four float values
176 * \param swizzleOut returns swizzle mask for accessing the constant
177 * \return index/position of the new parameter in the parameter list.
178 */
179GLint
180_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
181 const GLfloat values[4], GLuint size,
182 GLuint *swizzleOut)
183{
184 GLint pos;
185 GLuint swizzle;
186 ASSERT(size >= 1);
187 ASSERT(size <= 4);
188 size = 4; /* XXX temporary */
189 /* check if we already have this constant */
190 if (_mesa_lookup_parameter_constant(paramList, values,
191 size, &pos, &swizzle)) {
192 return pos;
193 }
194 return _mesa_add_parameter(paramList, NULL, values, size, PROGRAM_CONSTANT);
195}
196
197
198GLint
199_mesa_add_uniform(struct gl_program_parameter_list *paramList,
200 const char *name, GLuint size)
201{
202 GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
203 if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_UNIFORM) {
204 /* already in list */
205 return i;
206 }
207 else {
208 assert(size == 4);
209 i = _mesa_add_parameter(paramList, name, NULL, size, PROGRAM_UNIFORM);
210 return i;
211 }
212}
213
214
215GLint
216_mesa_add_varying(struct gl_program_parameter_list *paramList,
217 const char *name, GLuint size)
218{
219 GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
220 if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_VARYING) {
221 /* already in list */
222 return i;
223 }
224 else {
225 assert(size == 4);
226 i = _mesa_add_parameter(paramList, name, NULL, size, PROGRAM_VARYING);
227 return i;
228 }
229}
230
231
232
233
234#if 0 /* not used yet */
235/**
236 * Returns the number of 4-component registers needed to store a piece
237 * of GL state. For matrices this may be as many as 4 registers,
238 * everything else needs
239 * just 1 register.
240 */
241static GLuint
242sizeof_state_reference(const GLint *stateTokens)
243{
244 if (stateTokens[0] == STATE_MATRIX) {
245 GLuint rows = stateTokens[4] - stateTokens[3] + 1;
246 assert(rows >= 1);
247 assert(rows <= 4);
248 return rows;
249 }
250 else {
251 return 1;
252 }
253}
254#endif
255
256
257/**
258 * Add a new state reference to the parameter list.
259 * This will be used when the program contains something like this:
260 * PARAM ambient = state.material.front.ambient;
261 *
262 * \param paramList the parameter list
263 * \param state an array of 6 state tokens
264 * \return index of the new parameter.
265 */
266GLint
267_mesa_add_state_reference(struct gl_program_parameter_list *paramList,
268 const GLint *stateTokens)
269{
270 const GLuint size = 4; /* XXX fix */
271 const char *name;
272 GLint index;
273
274 /* Check if the state reference is already in the list */
275 for (index = 0; index < paramList->NumParameters; index++) {
276 GLuint i, match = 0;
277 for (i = 0; i < 6; i++) {
278 if (paramList->Parameters[index].StateIndexes[i] == stateTokens[i]) {
279 match++;
280 }
281 else {
282 break;
283 }
284 }
285 if (match == 6) {
286 /* this state reference is already in the parameter list */
287 return index;
288 }
289 }
290
291 name = _mesa_program_state_string(stateTokens);
292 index = _mesa_add_parameter(paramList, name, NULL, size, PROGRAM_STATE_VAR);
293 if (index >= 0) {
294 GLuint i;
295 for (i = 0; i < 6; i++) {
296 paramList->Parameters[index].StateIndexes[i]
297 = (gl_state_index) stateTokens[i];
298 }
299 paramList->StateFlags |= _mesa_program_state_flags(stateTokens);
300 }
301
302 /* free name string here since we duplicated it in add_parameter() */
303 _mesa_free((void *) name);
304
305 return index;
306}
307
308
309/**
310 * Lookup a parameter value by name in the given parameter list.
311 * \return pointer to the float[4] values.
312 */
313GLfloat *
314_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList,
315 GLsizei nameLen, const char *name)
316{
317 GLuint i = _mesa_lookup_parameter_index(paramList, nameLen, name);
318 if (i < 0)
319 return NULL;
320 else
321 return paramList->ParameterValues[i];
322}
323
324
325/**
326 * Given a program parameter name, find its position in the list of parameters.
327 * \param paramList the parameter list to search
328 * \param nameLen length of name (in chars).
329 * If length is negative, assume that name is null-terminated.
330 * \param name the name to search for
331 * \return index of parameter in the list.
332 */
333GLint
334_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList,
335 GLsizei nameLen, const char *name)
336{
337 GLint i;
338
339 if (!paramList)
340 return -1;
341
342 if (nameLen == -1) {
343 /* name is null-terminated */
344 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
345 if (paramList->Parameters[i].Name &&
346 _mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
347 return i;
348 }
349 }
350 else {
351 /* name is not null-terminated, use nameLen */
352 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
353 if (paramList->Parameters[i].Name &&
354 _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
355 && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
356 return i;
357 }
358 }
359 return -1;
360}
361
362
363/**
364 * Look for a float vector in the given parameter list. The float vector
365 * may be of length 1, 2, 3 or 4.
366 * \param paramList the parameter list to search
367 * \param v the float vector to search for
368 * \param size number of element in v
369 * \param posOut returns the position of the constant, if found
370 * \param swizzleOut returns a swizzle mask describing location of the
371 * vector elements if found
372 * \return GL_TRUE if found, GL_FALSE if not found
373 */
374GLboolean
375_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *paramList,
376 const GLfloat v[], GLsizei vSize,
377 GLint *posOut, GLuint *swizzleOut)
378{
379 GLuint i;
380
381 assert(vSize >= 1);
382 assert(vSize <= 4);
383
384 if (!paramList)
385 return -1;
386
387 for (i = 0; i < paramList->NumParameters; i++) {
388 if (paramList->Parameters[i].Type == PROGRAM_CONSTANT) {
389 const GLint maxShift = 4 - vSize;
390 GLint shift, j;
391 for (shift = 0; shift <= maxShift; shift++) {
392 GLint matched = 0;
393 GLuint swizzle[4];
394 swizzle[0] = swizzle[1] = swizzle[2] = swizzle[3] = 0;
395 /* XXX we could do out-of-order swizzle matches too, someday */
396 for (j = 0; j < vSize; j++) {
397 assert(shift + j < 4);
398 if (paramList->ParameterValues[i][shift + j] == v[j]) {
399 matched++;
400 swizzle[j] = shift + j;
401 ASSERT(swizzle[j] >= SWIZZLE_X);
402 ASSERT(swizzle[j] <= SWIZZLE_W);
403 }
404 }
405 if (matched == vSize) {
406 /* found! */
407 *posOut = i;
408 *swizzleOut = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
409 swizzle[2], swizzle[3]);
410 return GL_TRUE;
411 }
412 }
413 }
414 }
415
416 *posOut = -1;
417 return GL_FALSE;
418}
419
420
421struct gl_program_parameter_list *
422_mesa_clone_parameter_list(const struct gl_program_parameter_list *list)
423{
424 struct gl_program_parameter_list *clone;
425 GLuint i;
426
427 clone = _mesa_new_parameter_list();
428 if (!clone)
429 return NULL;
430
431 /** Not too efficient, but correct */
432 for (i = 0; i < list->NumParameters; i++) {
433 struct gl_program_parameter *p = list->Parameters + i;
434 GLint j = _mesa_add_parameter(clone, p->Name, list->ParameterValues[i],
435 p->Size, p->Type);
436 ASSERT(j >= 0);
437 /* copy state indexes */
438 if (p->Type == PROGRAM_STATE_VAR) {
439 GLint k;
440 struct gl_program_parameter *q = clone->Parameters + j;
441 for (k = 0; k < 6; k++) {
442 q->StateIndexes[k] = p->StateIndexes[k];
443 }
444 }
445 }
446
447 return clone;
448}