Example #1
0
void
glsl_print_type(const glsl_type *type, FILE *fp)
{
   if (type->base_type == GLSL_TYPE_ARRAY) {
      glsl_print_type(type->fields.array, fp);
      fprintf(fp, "[%u]", type->length);
   } else if ((type->base_type == GLSL_TYPE_STRUCT)
              && !is_gl_identifier(type->name)) {
      fprintf(fp, "%s@%p", type->name, (void *) type);
   } else {
      fprintf(fp, "%s", type->name);
   }
}
Example #2
0
static bool
validate_io(struct gl_shader_program *producer,
            struct gl_shader_program *consumer)
{
   if (producer == consumer)
      return true;

   bool valid = true;

   gl_shader_variable const **outputs =
      (gl_shader_variable const **) calloc(producer->NumProgramResourceList,
                                           sizeof(gl_shader_variable *));
   if (outputs == NULL)
      return false;

   /* Section 7.4.1 (Shader Interface Matching) of the OpenGL ES 3.1 spec
    * says:
    *
    *    At an interface between program objects, the set of inputs and
    *    outputs are considered to match exactly if and only if:
    *
    *    - Every declared input variable has a matching output, as described
    *      above.
    *    - There are no user-defined output variables declared without a
    *      matching input variable declaration.
    *
    * Every input has an output, and every output has an input.  Scan the list
    * of producer resources once, and generate the list of outputs.  As inputs
    * and outputs are matched, remove the matched outputs from the set.  At
    * the end, the set must be empty.  If the set is not empty, then there is
    * some output that did not have an input.
    */
   unsigned num_outputs = 0;
   for (unsigned i = 0; i < producer->NumProgramResourceList; i++) {
      struct gl_program_resource *res = &producer->ProgramResourceList[i];

      if (res->Type != GL_PROGRAM_OUTPUT)
         continue;

      gl_shader_variable const *const var = RESOURCE_VAR(res);

      /* Section 7.4.1 (Shader Interface Matching) of the OpenGL ES 3.1 spec
       * says:
       *
       *    Built-in inputs or outputs do not affect interface matching.
       */
      if (is_gl_identifier(var->name))
         continue;

      outputs[num_outputs++] = var;
   }

   unsigned match_index = 0;
   for (unsigned i = 0; i < consumer->NumProgramResourceList; i++) {
      struct gl_program_resource *res = &consumer->ProgramResourceList[i];

      if (res->Type != GL_PROGRAM_INPUT)
         continue;

      gl_shader_variable const *const consumer_var = RESOURCE_VAR(res);
      gl_shader_variable const *producer_var = NULL;

      if (is_gl_identifier(consumer_var->name))
         continue;

      /* Inputs with explicit locations match other outputs with explicit
       * locations by location instead of by name.
       */
      if (consumer_var->explicit_location) {
         for (unsigned j = 0; j < num_outputs; j++) {
            const gl_shader_variable *const var = outputs[j];

            if (var->explicit_location &&
                consumer_var->location == var->location) {
               producer_var = var;
               match_index = j;
               break;
            }
         }
      } else {
         for (unsigned j = 0; j < num_outputs; j++) {
            const gl_shader_variable *const var = outputs[j];

            if (!var->explicit_location &&
                strcmp(consumer_var->name, var->name) == 0) {
               producer_var = var;
               match_index = j;
               break;
            }
         }
      }

      /* Section 7.4.1 (Shader Interface Matching) of the OpenGL ES 3.1 spec
       * says:
       *
       *    - An output variable is considered to match an input variable in
       *      the subsequent shader if:
       *
       *      - the two variables match in name, type, and qualification; or
       *
       *      - the two variables are declared with the same location
       *        qualifier and match in type and qualification.
       */
      if (producer_var == NULL) {
         valid = false;
         goto out;
      }

      /* An output cannot match more than one input, so remove the output from
       * the set of possible outputs.
       */
      outputs[match_index] = NULL;
      num_outputs--;
      if (match_index < num_outputs)
         outputs[match_index] = outputs[num_outputs];

      /* Section 9.2.2 (Separable Programs) of the GLSL ES spec says:
       *
       *    Qualifier Class|  Qualifier  |in/out
       *    ---------------+-------------+------
       *    Storage        |     in      |
       *                   |     out     |  N/A
       *                   |   uniform   |
       *    ---------------+-------------+------
       *    Auxiliary      |   centroid  |   No
       *    ---------------+-------------+------
       *                   |   location  |  Yes
       *                   | Block layout|  N/A
       *                   |   binding   |  N/A
       *                   |   offset    |  N/A
       *                   |   format    |  N/A
       *    ---------------+-------------+------
       *    Interpolation  |   smooth    |
       *                   |    flat     |  Yes
       *    ---------------+-------------+------
       *                   |    lowp     |
       *    Precision      |   mediump   |  Yes
       *                   |    highp    |
       *    ---------------+-------------+------
       *    Variance       |  invariant  |   No
       *    ---------------+-------------+------
       *    Memory         |     all     |  N/A
       *
       * Note that location mismatches are detected by the loops above that
       * find the producer variable that goes with the consumer variable.
       */
      if (producer_var->type != consumer_var->type ||
          producer_var->interpolation != consumer_var->interpolation ||
          producer_var->precision != consumer_var->precision) {
         valid = false;
         goto out;
      }

      if (producer_var->outermost_struct_type != consumer_var->outermost_struct_type) {
         valid = false;
         goto out;
      }

      if (producer_var->interface_type != consumer_var->interface_type) {
         valid = false;
         goto out;
      }
   }

