~ubuntu-branches/ubuntu/precise/mesa/precise-updates

« back to all changes in this revision

Viewing changes to src/glsl/link_uniforms.cpp

  • Committer: Package Import Robot
  • Author(s): Robert Hooker
  • Date: 2012-02-02 12:05:48 UTC
  • mfrom: (1.7.1) (3.3.27 sid)
  • Revision ID: package-import@ubuntu.com-20120202120548-nvkma85jq0h4coix
Tags: 8.0~rc2-0ubuntu4
Drop drisearchdir handling, it is no longer needed with multiarch
and dri-alternates being removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2011 Intel Corporation
 
3
 *
 
4
 * Permission is hereby granted, free of charge, to any person obtaining a
 
5
 * copy of this software and associated documentation files (the "Software"),
 
6
 * to deal in the Software without restriction, including without limitation
 
7
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
8
 * and/or sell copies of the Software, and to permit persons to whom the
 
9
 * Software is furnished to do so, subject to the following conditions:
 
10
 *
 
11
 * The above copyright notice and this permission notice (including the next
 
12
 * paragraph) shall be included in all copies or substantial portions of the
 
13
 * Software.
 
14
 *
 
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
21
 * DEALINGS IN THE SOFTWARE.
 
22
 */
 
23
 
 
24
#include "main/core.h"
 
25
#include "ir.h"
 
26
#include "linker.h"
 
27
#include "ir_uniform.h"
 
28
#include "glsl_symbol_table.h"
 
29
#include "program/hash_table.h"
 
30
 
 
31
/**
 
32
 * \file link_uniforms.cpp
 
33
 * Assign locations for GLSL uniforms.
 
34
 *
 
35
 * \author Ian Romanick <ian.d.romanick@intel.com>
 
36
 */
 
37
 
 
38
/**
 
39
 * Count the backing storage requirements for a type
 
40
 */
 
41
static unsigned
 
42
values_for_type(const glsl_type *type)
 
43
{
 
44
   if (type->is_sampler()) {
 
45
      return 1;
 
46
   } else if (type->is_array() && type->fields.array->is_sampler()) {
 
47
      return type->array_size();
 
48
   } else {
 
49
      return type->component_slots();
 
50
   }
 
51
}
 
52
 
 
53
void
 
54
uniform_field_visitor::process(ir_variable *var)
 
55
{
 
56
   const glsl_type *t = var->type;
 
57
 
 
58
   /* Only strdup the name if we actually will need to modify it. */
 
59
   if (t->is_record() || (t->is_array() && t->fields.array->is_record())) {
 
60
      char *name = ralloc_strdup(NULL, var->name);
 
61
      recursion(var->type, &name, strlen(name));
 
62
      ralloc_free(name);
 
63
   } else {
 
64
      this->visit_field(t, var->name);
 
65
   }
 
66
}
 
67
 
 
68
void
 
69
uniform_field_visitor::recursion(const glsl_type *t, char **name,
 
70
                                 unsigned name_length)
 
71
{
 
72
   /* Records need to have each field processed individually.
 
73
    *
 
74
    * Arrays of records need to have each array element processed
 
75
    * individually, then each field of the resulting array elements processed
 
76
    * individually.
 
77
    */
 
78
   if (t->is_record()) {
 
79
      for (unsigned i = 0; i < t->length; i++) {
 
80
         const char *field = t->fields.structure[i].name;
 
81
 
 
82
         /* Append '.field' to the current uniform name. */
 
83
         ralloc_asprintf_rewrite_tail(name, name_length, ".%s", field);
 
84
 
 
85
         recursion(t->fields.structure[i].type, name,
 
86
                   name_length + 1 + strlen(field));
 
87
      }
 
88
   } else if (t->is_array() && t->fields.array->is_record()) {
 
89
      for (unsigned i = 0; i < t->length; i++) {
 
90
         char subscript[13];
 
91
 
 
92
         /* Append the subscript to the current uniform name */
 
93
         const unsigned subscript_length = snprintf(subscript, 13, "[%u]", i);
 
94
         ralloc_asprintf_rewrite_tail(name, name_length, "%s", subscript);
 
95
 
 
96
         recursion(t->fields.array, name, name_length + subscript_length);
 
97
      }
 
98
   } else {
 
99
      this->visit_field(t, *name);
 
100
   }
 
101
}
 
