• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * 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 #include "main/glheader.h"
32 #include "main/macros.h"
33 #include "main/errors.h"
34 #include "util/u_memory.h"
35 #include "prog_instruction.h"
36 #include "prog_parameter.h"
37 #include "prog_statevars.h"
38 
39 
40 /**
41  * Look for a float vector in the given parameter list.  The float vector
42  * may be of length 1, 2, 3 or 4.  If swizzleOut is non-null, we'll try
43  * swizzling to find a match.
44  * \param list  the parameter list to search
45  * \param v  the float vector to search for
46  * \param vSize  number of element in v
47  * \param posOut  returns the position of the constant, if found
48  * \param swizzleOut  returns a swizzle mask describing location of the
49  *                    vector elements if found.
50  * \return GL_TRUE if found, GL_FALSE if not found
51  */
52 static GLboolean
lookup_parameter_constant(const struct gl_program_parameter_list * list,const gl_constant_value v[],GLuint vSize,GLint * posOut,GLuint * swizzleOut)53 lookup_parameter_constant(const struct gl_program_parameter_list *list,
54                           const gl_constant_value v[], GLuint vSize,
55                           GLint *posOut, GLuint *swizzleOut)
56 {
57    GLuint i;
58 
59    assert(vSize >= 1);
60    assert(vSize <= 4);
61 
62    if (!list) {
63       *posOut = -1;
64       return GL_FALSE;
65    }
66 
67    for (i = 0; i < list->NumParameters; i++) {
68       if (list->Parameters[i].Type == PROGRAM_CONSTANT) {
69          unsigned offset = list->Parameters[i].ValueOffset;
70 
71          if (!swizzleOut) {
72             /* swizzle not allowed */
73             GLuint j, match = 0;
74             for (j = 0; j < vSize; j++) {
75                if (v[j].u == list->ParameterValues[offset + j].u)
76                   match++;
77             }
78             if (match == vSize) {
79                *posOut = i;
80                return GL_TRUE;
81             }
82          }
83          else {
84             /* try matching w/ swizzle */
85              if (vSize == 1) {
86                 /* look for v[0] anywhere within float[4] value */
87                 GLuint j;
88                 for (j = 0; j < list->Parameters[i].Size; j++) {
89                    if (list->ParameterValues[offset + j].u == v[0].u) {
90                       /* found it */
91                       *posOut = i;
92                       *swizzleOut = MAKE_SWIZZLE4(j, j, j, j);
93                       return GL_TRUE;
94                    }
95                 }
96              }
97              else if (vSize <= list->Parameters[i].Size) {
98                 /* see if we can match this constant (with a swizzle) */
99                 GLuint swz[4];
100                 GLuint match = 0, j, k;
101                 for (j = 0; j < vSize; j++) {
102                    if (v[j].u == list->ParameterValues[offset + j].u) {
103                       swz[j] = j;
104                       match++;
105                    }
106                    else {
107                       for (k = 0; k < list->Parameters[i].Size; k++) {
108                          if (v[j].u == list->ParameterValues[offset + k].u) {
109                             swz[j] = k;
110                             match++;
111                             break;
112                          }
113                       }
114                    }
115                 }
116                 /* smear last value to remaining positions */
117                 for (; j < 4; j++)
118                    swz[j] = swz[j-1];
119 
120                 if (match == vSize) {
121                    *posOut = i;
122                    *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
123                    return GL_TRUE;
124                 }
125              }
126          }
127       }
128    }
129 
130    *posOut = -1;
131    return GL_FALSE;
132 }
133 
134 
135 struct gl_program_parameter_list *
_mesa_new_parameter_list(void)136 _mesa_new_parameter_list(void)
137 {
138    struct gl_program_parameter_list *list =
139       CALLOC_STRUCT(gl_program_parameter_list);
140    if (!list)
141       return NULL;
142 
143    list->UniformBytes = 0;
144    list->FirstStateVarIndex = INT_MAX;
145    list->LastStateVarIndex = 0;
146    return list;
147 }
148 
149 
150 struct gl_program_parameter_list *
_mesa_new_parameter_list_sized(unsigned size)151 _mesa_new_parameter_list_sized(unsigned size)
152 {
153    struct gl_program_parameter_list *p = _mesa_new_parameter_list();
154 
155 
156    if ((p != NULL) && (size != 0)) {
157       _mesa_reserve_parameter_storage(p, size, size);
158 
159       if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) {
160          free(p->Parameters);
161          align_free(p->ParameterValues);
162          free(p);
163          p = NULL;
164       }
165    }
166 
167    return p;
168 }
169 
170 
171 /**
172  * Free a parameter list and all its parameters
173  */
174 void
_mesa_free_parameter_list(struct gl_program_parameter_list * paramList)175 _mesa_free_parameter_list(struct gl_program_parameter_list *paramList)
176 {
177    GLuint i;
178    for (i = 0; i < paramList->NumParameters; i++) {
179       free((void *)paramList->Parameters[i].Name);
180    }
181    free(paramList->Parameters);
182    align_free(paramList->ParameterValues);
183    FREE(paramList);
184 }
185 
186 
187 /**
188  * Make sure there are enough unused parameter slots. Reallocate the list
189  * if needed.
190  *
191  * \param paramList        where to reserve parameter slots
192  * \param reserve_params   number of parameter description slots
193  * \param reserve_values   number of parameter vec4 slots
194  */
195 void
_mesa_reserve_parameter_storage(struct gl_program_parameter_list * paramList,unsigned reserve_params,unsigned reserve_values)196 _mesa_reserve_parameter_storage(struct gl_program_parameter_list *paramList,
197                                 unsigned reserve_params,
198                                 unsigned reserve_values)
199 {
200    const GLuint oldNum = paramList->NumParameters;
201    const unsigned oldValNum = paramList->NumParameterValues;
202    const unsigned needSizeValues = oldValNum + reserve_values * 4;
203 
204    if (paramList->DisallowRealloc &&
205        (oldNum + reserve_params > paramList->Size ||
206         needSizeValues > paramList->SizeValues)) {
207       _mesa_problem(NULL, "Parameter storage reallocation disallowed.\n"
208                           "This is a Mesa bug.\n"
209                           "Increase the reservation size in the code (wanted bytes %u, have %u || wanted values %u have %u).",
210                           oldNum + reserve_params, paramList->Size, needSizeValues, paramList->SizeValues);
211       abort();
212    }
213 
214    if (oldNum + reserve_params > paramList->Size) {
215       /* Need to grow the parameter list array (alloc some extra) */
216       paramList->Size += 4 * reserve_params;
217 
218       /* realloc arrays */
219       paramList->Parameters =
220          realloc(paramList->Parameters,
221                  paramList->Size * sizeof(struct gl_program_parameter));
222    }
223 
224    if (needSizeValues > paramList->SizeValues) {
225       unsigned oldSize = paramList->SizeValues;
226       paramList->SizeValues = needSizeValues + 16; /* alloc some extra */
227 
228       paramList->ParameterValues = (gl_constant_value *)
229          align_realloc(paramList->ParameterValues,         /* old buf */
230                        oldValNum * sizeof(gl_constant_value),/* old sz */
231                        /* Overallocate the size by 12 because matrix rows can
232                         * be allocated partially but fetch_state always writes
233                         * 4 components (16 bytes).
234                         */
235                        paramList->SizeValues * sizeof(gl_constant_value) +
236                        12, 16);
237       /* The values are written to the shader cache, so clear them. */
238       memset(paramList->ParameterValues + oldSize, 0,
239              (paramList->SizeValues - oldSize) * sizeof(gl_constant_value));
240    }
241 }
242 
243 
244 /**
245  * Disallow reallocating the parameter storage, so that uniform storage
246  * can have pointers pointing to it.
247  */
248 void
_mesa_disallow_parameter_storage_realloc(struct gl_program_parameter_list * paramList)249 _mesa_disallow_parameter_storage_realloc(struct gl_program_parameter_list *paramList)
250 {
251    paramList->DisallowRealloc = true;
252 }
253 
254 
255 /**
256  * Add a new parameter to a parameter list.
257  * Note that parameter values are usually 4-element GLfloat vectors.
258  * When size > 4 we'll allocate a sequential block of parameters to
259  * store all the values (in blocks of 4).
260  *
261  * \param paramList  the list to add the parameter to
262  * \param type  type of parameter, such as
263  * \param name  the parameter name, will be duplicated/copied!
264  * \param size  number of elements in 'values' vector (1..4, or more)
265  * \param datatype  GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE.
266  * \param values  initial parameter value, up to 4 gl_constant_values, or NULL
267  * \param state  state indexes, or NULL
268  * \return  index of new parameter in the list, or -1 if error (out of mem)
269  */
270 GLint
_mesa_add_parameter(struct gl_program_parameter_list * paramList,gl_register_file type,const char * name,GLuint size,GLenum datatype,const gl_constant_value * values,const gl_state_index16 state[STATE_LENGTH],bool pad_and_align)271 _mesa_add_parameter(struct gl_program_parameter_list *paramList,
272                     gl_register_file type, const char *name,
273                     GLuint size, GLenum datatype,
274                     const gl_constant_value *values,
275                     const gl_state_index16 state[STATE_LENGTH],
276                     bool pad_and_align)
277 {
278    assert(0 < size);
279    const int oldNum = paramList->NumParameters;
280    unsigned oldValNum = paramList->NumParameterValues;
281    const unsigned padded_size = pad_and_align ? align(size, 4) : size;
282 
283    if (pad_and_align)
284       oldValNum = align(oldValNum, 4); /* pad start to a vec4 boundary */
285    else if (_mesa_gl_datatype_is_64bit(datatype))
286       oldValNum = align(oldValNum, 2); /* pad start to 64-bit */
287 
288    unsigned elements = (oldValNum - paramList->NumParameterValues) + padded_size;
289    _mesa_reserve_parameter_storage(paramList, 1, DIV_ROUND_UP(elements, 4));
290 
291    if (!paramList->Parameters ||
292        !paramList->ParameterValues) {
293       /* out of memory */
294       paramList->NumParameters = 0;
295       paramList->Size = 0;
296       paramList->SizeValues = 0;
297       return -1;
298    }
299 
300    paramList->NumParameters = oldNum + 1;
301 
302    paramList->NumParameterValues = oldValNum + padded_size;
303 
304    memset(&paramList->Parameters[oldNum], 0,
305           sizeof(struct gl_program_parameter));
306 
307    struct gl_program_parameter *p = paramList->Parameters + oldNum;
308    p->Name = strdup(name ? name : "");
309    p->Type = type;
310    p->Size = size;
311    p->Padded = pad_and_align;
312    p->DataType = datatype;
313 
314    paramList->Parameters[oldNum].ValueOffset = oldValNum;
315    if (values) {
316       if (size >= 4) {
317          memcpy(paramList->ParameterValues + oldValNum, values,
318                 size * sizeof(values[0]));
319       } else {
320          /* copy 1, 2 or 3 values */
321          assert(size < 4);
322          unsigned j;
323          for (j = 0; j < size; j++) {
324             paramList->ParameterValues[oldValNum + j].f = values[j].f;
325          }
326 
327          /* Zero out padding (if any) to avoid valgrind errors */
328          for (; j < padded_size; j++) {
329             paramList->ParameterValues[oldValNum + j].f = 0;
330          }
331       }
332    } else {
333       for (unsigned j = 0; j < padded_size; j++) {
334          paramList->ParameterValues[oldValNum + j].f = 0;
335       }
336    }
337 
338    if (state) {
339       for (unsigned i = 0; i < STATE_LENGTH; i++)
340          paramList->Parameters[oldNum].StateIndexes[i] = state[i];
341    } else {
342       paramList->Parameters[oldNum].StateIndexes[0] = STATE_NOT_STATE_VAR;
343    }
344 
345    if (type == PROGRAM_UNIFORM || type == PROGRAM_CONSTANT) {
346       paramList->UniformBytes =
347          MAX2(paramList->UniformBytes,
348               (paramList->Parameters[oldNum].ValueOffset +
349                paramList->Parameters[oldNum].Size) * 4);
350    } else if (type == PROGRAM_STATE_VAR) {
351       paramList->FirstStateVarIndex =
352          MIN2(paramList->FirstStateVarIndex, oldNum);
353       paramList->LastStateVarIndex =
354          MAX2(paramList->LastStateVarIndex, oldNum);
355    } else {
356       unreachable("invalid parameter type");
357    }
358 
359    assert(paramList->NumParameters <= paramList->Size);
360    assert(paramList->NumParameterValues <= paramList->SizeValues);
361 
362    return (GLint) oldNum;
363 }
364 
365 
366 /**
367  * Add a new unnamed constant to the parameter list.  This will be used
368  * when a fragment/vertex program contains something like this:
369  *    MOV r, { 0, 1, 2, 3 };
370  * If swizzleOut is non-null we'll search the parameter list for an
371  * existing instance of the constant which matches with a swizzle.
372  *
373  * \param paramList  the parameter list
374  * \param values  four float values
375  * \param swizzleOut  returns swizzle mask for accessing the constant
376  * \return index/position of the new parameter in the parameter list.
377  */
378 GLint
_mesa_add_typed_unnamed_constant(struct gl_program_parameter_list * paramList,const gl_constant_value * values,GLuint size,GLenum datatype,GLuint * swizzleOut)379 _mesa_add_typed_unnamed_constant(struct gl_program_parameter_list *paramList,
380                            const gl_constant_value *values, GLuint size,
381                            GLenum datatype, GLuint *swizzleOut)
382 {
383    GLint pos;
384    assert(size >= 1);
385    assert(size <= 4);
386 
387    if (swizzleOut &&
388        lookup_parameter_constant(paramList, values, size, &pos, swizzleOut)) {
389       return pos;
390    }
391 
392    /* Look for empty space in an already unnamed constant parameter
393     * to add this constant.  This will only work for single-element
394     * constants because we rely on smearing (i.e. .yyyy or .zzzz).
395     */
396    if (size == 1 && swizzleOut) {
397       for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) {
398          struct gl_program_parameter *p = paramList->Parameters + pos;
399          unsigned offset = paramList->Parameters[pos].ValueOffset;
400          if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) {
401             /* ok, found room */
402             gl_constant_value *pVal = paramList->ParameterValues + offset;
403             GLuint swz = p->Size; /* 1, 2 or 3 for Y, Z, W */
404             pVal[p->Size] = values[0];
405             p->Size++;
406             *swizzleOut = MAKE_SWIZZLE4(swz, swz, swz, swz);
407             return pos;
408          }
409       }
410    }
411 
412    /* add a new parameter to store this constant */
413    pos = _mesa_add_parameter(paramList, PROGRAM_CONSTANT, NULL,
414                              size, datatype, values, NULL, true);
415    if (pos >= 0 && swizzleOut) {
416       if (size == 1)
417          *swizzleOut = SWIZZLE_XXXX;
418       else
419          *swizzleOut = SWIZZLE_NOOP;
420    }
421    return pos;
422 }
423 
424 GLint
_mesa_add_sized_state_reference(struct gl_program_parameter_list * paramList,const gl_state_index16 stateTokens[STATE_LENGTH],const unsigned size,bool pad_and_align)425 _mesa_add_sized_state_reference(struct gl_program_parameter_list *paramList,
426                                 const gl_state_index16 stateTokens[STATE_LENGTH],
427                                 const unsigned size, bool pad_and_align)
428 {
429    char *name;
430    GLint index;
431 
432    /* Check if the state reference is already in the list */
433    for (index = 0; index < (GLint) paramList->NumParameters; index++) {
434       if (!memcmp(paramList->Parameters[index].StateIndexes,
435                   stateTokens,
436                   sizeof(paramList->Parameters[index].StateIndexes))) {
437          return index;
438       }
439    }
440 
441    name = _mesa_program_state_string(stateTokens);
442    index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name,
443                                size, GL_NONE, NULL, stateTokens,
444                                pad_and_align);
445    paramList->StateFlags |= _mesa_program_state_flags(stateTokens);
446 
447    /* free name string here since we duplicated it in add_parameter() */
448    free(name);
449 
450    return index;
451 }
452 
453 
454 /**
455  * Add a new state reference to the parameter list.
456  * This will be used when the program contains something like this:
457  *    PARAM ambient = state.material.front.ambient;
458  *
459  * \param paramList  the parameter list
460  * \param stateTokens  an array of STATE_LENGTH state tokens
461  * \return index of the new parameter.
462  */
463 GLint
_mesa_add_state_reference(struct gl_program_parameter_list * paramList,const gl_state_index16 stateTokens[STATE_LENGTH])464 _mesa_add_state_reference(struct gl_program_parameter_list *paramList,
465                           const gl_state_index16 stateTokens[STATE_LENGTH])
466 {
467    return _mesa_add_sized_state_reference(paramList, stateTokens, 4, true);
468 }
469 
470 void
_mesa_recompute_parameter_bounds(struct gl_program_parameter_list * list)471 _mesa_recompute_parameter_bounds(struct gl_program_parameter_list *list)
472 {
473    list->UniformBytes = 0;
474    list->FirstStateVarIndex = INT_MAX;
475    list->LastStateVarIndex = 0;
476 
477    for (int i = 0; i < (int)list->NumParameters; i++) {
478       if (list->Parameters[i].Type == PROGRAM_STATE_VAR) {
479          list->FirstStateVarIndex = MIN2(list->FirstStateVarIndex, i);
480          list->LastStateVarIndex = MAX2(list->LastStateVarIndex, i);
481       } else {
482          list->UniformBytes = MAX2(list->UniformBytes,
483                                    (list->Parameters[i].ValueOffset +
484                                     list->Parameters[i].Size) * 4);
485       }
486    }
487 }
488