 out:
   free(outputs);
   return valid && num_outputs == 0;
}
Example #3
0
    virtual void visit_field(const glsl_type *type, const char *name,
                             bool row_major, const glsl_type *record_type,
                             bool /* last_field */)
    {
        assert(!type->without_array()->is_record());
        assert(!type->without_array()->is_interface());

        unsigned id;
        bool found = this->map->get(id, name);
        assert(found);

        if (!found)
            return;

        const glsl_type *base_type;
        if (type->is_array()) {
            this->uniforms[id].array_elements = type->length;
            base_type = type->fields.array;
        } else {
            this->uniforms[id].array_elements = 0;
            base_type = type;
        }

        /* This assigns uniform indices to sampler and image uniforms. */
        handle_samplers(base_type, &this->uniforms[id]);
        handle_images(base_type, &this->uniforms[id]);
        handle_subroutines(base_type, &this->uniforms[id]);

        /* If there is already storage associated with this uniform or if the
         * uniform is set as builtin, it means that it was set while processing
         * an earlier shader stage.  For example, we may be processing the
         * uniform in the fragment shader, but the uniform was already processed
         * in the vertex shader.
         */
        if (this->uniforms[id].storage != NULL || this->uniforms[id].builtin) {
            return;
        }

        /* Assign explicit locations. */
        if (current_var->data.explicit_location) {
            /* Set sequential locations for struct fields. */
            if (record_type != NULL) {
                const unsigned entries = MAX2(1, this->uniforms[id].array_elements);
                this->uniforms[id].remap_location =
                    current_var->data.location + field_counter;
                field_counter += entries;
            } else {
                this->uniforms[id].remap_location = current_var->data.location;
            }
        } else {
            /* Initialize to to indicate that no location is set */
            this->uniforms[id].remap_location = UNMAPPED_UNIFORM_LOC;
        }

        this->uniforms[id].name = ralloc_strdup(this->uniforms, name);
        this->uniforms[id].type = base_type;
        this->uniforms[id].initialized = 0;
        this->uniforms[id].num_driver_storage = 0;
        this->uniforms[id].driver_storage = NULL;
        this->uniforms[id].atomic_buffer_index = -1;
        this->uniforms[id].hidden =
            current_var->data.how_declared == ir_var_hidden;
        this->uniforms[id].builtin = is_gl_identifier(name);

        /* Do not assign storage if the uniform is builtin */
        if (!this->uniforms[id].builtin)
            this->uniforms[id].storage = this->values;

        if (this->ubo_block_index != -1) {
            this->uniforms[id].block_index = this->ubo_block_index;

            const unsigned alignment = type->std140_base_alignment(row_major);
            this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment);
            this->uniforms[id].offset = this->ubo_byte_offset;
            this->ubo_byte_offset += type->std140_size(row_major);

            if (type->is_array()) {
                this->uniforms[id].array_stride =
                    glsl_align(type->fields.array->std140_size(row_major), 16);
            } else {
                this->uniforms[id].array_stride = 0;
            }

            if (type->without_array()->is_matrix()) {
                const glsl_type *matrix = type->without_array();
                const unsigned N = matrix->base_type == GLSL_TYPE_DOUBLE ? 8 : 4;
                const unsigned items = row_major ? matrix->matrix_columns : matrix->vector_elements;

                assert(items <= 4);
                this->uniforms[id].matrix_stride = glsl_align(items * N, 16);
                this->uniforms[id].row_major = row_major;
            } else {
                this->uniforms[id].matrix_stride = 0;
                this->uniforms[id].row_major = false;
            }
        } else {
            this->uniforms[id].block_index = -1;
            this->uniforms[id].offset = -1;
            this->uniforms[id].array_stride = -1;
            this->uniforms[id].matrix_stride = -1;
            this->uniforms[id].row_major = false;
        }

        this->values += values_for_type(type);
    }
