[Mesa-dev] [PATCH v2 13/15] glsl linker: support arrays of interface block instances

Kenneth Graunke kenneth at whitecape.org
Sat Mar 23 13:48:44 PDT 2013


On 03/19/2013 03:57 AM, Pohjolainen, Topi wrote:
> On Mon, Mar 18, 2013 at 04:35:10PM -0700, Jordan Justen wrote:
>> With this change we now support interface block arrays.
>> For example, cases like this:
>>
>> out block_name {
>>      float f;
>> } block_instance[2];
>>
>> This allows Mesa to pass the piglit glsl-1.50 test:
>> * execution/interface-blocks-complex-vs-fs.shader_test
>>
>> Signed-off-by: Jordan Justen <jordan.l.justen at intel.com>
>> ---
>>   src/glsl/lower_named_interface_blocks.cpp |   53 ++++++++++++++++++++++++-----
>>   1 file changed, 44 insertions(+), 9 deletions(-)
>>
>> diff --git a/src/glsl/lower_named_interface_blocks.cpp b/src/glsl/lower_named_interface_blocks.cpp
>> index 2e0c322..405e7a9 100644
>> --- a/src/glsl/lower_named_interface_blocks.cpp
>> +++ b/src/glsl/lower_named_interface_blocks.cpp
>> @@ -107,22 +107,47 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions)
>>            if (var->mode == ir_var_uniform)
>>               continue;
>>
>> -         const glsl_type *const t = var->type;
>> +         const glsl_type * iface_t = var->type;
>> +         const glsl_type * array_t = NULL;
>>            exec_node *insert_pos = var;
>> -         char *iface_field_name;
>> -         for (unsigned i = 0; i < t->length; i++) {
>> -            iface_field_name = ralloc_asprintf(mem_ctx, "%s.%s", t->name,
>> -                                               t->fields.structure[i].name);
>> +
>> +         if (iface_t->is_array()) {
>> +            array_t = iface_t;
>> +            iface_t = array_t->fields.array;
>> +         }
>> +
>> +         assert (iface_t->is_interface());
>> +
>> +         for (unsigned i = 0; i < iface_t->length; i++) {
>> +            const char * field_name = iface_t->fields.structure[i].name;
>> +            char *iface_field_name =
>> +               ralloc_asprintf(mem_ctx, "%s.%s",
>> +                               iface_t->name, field_name);
>>
>>               ir_variable *found_var =
>>                  (ir_variable *) hash_table_find(interface_namespace,
>>                                                  iface_field_name);
>>               if (!found_var) {
>>                  ir_variable *new_var =
>> -                  new(mem_ctx) ir_variable(t->fields.structure[i].type,
>> -                                           ralloc_strdup(mem_ctx, t->fields.structure[i].name),
>> +                  new(mem_ctx) ir_variable(iface_t->fields.structure[i].type,
>> +                                           ralloc_strdup(mem_ctx, iface_t->fields.structure[i].name),
>>                                              (ir_variable_mode) var->mode);
>> -               new_var->interface_type = t;
>> +               if (array_t != NULL) {
>> +                  const glsl_type *new_array_type =
>> +                     glsl_type::get_array_instance(
>> +                        iface_t->fields.structure[i].type,
>> +                        array_t->length);
>> +                  char *array_var_name =
>> +                     ralloc_asprintf(mem_ctx, "%s[%d]",
>> +                                     new_var->name, array_t->length);
>> +                  ir_variable *new_array_var =
>> +                     new(mem_ctx) ir_variable(new_array_type,
>> +                                              array_var_name,
>> +                                              (ir_variable_mode) var->mode);
>> +                  new_var = new_array_var;
>
> Don't you leak the previously allocated instance of 'ir_variable' (assigned to
> 'new_var')? Or is it just left until 'mem_ctx' gets released?
> I'm not that familiar with the glsl core that I may well be missing something.

This is actually fairly common in the GLSL code - we routinely just drop 
allocated memory on the floor.  But, it all works out thanks to the 
magic of talloc/ralloc(*).

With talloc, you allocate memory out af a 'context'.  Freeing a context 
frees any memory associated with it, which means you can free a whole 
bunch of things without tracking them all down and calling free() on 
each individual pointer.  It also means you don't need to explicitly 
keep pointers to each object, as the memory context does that for you.

Any talloced piece of memory is also a new context, which allows you to 
create a tree-like structure (the 't' in talloc is for 'tree', and the 
'r' in ralloc is for 'recursive').

In the GLSL compiler, we allocate IR out of either the parser state or 
the gl_shader object (I forget which).  During optimization, linking, 
and so on, we create new IR, and remove other IR, all without worrying 
about memory.  Then, when we're done compiling/linking, we walk through 
the remaining IR tree, calling talloc_steal() on each remaining IR node 
to reparent the memory to a second memory context.  Then we free the 
original memory context, which now contains only the junk we don't need 
anymore.

(*) ralloc is my poor man's reimplementation of talloc, licensed under 
the MIT license rather than LGPLv3.  It also has a slightly different 
API and performance characteristics.


More information about the mesa-dev mailing list