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); } }
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; }
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); }
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; } }