102
 
 
103
/**
 
104
 * Class to help calculate the storage requirements for a set of uniforms
 
105
 *
 
106
 * As uniforms are added to the active set the number of active uniforms and
 
107
 * the storage requirements for those uniforms are accumulated.  The active
 
108
 * uniforms are added the the hash table supplied to the constructor.
 
109
 *
 
110
 * If the same uniform is added multiple times (i.e., once for each shader
 
111
 * target), it will only be accounted once.
 
112
 */
 
113
class count_uniform_size : public uniform_field_visitor {
 
114
public:
 
115
   count_uniform_size(struct string_to_uint_map *map)
 
116
      : num_active_uniforms(0), num_values(0), num_shader_samplers(0),
 
117
        num_shader_uniform_components(0), map(map)
 
118
   {
 
119
      /* empty */
 
120
   }
 
121
 
 
122
   void start_shader()
 
123
   {
 
124
      this->num_shader_samplers = 0;
 
125
      this->num_shader_uniform_components = 0;
 
126
   }
 
127
 
 
128
   /**
 
129
    * Total number of active uniforms counted
 
130
    */
 
131
   unsigned num_active_uniforms;
 
132
 
 
133
   /**
 
134
    * Number of data values required to back the storage for the active uniforms
 
135
    */
 
136
   unsigned num_values;
 
137
 
 
138
   /**
 
139
    * Number of samplers used
 
140
    */
 
141
   unsigned num_shader_samplers;
 
142
 
 
143
   /**
 
144
    * Number of uniforms used in the current shader
 
145
    */
 
146
   unsigned num_shader_uniform_components;
 
147
 
 
148
private:
 
149
   virtual void visit_field(const glsl_type *type, const char *name)
 
150
   {
 
151
      assert(!type->is_record());
 
152
      assert(!(type->is_array() && type->fields.array->is_record()));
 
153
 
 
154
      /* Count the number of samplers regardless of whether the uniform is
 
155
       * already in the hash table.  The hash table prevents adding the same
 
156
       * uniform for multiple shader targets, but in this case we want to
 
157
       * count it for each shader target.
 
158
       */
 
159
      const unsigned values = values_for_type(type);
 
160
      if (type->contains_sampler()) {
 
161
         this->num_shader_samplers +=
 
162
            type->is_array() ? type->array_size() : 1;
 
163
      } else {
 
164
         /* Accumulate the total number of uniform slots used by this shader.
 
165
          * Note that samplers do not count against this limit because they
 
166
          * don't use any storage on current hardware.
 
167
          */
 
168
         this->num_shader_uniform_components += values;
 
169
      }
 
170
 
 
171
      /* If the uniform is already in the map, there's nothing more to do.
 
172
       */
 
173
      unsigned id;
 
174
      if (this->map->get(id, name))
 
175
         return;
 
176
 
 
177
      char *key = strdup(name);
 
178
      this->map->put(this->num_active_uniforms, key);
 
179
 
 
180
      /* Each leaf uniform occupies one entry in the list of active
 
181
       * uniforms.
 
182
       */
 
183
      this->num_active_uniforms++;
 
184
      this->num_values += values;
 
185
   }
 
186
 
 
187
   struct string_to_uint_map *map;
 
188
};
 
189
 
 
190
/**
 
191
 * Class to help parcel out pieces of backing storage to uniforms
 
192
 *
 
193
 * Each uniform processed has some range of the \c gl_constant_value
 
194
 * structures associated with it.  The association is done by finding
 
195
 * the uniform in the \c string_to_uint_map and using the value from
 
196
 * the map to connect that slot in the \c gl_uniform_storage table
 
197
 * with the next available slot in the \c gl_constant_value array.
 
198
 *
 
199
 * \warning
 
200
 * This class assumes that every uniform that will be processed is
 
201
 * already in the \c string_to_uint_map.  In addition, it assumes that
 
202
 * the \c gl_uniform_storage and \c gl_constant_value arrays are "big
 
203
 * enough."
 
204
 */
 
