Home | History | Annotate | Download | only in program
      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       if (paramList->Parameters[i].Name)
     84 	 free((void *) paramList->Parameters[i].Name);
     85    }
     86    free(paramList->Parameters);
     87    if (paramList->ParameterValues)
     88       _mesa_align_free(paramList->ParameterValues);
     89    free(paramList);
     90 }
     91 
     92 
     93 /**
     94  * Add a new parameter to a parameter list.
     95  * Note that parameter values are usually 4-element GLfloat vectors.
     96  * When size > 4 we'll allocate a sequential block of parameters to
     97  * store all the values (in blocks of 4).
     98  *
     99  * \param paramList  the list to add the parameter to
    100  * \param type  type of parameter, such as
    101  * \param name  the parameter name, will be duplicated/copied!
    102  * \param size  number of elements in 'values' vector (1..4, or more)
    103  * \param datatype  GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE.
    104  * \param values  initial parameter value, up to 4 gl_constant_values, or NULL
    105  * \param state  state indexes, or NULL
    106  * \return  index of new parameter in the list, or -1 if error (out of mem)
    107  */
    108 GLint
    109 _mesa_add_parameter(struct gl_program_parameter_list *paramList,
    110                     gl_register_file type, const char *name,
    111                     GLuint size, GLenum datatype,
    112                     const gl_constant_value *values,
    113                     const gl_state_index state[STATE_LENGTH],
    114                     GLbitfield flags)
    115 {
    116    const GLuint oldNum = paramList->NumParameters;
    117    const GLuint sz4 = (size + 3) / 4; /* no. of new param slots needed */
    118 
    119    assert(size > 0);
    120 
    121    if (oldNum + sz4 > paramList->Size) {
    122       /* Need to grow the parameter list array (alloc some extra) */
    123       paramList->Size = paramList->Size + 4 * sz4;
    124 
    125       /* realloc arrays */
    126       paramList->Parameters = (struct gl_program_parameter *)
    127 	 _mesa_realloc(paramList->Parameters,
    128 		       oldNum * sizeof(struct gl_program_parameter),
    129 		       paramList->Size * sizeof(struct gl_program_parameter));
    130 
    131       paramList->ParameterValues = (gl_constant_value (*)[4])
    132          _mesa_align_realloc(paramList->ParameterValues,         /* old buf */
    133                              oldNum * 4 * sizeof(gl_constant_value),/* old sz */
    134                              paramList->Size*4*sizeof(gl_constant_value),/*new*/
    135                              16);
    136    }
    137 
    138    if (!paramList->Parameters ||
    139        !paramList->ParameterValues) {
    140       /* out of memory */
    141       paramList->NumParameters = 0;
    142       paramList->Size = 0;
    143       return -1;
    144    }
    145    else {
    146       GLuint i, j;
    147 
    148       paramList->NumParameters = oldNum + sz4;
    149 
    150       memset(&paramList->Parameters[oldNum], 0,
    151              sz4 * sizeof(struct gl_program_parameter));
    152 
    153       for (i = 0; i < sz4; i++) {
    154          struct gl_program_parameter *p = paramList->Parameters + oldNum + i;
    155          p->Name = name ? _mesa_strdup(name) : NULL;
    156          p->Type = type;
    157          p->Size = size;
    158          p->DataType = datatype;
    159          p->Flags = flags;
    160          if (values) {
    161             COPY_4V(paramList->ParameterValues[oldNum + i], values);
    162             values += 4;
    163             p->Initialized = GL_TRUE;
    164          }
    165          else {
    166             /* silence valgrind */
    167             for (j = 0; j < 4; j++)
    168             	paramList->ParameterValues[oldNum + i][j].f = 0;
    169          }
    170          size -= 4;
    171       }
    172 
    173       if (state) {
    174          for (i = 0; i < STATE_LENGTH; i++)
    175             paramList->Parameters[oldNum].StateIndexes[i] = state[i];
    176       }
    177 
    178       return (GLint) oldNum;
    179    }
    180 }
    181 
    182 
    183 /**
    184  * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
    185  * \return index of the new entry in the parameter list
    186  */
    187 GLint
    188 _mesa_add_named_parameter(struct gl_program_parameter_list *paramList,
    189                           const char *name, const gl_constant_value values[4])
    190 {
    191    return _mesa_add_parameter(paramList, PROGRAM_NAMED_PARAM, name,
    192                               4, GL_NONE, values, NULL, 0x0);
    193 
    194 }
    195 
    196 
    197 /**
    198  * Add a new named constant to the parameter list.
    199  * This will be used when the program contains something like this:
    200  *    PARAM myVals = { 0, 1, 2, 3 };
    201  *
    202  * \param paramList  the parameter list
    203  * \param name  the name for the constant
    204  * \param values  four float values
    205  * \return index/position of the new parameter in the parameter list
    206  */
    207 GLint
    208 _mesa_add_named_constant(struct gl_program_parameter_list *paramList,
    209                          const char *name, const gl_constant_value values[4],
    210                          GLuint size)
    211 {
    212    /* first check if this is a duplicate constant */
    213    GLint pos;
    214    for (pos = 0; pos < (GLint)paramList->NumParameters; pos++) {
    215       const gl_constant_value *pvals = paramList->ParameterValues[pos];
    216       if (pvals[0].u == values[0].u &&
    217           pvals[1].u == values[1].u &&
    218           pvals[2].u == values[2].u &&
    219           pvals[3].u == values[3].u &&
    220           strcmp(paramList->Parameters[pos].Name, name) == 0) {
    221          /* Same name and value is already in the param list - reuse it */
    222          return pos;
    223       }
    224    }
    225    /* not found, add new parameter */
    226    return _mesa_add_parameter(paramList, PROGRAM_CONSTANT, name,
    227                               size, GL_NONE, values, NULL, 0x0);
    228 }
    229 
    230 
    231 /**
    232  * Add a new unnamed constant to the parameter list.  This will be used
    233  * when a fragment/vertex program contains something like this:
    234  *    MOV r, { 0, 1, 2, 3 };
    235  * If swizzleOut is non-null we'll search the parameter list for an
    236  * existing instance of the constant which matches with a swizzle.
    237  *
    238  * \param paramList  the parameter list
    239  * \param values  four float values
    240  * \param swizzleOut  returns swizzle mask for accessing the constant
    241  * \return index/position of the new parameter in the parameter list.
    242  */
    243 GLint
    244 _mesa_add_typed_unnamed_constant(struct gl_program_parameter_list *paramList,
    245                            const gl_constant_value values[4], GLuint size,
    246                            GLenum datatype, GLuint *swizzleOut)
    247 {
    248    GLint pos;
    249    ASSERT(size >= 1);
    250    ASSERT(size <= 4);
    251 
    252    if (swizzleOut &&
    253        _mesa_lookup_parameter_constant(paramList, values,
    254                                        size, &pos, swizzleOut)) {
    255       return pos;
    256    }
    257 
    258    /* Look for empty space in an already unnamed constant parameter
    259     * to add this constant.  This will only work for single-element
    260     * constants because we rely on smearing (i.e. .yyyy or .zzzz).
    261     */
    262    if (size == 1 && swizzleOut) {
    263       for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) {
    264          struct gl_program_parameter *p = paramList->Parameters + pos;
    265          if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) {
    266             /* ok, found room */
    267             gl_constant_value *pVal = paramList->ParameterValues[pos];
    268             GLuint swz = p->Size; /* 1, 2 or 3 for Y, Z, W */
    269             pVal[p->Size] = values[0];
    270             p->Size++;
    271             *swizzleOut = MAKE_SWIZZLE4(swz, swz, swz, swz);
    272             return pos;
    273          }
    274       }
    275    }
    276 
    277    /* add a new parameter to store this constant */
    278    pos = _mesa_add_parameter(paramList, PROGRAM_CONSTANT, NULL,
    279                              size, datatype, values, NULL, 0x0);
    280    if (pos >= 0 && swizzleOut) {
    281       if (size == 1)
    282          *swizzleOut = SWIZZLE_XXXX;
    283       else
    284          *swizzleOut = SWIZZLE_NOOP;
    285    }
    286    return pos;
    287 }
    288 
    289 /**
    290  * Add a new unnamed constant to the parameter list.  This will be used
    291  * when a fragment/vertex program contains something like this:
    292  *    MOV r, { 0, 1, 2, 3 };
    293  * If swizzleOut is non-null we'll search the parameter list for an
    294  * existing instance of the constant which matches with a swizzle.
    295  *
    296  * \param paramList  the parameter list
    297  * \param values  four float values
    298  * \param swizzleOut  returns swizzle mask for accessing the constant
    299  * \return index/position of the new parameter in the parameter list.
    300  * \sa _mesa_add_typed_unnamed_constant
    301  */
    302 GLint
    303 _mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
    304                            const gl_constant_value values[4], GLuint size,
    305                            GLuint *swizzleOut)
    306 {
    307    return _mesa_add_typed_unnamed_constant(paramList, values, size, GL_NONE,
    308                                            swizzleOut);
    309 }
    310 
    311 /**
    312  * Add parameter representing a varying variable.
    313  */
    314 GLint
    315 _mesa_add_varying(struct gl_program_parameter_list *paramList,
    316                   const char *name, GLuint size, GLenum datatype,
    317                   GLbitfield flags)
    318 {
    319    GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
    320    if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_VARYING) {
    321       /* already in list */
    322       return i;
    323    }
    324    else {
    325       /*assert(size == 4);*/
    326       i = _mesa_add_parameter(paramList, PROGRAM_VARYING, name,
    327                               size, datatype, NULL, NULL, flags);
    328       return i;
    329    }
    330 }
    331 
    332 
    333 /**
    334  * Add parameter representing a vertex program attribute.
    335  * \param size  size of attribute (in floats), may be -1 if unknown
    336  * \param attrib  the attribute index, or -1 if unknown
    337  */
    338 GLint
    339 _mesa_add_attribute(struct gl_program_parameter_list *paramList,
    340                     const char *name, GLint size, GLenum datatype, GLint attrib)
    341 {
    342    GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
    343    if (i >= 0) {
    344       /* replace */
    345       if (attrib < 0)
    346          attrib = i;
    347       paramList->Parameters[i].StateIndexes[0] = attrib;
    348    }
    349    else {
    350       /* add */
    351       gl_state_index state[STATE_LENGTH];
    352       state[0] = (gl_state_index) attrib;
    353       if (size < 0)
    354          size = 4;
    355       i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name,
    356                               size, datatype, NULL, state, 0x0);
    357    }
    358    return i;
    359 }
    360 
    361 
    362 
    363 #if 0 /* not used yet */
    364 /**
    365  * Returns the number of 4-component registers needed to store a piece
    366  * of GL state.  For matrices this may be as many as 4 registers,
    367  * everything else needs
    368  * just 1 register.
    369  */
    370 static GLuint
    371 sizeof_state_reference(const GLint *stateTokens)
    372 {
    373    if (stateTokens[0] == STATE_MATRIX) {
    374       GLuint rows = stateTokens[4] - stateTokens[3] + 1;
    375       assert(rows >= 1);
    376       assert(rows <= 4);
    377       return rows;
    378    }
    379    else {
    380       return 1;
    381    }
    382 }
    383 #endif
    384 
    385 
    386 /**
    387  * Add a new state reference to the parameter list.
    388  * This will be used when the program contains something like this:
    389  *    PARAM ambient = state.material.front.ambient;
    390  *
    391  * \param paramList  the parameter list
    392  * \param stateTokens  an array of 5 (STATE_LENGTH) state tokens
    393  * \return index of the new parameter.
    394  */
    395 GLint
    396 _mesa_add_state_reference(struct gl_program_parameter_list *paramList,
    397                           const gl_state_index stateTokens[STATE_LENGTH])
    398 {
    399    const GLuint size = 4; /* XXX fix */
    400    char *name;
    401    GLint index;
    402 
    403    /* Check if the state reference is already in the list */
    404    for (index = 0; index < (GLint) paramList->NumParameters; index++) {
    405       if (!memcmp(paramList->Parameters[index].StateIndexes,
    406 		  stateTokens, STATE_LENGTH * sizeof(gl_state_index))) {
    407 	 return index;
    408       }
    409    }
    410 
    411    name = _mesa_program_state_string(stateTokens);
    412    index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name,
    413                                size, GL_NONE,
    414                                NULL, (gl_state_index *) stateTokens, 0x0);
    415    paramList->StateFlags |= _mesa_program_state_flags(stateTokens);
    416 
    417    /* free name string here since we duplicated it in add_parameter() */
    418    free(name);
    419 
    420    return index;
    421 }
    422 
    423 
    424 /**
    425  * Lookup a parameter value by name in the given parameter list.
    426  * \return pointer to the float[4] values.
    427  */
    428 gl_constant_value *
    429 _mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList,
    430                              GLsizei nameLen, const char *name)
    431 {
    432    GLint i = _mesa_lookup_parameter_index(paramList, nameLen, name);
    433    if (i < 0)
    434       return NULL;
    435    else
    436       return paramList->ParameterValues[i];
    437 }
    438 
    439 
    440 /**
    441  * Given a program parameter name, find its position in the list of parameters.
    442  * \param paramList  the parameter list to search
    443  * \param nameLen  length of name (in chars).
    444  *                 If length is negative, assume that name is null-terminated.
    445  * \param name  the name to search for
    446  * \return index of parameter in the list.
    447  */
    448 GLint
    449 _mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList,
    450                              GLsizei nameLen, const char *name)
    451 {
    452    GLint i;
    453 
    454    if (!paramList)
    455       return -1;
    456 
    457    if (nameLen == -1) {
    458       /* name is null-terminated */
    459       for (i = 0; i < (GLint) paramList->NumParameters; i++) {
    460          if (paramList->Parameters[i].Name &&
    461 	     strcmp(paramList->Parameters[i].Name, name) == 0)
    462             return i;
    463       }
    464    }
    465    else {
    466       /* name is not null-terminated, use nameLen */
    467       for (i = 0; i < (GLint) paramList->NumParameters; i++) {
    468          if (paramList->Parameters[i].Name &&
    469 	     strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
    470              && strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
    471             return i;
    472       }
    473    }
    474    return -1;
    475 }
    476 
    477 
    478 /**
    479  * Look for a float vector in the given parameter list.  The float vector
    480  * may be of length 1, 2, 3 or 4.  If swizzleOut is non-null, we'll try
    481  * swizzling to find a match.
    482  * \param list  the parameter list to search
    483  * \param v  the float vector to search for
    484  * \param vSize  number of element in v
    485  * \param posOut  returns the position of the constant, if found
    486  * \param swizzleOut  returns a swizzle mask describing location of the
    487  *                    vector elements if found.
    488  * \return GL_TRUE if found, GL_FALSE if not found
    489  */
    490 GLboolean
    491 _mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list,
    492                                 const gl_constant_value v[], GLuint vSize,
    493                                 GLint *posOut, GLuint *swizzleOut)
    494 {
    495    GLuint i;
    496 
    497    assert(vSize >= 1);
    498    assert(vSize <= 4);
    499 
    500    if (!list) {
    501       *posOut = -1;
    502       return GL_FALSE;
    503    }
    504 
    505    for (i = 0; i < list->NumParameters; i++) {
    506       if (list->Parameters[i].Type == PROGRAM_CONSTANT) {
    507          if (!swizzleOut) {
    508             /* swizzle not allowed */
    509             GLuint j, match = 0;
    510             for (j = 0; j < vSize; j++) {
    511                if (v[j].u == list->ParameterValues[i][j].u)
    512                   match++;
    513             }
    514             if (match == vSize) {
    515                *posOut = i;
    516                return GL_TRUE;
    517             }
    518          }
    519          else {
    520             /* try matching w/ swizzle */
    521              if (vSize == 1) {
    522                 /* look for v[0] anywhere within float[4] value */
    523                 GLuint j;
    524                 for (j = 0; j < list->Parameters[i].Size; j++) {
    525                    if (list->ParameterValues[i][j].u == v[0].u) {
    526                       /* found it */
    527                       *posOut = i;
    528                       *swizzleOut = MAKE_SWIZZLE4(j, j, j, j);
    529                       return GL_TRUE;
    530                    }
    531                 }
    532              }
    533              else if (vSize <= list->Parameters[i].Size) {
    534                 /* see if we can match this constant (with a swizzle) */
    535                 GLuint swz[4];
    536                 GLuint match = 0, j, k;
    537                 for (j = 0; j < vSize; j++) {
    538                    if (v[j].u == list->ParameterValues[i][j].u) {
    539                       swz[j] = j;
    540                       match++;
    541                    }
    542                    else {
    543                       for (k = 0; k < list->Parameters[i].Size; k++) {
    544                          if (v[j].u == list->ParameterValues[i][k].u) {
    545                             swz[j] = k;
    546                             match++;
    547                             break;
    548                          }
    549                       }
    550                    }
    551                 }
    552                 /* smear last value to remaining positions */
    553                 for (; j < 4; j++)
    554                    swz[j] = swz[j-1];
    555 
    556                 if (match == vSize) {
    557                    *posOut = i;
    558                    *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
    559                    return GL_TRUE;
    560                 }
    561              }
    562          }
    563       }
    564    }
    565 
    566    *posOut = -1;
    567    return GL_FALSE;
    568 }
    569 
    570 
    571 struct gl_program_parameter_list *
    572 _mesa_clone_parameter_list(const struct gl_program_parameter_list *list)
    573 {
    574    struct gl_program_parameter_list *clone;
    575    GLuint i;
    576 
    577    clone = _mesa_new_parameter_list();
    578    if (!clone)
    579       return NULL;
    580 
    581    /** Not too efficient, but correct */
    582    for (i = 0; i < list->NumParameters; i++) {
    583       struct gl_program_parameter *p = list->Parameters + i;
    584       struct gl_program_parameter *pCopy;
    585       GLuint size = MIN2(p->Size, 4);
    586       GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType,
    587                                     list->ParameterValues[i], NULL, 0x0);
    588       ASSERT(j >= 0);
    589       pCopy = clone->Parameters + j;
    590       pCopy->Flags = p->Flags;
    591       /* copy state indexes */
    592       if (p->Type == PROGRAM_STATE_VAR) {
    593          GLint k;
    594          for (k = 0; k < STATE_LENGTH; k++) {
    595             pCopy->StateIndexes[k] = p->StateIndexes[k];
    596          }
    597       }
    598       else {
    599          clone->Parameters[j].Size = p->Size;
    600       }
    601 
    602    }
    603 
    604    clone->StateFlags = list->StateFlags;
    605 
    606    return clone;
    607 }
    608 
    609 
    610 /**
    611  * Return a new parameter list which is listA + listB.
    612  */
    613 struct gl_program_parameter_list *
    614 _mesa_combine_parameter_lists(const struct gl_program_parameter_list *listA,
    615                               const struct gl_program_parameter_list *listB)
    616 {
    617    struct gl_program_parameter_list *list;
    618 
    619    if (listA) {
    620       list = _mesa_clone_parameter_list(listA);
    621       if (list && listB) {
    622          GLuint i;
    623          for (i = 0; i < listB->NumParameters; i++) {
    624             struct gl_program_parameter *param = listB->Parameters + i;
    625             _mesa_add_parameter(list, param->Type, param->Name, param->Size,
    626                                 param->DataType,
    627                                 listB->ParameterValues[i],
    628                                 param->StateIndexes,
    629                                 param->Flags);
    630          }
    631       }
    632    }
    633    else if (listB) {
    634       list = _mesa_clone_parameter_list(listB);
    635    }
    636    else {
    637       list = NULL;
    638    }
    639    return list;
    640 }
    641 
    642 
    643 /**
    644  * Count the number of parameters in the last that match the given type.
    645  */
    646 GLuint
    647 _mesa_num_parameters_of_type(const struct gl_program_parameter_list *list,
    648                              gl_register_file type)
    649 {
    650    GLuint i, count = 0;
    651    if (list) {
    652       for (i = 0; i < list->NumParameters; i++) {
    653          if (list->Parameters[i].Type == type)
    654             count++;
    655       }
    656    }
    657    return count;
    658 }
    659