OSDN Git Service

mesa: Remove dead _mesa_num_parameters_of_type() function.
[android-x86/external-mesa.git] / src / mesa / program / prog_parameter.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.3
4  *
5  * Copyright (C) 1999-2008  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 "main/glheader.h"
33 #include "main/imports.h"
34 #include "main/macros.h"
35 #include "prog_instruction.h"
36 #include "prog_parameter.h"
37 #include "prog_statevars.h"
38
39
40 struct gl_program_parameter_list *
41 _mesa_new_parameter_list(void)
42 {
43    return CALLOC_STRUCT(gl_program_parameter_list);
44 }
45
46
47 struct gl_program_parameter_list *
48 _mesa_new_parameter_list_sized(unsigned size)
49 {
50    struct gl_program_parameter_list *p = _mesa_new_parameter_list();
51
52    if ((p != NULL) && (size != 0)) {
53       p->Size = size;
54
55       /* alloc arrays */
56       p->Parameters = (struct gl_program_parameter *)
57          calloc(1, size * sizeof(struct gl_program_parameter));
58
59       p->ParameterValues = (gl_constant_value (*)[4])
60          _mesa_align_malloc(size * 4 *sizeof(gl_constant_value), 16);
61
62
63       if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) {
64          free(p->Parameters);
65          _mesa_align_free(p->ParameterValues);
66          free(p);
67          p = NULL;
68       }
69    }
70
71    return p;
72 }
73
74
75 /**
76  * Free a parameter list and all its parameters
77  */
78 void
79 _mesa_free_parameter_list(struct gl_program_parameter_list *paramList)
80 {
81    GLuint i;
82    for (i = 0; i < paramList->NumParameters; i++) {
83       free((void *)paramList->Parameters[i].Name);
84    }
85    free(paramList->Parameters);
86    if (paramList->ParameterValues)
87       _mesa_align_free(paramList->ParameterValues);
88    free(paramList);
89 }
90
91
92 /**
93  * Add a new parameter to a parameter list.
94  * Note that parameter values are usually 4-element GLfloat vectors.
95  * When size > 4 we'll allocate a sequential block of parameters to
96  * store all the values (in blocks of 4).
97  *
98  * \param paramList  the list to add the parameter to
99  * \param type  type of parameter, such as 
100  * \param name  the parameter name, will be duplicated/copied!
101  * \param size  number of elements in 'values' vector (1..4, or more)
102  * \param datatype  GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE.
103  * \param values  initial parameter value, up to 4 gl_constant_values, or NULL
104  * \param state  state indexes, or NULL
105  * \return  index of new parameter in the list, or -1 if error (out of mem)
106  */
107 GLint
108 _mesa_add_parameter(struct gl_program_parameter_list *paramList,
109                     gl_register_file type, const char *name,
110                     GLuint size, GLenum datatype,
111                     const gl_constant_value *values,
112                     const gl_state_index state[STATE_LENGTH])
113 {
114    const GLuint oldNum = paramList->NumParameters;
115    const GLuint sz4 = (size + 3) / 4; /* no. of new param slots needed */
116
117    assert(size > 0);
118
119    if (oldNum + sz4 > paramList->Size) {
120       /* Need to grow the parameter list array (alloc some extra) */
121       paramList->Size = paramList->Size + 4 * sz4;
122
123       /* realloc arrays */
124       paramList->Parameters = (struct gl_program_parameter *)
125          _mesa_realloc(paramList->Parameters,
126                        oldNum * sizeof(struct gl_program_parameter),
127                        paramList->Size * sizeof(struct gl_program_parameter));
128
129       paramList->ParameterValues = (gl_constant_value (*)[4])
130          _mesa_align_realloc(paramList->ParameterValues,         /* old buf */
131                              oldNum * 4 * sizeof(gl_constant_value),/* old sz */
132                              paramList->Size*4*sizeof(gl_constant_value),/*new*/
133                              16);
134    }
135
136    if (!paramList->Parameters ||
137        !paramList->ParameterValues) {
138       /* out of memory */
139       paramList->NumParameters = 0;
140       paramList->Size = 0;
141       return -1;
142    }
143    else {
144       GLuint i, j;
145
146       paramList->NumParameters = oldNum + sz4;
147
148       memset(&paramList->Parameters[oldNum], 0,
149              sz4 * sizeof(struct gl_program_parameter));
150
151       for (i = 0; i < sz4; i++) {
152          struct gl_program_parameter *p = paramList->Parameters + oldNum + i;
153          p->Name = name ? _mesa_strdup(name) : NULL;
154          p->Type = type;
155          p->Size = size;
156          p->DataType = datatype;
157          if (values) {
158             COPY_4V(paramList->ParameterValues[oldNum + i], values);
159             values += 4;
160             p->Initialized = GL_TRUE;
161          }
162          else {
163             /* silence valgrind */
164             for (j = 0; j < 4; j++)
165                 paramList->ParameterValues[oldNum + i][j].f = 0;
166          }
167          size -= 4;
168       }
169
170       if (state) {
171          for (i = 0; i < STATE_LENGTH; i++)
172             paramList->Parameters[oldNum].StateIndexes[i] = state[i];
173       }
174
175       return (GLint) oldNum;
176    }
177 }
178
179
180 /**
181  * Add a new named constant to the parameter list.
182  * This will be used when the program contains something like this:
183  *    PARAM myVals = { 0, 1, 2, 3 };
184  *
185  * \param paramList  the parameter list
186  * \param name  the name for the constant
187  * \param values  four float values
188  * \return index/position of the new parameter in the parameter list
189  */
190 GLint
191 _mesa_add_named_constant(struct gl_program_parameter_list *paramList,
192                          const char *name, const gl_constant_value values[4],
193                          GLuint size)
194 {
195    /* first check if this is a duplicate constant */
196    GLint pos;
197    for (pos = 0; pos < (GLint)paramList->NumParameters; pos++) {
198       const gl_constant_value *pvals = paramList->ParameterValues[pos];
199       if (pvals[0].u == values[0].u &&
200           pvals[1].u == values[1].u &&
201           pvals[2].u == values[2].u &&
202           pvals[3].u == values[3].u &&
203           strcmp(paramList->Parameters[pos].Name, name) == 0) {
204          /* Same name and value is already in the param list - reuse it */
205          return pos;
206       }
207    }
208    /* not found, add new parameter */
209    return _mesa_add_parameter(paramList, PROGRAM_CONSTANT, name,
210                               size, GL_NONE, values, NULL);
211 }
212
213
214 /**
215  * Add a new unnamed constant to the parameter list.  This will be used
216  * when a fragment/vertex program contains something like this:
217  *    MOV r, { 0, 1, 2, 3 };
218  * If swizzleOut is non-null we'll search the parameter list for an
219  * existing instance of the constant which matches with a swizzle.
220  *
221  * \param paramList  the parameter list
222  * \param values  four float values
223  * \param swizzleOut  returns swizzle mask for accessing the constant
224  * \return index/position of the new parameter in the parameter list.
225  */
226 GLint
227 _mesa_add_typed_unnamed_constant(struct gl_program_parameter_list *paramList,
228                            const gl_constant_value values[4], GLuint size,
229                            GLenum datatype, GLuint *swizzleOut)
230 {
231    GLint pos;
232    ASSERT(size >= 1);
233    ASSERT(size <= 4);
234
235    if (swizzleOut &&
236        _mesa_lookup_parameter_constant(paramList, values,
237                                        size, &pos, swizzleOut)) {
238       return pos;
239    }
240
241    /* Look for empty space in an already unnamed constant parameter
242     * to add this constant.  This will only work for single-element
243     * constants because we rely on smearing (i.e. .yyyy or .zzzz).
244     */
245    if (size == 1 && swizzleOut) {
246       for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) {
247          struct gl_program_parameter *p = paramList->Parameters + pos;
248          if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) {
249             /* ok, found room */
250             gl_constant_value *pVal = paramList->ParameterValues[pos];
251             GLuint swz = p->Size; /* 1, 2 or 3 for Y, Z, W */
252             pVal[p->Size] = values[0];
253             p->Size++;
254             *swizzleOut = MAKE_SWIZZLE4(swz, swz, swz, swz);
255             return pos;
256          }
257       }
258    }
259
260    /* add a new parameter to store this constant */
261    pos = _mesa_add_parameter(paramList, PROGRAM_CONSTANT, NULL,
262                              size, datatype, values, NULL);
263    if (pos >= 0 && swizzleOut) {
264       if (size == 1)
265          *swizzleOut = SWIZZLE_XXXX;
266       else
267          *swizzleOut = SWIZZLE_NOOP;
268    }
269    return pos;
270 }
271
272 /**
273  * Add a new unnamed constant to the parameter list.  This will be used
274  * when a fragment/vertex program contains something like this:
275  *    MOV r, { 0, 1, 2, 3 };
276  * If swizzleOut is non-null we'll search the parameter list for an
277  * existing instance of the constant which matches with a swizzle.
278  *
279  * \param paramList  the parameter list
280  * \param values  four float values
281  * \param swizzleOut  returns swizzle mask for accessing the constant
282  * \return index/position of the new parameter in the parameter list.
283  * \sa _mesa_add_typed_unnamed_constant
284  */
285 GLint
286 _mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
287                            const gl_constant_value values[4], GLuint size,
288                            GLuint *swizzleOut)
289 {
290    return _mesa_add_typed_unnamed_constant(paramList, values, size, GL_NONE,
291                                            swizzleOut);
292 }
293
294 #if 0 /* not used yet */
295 /**
296  * Returns the number of 4-component registers needed to store a piece
297  * of GL state.  For matrices this may be as many as 4 registers,
298  * everything else needs
299  * just 1 register.
300  */
301 static GLuint
302 sizeof_state_reference(const GLint *stateTokens)
303 {
304    if (stateTokens[0] == STATE_MATRIX) {
305       GLuint rows = stateTokens[4] - stateTokens[3] + 1;
306       assert(rows >= 1);
307       assert(rows <= 4);
308       return rows;
309    }
310    else {
311       return 1;
312    }
313 }
314 #endif
315
316
317 /**
318  * Add a new state reference to the parameter list.
319  * This will be used when the program contains something like this:
320  *    PARAM ambient = state.material.front.ambient;
321  *
322  * \param paramList  the parameter list
323  * \param stateTokens  an array of 5 (STATE_LENGTH) state tokens
324  * \return index of the new parameter.
325  */
326 GLint
327 _mesa_add_state_reference(struct gl_program_parameter_list *paramList,
328                           const gl_state_index stateTokens[STATE_LENGTH])
329 {
330    const GLuint size = 4; /* XXX fix */
331    char *name;
332    GLint index;
333
334    /* Check if the state reference is already in the list */
335    for (index = 0; index < (GLint) paramList->NumParameters; index++) {
336       if (!memcmp(paramList->Parameters[index].StateIndexes,
337                   stateTokens, STATE_LENGTH * sizeof(gl_state_index))) {
338          return index;
339       }
340    }
341
342    name = _mesa_program_state_string(stateTokens);
343    index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name,
344                                size, GL_NONE,
345                                NULL, (gl_state_index *) stateTokens);
346    paramList->StateFlags |= _mesa_program_state_flags(stateTokens);
347
348    /* free name string here since we duplicated it in add_parameter() */
349    free(name);
350
351    return index;
352 }
353
354
355 /**
356  * Lookup a parameter value by name in the given parameter list.
357  * \return pointer to the float[4] values.
358  */
359 gl_constant_value *
360 _mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList,
361                              GLsizei nameLen, const char *name)
362 {
363    GLint i = _mesa_lookup_parameter_index(paramList, nameLen, name);
364    if (i < 0)
365       return NULL;
366    else
367       return paramList->ParameterValues[i];
368 }
369
370
371 /**
372  * Given a program parameter name, find its position in the list of parameters.
373  * \param paramList  the parameter list to search
374  * \param nameLen  length of name (in chars).
375  *                 If length is negative, assume that name is null-terminated.
376  * \param name  the name to search for
377  * \return index of parameter in the list.
378  */
379 GLint
380 _mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList,
381                              GLsizei nameLen, const char *name)
382 {
383    GLint i;
384
385    if (!paramList)
386       return -1;
387
388    if (nameLen == -1) {
389       /* name is null-terminated */
390       for (i = 0; i < (GLint) paramList->NumParameters; i++) {
391          if (paramList->Parameters[i].Name &&
392              strcmp(paramList->Parameters[i].Name, name) == 0)
393             return i;
394       }
395    }
396    else {
397       /* name is not null-terminated, use nameLen */
398       for (i = 0; i < (GLint) paramList->NumParameters; i++) {
399          if (paramList->Parameters[i].Name &&
400              strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
401              && strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
402             return i;
403       }
404    }
405    return -1;
406 }
407
408
409 /**
410  * Look for a float vector in the given parameter list.  The float vector
411  * may be of length 1, 2, 3 or 4.  If swizzleOut is non-null, we'll try
412  * swizzling to find a match.
413  * \param list  the parameter list to search
414  * \param v  the float vector to search for
415  * \param vSize  number of element in v
416  * \param posOut  returns the position of the constant, if found
417  * \param swizzleOut  returns a swizzle mask describing location of the
418  *                    vector elements if found.
419  * \return GL_TRUE if found, GL_FALSE if not found
420  */
421 GLboolean
422 _mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list,
423                                 const gl_constant_value v[], GLuint vSize,
424                                 GLint *posOut, GLuint *swizzleOut)
425 {
426    GLuint i;
427
428    assert(vSize >= 1);
429    assert(vSize <= 4);
430
431    if (!list) {
432       *posOut = -1;
433       return GL_FALSE;
434    }
435
436    for (i = 0; i < list->NumParameters; i++) {
437       if (list->Parameters[i].Type == PROGRAM_CONSTANT) {
438          if (!swizzleOut) {
439             /* swizzle not allowed */
440             GLuint j, match = 0;
441             for (j = 0; j < vSize; j++) {
442                if (v[j].u == list->ParameterValues[i][j].u)
443                   match++;
444             }
445             if (match == vSize) {
446                *posOut = i;
447                return GL_TRUE;
448             }
449          }
450          else {
451             /* try matching w/ swizzle */
452              if (vSize == 1) {
453                 /* look for v[0] anywhere within float[4] value */
454                 GLuint j;
455                 for (j = 0; j < list->Parameters[i].Size; j++) {
456                    if (list->ParameterValues[i][j].u == v[0].u) {
457                       /* found it */
458                       *posOut = i;
459                       *swizzleOut = MAKE_SWIZZLE4(j, j, j, j);
460                       return GL_TRUE;
461                    }
462                 }
463              }
464              else if (vSize <= list->Parameters[i].Size) {
465                 /* see if we can match this constant (with a swizzle) */
466                 GLuint swz[4];
467                 GLuint match = 0, j, k;
468                 for (j = 0; j < vSize; j++) {
469                    if (v[j].u == list->ParameterValues[i][j].u) {
470                       swz[j] = j;
471                       match++;
472                    }
473                    else {
474                       for (k = 0; k < list->Parameters[i].Size; k++) {
475                          if (v[j].u == list->ParameterValues[i][k].u) {
476                             swz[j] = k;
477                             match++;
478                             break;
479                          }
480                       }
481                    }
482                 }
483                 /* smear last value to remaining positions */
484                 for (; j < 4; j++)
485                    swz[j] = swz[j-1];
486
487                 if (match == vSize) {
488                    *posOut = i;
489                    *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
490                    return GL_TRUE;
491                 }
492              }
493          }
494       }
495    }
496
497    *posOut = -1;
498    return GL_FALSE;
499 }
500
501
502 struct gl_program_parameter_list *
503 _mesa_clone_parameter_list(const struct gl_program_parameter_list *list)
504 {
505    struct gl_program_parameter_list *clone;
506    GLuint i;
507
508    clone = _mesa_new_parameter_list();
509    if (!clone)
510       return NULL;
511
512    /** Not too efficient, but correct */
513    for (i = 0; i < list->NumParameters; i++) {
514       struct gl_program_parameter *p = list->Parameters + i;
515       struct gl_program_parameter *pCopy;
516       GLuint size = MIN2(p->Size, 4);
517       GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType,
518                                     list->ParameterValues[i], NULL);
519       ASSERT(j >= 0);
520       pCopy = clone->Parameters + j;
521       /* copy state indexes */
522       if (p->Type == PROGRAM_STATE_VAR) {
523          GLint k;
524          for (k = 0; k < STATE_LENGTH; k++) {
525             pCopy->StateIndexes[k] = p->StateIndexes[k];
526          }
527       }
528       else {
529          clone->Parameters[j].Size = p->Size;
530       }
531       
532    }
533
534    clone->StateFlags = list->StateFlags;
535
536    return clone;
537 }
538
539
540 /**
541  * Return a new parameter list which is listA + listB.
542  */
543 struct gl_program_parameter_list *
544 _mesa_combine_parameter_lists(const struct gl_program_parameter_list *listA,
545                               const struct gl_program_parameter_list *listB)
546 {
547    struct gl_program_parameter_list *list;
548
549    if (listA) {
550       list = _mesa_clone_parameter_list(listA);
551       if (list && listB) {
552          GLuint i;
553          for (i = 0; i < listB->NumParameters; i++) {
554             struct gl_program_parameter *param = listB->Parameters + i;
555             _mesa_add_parameter(list, param->Type, param->Name, param->Size,
556                                 param->DataType,
557                                 listB->ParameterValues[i],
558                                 param->StateIndexes);
559          }
560       }
561    }
562    else if (listB) {
563       list = _mesa_clone_parameter_list(listB);
564    }
565    else {
566       list = NULL;
567    }
568    return list;
569 }