205
class parcel_out_uniform_storage : public uniform_field_visitor {
 
206
public:
 
207
   parcel_out_uniform_storage(struct string_to_uint_map *map,
 
208
                              struct gl_uniform_storage *uniforms,
 
209
                              union gl_constant_value *values)
 
210
      : map(map), uniforms(uniforms), next_sampler(0), values(values)
 
211
   {
 
212
      memset(this->targets, 0, sizeof(this->targets));
 
213
   }
 
214
 
 
215
   void start_shader()
 
216
   {
 
217
      this->shader_samplers_used = 0;
 
218
      this->shader_shadow_samplers = 0;
 
219
   }
 
220
 
 
221
private:
 
222
   virtual void visit_field(const glsl_type *type, const char *name)
 
223
   {
 
224
      assert(!type->is_record());
 
225
      assert(!(type->is_array() && type->fields.array->is_record()));
 
226
 
 
227
      unsigned id;
 
228
      bool found = this->map->get(id, name);
 
229
      assert(found);
 
230
 
 
231
      if (!found)
 
232
         return;
 
233
 
 
234
      /* If there is already storage associated with this uniform, it means
 
235
       * that it was set while processing an earlier shader stage.  For
 
236
       * example, we may be processing the uniform in the fragment shader, but
 
237
       * the uniform was already processed in the vertex shader.
 
238
       */
 
239
      if (this->uniforms[id].storage != NULL) {
 
240
         /* If the uniform already has storage set from another shader stage,
 
241
          * mark the samplers used for this shader stage.
 
242
          */
 
243
         if (type->contains_sampler()) {
 
244
            const unsigned count = MAX2(1, this->uniforms[id].array_elements);
 
245
            const unsigned shadow = (type->is_array())
 
246
               ? type->fields.array->sampler_shadow : type->sampler_shadow;
 
247
 
 
248
            for (unsigned i = 0; i < count; i++) {
 
249
               const unsigned s = this->uniforms[id].sampler + i;
 
250
 
 
251
               this->shader_samplers_used |= 1U << s;
 
252
               this->shader_shadow_samplers |= shadow << s;
 
253
            }
 
254
         }
 
255
 
 
256
         return;
 
257
      }
 
258
 
 
259
      const glsl_type *base_type;
 
260
      if (type->is_array()) {
 
261
         this->uniforms[id].array_elements = type->length;
 
262
         base_type = type->fields.array;
 
263
      } else {
 
264
         this->uniforms[id].array_elements = 0;
 
265
         base_type = type;
 
266
      }
 
267
 
 
268
      if (base_type->is_sampler()) {
 
269
         this->uniforms[id].sampler = this->next_sampler;
 
270
 
 
271
         /* Increment the sampler by 1 for non-arrays and by the number of
 
272
          * array elements for arrays.
 
273
          */
 
274
         this->next_sampler += MAX2(1, this->uniforms[id].array_elements);
 
275
 
 
276
         const gl_texture_index target = base_type->sampler_index();
 
277
         const unsigned shadow = base_type->sampler_shadow;
 
278
         for (unsigned i = this->uniforms[id].sampler
 
279
                 ; i < this->next_sampler
 
280
                 ; i++) {
 
281
            this->targets[i] = target;
 
282
            this->shader_samplers_used |= 1U << i;
 
283
            this->shader_shadow_samplers |= shadow << i;
 
284
         }
 
285
 
 
286
      } else {
 
287
         this->uniforms[id].sampler = ~0;
 
288
      }
 
289
 
 
290
      this->uniforms[id].name = ralloc_strdup(this->uniforms, name);
 
291
      this->uniforms[id].type = base_type;
 
292
      this->uniforms[id].initialized = 0;
 
293
      this->uniforms[id].num_driver_storage = 0;
 
294
      this->uniforms[id].driver_storage = NULL;
 
295
      this->uniforms[id].storage = this->values;
 
296
 
 
297
      this->values += values_for_type(type);
 
298
   }
 
299
 
 
300
   struct string_to_uint_map *map;
 
301
 
 
302
   struct gl_uniform_storage *uniforms;
 
303
   unsigned next_sampler;
 
304
 
 
305
public:
 
306
   union gl_constant_value *values;
 
307
 
 
308
   gl_texture_index targets[MAX_SAMPLERS];
 
309
 
 
310
   /**
 
311
    * Mask of samplers used by the current shader stage.
 
312
    */
 
313
   unsigned shader_samplers_used;
 
314
 
 
315
   /**
 
316
    * Mask of samplers used by the current shader stage for shadows.
 
317
    */
 
318
   unsigned shader_shadow_samplers;
 
319
};
 
320
 
 
321
void
 
322
link_assign_uniform_locations(struct gl_shader_program *prog)
 