Example #4
0
static GLint
program_resource_location(struct gl_shader_program *shProg,
                          struct gl_program_resource *res, const char *name,
                          unsigned array_index)
{
   /* Built-in locations should report GL_INVALID_INDEX. */
   if (is_gl_identifier(name))
      return GL_INVALID_INDEX;

   /* VERT_ATTRIB_GENERIC0 and FRAG_RESULT_DATA0 are decremented as these
    * offsets are used internally to differentiate between built-in attributes
    * and user-defined attributes.
    */
   switch (res->Type) {
   case GL_PROGRAM_INPUT:
      /* If the input is an array, fail if the index is out of bounds. */
      if (array_index > 0
          && array_index >= RESOURCE_VAR(res)->type->length) {
         return -1;
      }
      return RESOURCE_VAR(res)->data.location + array_index - VERT_ATTRIB_GENERIC0;
   case GL_PROGRAM_OUTPUT:
      /* If the output is an array, fail if the index is out of bounds. */
      if (array_index > 0
          && array_index >= RESOURCE_VAR(res)->type->length) {
         return -1;
      }
      return RESOURCE_VAR(res)->data.location + array_index - FRAG_RESULT_DATA0;
   case GL_UNIFORM:
      /* If the uniform is built-in, fail. */
      if (RESOURCE_UNI(res)->builtin)
         return -1;

     /* From page 79 of the OpenGL 4.2 spec:
      *
      *     "A valid name cannot be a structure, an array of structures, or any
      *     portion of a single vector or a matrix."
      */
      if (RESOURCE_UNI(res)->type->without_array()->is_record())
         return -1;

      /* From the GL_ARB_uniform_buffer_object spec:
       *
       *     "The value -1 will be returned if <name> does not correspond to an
       *     active uniform variable name in <program>, if <name> is associated
       *     with a named uniform block, or if <name> starts with the reserved
       *     prefix "gl_"."
       */
      if (RESOURCE_UNI(res)->block_index != -1 ||
          RESOURCE_UNI(res)->atomic_buffer_index != -1)
         return -1;

      /* fallthrough */
   case GL_VERTEX_SUBROUTINE_UNIFORM:
   case GL_GEOMETRY_SUBROUTINE_UNIFORM:
   case GL_FRAGMENT_SUBROUTINE_UNIFORM:
   case GL_COMPUTE_SUBROUTINE_UNIFORM:
   case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
   case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
      /* If the uniform is an array, fail if the index is out of bounds. */
      if (array_index > 0
          && array_index >= RESOURCE_UNI(res)->array_elements) {
         return -1;
      }

      /* location in remap table + array element offset */
      return RESOURCE_UNI(res)->remap_location + array_index;
   default:
      return -1;
   }
}