[Mesa-dev] [PATCH 3/4] linker: Add uniform_field_visitor class to process leaf fields of a uniform

Kenneth Graunke kenneth at whitecape.org
Mon Oct 24 19:28:58 PDT 2011


On 10/24/2011 02:16 PM, Ian Romanick wrote:
> From: Ian Romanick <ian.d.romanick at intel.com>
> 
> Signed-off-by: Ian Romanick <ian.d.romanick at intel.com>
> ---
>  src/glsl/Makefile          |    1 +
>  src/glsl/link_uniforms.cpp |  116 ++++++++++++++++++++++++++++++++++++++++++++
>  src/glsl/linker.h          |   45 +++++++++++++++++
>  3 files changed, 162 insertions(+), 0 deletions(-)
>  create mode 100644 src/glsl/link_uniforms.cpp
> 
> diff --git a/src/glsl/Makefile b/src/glsl/Makefile
> index b2efb2a..504f1fb 100644
> --- a/src/glsl/Makefile
> +++ b/src/glsl/Makefile
> @@ -53,6 +53,7 @@ CXX_SOURCES = \
>  	ir_variable_refcount.cpp \
>  	linker.cpp \
>  	link_functions.cpp \
> +	link_uniforms.cpp \
>  	loop_analysis.cpp \
>  	loop_controls.cpp \
>  	loop_unroll.cpp \
> diff --git a/src/glsl/link_uniforms.cpp b/src/glsl/link_uniforms.cpp
> new file mode 100644
> index 0000000..38bc00c
> --- /dev/null
> +++ b/src/glsl/link_uniforms.cpp
> @@ -0,0 +1,116 @@
> +/*
> + * Copyright © 2011 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include "main/core.h"
> +#include "ir.h"
> +#include "linker.h"
> +#include "glsl_symbol_table.h"
> +#include "program/hash_table.h"
> +
> +/**
> + * \file link_uniforms.cpp
> + * Assign locations for GLSL uniforms.
> + *
> + * \author Ian Romanick <ian.d.romanick at intel.com>
> + */
> +
> +void uniform_field_visitor::process(ir_variable *var)
> +{
> +   char *name = const_cast<char *>(var->name);

I loathe const_cast<>---it's just evil.  I declare my variables const
for a reason, and I don't want people screwing them up.  Guess how fun
it is to debug issues caused by your supposedly const values changing
out from under you?

I see that you're trying to avoid a strdup in the common case, which is
good, but I'd prefer a less dirty solution.

> +   unsigned len = 0;
> +
> +   recursion(var->type, &name, strlen(name), len);
> +   if (name != var->name)
> +      free(name);
> +}
> +
> +void uniform_field_visitor::recursion(const glsl_type *t, char **name,
> +				      unsigned name_length,
> +				      unsigned &name_buffer_length)
> +{
> +   /* Records need to have each field processed individually.
> +    *
> +    * Arrays of records need to have each array element processed
> +    * individually, then each field of the resulting array elements processed
> +    * individually.
> +    */
> +   if (t->is_record()) {
> +      for (unsigned i = 0; i < t->length; i++) {
> +	 const unsigned len = strlen(t->fields.structure[i].name);
> +
> +	 /* Size of "name.field\0".
> +	  */
> +	 const unsigned field_length = name_length + 1 + len + 1;
> +
> +	 /* Grow the name buffer if it is not large enough to hold the fully
> +	  * qualified name of this field.
> +	  */
> +	 if (name_buffer_length < field_length) {
> +	    if (name_buffer_length == 0) {
> +	       name_buffer_length = field_length + 16;
> +	       char *tmp = (char *) malloc(name_buffer_length);
> +	       strcpy(tmp, *name);
> +
> +	       *name = tmp;
> +	    } else {
> +	       name_buffer_length = field_length + 16;
> +	       *name = (char *) realloc(*name, name_buffer_length);
> +	    }
> +	 }
> +
> +	 /* Append '.field' to the current uniform name.
> +	  */
> +	 (*name)[name_length] = '.';
> +	 memcpy(& (*name)[name_length+1], t->fields.structure[i].name, len);
> +	 (*name)[field_length - 1] = '\0';

Maybe it's just me, but I find this code rather impenetrable what with
all the buffer management and string munging.  mallocs, reallocs,
memcpys, strcpys, extra parameters, the magic constant + 16...

Yet, all it does is generate names such as
  some_struct.foo
  some_struct.bar
  some_struct.baz
and call a function for each of those.  That's really simple.

I understand that you're trying to avoid unnecessary strlen() calls, but
there has to be a better way.

I've added some new functionality to ralloc that should make this a lot
cleaner.  I'll send it out shortly.

> +	 recursion(t->fields.structure[i].type,
> +		   name, field_length - 1, name_buffer_length);
> +      }
> +   } else if (t->is_array() && t->fields.array->is_record()) {
> +      const unsigned extra = unsigned(ceil(log10(float(t->length)))) + 2;
> +      const unsigned field_length = name_length + extra;
> +
> +      if (name_buffer_length < field_length) {
> +	 if (name_buffer_length == 0) {
> +	    name_buffer_length = field_length + 16;
> +	    char *tmp = (char *) malloc(name_buffer_length);
> +	    strcpy(tmp, *name);
> +
> +	    *name = tmp;
> +	 } else {
> +	    name_buffer_length = field_length + 16;
> +	    *name = (char *) realloc(*name, name_buffer_length);
> +	 }
> +      }
> +
> +      for (unsigned i = 0; i < t->length; i++) {
> +	 const unsigned len = name_length
> +	    + sprintf(&(*name)[name_length], "[%d]", i);
> +
> +	 recursion(t->fields.array, name, len, name_buffer_length);
> +      }
> +   } else {
> +      this->visit_field(t, *name);
> +   }
> +}
> diff --git a/src/glsl/linker.h b/src/glsl/linker.h
> index 769cf68..2bd2b47 100644
> --- a/src/glsl/linker.h
> +++ b/src/glsl/linker.h
> @@ -1,3 +1,4 @@
> +/* -*- c++ -*- */
>  /*
>   * Copyright © 2010 Intel Corporation
>   *
> @@ -29,4 +30,48 @@ extern bool
>  link_function_calls(gl_shader_program *prog, gl_shader *main,
>  		    gl_shader **shader_list, unsigned num_shaders);
>  
> +
> +/**
> + * Class for processing all of the leaf fields of an uniform
> + *
> + * Leaves are, roughly speaking, the parts of the uniform that the application
> + * could query with \c glGetUniformLocation (or that could be returned by
> + * \c glGetActiveUniforms).
> + *
> + * Classes my derive from this class to implement specific functionality.
> + * This class only provides the mechanism to iterate over the leaves.  Derived
> + * classes must implement \c ::visit_field and may override \c ::process.
> + */
> +class uniform_field_visitor {
> +public:
> +   /**
> +    * Begin processing a uniform
> +    *
> +    * Classes that overload this function should call \c ::process from the
> +    * base class to start the recursive processing of the uniform.
> +    *
> +    * \param var  The uniform variable that is to be processed
> +    *
> +    * Calls \c ::visit_field for each leaf of the uniform.
> +    */
> +   void process(ir_variable *var);
> +
> +protected:
> +   /**
> +    * Method invoked for each leaf of the uniform
> +    *
> +    * \param type  Type of the field.
> +    * \param name  Fully qualified name of the field.
> +    */
> +   virtual void visit_field(const glsl_type *type, const char *name) = 0;
> +
> +private:
> +   /**
> +    * \param name_length  Length of the current name \b not including the
> +    *                     terminating \c NUL character.
> +    */
> +   void recursion(const glsl_type *t, char **name, unsigned name_length,
> +		  unsigned &name_buffer_length);
> +};
> +
>  #endif /* GLSL_LINKER_H */



More information about the mesa-dev mailing list