323
{
 
324
   ralloc_free(prog->UniformStorage);
 
325
   prog->UniformStorage = NULL;
 
326
   prog->NumUserUniformStorage = 0;
 
327
 
 
328
   if (prog->UniformHash != NULL) {
 
329
      prog->UniformHash->clear();
 
330
   } else {
 
331
      prog->UniformHash = new string_to_uint_map;
 
332
   }
 
333
 
 
334
   for (unsigned i = 0; i < Elements(prog->SamplerUnits); i++) {
 
335
      prog->SamplerUnits[i] = i;
 
336
   }
 
337
 
 
338
   /* First pass: Count the uniform resources used by the user-defined
 
339
    * uniforms.  While this happens, each active uniform will have an index
 
340
    * assigned to it.
 
341
    *
 
342
    * Note: this is *NOT* the index that is returned to the application by
 
343
    * glGetUniformLocation.
 
344
    */
 
345
   count_uniform_size uniform_size(prog->UniformHash);
 
346
   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
 
347
      if (prog->_LinkedShaders[i] == NULL)
 
348
         continue;
 
349
 
 
350
      /* Reset various per-shader target counts.
 
351
       */
 
352
      uniform_size.start_shader();
 
353
 
 
354
      foreach_list(node, prog->_LinkedShaders[i]->ir) {
 
355
         ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
356
 
 
357
         if ((var == NULL) || (var->mode != ir_var_uniform))
 
358
            continue;
 
359
 
 
360
         /* FINISHME: Update code to process built-in uniforms!
 
361
          */
 
362
         if (strncmp("gl_", var->name, 3) == 0)
 
363
            continue;
 
364
 
 
365
         uniform_size.process(var);
 
366
      }
 
367
 
 
368
      prog->_LinkedShaders[i]->num_samplers = uniform_size.num_shader_samplers;
 
369
      prog->_LinkedShaders[i]->num_uniform_components =
 
370
         uniform_size.num_shader_uniform_components;
 
371
   }
 
372
 
 
373
   const unsigned num_user_uniforms = uniform_size.num_active_uniforms;
 
374
   const unsigned num_data_slots = uniform_size.num_values;
 
375
 
 
376
   /* On the outside chance that there were no uniforms, bail out.
 
377
    */
 
378
   if (num_user_uniforms == 0)
 
379
      return;
 
380
 
 
381
   struct gl_uniform_storage *uniforms =
 
382
      rzalloc_array(prog, struct gl_uniform_storage, num_user_uniforms);
 
383
   union gl_constant_value *data =
 
384
      rzalloc_array(uniforms, union gl_constant_value, num_data_slots);
 
385
#ifndef NDEBUG
 
386
   union gl_constant_value *data_end = &data[num_data_slots];
 
387
#endif
 
388
 
 
389
   parcel_out_uniform_storage parcel(prog->UniformHash, uniforms, data);
 
390
 
 
391
   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
 
392
      if (prog->_LinkedShaders[i] == NULL)
 
393
         continue;
 
394
 
 
395
      /* Reset various per-shader target counts.
 
396
       */
 
397
      parcel.start_shader();
 
398
 
 
399
      foreach_list(node, prog->_LinkedShaders[i]->ir) {
 
400
         ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
401
 
 
402
         if ((var == NULL) || (var->mode != ir_var_uniform))
 
403
            continue;
 
404
 
 
405
         /* FINISHME: Update code to process built-in uniforms!
 
406
          */
 
407
         if (strncmp("gl_", var->name, 3) == 0)
 
408
            continue;
 
409
 
 
410
         parcel.process(var);
 
411
      }
 
412
 
 
413
      prog->_LinkedShaders[i]->active_samplers = parcel.shader_samplers_used;
 
414
      prog->_LinkedShaders[i]->shadow_samplers = parcel.shader_shadow_samplers;
 
415
   }
 
416
 
 
417
   assert(sizeof(prog->SamplerTargets) == sizeof(parcel.targets));
 
418
   memcpy(prog->SamplerTargets, parcel.targets, sizeof(prog->SamplerTargets));
 
419
 
 
420
#ifndef NDEBUG
 
421
   for (unsigned i = 0; i < num_user_uniforms; i++) {
 
422
      assert(uniforms[i].storage != NULL);
 
423
   }
 
424
 
 
425
   assert(parcel.values == data_end);
 
426
#endif
 
427
 
 
428
   prog->NumUserUniformStorage = num_user_uniforms;
 
429
   prog->UniformStorage = uniforms;
 
430
 
 
431
   return;
 
432
}